FreeSwitchDirectory.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using log4net;
  28. using System;
  29. using System.Reflection;
  30. using System.Text;
  31. using System.Collections;
  32. namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
  33. {
  34. public class FreeSwitchDirectory
  35. {
  36. private static readonly ILog m_log =
  37. LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  38. public Hashtable HandleDirectoryRequest(string Context, string Realm, Hashtable request)
  39. {
  40. Hashtable response = new Hashtable();
  41. string domain = (string) request["domain"];
  42. if (domain != Realm) {
  43. response["content_type"] = "text/xml";
  44. response["keepalive"] = false;
  45. response["int_response_code"] = 200;
  46. response["str_response_string"] = "";
  47. } else {
  48. m_log.DebugFormat("[FreeSwitchDirectory] HandleDirectoryRequest called with {0}",request.ToString());
  49. // information in the request we might be interested in
  50. // Request 1 sip_auth for users account
  51. //Event-Calling-Function=sofia_reg_parse_auth
  52. //Event-Calling-Line-Number=1494
  53. //action=sip_auth
  54. //sip_user_agent=Vivox-SDK-2.1.3010.6151-Mac%20(Feb-11-2009/16%3A42%3A41)
  55. //sip_auth_username=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==)
  56. //sip_auth_realm=9.20.151.43
  57. //sip_contact_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==)
  58. //sip_contact_host=192.168.0.3 // this shouldnt really be a local IP, investigate STUN servers
  59. //sip_to_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D
  60. //sip_to_host=9.20.151.43
  61. //sip_auth_method=REGISTER
  62. //user=xhZuXKmRpECyr2AARJYyGgg%3D%3D
  63. //domain=9.20.151.43
  64. //ip=9.167.220.137 // this is the correct IP rather than sip_contact_host above when through a vpn or NAT setup
  65. foreach (DictionaryEntry item in request)
  66. {
  67. m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}", item.Key, item.Value);
  68. }
  69. string eventCallingFunction = (string) request["Event-Calling-Function"];
  70. if (eventCallingFunction == null)
  71. {
  72. eventCallingFunction = "sofia_reg_parse_auth";
  73. }
  74. if (eventCallingFunction.Length == 0)
  75. {
  76. eventCallingFunction = "sofia_reg_parse_auth";
  77. }
  78. if (eventCallingFunction == "sofia_reg_parse_auth")
  79. {
  80. string sipAuthMethod = (string)request["sip_auth_method"];
  81. if (sipAuthMethod == "REGISTER")
  82. {
  83. response = HandleRegister(Context, Realm, request);
  84. }
  85. else if (sipAuthMethod == "INVITE")
  86. {
  87. response = HandleInvite(Context, Realm, request);
  88. }
  89. else
  90. {
  91. m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod);
  92. response["int_response_code"] = 404;
  93. response["content_type"] = "text/xml";
  94. response["str_response_string"] = "";
  95. }
  96. }
  97. else if (eventCallingFunction == "switch_xml_locate_user")
  98. {
  99. response = HandleLocateUser(Realm, request);
  100. }
  101. else if (eventCallingFunction == "user_data_function") // gets called when an avatar to avatar call is made
  102. {
  103. response = HandleLocateUser(Realm, request);
  104. }
  105. else if (eventCallingFunction == "user_outgoing_channel")
  106. {
  107. response = HandleRegister(Context, Realm, request);
  108. }
  109. else if (eventCallingFunction == "config_sofia") // happens once on freeswitch startup
  110. {
  111. response = HandleConfigSofia(Context, Realm, request);
  112. }
  113. else if (eventCallingFunction == "switch_load_network_lists")
  114. {
  115. //response = HandleLoadNetworkLists(request);
  116. response["int_response_code"] = 404;
  117. response["keepalive"] = false;
  118. response["content_type"] = "text/xml";
  119. response["str_response_string"] = "";
  120. }
  121. else
  122. {
  123. m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction);
  124. response["int_response_code"] = 404;
  125. response["keepalive"] = false;
  126. response["content_type"] = "text/xml";
  127. response["str_response_string"] = "";
  128. }
  129. }
  130. return response;
  131. }
  132. private Hashtable HandleRegister(string Context, string Realm, Hashtable request)
  133. {
  134. m_log.Info("[FreeSwitchDirectory] HandleRegister called");
  135. // TODO the password we return needs to match that sent in the request, this is hard coded for now
  136. string password = "1234";
  137. string domain = (string) request["domain"];
  138. string user = (string) request["user"];
  139. Hashtable response = new Hashtable();
  140. response["content_type"] = "text/xml";
  141. response["keepalive"] = false;
  142. response["int_response_code"] = 200;
  143. response["str_response_string"] = String.Format(
  144. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
  145. "<document type=\"freeswitch/xml\">\r\n" +
  146. "<section name=\"directory\" description=\"User Directory\">\r\n" +
  147. "<domain name=\"{0}\">\r\n" +
  148. "<user id=\"{1}\">\r\n" +
  149. "<params>\r\n" +
  150. "<param name=\"password\" value=\"{2}\" />\r\n" +
  151. "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
  152. "</params>\r\n" +
  153. "<variables>\r\n" +
  154. "<variable name=\"user_context\" value=\"{3}\" />\r\n" +
  155. "<variable name=\"presence_id\" value=\"{1}@{0}\"/>"+
  156. "</variables>\r\n" +
  157. "</user>\r\n" +
  158. "</domain>\r\n" +
  159. "</section>\r\n" +
  160. "</document>\r\n",
  161. domain , user, password, Context);
  162. return response;
  163. }
  164. private Hashtable HandleInvite(string Context, string Realm, Hashtable request)
  165. {
  166. m_log.Info("[FreeSwitchDirectory] HandleInvite called");
  167. // TODO the password we return needs to match that sent in the request, this is hard coded for now
  168. string password = "1234";
  169. string domain = (string) request["domain"];
  170. string user = (string) request["user"];
  171. string sipRequestUser = (string) request["sip_request_user"];
  172. Hashtable response = new Hashtable();
  173. response["content_type"] = "text/xml";
  174. response["keepalive"] = false;
  175. response["int_response_code"] = 200;
  176. response["str_response_string"] = String.Format(
  177. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
  178. "<document type=\"freeswitch/xml\">\r\n" +
  179. "<section name=\"directory\" description=\"User Directory\">\r\n" +
  180. "<domain name=\"{0}\">\r\n" +
  181. "<user id=\"{1}\">\r\n" +
  182. "<params>\r\n" +
  183. "<param name=\"password\" value=\"{2}\" />\r\n" +
  184. "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${1}@${{dialed_domain}}}}${{sofia_contact(${1}@${{dialed_domain}})}}\"/>\r\n" +
  185. "</params>\r\n" +
  186. "<variables>\r\n" +
  187. "<variable name=\"user_context\" value=\"{4}\" />\r\n" +
  188. "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+
  189. "</variables>\r\n" +
  190. "</user>\r\n" +
  191. "<user id=\"{3}\">\r\n" +
  192. "<params>\r\n" +
  193. "<param name=\"password\" value=\"{2}\" />\r\n" +
  194. "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${3}@${{dialed_domain}}}}${{sofia_contact(${3}@${{dialed_domain}})}}\"/>\r\n" +
  195. "</params>\r\n" +
  196. "<variables>\r\n" +
  197. "<variable name=\"user_context\" value=\"{4}\" />\r\n" +
  198. "<variable name=\"presence_id\" value=\"{3}@$${{domain}}\"/>"+
  199. "</variables>\r\n" +
  200. "</user>\r\n" +
  201. "</domain>\r\n" +
  202. "</section>\r\n" +
  203. "</document>\r\n",
  204. domain , user, password,sipRequestUser, Context);
  205. return response;
  206. }
  207. private Hashtable HandleLocateUser(String Realm, Hashtable request)
  208. {
  209. m_log.Info("[FreeSwitchDirectory] HandleLocateUser called");
  210. // TODO the password we return needs to match that sent in the request, this is hard coded for now
  211. string domain = (string) request["domain"];
  212. string user = (string) request["user"];
  213. Hashtable response = new Hashtable();
  214. response["content_type"] = "text/xml";
  215. response["keepalive"] = false;
  216. response["int_response_code"] = 200;
  217. response["str_response_string"] = String.Format(
  218. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
  219. "<document type=\"freeswitch/xml\">\r\n" +
  220. "<section name=\"directory\" description=\"User Directory\">\r\n" +
  221. "<domain name=\"{0}\">\r\n" +
  222. "<params>\r\n" +
  223. "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
  224. "</params>\r\n" +
  225. "<user id=\"{1}\">\r\n" +
  226. "<variables>\r\n"+
  227. "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
  228. "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+
  229. "</variables>\r\n"+
  230. "</user>\r\n" +
  231. "</domain>\r\n" +
  232. "</section>\r\n" +
  233. "</document>\r\n",
  234. domain , user);
  235. return response;
  236. }
  237. private Hashtable HandleConfigSofia(string Context, string Realm, Hashtable request)
  238. {
  239. m_log.Info("[FreeSwitchDirectory] HandleConfigSofia called");
  240. // TODO the password we return needs to match that sent in the request, this is hard coded for now
  241. string domain = (string) request["domain"];
  242. Hashtable response = new Hashtable();
  243. response["content_type"] = "text/xml";
  244. response["keepalive"] = false;
  245. response["int_response_code"] = 200;
  246. response["str_response_string"] = String.Format(
  247. "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
  248. "<document type=\"freeswitch/xml\">\r\n" +
  249. "<section name=\"directory\" description=\"User Directory\">\r\n" +
  250. "<domain name=\"{0}\">\r\n" +
  251. "<params>\r\n" +
  252. "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
  253. "</params>\r\n" +
  254. "<groups name=\"default\">\r\n"+
  255. "<users>\r\n"+
  256. "<user id=\"$${{default_provider}}\">\r\n"+
  257. "<gateways>\r\n"+
  258. "<gateway name=\"$${{default_provider}}\">\r\n"+
  259. "<param name=\"username\" value=\"$${{default_provider_username}}\"/>\r\n"+
  260. "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+
  261. "<param name=\"from-user\" value=\"$${{default_provider_username}}\"/>\r\n"+
  262. "<param name=\"from-domain\" value=\"$${{default_provider_from_domain}}\"/>\r\n"+
  263. "<param name=\"expire-seconds\" value=\"600\"/>\r\n"+
  264. "<param name=\"register\" value=\"$${{default_provider_register}}\"/>\r\n"+
  265. "<param name=\"retry-seconds\" value=\"30\"/>\r\n"+
  266. "<param name=\"extension\" value=\"$${{default_provider_contact}}\"/>\r\n"+
  267. "<param name=\"contact-params\" value=\"domain_name=$${{domain}}\"/>\r\n"+
  268. "<param name=\"context\" value=\"{1}\"/>\r\n"+
  269. "</gateway>\r\n"+
  270. "</gateways>\r\n"+
  271. "<params>\r\n"+
  272. "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+
  273. "</params>\r\n"+
  274. "</user>\r\n"+
  275. "</users>"+
  276. "</groups>\r\n" +
  277. "<variables>\r\n"+
  278. "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
  279. "</variables>\r\n"+
  280. "</domain>\r\n" +
  281. "</section>\r\n" +
  282. "</document>\r\n",
  283. domain, Context);
  284. return response;
  285. }
  286. // private Hashtable HandleLoadNetworkLists(Hashtable request)
  287. // {
  288. // m_log.Info("[FreeSwitchDirectory] HandleLoadNetworkLists called");
  289. //
  290. // // TODO the password we return needs to match that sent in the request, this is hard coded for now
  291. // string domain = (string) request["domain"];
  292. //
  293. // Hashtable response = new Hashtable();
  294. // response["content_type"] = "text/xml";
  295. // response["keepalive"] = false;
  296. // response["int_response_code"] = 200;
  297. // response["str_response_string"] = String.Format(
  298. // "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
  299. // "<document type=\"freeswitch/xml\">\r\n" +
  300. // "<section name=\"directory\" description=\"User Directory\">\r\n" +
  301. // "<domain name=\"{0}\">\r\n" +
  302. // "<params>\r\n" +
  303. // "<param name=\"dial-string\" value=\"{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
  304. // "</params>\r\n" +
  305. // "<groups name=\"default\"><users/></groups>\r\n" +
  306. // "<variables>\r\n"+
  307. // "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
  308. // "</variables>\r\n"+
  309. // "</domain>\r\n" +
  310. // "</section>\r\n" +
  311. // "</document>\r\n",
  312. // domain);
  313. //
  314. //
  315. // return response;
  316. // }
  317. }
  318. }