PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/bbb-voice/src/main/java/local/server/ServerEngine.java

https://github.com/dozeo/bigbluebutton
Java | 334 lines | 157 code | 48 blank | 129 comment | 36 complexity | 450c5df27531ab75b761b0c9af65da74 MD5 | raw file
  1. /*
  2. * Copyright (C) 2005 Luca Veltri - University of Parma - Italy
  3. *
  4. * This source code is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This source code is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this source code; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. *
  18. * Author(s):
  19. * Luca Veltri (luca.veltri@unipr.it)
  20. */
  21. package local.server;
  22. import org.zoolu.sip.address.SipURL;
  23. import org.zoolu.sip.provider.*;
  24. import org.zoolu.sip.header.MultipleHeader;
  25. import org.zoolu.sip.header.ViaHeader;
  26. import org.zoolu.sip.header.Header;
  27. import org.zoolu.sip.header.RouteHeader;
  28. import org.zoolu.sip.header.RequestLine;
  29. import org.zoolu.sip.header.MaxForwardsHeader;
  30. import org.zoolu.sip.header.MultipleHeader;
  31. import org.zoolu.sip.message.Message;
  32. import org.zoolu.sip.message.SipResponses;
  33. import org.zoolu.sip.message.MessageFactory;
  34. import org.zoolu.tools.Log;
  35. import org.zoolu.tools.LogLevel;
  36. import org.zoolu.tools.SimpleDigest;
  37. import java.util.Vector;
  38. /** Class ServerEngine implement a stateless abstract SIP Server.
  39. * The ServerEngine can act as SIP Proxy Server, SIP Registrar Server or both.
  40. * <p> For each incoming message, the ServerEngine fires one of the following
  41. * abstract methods:
  42. * <ul>
  43. * <li>public abstract processRequestToRemoteUA(Message),</li>
  44. * <li>public abstract processRequestToLocalServer(Message),</li>
  45. * <li>public abstract processRequestToLocalServer(Message),</li>
  46. * <li>public abstract processResponse(Message).</li>
  47. * </ul>
  48. * depending of the type of received message.
  49. */
  50. public abstract class ServerEngine implements SipProviderListener
  51. {
  52. /** Name of the Loop-Tag header field.
  53. * It is used as temporary filed for carry loop detection information,
  54. * added to the via branch parameter of the forwarded requests. */
  55. protected static final String Loop_Tag="Loop-Tag";
  56. /** Event logger. */
  57. protected Log log=null;
  58. /** ServerProfile of the server. */
  59. protected ServerProfile server_profile=null;
  60. /** SipProvider used by the server. */
  61. protected SipProvider sip_provider=null;
  62. /** Costructs a void ServerEngine */
  63. protected ServerEngine() {}
  64. // *************************** abstract methods ***************************
  65. /** When a new request message is received for a remote UA */
  66. public abstract void processRequestToRemoteUA(Message req);
  67. /** When a new request message is received for a locally registered user */
  68. public abstract void processRequestToLocalUser(Message req);
  69. /** When a new request request is received for the local server */
  70. public abstract void processRequestToLocalServer(Message req);
  71. /** When a new response message is received */
  72. public abstract void processResponse(Message resp);
  73. // **************************** public methods ****************************
  74. /** Costructs a new ServerEngine on SipProvider <i>provider</i>,
  75. * and adds it as SipProviderListener. */
  76. public ServerEngine(SipProvider provider, ServerProfile profile)
  77. { server_profile=profile;
  78. sip_provider=provider;
  79. log=sip_provider.getLog();
  80. sip_provider.addSipProviderListener(SipProvider.ANY,this);
  81. }
  82. /** When a new message is received by the SipProvider.
  83. * If the received message is a request, it cheks for loops, */
  84. public void onReceivedMessage(SipProvider provider, Message msg)
  85. { printLog("message received",LogLevel.MEDIUM);
  86. if (msg.isRequest()) // it is an INVITE or ACK or BYE or OPTIONS or REGISTER or CANCEL
  87. { printLog("message is a request",LogLevel.MEDIUM);
  88. // validate the message
  89. Message err_resp=validateRequest(msg);
  90. if (err_resp!=null)
  91. { // for non-ACK requests respond with an error message
  92. if (!msg.isAck()) sip_provider.sendMessage(err_resp);
  93. return;
  94. }
  95. // target
  96. SipURL target=msg.getRequestLine().getAddress();
  97. // check if this server is the target
  98. //boolean this_is_target=isResponsibleFor(target.getHost(),target.getPort());
  99. // look if the msg sent by the previous UA is compliant with the RFC2543 Strict Route rule..
  100. if (isResponsibleFor(target.getHost(),target.getPort()) && msg.hasRouteHeader())
  101. {
  102. //SipURL route_url=msg.getRouteHeader().getNameAddress().getAddress();
  103. SipURL route_url=(new RouteHeader(msg.getRoutes().getBottom())).getNameAddress().getAddress();
  104. if (!route_url.hasLr())
  105. { printLog("probably the message was compliant to RFC2543 Strict Route rule: message is updated to RFC3261",LogLevel.MEDIUM);
  106. // the message has been sent to this server according with RFC2543 Strict Route
  107. // the proxy MUST replace the Request-URI in the request with the last
  108. // value from the Route header field, and remove that value from the
  109. // Route header field. The proxy MUST then proceed as if it received
  110. // this modified request.
  111. msg.rfc2543toRfc3261RouteUpdate();
  112. // update the target
  113. target=msg.getRequestLine().getAddress();
  114. printLog("new recipient: "+target.toString(),LogLevel.LOW);
  115. // check again if this server is the target
  116. //this_is_target=matchesDomainName(target.getHost(),target.getPort());
  117. }
  118. }
  119. // removes the local Route value, if present
  120. /*if (msg.hasRouteHeader())
  121. { MultipleHeader mr=msg.getRoutes();
  122. SipURL top_route=(new RouteHeader(mr.getTop())).getNameAddress().getAddress();
  123. if (matchesDomainName(top_route.getHost(),top_route.getPort()))
  124. { mr.removeTop();
  125. if (mr.size()>0) msg.setRoutes(mr);
  126. else msg.removeRoutes();
  127. }
  128. }*/
  129. // check whether the request is for a domain the server is responsible for
  130. if (isResponsibleFor(msg))
  131. {
  132. printLog("the request is for the local server",LogLevel.LOW);
  133. if (target.hasUserName())
  134. { printLog("the request is for a local user",LogLevel.LOW);
  135. processRequestToLocalUser(msg);
  136. }
  137. else
  138. { printLog("no username: the request is for the local server",LogLevel.LOW);
  139. processRequestToLocalServer(msg);
  140. }
  141. }
  142. else // the request is NOT for the "local" server
  143. {
  144. printLog("the request is not for the local server",LogLevel.LOW);
  145. processRequestToRemoteUA(msg);
  146. }
  147. }
  148. else // the message may be a response
  149. {
  150. if (msg.isResponse())
  151. { printLog("message is a response",LogLevel.LOW);
  152. processResponse(msg);
  153. }
  154. else printWarning("received message is not recognized as a request nor a response: discarded",LogLevel.HIGH);
  155. }
  156. }
  157. /** Relays the massage.
  158. * Called after a received message has been successful processed for being relayed */
  159. //protected void sendMessage(Message msg)
  160. //{ printLog("sending the successfully processed message",LogLevel.MEDIUM);
  161. // sip_provider.sendMessage(msg);
  162. //}
  163. /** Whether the server is responsible for the given <i>domain</i>
  164. * (i.e. the <i>domain</i> is included in the local domain names list)
  165. * and <i>port</i> (if >0) matches the local server port. */
  166. protected boolean isResponsibleFor(String domain, int port)
  167. { // check port
  168. if (!server_profile.domain_port_any && port>0 && port!=sip_provider.getPort()) return false;
  169. // check host address
  170. if (domain.equals(sip_provider.getViaAddress())) return true;
  171. // check domain name
  172. boolean it_is=false;
  173. for (int i=0; i<server_profile.domain_names.length; i++)
  174. { if (server_profile.domain_names[i].equals(domain)) { it_is=true; break; }
  175. }
  176. return it_is;
  177. }
  178. /** Whether the server is responsible for the request-uri of the request <i>req</i>. */
  179. protected boolean isResponsibleFor(Message req)
  180. { SipURL target=req.getRequestLine().getAddress();
  181. return isResponsibleFor(target.getHost(),target.getPort());
  182. }
  183. /** Whether the request is for the local server */
  184. /*protected boolean isTargetOf(Message req)
  185. { SipURL target=req.getRequestLine().getAddress();
  186. if (!isResponsibleFor(target.getHost(),target.getPort())) return false;
  187. // else, request-uri matches a domain the server is responsible for
  188. if (!req.hasRouteHeader()) return true;
  189. // else, has route..
  190. MultipleHeader route=req.getRoutes();
  191. if (route.size()>1) return false;
  192. // else, only 1 route, check it
  193. target=(new RouteHeader(route.getTop())).getNameAddress().getAddress();
  194. if (!isResponsibleFor(target.getHost(),target.getPort())) return false;
  195. // else
  196. return true;
  197. }*/
  198. /** Gets a String of the list of local domain names. */
  199. protected String getLocalDomains()
  200. { if (server_profile.domain_names.length>0)
  201. { String str="";
  202. for (int i=0; i<server_profile.domain_names.length-1; i++)
  203. { str+=server_profile.domain_names[i]+", ";
  204. }
  205. return str+server_profile.domain_names[server_profile.domain_names.length-1];
  206. }
  207. else return "";
  208. }
  209. /** Validates the message.
  210. * @return It returns 0 if the message validation successes, otherwise return the error code. */
  211. protected Message validateRequest(Message msg)
  212. { printLog("inside validateRequest(msg)",LogLevel.LOW);
  213. int err_code=0;
  214. // Max-Forwads
  215. if (err_code==0)
  216. { MaxForwardsHeader mfh=msg.getMaxForwardsHeader();
  217. if (mfh!=null && mfh.getNumber()==0) err_code=483;
  218. }
  219. // Loops
  220. // Insert also a temporary Loop-Tag header field in order to correctly compose
  221. // the branch field when forwarding the message.
  222. // This behaviour has been choosen since the message validation is done
  223. // when receiving the message while the information used for loop detection
  224. // (the branch parameter) is calculated and added when sending the message.
  225. // Note that the RFC suggests to calculate the branch parameter based on
  226. // the original request-uri, but the request-uri has been already replaced
  227. // and forgotten when processing the message for calculating the branch! ;)
  228. if (err_code==0 && server_profile.loop_detection)
  229. { String loop_tag=pickLoopTag(msg);
  230. // add temporary Loop-Tag header field
  231. msg.setHeader(new Header(Loop_Tag,loop_tag));
  232. // check for loop
  233. if (!msg.hasRouteHeader())
  234. { Vector v=msg.getVias().getHeaders();
  235. for (int i=0; i<v.size(); i++)
  236. { ViaHeader vh=new ViaHeader((Header)v.elementAt(i));
  237. if (sip_provider.getViaAddress().equals(vh.getHost()) && sip_provider.getPort()==vh.getPort())
  238. { // possible loop
  239. if (!vh.hasBranch()) err_code=482;
  240. else
  241. { // check branch
  242. String branch=vh.getBranch();
  243. if (branch.indexOf(loop_tag,branch.length()-loop_tag.length())>=0) err_code=482;
  244. }
  245. }
  246. }
  247. }
  248. }
  249. // Proxy-Require
  250. // Proxy-Authorization
  251. if (err_code>0)
  252. { String reason=SipResponses.reasonOf(err_code);
  253. printLog("Message validation failed ("+reason+"), message discarded",LogLevel.HIGH);
  254. return MessageFactory.createResponse(msg,err_code,reason,null);
  255. }
  256. else return null;
  257. }
  258. /** Picks an unique branch value based on a SIP message.
  259. * This value could also be used for loop detection. */
  260. /*public String pickBranch(Message msg)
  261. { String branch=sip_provider.pickBranch(msg);
  262. if (server_profile.loop_detection) branch+=pickLoopTag(msg);
  263. return branch;
  264. }*/
  265. /** Picks the token used for loop detection. */
  266. private String pickLoopTag(Message msg)
  267. { StringBuffer sb=new StringBuffer();
  268. sb.append(msg.getToHeader().getTag());
  269. sb.append(msg.getFromHeader().getTag());
  270. sb.append(msg.getCallIdHeader().getCallId());
  271. sb.append(msg.getRequestLine().getAddress().toString());
  272. sb.append(msg.getCSeqHeader().getSequenceNumber());
  273. MultipleHeader rr=msg.getRoutes();
  274. if (rr!=null) sb.append(rr.size());
  275. return (new SimpleDigest(7,sb.toString())).asHex();
  276. }
  277. // ********************************* logs *********************************
  278. /** Adds a new string to the default Log */
  279. private void printLog(String str, int level)
  280. { if (log!=null) log.println("ServerEngine: "+str,level+SipStack.LOG_LEVEL_UA);
  281. }
  282. /** Adds a Warning message to the default Log */
  283. private final void printWarning(String str, int level)
  284. { printLog("WARNING: "+str,level);
  285. }
  286. }