aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDialplan.cs104
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDirectory.cs348
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs275
-rw-r--r--OpenSim/Server/Handlers/Freeswitch/FreeswitchServerConnector.cs65
-rw-r--r--OpenSim/Server/Handlers/Freeswitch/FreeswitchServerGetHandler.cs72
-rw-r--r--OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs103
-rw-r--r--OpenSim/Services/FreeswitchService/FreeswitchService.cs359
-rw-r--r--OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs36
-rw-r--r--OpenSim/Services/Interfaces/IFreeswitchService.cs5
-rw-r--r--bin/OpenSim.ini.example63
-rw-r--r--bin/Robust.ini.example13
-rw-r--r--prebuild.xml1
12 files changed, 715 insertions, 729 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDialplan.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDialplan.cs
deleted file mode 100644
index 46ad30f..0000000
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDialplan.cs
+++ /dev/null
@@ -1,104 +0,0 @@
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
28using log4net;
29using System;
30using System.Reflection;
31using System.Text;
32using System.Collections;
33
34namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
35{
36 public class FreeSwitchDialplan
37 {
38 private static readonly ILog m_log =
39 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40
41
42 public Hashtable HandleDialplanRequest(string Context, string Realm, Hashtable request)
43 {
44 m_log.DebugFormat("[FreeSwitchVoice] HandleDialplanRequest called with {0}",request.ToString());
45
46 Hashtable response = new Hashtable();
47
48 foreach (DictionaryEntry item in request)
49 {
50 m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}",item.Key, item.Value);
51 }
52
53 string requestcontext = (string) request["Hunt-Context"];
54 response["content_type"] = "text/xml";
55 response["keepalive"] = false;
56 response["int_response_code"] = 200;
57 if (Context != String.Empty && Context != requestcontext)
58 {
59 m_log.Debug("[FreeSwitchDirectory] returning empty as it's for another context");
60 response["str_response_string"] = "";
61 } else {
62 response["str_response_string"] = String.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
63 <document type=""freeswitch/xml"">
64 <section name=""dialplan"">
65 <context name=""{0}"">" +
66
67/* <!-- dial via SIP uri -->
68 <extension name=""sip_uri"">
69 <condition field=""destination_number"" expression=""^sip:(.*)$"">
70 <action application=""bridge"" data=""sofia/${use_profile}/$1""/>
71 <!--<action application=""bridge"" data=""$1""/>-->
72 </condition>
73 </extension>*/
74
75 @"<extension name=""opensim_conferences"">
76 <condition field=""destination_number"" expression=""^confctl-(.*)$"">
77 <action application=""answer""/>
78 <action application=""conference"" data=""$1-{1}@{0}""/>
79 </condition>
80 </extension>
81
82 <extension name=""opensim_conf"">
83 <condition field=""destination_number"" expression=""^conf-(.*)$"">
84 <action application=""answer""/>
85 <action application=""conference"" data=""$1-{1}@{0}""/>
86 </condition>
87 </extension>
88
89 <extension name=""avatar"">
90 <condition field=""destination_number"" expression=""^(x.*)$"">
91 <action application=""bridge"" data=""user/$1""/>
92 </condition>
93 </extension>
94
95 </context>
96 </section>
97 </document>", Context, Realm);
98 }
99
100 return response;
101 }
102 }
103
104}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDirectory.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDirectory.cs
deleted file mode 100644
index 17cdf74..0000000
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchDirectory.cs
+++ /dev/null
@@ -1,348 +0,0 @@
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
28using log4net;
29using System;
30using System.Reflection;
31using System.Text;
32using System.Collections;
33
34namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
35{
36 public class FreeSwitchDirectory
37 {
38 private static readonly ILog m_log =
39 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40
41 public Hashtable HandleDirectoryRequest(string Context, string Realm, Hashtable request)
42 {
43 Hashtable response = new Hashtable();
44 string domain = (string) request["domain"];
45 if (domain != Realm) {
46 response["content_type"] = "text/xml";
47 response["keepalive"] = false;
48 response["int_response_code"] = 200;
49 response["str_response_string"] = "";
50 } else {
51 m_log.DebugFormat("[FreeSwitchDirectory] HandleDirectoryRequest called with {0}",request.ToString());
52
53 // information in the request we might be interested in
54
55 // Request 1 sip_auth for users account
56
57 //Event-Calling-Function=sofia_reg_parse_auth
58 //Event-Calling-Line-Number=1494
59 //action=sip_auth
60 //sip_user_agent=Vivox-SDK-2.1.3010.6151-Mac%20(Feb-11-2009/16%3A42%3A41)
61 //sip_auth_username=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==)
62 //sip_auth_realm=9.20.151.43
63 //sip_contact_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==)
64 //sip_contact_host=192.168.0.3 // this shouldnt really be a local IP, investigate STUN servers
65 //sip_to_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D
66 //sip_to_host=9.20.151.43
67 //sip_auth_method=REGISTER
68 //user=xhZuXKmRpECyr2AARJYyGgg%3D%3D
69 //domain=9.20.151.43
70 //ip=9.167.220.137 // this is the correct IP rather than sip_contact_host above when through a vpn or NAT setup
71
72 foreach (DictionaryEntry item in request)
73 {
74 m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}", item.Key, item.Value);
75 }
76
77 string eventCallingFunction = (string) request["Event-Calling-Function"];
78 if (eventCallingFunction == null)
79 {
80 eventCallingFunction = "sofia_reg_parse_auth";
81 }
82
83 if (eventCallingFunction.Length == 0)
84 {
85 eventCallingFunction = "sofia_reg_parse_auth";
86 }
87
88 if (eventCallingFunction == "sofia_reg_parse_auth")
89 {
90 string sipAuthMethod = (string)request["sip_auth_method"];
91
92 if (sipAuthMethod == "REGISTER")
93 {
94 response = HandleRegister(Context, Realm, request);
95 }
96 else if (sipAuthMethod == "INVITE")
97 {
98 response = HandleInvite(Context, Realm, request);
99 }
100 else
101 {
102 m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod);
103 response["int_response_code"] = 404;
104 response["content_type"] = "text/xml";
105 response["str_response_string"] = "";
106 }
107 }
108 else if (eventCallingFunction == "switch_xml_locate_user")
109 {
110 response = HandleLocateUser(Realm, request);
111 }
112 else if (eventCallingFunction == "user_data_function") // gets called when an avatar to avatar call is made
113 {
114 response = HandleLocateUser(Realm, request);
115 }
116 else if (eventCallingFunction == "user_outgoing_channel")
117 {
118 response = HandleRegister(Context, Realm, request);
119 }
120 else if (eventCallingFunction == "config_sofia") // happens once on freeswitch startup
121 {
122 response = HandleConfigSofia(Context, Realm, request);
123 }
124 else if (eventCallingFunction == "switch_load_network_lists")
125 {
126 //response = HandleLoadNetworkLists(request);
127 response["int_response_code"] = 404;
128 response["keepalive"] = false;
129 response["content_type"] = "text/xml";
130 response["str_response_string"] = "";
131 }
132 else
133 {
134 m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction);
135 response["int_response_code"] = 404;
136 response["keepalive"] = false;
137 response["content_type"] = "text/xml";
138 response["str_response_string"] = "";
139 }
140 }
141 return response;
142 }
143
144 private Hashtable HandleRegister(string Context, string Realm, Hashtable request)
145 {
146 m_log.Info("[FreeSwitchDirectory] HandleRegister called");
147
148 // TODO the password we return needs to match that sent in the request, this is hard coded for now
149 string password = "1234";
150 string domain = (string) request["domain"];
151 string user = (string) request["user"];
152
153 Hashtable response = new Hashtable();
154 response["content_type"] = "text/xml";
155 response["keepalive"] = false;
156 response["int_response_code"] = 200;
157
158 response["str_response_string"] = String.Format(
159 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
160 "<document type=\"freeswitch/xml\">\r\n" +
161 "<section name=\"directory\" description=\"User Directory\">\r\n" +
162 "<domain name=\"{0}\">\r\n" +
163 "<user id=\"{1}\">\r\n" +
164 "<params>\r\n" +
165 "<param name=\"password\" value=\"{2}\" />\r\n" +
166 "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
167 "</params>\r\n" +
168 "<variables>\r\n" +
169 "<variable name=\"user_context\" value=\"{3}\" />\r\n" +
170 "<variable name=\"presence_id\" value=\"{1}@{0}\"/>"+
171 "</variables>\r\n" +
172 "</user>\r\n" +
173 "</domain>\r\n" +
174 "</section>\r\n" +
175 "</document>\r\n",
176 domain , user, password, Context);
177
178 return response;
179 }
180
181 private Hashtable HandleInvite(string Context, string Realm, Hashtable request)
182 {
183 m_log.Info("[FreeSwitchDirectory] HandleInvite called");
184
185 // TODO the password we return needs to match that sent in the request, this is hard coded for now
186 string password = "1234";
187 string domain = (string) request["domain"];
188 string user = (string) request["user"];
189 string sipRequestUser = (string) request["sip_request_user"];
190
191 Hashtable response = new Hashtable();
192 response["content_type"] = "text/xml";
193 response["keepalive"] = false;
194 response["int_response_code"] = 200;
195 response["str_response_string"] = String.Format(
196 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
197 "<document type=\"freeswitch/xml\">\r\n" +
198 "<section name=\"directory\" description=\"User Directory\">\r\n" +
199 "<domain name=\"{0}\">\r\n" +
200 "<user id=\"{1}\">\r\n" +
201 "<params>\r\n" +
202 "<param name=\"password\" value=\"{2}\" />\r\n" +
203 "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${1}@${{dialed_domain}}}}${{sofia_contact(${1}@${{dialed_domain}})}}\"/>\r\n" +
204 "</params>\r\n" +
205 "<variables>\r\n" +
206 "<variable name=\"user_context\" value=\"{4}\" />\r\n" +
207 "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+
208 "</variables>\r\n" +
209 "</user>\r\n" +
210 "<user id=\"{3}\">\r\n" +
211 "<params>\r\n" +
212 "<param name=\"password\" value=\"{2}\" />\r\n" +
213 "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${3}@${{dialed_domain}}}}${{sofia_contact(${3}@${{dialed_domain}})}}\"/>\r\n" +
214 "</params>\r\n" +
215 "<variables>\r\n" +
216 "<variable name=\"user_context\" value=\"{4}\" />\r\n" +
217 "<variable name=\"presence_id\" value=\"{3}@$${{domain}}\"/>"+
218 "</variables>\r\n" +
219 "</user>\r\n" +
220 "</domain>\r\n" +
221 "</section>\r\n" +
222 "</document>\r\n",
223 domain , user, password,sipRequestUser, Context);
224
225 return response;
226 }
227
228 private Hashtable HandleLocateUser(String Realm, Hashtable request)
229 {
230 m_log.Info("[FreeSwitchDirectory] HandleLocateUser called");
231
232 // TODO the password we return needs to match that sent in the request, this is hard coded for now
233 string domain = (string) request["domain"];
234 string user = (string) request["user"];
235
236 Hashtable response = new Hashtable();
237 response["content_type"] = "text/xml";
238 response["keepalive"] = false;
239 response["int_response_code"] = 200;
240 response["str_response_string"] = String.Format(
241 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
242 "<document type=\"freeswitch/xml\">\r\n" +
243 "<section name=\"directory\" description=\"User Directory\">\r\n" +
244 "<domain name=\"{0}\">\r\n" +
245 "<params>\r\n" +
246 "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
247 "</params>\r\n" +
248 "<user id=\"{1}\">\r\n" +
249 "<variables>\r\n"+
250 "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
251 "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+
252 "</variables>\r\n"+
253 "</user>\r\n" +
254 "</domain>\r\n" +
255 "</section>\r\n" +
256 "</document>\r\n",
257 domain , user);
258
259 return response;
260 }
261
262 private Hashtable HandleConfigSofia(string Context, string Realm, Hashtable request)
263 {
264 m_log.Info("[FreeSwitchDirectory] HandleConfigSofia called");
265
266 // TODO the password we return needs to match that sent in the request, this is hard coded for now
267 string domain = (string) request["domain"];
268
269 Hashtable response = new Hashtable();
270 response["content_type"] = "text/xml";
271 response["keepalive"] = false;
272 response["int_response_code"] = 200;
273 response["str_response_string"] = String.Format(
274 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
275 "<document type=\"freeswitch/xml\">\r\n" +
276 "<section name=\"directory\" description=\"User Directory\">\r\n" +
277 "<domain name=\"{0}\">\r\n" +
278 "<params>\r\n" +
279 "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
280 "</params>\r\n" +
281 "<groups name=\"default\">\r\n"+
282 "<users>\r\n"+
283 "<user id=\"$${{default_provider}}\">\r\n"+
284 "<gateways>\r\n"+
285 "<gateway name=\"$${{default_provider}}\">\r\n"+
286 "<param name=\"username\" value=\"$${{default_provider_username}}\"/>\r\n"+
287 "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+
288 "<param name=\"from-user\" value=\"$${{default_provider_username}}\"/>\r\n"+
289 "<param name=\"from-domain\" value=\"$${{default_provider_from_domain}}\"/>\r\n"+
290 "<param name=\"expire-seconds\" value=\"600\"/>\r\n"+
291 "<param name=\"register\" value=\"$${{default_provider_register}}\"/>\r\n"+
292 "<param name=\"retry-seconds\" value=\"30\"/>\r\n"+
293 "<param name=\"extension\" value=\"$${{default_provider_contact}}\"/>\r\n"+
294 "<param name=\"contact-params\" value=\"domain_name=$${{domain}}\"/>\r\n"+
295 "<param name=\"context\" value=\"{1}\"/>\r\n"+
296 "</gateway>\r\n"+
297 "</gateways>\r\n"+
298 "<params>\r\n"+
299 "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+
300 "</params>\r\n"+
301 "</user>\r\n"+
302 "</users>"+
303 "</groups>\r\n" +
304 "<variables>\r\n"+
305 "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
306 "</variables>\r\n"+
307 "</domain>\r\n" +
308 "</section>\r\n" +
309 "</document>\r\n",
310 domain, Context);
311
312 return response;
313 }
314
315
316// private Hashtable HandleLoadNetworkLists(Hashtable request)
317// {
318// m_log.Info("[FreeSwitchDirectory] HandleLoadNetworkLists called");
319//
320// // TODO the password we return needs to match that sent in the request, this is hard coded for now
321// string domain = (string) request["domain"];
322//
323// Hashtable response = new Hashtable();
324// response["content_type"] = "text/xml";
325// response["keepalive"] = false;
326// response["int_response_code"] = 200;
327// response["str_response_string"] = String.Format(
328// "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
329// "<document type=\"freeswitch/xml\">\r\n" +
330// "<section name=\"directory\" description=\"User Directory\">\r\n" +
331// "<domain name=\"{0}\">\r\n" +
332// "<params>\r\n" +
333// "<param name=\"dial-string\" value=\"{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
334// "</params>\r\n" +
335// "<groups name=\"default\"><users/></groups>\r\n" +
336// "<variables>\r\n"+
337// "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
338// "</variables>\r\n"+
339// "</domain>\r\n" +
340// "</section>\r\n" +
341// "</document>\r\n",
342// domain);
343//
344//
345// return response;
346// }
347 }
348}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
index 242bc3f..a5e553c 100644
--- a/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
+++ b/OpenSim/Region/OptionalModules/Avatar/Voice/FreeSwitchVoice/FreeSwitchVoiceModule.cs
@@ -37,10 +37,12 @@ using System.Collections;
37using System.Collections.Generic; 37using System.Collections.Generic;
38using System.Reflection; 38using System.Reflection;
39using OpenMetaverse; 39using OpenMetaverse;
40using OpenMetaverse.StructuredData;
40using log4net; 41using log4net;
41using Nini.Config; 42using Nini.Config;
42using Nwc.XmlRpc; 43using Nwc.XmlRpc;
43using OpenSim.Framework; 44using OpenSim.Framework;
45using Mono.Addins;
44 46
45using OpenSim.Framework.Capabilities; 47using OpenSim.Framework.Capabilities;
46using OpenSim.Framework.Servers; 48using OpenSim.Framework.Servers;
@@ -49,28 +51,27 @@ using OpenSim.Region.Framework.Interfaces;
49using OpenSim.Region.Framework.Scenes; 51using OpenSim.Region.Framework.Scenes;
50using Caps = OpenSim.Framework.Capabilities.Caps; 52using Caps = OpenSim.Framework.Capabilities.Caps;
51using System.Text.RegularExpressions; 53using System.Text.RegularExpressions;
54using OpenSim.Server.Base;
55using OpenSim.Services.Interfaces;
56using OSDMap = OpenMetaverse.StructuredData.OSDMap;
52 57
53namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice 58namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
54{ 59{
55 public class FreeSwitchVoiceModule : IRegionModule, IVoiceModule 60 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "FreeSwitchVoiceModule")]
61 public class FreeSwitchVoiceModule : INonSharedRegionModule, IVoiceModule
56 { 62 {
57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 63 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58 64
59 private bool UseProxy = false;
60
61 // Capability string prefixes 65 // Capability string prefixes
62 private static readonly string m_parcelVoiceInfoRequestPath = "0007/"; 66 private static readonly string m_parcelVoiceInfoRequestPath = "0007/";
63 private static readonly string m_provisionVoiceAccountRequestPath = "0008/"; 67 private static readonly string m_provisionVoiceAccountRequestPath = "0008/";
64 private static readonly string m_chatSessionRequestPath = "0009/"; 68 private static readonly string m_chatSessionRequestPath = "0009/";
65 69
66 // Control info 70 // Control info
67 private static bool m_WOF = true; 71 private static bool m_Enabled = false;
68 private static bool m_pluginEnabled = false;
69 72
70 // FreeSwitch server is going to contact us and ask us all 73 // FreeSwitch server is going to contact us and ask us all
71 // sorts of things. 74 // sorts of things.
72 private static string m_freeSwitchServerUser;
73 private static string m_freeSwitchServerPass;
74 75
75 // SLVoice client will do a GET on this prefix 76 // SLVoice client will do a GET on this prefix
76 private static string m_freeSwitchAPIPrefix; 77 private static string m_freeSwitchAPIPrefix;
@@ -84,143 +85,146 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
84 private static string m_freeSwitchRealm; 85 private static string m_freeSwitchRealm;
85 private static string m_freeSwitchSIPProxy; 86 private static string m_freeSwitchSIPProxy;
86 private static bool m_freeSwitchAttemptUseSTUN; 87 private static bool m_freeSwitchAttemptUseSTUN;
87 // private static string m_freeSwitchSTUNServer;
88 private static string m_freeSwitchEchoServer; 88 private static string m_freeSwitchEchoServer;
89 private static int m_freeSwitchEchoPort; 89 private static int m_freeSwitchEchoPort;
90 private static string m_freeSwitchDefaultWellKnownIP; 90 private static string m_freeSwitchDefaultWellKnownIP;
91 private static int m_freeSwitchDefaultTimeout; 91 private static int m_freeSwitchDefaultTimeout;
92 // private static int m_freeSwitchSubscribeRetry;
93 private static string m_freeSwitchUrlResetPassword; 92 private static string m_freeSwitchUrlResetPassword;
94 // private static IPEndPoint m_FreeSwitchServiceIP; 93 private uint m_freeSwitchServicePort;
95 private int m_freeSwitchServicePort;
96 private string m_openSimWellKnownHTTPAddress; 94 private string m_openSimWellKnownHTTPAddress;
97 private string m_freeSwitchContext; 95 private string m_freeSwitchContext;
98 96
99 private FreeSwitchDirectory m_FreeSwitchDirectory;
100 private FreeSwitchDialplan m_FreeSwitchDialplan;
101
102 private readonly Dictionary<string, string> m_UUIDName = new Dictionary<string, string>(); 97 private readonly Dictionary<string, string> m_UUIDName = new Dictionary<string, string>();
103 private Dictionary<string, string> m_ParcelAddress = new Dictionary<string, string>(); 98 private Dictionary<string, string> m_ParcelAddress = new Dictionary<string, string>();
104 99
105 private Scene m_scene; 100 private Scene m_Scene;
106 101
102 private IConfig m_Config;
107 103
108 private IConfig m_config; 104 private IFreeswitchService m_FreeswitchService;
109 105
110 public void Initialise(Scene scene, IConfigSource config) 106 public void Initialise(IConfigSource config)
111 { 107 {
112 m_scene = scene; 108 m_Config = config.Configs["FreeSwitchVoice"];
113 m_config = config.Configs["FreeSwitchVoice"];
114 109
115 if (null == m_config) 110 if (m_Config == null)
116 { 111 {
117 m_log.Info("[FreeSwitchVoice] no config found, plugin disabled"); 112 m_log.Info("[FreeSwitchVoice] no config found, plugin disabled");
118 return; 113 return;
119 } 114 }
120 115
121 if (!m_config.GetBoolean("enabled", false)) 116 if (!m_Config.GetBoolean("Enabled", false))
122 { 117 {
123 m_log.Info("[FreeSwitchVoice] plugin disabled by configuration"); 118 m_log.Info("[FreeSwitchVoice] plugin disabled by configuration");
124 return; 119 return;
125 } 120 }
126 121
127 // This is only done the FIRST time this method is invoked. 122 try
128 if (m_WOF)
129 { 123 {
130 m_pluginEnabled = true; 124 string serviceDll = m_Config.GetString("LocalServiceModule",
131 m_WOF = false; 125 String.Empty);
132 126
133 try 127 if (serviceDll == String.Empty)
134 { 128 {
135 m_freeSwitchServerUser = m_config.GetString("freeswitch_server_user", String.Empty); 129 m_log.Error("[FreeSwitchVoice]: No LocalServiceModule named in section FreeSwitchVoice");
136 m_freeSwitchServerPass = m_config.GetString("freeswitch_server_pass", String.Empty); 130 return;
137 m_freeSwitchAPIPrefix = m_config.GetString("freeswitch_api_prefix", String.Empty); 131 }
138
139 // XXX: get IP address of HTTP server. (This can be this OpenSim server or another, or could be a dedicated grid service or may live on the freeswitch server)
140
141 string serviceIP = m_config.GetString("freeswitch_service_server", String.Empty);
142 int servicePort = m_config.GetInt("freeswitch_service_port", 80);
143 IPAddress serviceIPAddress = IPAddress.Parse(serviceIP);
144 // m_FreeSwitchServiceIP = new IPEndPoint(serviceIPAddress, servicePort);
145 m_freeSwitchServicePort = servicePort;
146 m_freeSwitchRealm = m_config.GetString("freeswitch_realm", String.Empty);
147 m_freeSwitchSIPProxy = m_config.GetString("freeswitch_sip_proxy", m_freeSwitchRealm);
148 m_freeSwitchAttemptUseSTUN = m_config.GetBoolean("freeswitch_attempt_stun", true);
149 // m_freeSwitchSTUNServer = m_config.GetString("freeswitch_stun_server", m_freeSwitchRealm);
150 m_freeSwitchEchoServer = m_config.GetString("freeswitch_echo_server", m_freeSwitchRealm);
151 m_freeSwitchEchoPort = m_config.GetInt("freeswitch_echo_port", 50505);
152 m_freeSwitchDefaultWellKnownIP = m_config.GetString("freeswitch_well_known_ip", m_freeSwitchRealm);
153 m_openSimWellKnownHTTPAddress = m_config.GetString("opensim_well_known_http_address", serviceIPAddress.ToString());
154 m_freeSwitchDefaultTimeout = m_config.GetInt("freeswitch_default_timeout", 5000);
155 // m_freeSwitchSubscribeRetry = m_config.GetInt("freeswitch_subscribe_retry", 120);
156 m_freeSwitchUrlResetPassword = m_config.GetString("freeswitch_password_reset_url", String.Empty);
157 m_freeSwitchContext = m_config.GetString("freeswitch_context", "default");
158
159 if (String.IsNullOrEmpty(m_freeSwitchServerUser) ||
160 String.IsNullOrEmpty(m_freeSwitchServerPass) ||
161 String.IsNullOrEmpty(m_freeSwitchRealm) ||
162 String.IsNullOrEmpty(m_freeSwitchAPIPrefix))
163 {
164 m_log.Error("[FreeSwitchVoice] plugin mis-configured");
165 m_log.Info("[FreeSwitchVoice] plugin disabled: incomplete configuration");
166 return;
167 }
168 132
169 // set up http request handlers for 133 Object[] args = new Object[] { config };
170 // - prelogin: viv_get_prelogin.php 134 m_FreeswitchService = ServerUtils.LoadPlugin<IFreeswitchService>(serviceDll, args);
171 // - signin: viv_signin.php 135
172 // - buddies: viv_buddy.php 136 string jsonConfig = m_FreeswitchService.GetJsonConfig();
173 // - ???: viv_watcher.php 137 OSDMap map = (OSDMap)OSDParser.DeserializeJson(jsonConfig);
174 // - signout: viv_signout.php 138
175 if (UseProxy) 139 m_freeSwitchAPIPrefix = map["APIPrefix"].AsString();
176 { 140 m_freeSwitchRealm = map["Realm"].AsString();
177 MainServer.Instance.AddHTTPHandler(String.Format("{0}/", m_freeSwitchAPIPrefix), 141 m_freeSwitchSIPProxy = map["SIPProxy"].AsString();
178 ForwardProxyRequest); 142 m_freeSwitchAttemptUseSTUN = map["AttemptUseSTUN"].AsBoolean();
179 } 143 m_freeSwitchEchoServer = map["EchoServer"].AsString();
180 else 144 m_freeSwitchEchoPort = map["EchoPort"].AsInteger();
181 { 145 m_freeSwitchDefaultWellKnownIP = map["DefaultWellKnownIP"].AsString();
182 MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_get_prelogin.php", m_freeSwitchAPIPrefix), 146 m_freeSwitchDefaultTimeout = map["DefaultTimeout"].AsInteger();
183 FreeSwitchSLVoiceGetPreloginHTTPHandler); 147 m_freeSwitchUrlResetPassword = String.Empty;
148 m_freeSwitchContext = map["Context"].AsString();
149
150 if (String.IsNullOrEmpty(m_freeSwitchRealm) ||
151 String.IsNullOrEmpty(m_freeSwitchAPIPrefix))
152 {
153 m_log.Error("[FreeSwitchVoice] plugin mis-configured");
154 m_log.Info("[FreeSwitchVoice] plugin disabled: incomplete configuration");
155 return;
156 }
184 157
185 // RestStreamHandler h = new 158 // set up http request handlers for
186 // RestStreamHandler("GET", 159 // - prelogin: viv_get_prelogin.php
187 // String.Format("{0}/viv_get_prelogin.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceGetPreloginHTTPHandler); 160 // - signin: viv_signin.php
188 // MainServer.Instance.AddStreamHandler(h); 161 // - buddies: viv_buddy.php
162 // - ???: viv_watcher.php
163 // - signout: viv_signout.php
164 MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_get_prelogin.php", m_freeSwitchAPIPrefix),
165 FreeSwitchSLVoiceGetPreloginHTTPHandler);
189 166
167 // RestStreamHandler h = new
168 // RestStreamHandler("GET",
169 // String.Format("{0}/viv_get_prelogin.php", m_freeSwitchAPIPrefix), FreeSwitchSLVoiceGetPreloginHTTPHandler);
170 // MainServer.Instance.AddStreamHandler(h);
190 171
191 172
192 MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_signin.php", m_freeSwitchAPIPrefix),
193 FreeSwitchSLVoiceSigninHTTPHandler);
194 173
195 // set up http request handlers to provide 174 MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_signin.php", m_freeSwitchAPIPrefix),
196 // on-demand FreeSwitch configuration to 175 FreeSwitchSLVoiceSigninHTTPHandler);
197 // FreeSwitch's mod_curl_xml
198 MainServer.Instance.AddHTTPHandler(String.Format("{0}/freeswitch-config", m_freeSwitchAPIPrefix),
199 FreeSwitchConfigHTTPHandler);
200 176
201 MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_buddy.php", m_freeSwitchAPIPrefix), 177 MainServer.Instance.AddHTTPHandler(String.Format("{0}/viv_buddy.php", m_freeSwitchAPIPrefix),
202 FreeSwitchSLVoiceBuddyHTTPHandler); 178 FreeSwitchSLVoiceBuddyHTTPHandler);
203 }
204 179
205 m_log.InfoFormat("[FreeSwitchVoice] using FreeSwitch server {0}", m_freeSwitchRealm); 180 m_log.InfoFormat("[FreeSwitchVoice] using FreeSwitch server {0}", m_freeSwitchRealm);
206 181
207 m_FreeSwitchDirectory = new FreeSwitchDirectory(); 182 m_Enabled = true;
208 m_FreeSwitchDialplan = new FreeSwitchDialplan();
209 183
210 m_pluginEnabled = true; 184 m_log.Info("[FreeSwitchVoice] plugin enabled");
211 m_WOF = false; 185 }
186 catch (Exception e)
187 {
188 m_log.ErrorFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.Message);
189 m_log.DebugFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.ToString());
190 return;
191 }
212 192
213 m_log.Info("[FreeSwitchVoice] plugin enabled"); 193 // This here is a region module trying to make a global setting.
194 // Not really a good idea but it's Windows only, so I can't test.
195 try
196 {
197 ServicePointManager.ServerCertificateValidationCallback += CustomCertificateValidation;
198 }
199 catch (NotImplementedException)
200 {
201 try
202 {
203#pragma warning disable 0612, 0618
204 // Mono does not implement the ServicePointManager.ServerCertificateValidationCallback yet! Don't remove this!
205 ServicePointManager.CertificatePolicy = new MonoCert();
206#pragma warning restore 0612, 0618
214 } 207 }
215 catch (Exception e) 208 catch (Exception)
216 { 209 {
217 m_log.ErrorFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.Message); 210 // COmmented multiline spam log message
218 m_log.DebugFormat("[FreeSwitchVoice] plugin initialization failed: {0}", e.ToString()); 211 //m_log.Error("[FreeSwitchVoice]: Certificate validation handler change not supported. You may get ssl certificate validation errors teleporting from your region to some SSL regions.");
219 return;
220 } 212 }
221 } 213 }
214 }
222 215
223 if (m_pluginEnabled) 216 public void AddRegion(Scene scene)
217 {
218 m_Scene = scene;
219
220 // We generate these like this: The region's external host name
221 // as defined in Regions.ini is a good address to use. It's a
222 // dotted quad (or should be!) and it can reach this host from
223 // a client. The port is grabbed from the region's HTTP server.
224 m_openSimWellKnownHTTPAddress = m_Scene.RegionInfo.ExternalHostName;
225 m_freeSwitchServicePort = MainServer.Instance.Port;
226
227 if (m_Enabled)
224 { 228 {
225 // we need to capture scene in an anonymous method 229 // we need to capture scene in an anonymous method
226 // here as we need it later in the callbacks 230 // here as we need it later in the callbacks
@@ -228,36 +232,21 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
228 { 232 {
229 OnRegisterCaps(scene, agentID, caps); 233 OnRegisterCaps(scene, agentID, caps);
230 }; 234 };
231
232 try
233 {
234 ServicePointManager.ServerCertificateValidationCallback += CustomCertificateValidation;
235 }
236 catch (NotImplementedException)
237 {
238 try
239 {
240#pragma warning disable 0612, 0618
241 // Mono does not implement the ServicePointManager.ServerCertificateValidationCallback yet! Don't remove this!
242 ServicePointManager.CertificatePolicy = new MonoCert();
243#pragma warning restore 0612, 0618
244 }
245 catch (Exception)
246 {
247 m_log.Error("[FreeSwitchVoice]: Certificate validation handler change not supported. You may get ssl certificate validation errors teleporting from your region to some SSL regions.");
248 }
249 }
250 } 235 }
251 } 236 }
252 237
253 public void PostInitialise() 238 public void RemoveRegion(Scene scene)
254 { 239 {
255 if (m_pluginEnabled) 240 }
241
242 public void RegionLoaded(Scene scene)
243 {
244 if (m_Enabled)
256 { 245 {
257 m_log.Info("[FreeSwitchVoice] registering IVoiceModule with the scene"); 246 m_log.Info("[FreeSwitchVoice] registering IVoiceModule with the scene");
258 247
259 // register the voice interface for this module, so the script engine can call us 248 // register the voice interface for this module, so the script engine can call us
260 m_scene.RegisterModuleInterface<IVoiceModule>(this); 249 scene.RegisterModuleInterface<IVoiceModule>(this);
261 } 250 }
262 } 251 }
263 252
@@ -270,9 +259,9 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
270 get { return "FreeSwitchVoiceModule"; } 259 get { return "FreeSwitchVoiceModule"; }
271 } 260 }
272 261
273 public bool IsSharedModule 262 public Type ReplaceableInterface
274 { 263 {
275 get { return true; } 264 get { return null; }
276 } 265 }
277 266
278 // <summary> 267 // <summary>
@@ -725,46 +714,6 @@ namespace OpenSim.Region.OptionalModules.Avatar.Voice.FreeSwitchVoice
725 714
726 response["int_response_code"] = 200; 715 response["int_response_code"] = 200;
727 return response; 716 return response;
728 /*
729 <level0>
730 <status>OK</status><body><status>Ok</status><cookie_name>lib_session</cookie_name>
731 * <cookie>xMj1QJSc7TA-G7XqcW6QXAg==:1290551700:050d35c6fef96f132f780d8039ff7592::</cookie>
732 * <auth_token>xMj1QJSc7TA-G7XqcW6QXAg==:1290551700:050d35c6fef96f132f780d8039ff7592::</auth_token>
733 * <primary>1</primary>
734 * <account_id>7449</account_id>
735 * <displayname>Teravus Ousley</displayname></body></level0>
736 */
737 }
738
739 public Hashtable FreeSwitchConfigHTTPHandler(Hashtable request)
740 {
741 m_log.DebugFormat("[FreeSwitchVoice] FreeSwitchConfigHTTPHandler called with {0}", (string)request["body"]);
742
743 Hashtable response = new Hashtable();
744 response["str_response_string"] = string.Empty;
745 // all the params come as NVPs in the request body
746 Hashtable requestBody = parseRequestBody((string) request["body"]);
747
748 // is this a dialplan or directory request
749 string section = (string) requestBody["section"];
750
751 if (section == "directory")
752 response = m_FreeSwitchDirectory.HandleDirectoryRequest(m_freeSwitchContext, m_freeSwitchRealm, requestBody);
753 else if (section == "dialplan")
754 response = m_FreeSwitchDialplan.HandleDialplanRequest(m_freeSwitchContext, m_freeSwitchRealm, requestBody);
755 else
756 m_log.WarnFormat("[FreeSwitchVoice]: section was {0}", section);
757
758 // XXX: re-generate dialplan:
759 // - conf == region UUID
760 // - conf number = region port
761 // -> TODO Initialise(): keep track of regions via events
762 // re-generate accounts for all avatars
763 // -> TODO Initialise(): keep track of avatars via events
764 Regex normalizeEndLines = new Regex(@"\r\n", RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.Multiline);
765
766 m_log.DebugFormat("[FreeSwitchVoice] FreeSwitchConfigHTTPHandler return {0}",normalizeEndLines.Replace(((string)response["str_response_string"]), ""));
767 return response;
768 } 717 }
769 718
770 public Hashtable parseRequestBody(string body) 719 public Hashtable parseRequestBody(string body)
diff --git a/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerConnector.cs b/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerConnector.cs
index 07bafc8..da56b87 100644
--- a/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerConnector.cs
+++ b/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerConnector.cs
@@ -26,18 +26,27 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Web;
31using System.Reflection;
29using Nini.Config; 32using Nini.Config;
30using OpenSim.Server.Base; 33using OpenSim.Server.Base;
31using OpenSim.Services.Interfaces; 34using OpenSim.Services.Interfaces;
32using OpenSim.Framework.Servers.HttpServer; 35using OpenSim.Framework.Servers.HttpServer;
33using OpenSim.Server.Handlers.Base; 36using OpenSim.Server.Handlers.Base;
37using log4net;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
34 40
35namespace OpenSim.Server.Handlers.Freeswitch 41namespace OpenSim.Server.Handlers.Freeswitch
36{ 42{
37 public class FreeswitchServerConnector : ServiceConnector 43 public class FreeswitchServerConnector : ServiceConnector
38 { 44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
39 private IFreeswitchService m_FreeswitchService; 47 private IFreeswitchService m_FreeswitchService;
40 private string m_ConfigName = "FreeswitchService"; 48 private string m_ConfigName = "FreeswitchService";
49 protected readonly string m_freeSwitchAPIPrefix = "/fsapi";
41 50
42 public FreeswitchServerConnector(IConfigSource config, IHttpServer server, string configName) : 51 public FreeswitchServerConnector(IConfigSource config, IHttpServer server, string configName) :
43 base(config, server, configName) 52 base(config, server, configName)
@@ -59,7 +68,61 @@ namespace OpenSim.Server.Handlers.Freeswitch
59 m_FreeswitchService = 68 m_FreeswitchService =
60 ServerUtils.LoadPlugin<IFreeswitchService>(freeswitchService, args); 69 ServerUtils.LoadPlugin<IFreeswitchService>(freeswitchService, args);
61 70
62 server.AddStreamHandler(new FreeswitchServerGetHandler(m_FreeswitchService)); 71 server.AddHTTPHandler(String.Format("{0}/freeswitch-config", m_freeSwitchAPIPrefix), FreeSwitchConfigHTTPHandler);
72 server.AddHTTPHandler(String.Format("{0}/region-config", m_freeSwitchAPIPrefix), RegionConfigHTTPHandler);
73 }
74
75 public Hashtable FreeSwitchConfigHTTPHandler(Hashtable request)
76 {
77 Hashtable response = new Hashtable();
78 response["str_response_string"] = string.Empty;
79 response["content_type"] = "text/plain";
80 response["keepalive"] = false;
81 response["int_response_code"] = 500;
82
83 Hashtable requestBody = ParseRequestBody((string) request["body"]);
84
85 string section = (string) requestBody["section"];
86
87 if (section == "directory")
88 response = m_FreeswitchService.HandleDirectoryRequest(requestBody);
89 else if (section == "dialplan")
90 response = m_FreeswitchService.HandleDialplanRequest(requestBody);
91 else
92 m_log.WarnFormat("[FreeSwitchVoice]: section was {0}", section);
93
94 return response;
63 } 95 }
96
97 private Hashtable ParseRequestBody(string body)
98 {
99 Hashtable bodyParams = new Hashtable();
100 // split string
101 string [] nvps = body.Split(new Char [] {'&'});
102
103 foreach (string s in nvps)
104 {
105 if (s.Trim() != "")
106 {
107 string [] nvp = s.Split(new Char [] {'='});
108 bodyParams.Add(HttpUtility.UrlDecode(nvp[0]), HttpUtility.UrlDecode(nvp[1]));
109 }
110 }
111
112 return bodyParams;
113 }
114
115 public Hashtable RegionConfigHTTPHandler(Hashtable request)
116 {
117 Hashtable response = new Hashtable();
118 response["content_type"] = "text/json";
119 response["keepalive"] = false;
120 response["int_response_code"] = 200;
121
122 response["str_response_string"] = m_FreeswitchService.GetJsonConfig();
123
124 return response;
125 }
126
64 } 127 }
65} 128}
diff --git a/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerGetHandler.cs b/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerGetHandler.cs
deleted file mode 100644
index 8b41742..0000000
--- a/OpenSim/Server/Handlers/Freeswitch/FreeswitchServerGetHandler.cs
+++ /dev/null
@@ -1,72 +0,0 @@
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
28using Nini.Config;
29using log4net;
30using System;
31using System.IO;
32using System.Reflection;
33using System.Net;
34using System.Text;
35using System.Text.RegularExpressions;
36using System.Xml;
37using System.Xml.Serialization;
38using OpenSim.Server.Base;
39using OpenSim.Services.Interfaces;
40using OpenSim.Framework;
41using OpenSim.Framework.Servers.HttpServer;
42
43namespace OpenSim.Server.Handlers.Freeswitch
44{
45 public class FreeswitchServerGetHandler : BaseStreamHandler
46 {
47 // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48
49 //private IFreeswitchService m_FreeswitchService;
50
51 public FreeswitchServerGetHandler(IFreeswitchService service) :
52 base("GET", "/api")
53 {
54 //m_FreeswitchService = service;
55 }
56
57 public override byte[] Handle(string path, Stream request,
58 OSHttpRequest httpRequest, OSHttpResponse httpResponse)
59 {
60 byte[] result = new byte[0];
61
62 string[] p = SplitParams(path);
63
64 if (p.Length == 0)
65 return result;
66
67 // Process web request
68
69 return result;
70 }
71 }
72}
diff --git a/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs
new file mode 100644
index 0000000..d63d99d
--- /dev/null
+++ b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs
@@ -0,0 +1,103 @@
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
28using log4net;
29using System;
30using System.IO;
31using System.Collections;
32using System.Reflection;
33using Nini.Config;
34using OpenSim.Framework;
35using OpenSim.Framework.Communications;
36using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Services.Interfaces;
38using OpenSim.Server.Base;
39using OpenMetaverse;
40
41namespace OpenSim.Services.Connectors
42{
43 public class RemoteFreeswitchConnector : IFreeswitchService
44 {
45 private static readonly ILog m_log =
46 LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType);
48
49 private string m_ServerURI = String.Empty;
50
51 public RemoteFreeswitchConnector()
52 {
53 }
54
55 public RemoteFreeswitchConnector(string serverURI)
56 {
57 m_ServerURI = Path.Combine(serverURI.TrimEnd('/'), "region-config");
58 }
59
60 public RemoteFreeswitchConnector(IConfigSource source)
61 {
62 Initialise(source);
63 }
64
65 public virtual void Initialise(IConfigSource source)
66 {
67 IConfig freeswitchConfig = source.Configs["FreeSwitchVoice"];
68 if (freeswitchConfig == null)
69 {
70 m_log.Error("[FREESWITCH CONNECTOR]: FreeSwitchVoice missing from OpenSim.ini");
71 throw new Exception("Freeswitch connector init error");
72 }
73
74 string serviceURI = freeswitchConfig.GetString("FreeswitchServiceURL",
75 String.Empty);
76
77 if (serviceURI == String.Empty)
78 {
79 m_log.Error("[FREESWITCH CONNECTOR]: No FreeswitchServiceURL named in section FreeSwitchVoice");
80 throw new Exception("Freeswitch connector init error");
81 }
82 m_ServerURI = serviceURI;
83 }
84
85 public Hashtable HandleDirectoryRequest(Hashtable requestBody)
86 {
87 // not used here
88 return new Hashtable();
89 }
90
91 public Hashtable HandleDialplanRequest(Hashtable requestBody)
92 {
93 // not used here
94 return new Hashtable();
95 }
96
97 public string GetJsonConfig()
98 {
99 return SynchronousRestFormsRequester.MakeRequest("GET",
100 m_ServerURI, String.Empty);
101 }
102 }
103}
diff --git a/OpenSim/Services/FreeswitchService/FreeswitchService.cs b/OpenSim/Services/FreeswitchService/FreeswitchService.cs
index 0a38300..fe6f5cd 100644
--- a/OpenSim/Services/FreeswitchService/FreeswitchService.cs
+++ b/OpenSim/Services/FreeswitchService/FreeswitchService.cs
@@ -26,6 +26,7 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Text;
29using System.Reflection; 30using System.Reflection;
30using Nini.Config; 31using Nini.Config;
31using log4net; 32using log4net;
@@ -33,19 +34,373 @@ using OpenSim.Framework;
33using OpenSim.Data; 34using OpenSim.Data;
34using OpenSim.Services.Interfaces; 35using OpenSim.Services.Interfaces;
35using OpenMetaverse; 36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using System.Collections;
36 39
37namespace OpenSim.Services.FreeswitchService 40namespace OpenSim.Services.FreeswitchService
38{ 41{
39 public class FreeswitchService : FreeswitchServiceBase, IFreeswitchService 42 public class FreeswitchService : FreeswitchServiceBase, IFreeswitchService
40 { 43 {
41 //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 44 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42 45
43 public FreeswitchService(IConfigSource config) : base(config) 46 public FreeswitchService(IConfigSource config) : base(config)
44 { 47 {
45 // Perform initilialization here 48 // Perform initilialization here
46 } 49 }
47 50
51 public Hashtable HandleDialplanRequest(Hashtable request)
52 {
53 m_log.DebugFormat("[FreeSwitchVoice] HandleDialplanRequest called with {0}",request.ToString());
54
55 Hashtable response = new Hashtable();
56
57 foreach (DictionaryEntry item in request)
58 {
59 m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}",item.Key, item.Value);
60 }
61
62 string requestcontext = (string) request["Hunt-Context"];
63 response["content_type"] = "text/xml";
64 response["keepalive"] = false;
65 response["int_response_code"] = 200;
66
67 if (m_freeSwitchContext != String.Empty && m_freeSwitchContext != requestcontext)
68 {
69 m_log.Debug("[FreeSwitchDirectory] returning empty as it's for another context");
70 response["str_response_string"] = "";
71 }
72 else
73 {
74 response["str_response_string"] = String.Format(@"<?xml version=""1.0"" encoding=""utf-8""?>
75 <document type=""freeswitch/xml"">
76 <section name=""dialplan"">
77 <context name=""{0}"">" +
78
79/* <!-- dial via SIP uri -->
80 <extension name=""sip_uri"">
81 <condition field=""destination_number"" expression=""^sip:(.*)$"">
82 <action application=""bridge"" data=""sofia/${use_profile}/$1""/>
83 <!--<action application=""bridge"" data=""$1""/>-->
84 </condition>
85 </extension>*/
86
87 @"<extension name=""opensim_conferences"">
88 <condition field=""destination_number"" expression=""^confctl-(.*)$"">
89 <action application=""answer""/>
90 <action application=""conference"" data=""$1-{1}@{0}""/>
91 </condition>
92 </extension>
93
94 <extension name=""opensim_conf"">
95 <condition field=""destination_number"" expression=""^conf-(.*)$"">
96 <action application=""answer""/>
97 <action application=""conference"" data=""$1-{1}@{0}""/>
98 </condition>
99 </extension>
100
101 <extension name=""avatar"">
102 <condition field=""destination_number"" expression=""^(x.*)$"">
103 <action application=""bridge"" data=""user/$1""/>
104 </condition>
105 </extension>
106
107 </context>
108 </section>
109 </document>", m_freeSwitchContext, m_freeSwitchRealm);
110 }
111
112 return response;
113 }
114
115 public Hashtable HandleDirectoryRequest(Hashtable request)
116 {
117 Hashtable response = new Hashtable();
118 string domain = (string) request["domain"];
119 if (domain != m_freeSwitchRealm) {
120 response["content_type"] = "text/xml";
121 response["keepalive"] = false;
122 response["int_response_code"] = 200;
123 response["str_response_string"] = "";
124 } else {
125 m_log.DebugFormat("[FreeSwitchDirectory] HandleDirectoryRequest called with {0}",request.ToString());
126
127 // information in the request we might be interested in
128
129 // Request 1 sip_auth for users account
130
131 //Event-Calling-Function=sofia_reg_parse_auth
132 //Event-Calling-Line-Number=1494
133 //action=sip_auth
134 //sip_user_agent=Vivox-SDK-2.1.3010.6151-Mac%20(Feb-11-2009/16%3A42%3A41)
135 //sip_auth_username=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==)
136 //sip_auth_realm=9.20.151.43
137 //sip_contact_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==)
138 //sip_contact_host=192.168.0.3 // this shouldnt really be a local IP, investigate STUN servers
139 //sip_to_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D
140 //sip_to_host=9.20.151.43
141 //sip_auth_method=REGISTER
142 //user=xhZuXKmRpECyr2AARJYyGgg%3D%3D
143 //domain=9.20.151.43
144 //ip=9.167.220.137 // this is the correct IP rather than sip_contact_host above when through a vpn or NAT setup
145
146 foreach (DictionaryEntry item in request)
147 {
148 m_log.InfoFormat("[FreeSwitchDirectory] requestBody item {0} {1}", item.Key, item.Value);
149 }
150
151 string eventCallingFunction = (string) request["Event-Calling-Function"];
152 if (eventCallingFunction == null)
153 {
154 eventCallingFunction = "sofia_reg_parse_auth";
155 }
156
157 if (eventCallingFunction.Length == 0)
158 {
159 eventCallingFunction = "sofia_reg_parse_auth";
160 }
161
162 if (eventCallingFunction == "sofia_reg_parse_auth")
163 {
164 string sipAuthMethod = (string)request["sip_auth_method"];
165
166 if (sipAuthMethod == "REGISTER")
167 {
168 response = HandleRegister(m_freeSwitchContext, m_freeSwitchRealm, request);
169 }
170 else if (sipAuthMethod == "INVITE")
171 {
172 response = HandleInvite(m_freeSwitchContext, m_freeSwitchRealm, request);
173 }
174 else
175 {
176 m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod);
177 response["int_response_code"] = 404;
178 response["content_type"] = "text/xml";
179 response["str_response_string"] = "";
180 }
181 }
182 else if (eventCallingFunction == "switch_xml_locate_user")
183 {
184 response = HandleLocateUser(m_freeSwitchRealm, request);
185 }
186 else if (eventCallingFunction == "user_data_function") // gets called when an avatar to avatar call is made
187 {
188 response = HandleLocateUser(m_freeSwitchRealm, request);
189 }
190 else if (eventCallingFunction == "user_outgoing_channel")
191 {
192 response = HandleRegister(m_freeSwitchContext, m_freeSwitchRealm, request);
193 }
194 else if (eventCallingFunction == "config_sofia") // happens once on freeswitch startup
195 {
196 response = HandleConfigSofia(m_freeSwitchContext, m_freeSwitchRealm, request);
197 }
198 else if (eventCallingFunction == "switch_load_network_lists")
199 {
200 //response = HandleLoadNetworkLists(request);
201 response["int_response_code"] = 404;
202 response["keepalive"] = false;
203 response["content_type"] = "text/xml";
204 response["str_response_string"] = "";
205 }
206 else
207 {
208 m_log.ErrorFormat("[FreeSwitchVoice] HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction);
209 response["int_response_code"] = 404;
210 response["keepalive"] = false;
211 response["content_type"] = "text/xml";
212 response["str_response_string"] = "";
213 }
214 }
215 return response;
216 }
217
218 private Hashtable HandleRegister(string Context, string Realm, Hashtable request)
219 {
220 m_log.Info("[FreeSwitchDirectory] HandleRegister called");
221
222 // TODO the password we return needs to match that sent in the request, this is hard coded for now
223 string password = "1234";
224 string domain = (string) request["domain"];
225 string user = (string) request["user"];
226
227 Hashtable response = new Hashtable();
228 response["content_type"] = "text/xml";
229 response["keepalive"] = false;
230 response["int_response_code"] = 200;
231
232 response["str_response_string"] = String.Format(
233 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
234 "<document type=\"freeswitch/xml\">\r\n" +
235 "<section name=\"directory\" description=\"User Directory\">\r\n" +
236 "<domain name=\"{0}\">\r\n" +
237 "<user id=\"{1}\">\r\n" +
238 "<params>\r\n" +
239 "<param name=\"password\" value=\"{2}\" />\r\n" +
240 "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
241 "</params>\r\n" +
242 "<variables>\r\n" +
243 "<variable name=\"user_context\" value=\"{3}\" />\r\n" +
244 "<variable name=\"presence_id\" value=\"{1}@{0}\"/>"+
245 "</variables>\r\n" +
246 "</user>\r\n" +
247 "</domain>\r\n" +
248 "</section>\r\n" +
249 "</document>\r\n",
250 domain , user, password, Context);
251
252 return response;
253 }
254
255 private Hashtable HandleInvite(string Context, string Realm, Hashtable request)
256 {
257 m_log.Info("[FreeSwitchDirectory] HandleInvite called");
258
259 // TODO the password we return needs to match that sent in the request, this is hard coded for now
260 string password = "1234";
261 string domain = (string) request["domain"];
262 string user = (string) request["user"];
263 string sipRequestUser = (string) request["sip_request_user"];
264
265 Hashtable response = new Hashtable();
266 response["content_type"] = "text/xml";
267 response["keepalive"] = false;
268 response["int_response_code"] = 200;
269 response["str_response_string"] = String.Format(
270 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
271 "<document type=\"freeswitch/xml\">\r\n" +
272 "<section name=\"directory\" description=\"User Directory\">\r\n" +
273 "<domain name=\"{0}\">\r\n" +
274 "<user id=\"{1}\">\r\n" +
275 "<params>\r\n" +
276 "<param name=\"password\" value=\"{2}\" />\r\n" +
277 "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${1}@${{dialed_domain}}}}${{sofia_contact(${1}@${{dialed_domain}})}}\"/>\r\n" +
278 "</params>\r\n" +
279 "<variables>\r\n" +
280 "<variable name=\"user_context\" value=\"{4}\" />\r\n" +
281 "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+
282 "</variables>\r\n" +
283 "</user>\r\n" +
284 "<user id=\"{3}\">\r\n" +
285 "<params>\r\n" +
286 "<param name=\"password\" value=\"{2}\" />\r\n" +
287 "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${3}@${{dialed_domain}}}}${{sofia_contact(${3}@${{dialed_domain}})}}\"/>\r\n" +
288 "</params>\r\n" +
289 "<variables>\r\n" +
290 "<variable name=\"user_context\" value=\"{4}\" />\r\n" +
291 "<variable name=\"presence_id\" value=\"{3}@$${{domain}}\"/>"+
292 "</variables>\r\n" +
293 "</user>\r\n" +
294 "</domain>\r\n" +
295 "</section>\r\n" +
296 "</document>\r\n",
297 domain , user, password,sipRequestUser, Context);
298
299 return response;
300 }
48 301
49 // Implement IFreeswitchService here 302 private Hashtable HandleLocateUser(String Realm, Hashtable request)
303 {
304 m_log.Info("[FreeSwitchDirectory] HandleLocateUser called");
305
306 // TODO the password we return needs to match that sent in the request, this is hard coded for now
307 string domain = (string) request["domain"];
308 string user = (string) request["user"];
309
310 Hashtable response = new Hashtable();
311 response["content_type"] = "text/xml";
312 response["keepalive"] = false;
313 response["int_response_code"] = 200;
314 response["str_response_string"] = String.Format(
315 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
316 "<document type=\"freeswitch/xml\">\r\n" +
317 "<section name=\"directory\" description=\"User Directory\">\r\n" +
318 "<domain name=\"{0}\">\r\n" +
319 "<params>\r\n" +
320 "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
321 "</params>\r\n" +
322 "<user id=\"{1}\">\r\n" +
323 "<variables>\r\n"+
324 "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
325 "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+
326 "</variables>\r\n"+
327 "</user>\r\n" +
328 "</domain>\r\n" +
329 "</section>\r\n" +
330 "</document>\r\n",
331 domain , user);
332
333 return response;
334 }
335
336 private Hashtable HandleConfigSofia(string Context, string Realm, Hashtable request)
337 {
338 m_log.Info("[FreeSwitchDirectory] HandleConfigSofia called");
339
340 // TODO the password we return needs to match that sent in the request, this is hard coded for now
341 string domain = (string) request["domain"];
342
343 Hashtable response = new Hashtable();
344 response["content_type"] = "text/xml";
345 response["keepalive"] = false;
346 response["int_response_code"] = 200;
347 response["str_response_string"] = String.Format(
348 "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" +
349 "<document type=\"freeswitch/xml\">\r\n" +
350 "<section name=\"directory\" description=\"User Directory\">\r\n" +
351 "<domain name=\"{0}\">\r\n" +
352 "<params>\r\n" +
353 "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" +
354 "</params>\r\n" +
355 "<groups name=\"default\">\r\n"+
356 "<users>\r\n"+
357 "<user id=\"$${{default_provider}}\">\r\n"+
358 "<gateways>\r\n"+
359 "<gateway name=\"$${{default_provider}}\">\r\n"+
360 "<param name=\"username\" value=\"$${{default_provider_username}}\"/>\r\n"+
361 "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+
362 "<param name=\"from-user\" value=\"$${{default_provider_username}}\"/>\r\n"+
363 "<param name=\"from-domain\" value=\"$${{default_provider_from_domain}}\"/>\r\n"+
364 "<param name=\"expire-seconds\" value=\"600\"/>\r\n"+
365 "<param name=\"register\" value=\"$${{default_provider_register}}\"/>\r\n"+
366 "<param name=\"retry-seconds\" value=\"30\"/>\r\n"+
367 "<param name=\"extension\" value=\"$${{default_provider_contact}}\"/>\r\n"+
368 "<param name=\"contact-params\" value=\"domain_name=$${{domain}}\"/>\r\n"+
369 "<param name=\"context\" value=\"{1}\"/>\r\n"+
370 "</gateway>\r\n"+
371 "</gateways>\r\n"+
372 "<params>\r\n"+
373 "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+
374 "</params>\r\n"+
375 "</user>\r\n"+
376 "</users>"+
377 "</groups>\r\n" +
378 "<variables>\r\n"+
379 "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+
380 "</variables>\r\n"+
381 "</domain>\r\n" +
382 "</section>\r\n" +
383 "</document>\r\n",
384 domain, Context);
385
386 return response;
387 }
388
389 public string GetJsonConfig()
390 {
391 OSDMap map = new OSDMap(9);
392
393 map.Add("Realm", m_freeSwitchRealm);
394 map.Add("SIPProxy", m_freeSwitchSIPProxy);
395 map.Add("AttemptUseSTUN", m_freeSwitchAttemptUseSTUN);
396 map.Add("EchoServer", m_freeSwitchEchoServer);
397 map.Add("EchoPort", m_freeSwitchEchoPort);
398 map.Add("DefaultWellKnownIP", m_freeSwitchDefaultWellKnownIP);
399 map.Add("DefaultTimeout", m_freeSwitchDefaultTimeout);
400 map.Add("Context", m_freeSwitchContext);
401 map.Add("APIPrefix", m_freeSwitchAPIPrefix);
402
403 return OSDParser.SerializeJsonString(map);
404 }
50 } 405 }
51} 406}
diff --git a/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs b/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs
index 83fecef..ebbb1b0 100644
--- a/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs
+++ b/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs
@@ -31,11 +31,28 @@ using Nini.Config;
31using OpenSim.Framework; 31using OpenSim.Framework;
32using OpenSim.Services.Interfaces; 32using OpenSim.Services.Interfaces;
33using OpenSim.Services.Base; 33using OpenSim.Services.Base;
34using log4net;
34 35
35namespace OpenSim.Services.FreeswitchService 36namespace OpenSim.Services.FreeswitchService
36{ 37{
37 public class FreeswitchServiceBase : ServiceBase 38 public class FreeswitchServiceBase : ServiceBase
38 { 39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 protected string m_freeSwitchRealm;
43 protected string m_freeSwitchSIPProxy;
44 protected bool m_freeSwitchAttemptUseSTUN = false;
45 protected string m_freeSwitchEchoServer;
46 protected int m_freeSwitchEchoPort = 50505;
47 protected string m_freeSwitchDefaultWellKnownIP;
48 protected int m_freeSwitchDefaultTimeout = 5000;
49 protected string m_freeSwitchContext = "default";
50 protected string m_freeSwitchServerUser = "freeswitch";
51 protected string m_freeSwitchServerPass = "password";
52 protected readonly string m_freeSwitchAPIPrefix = "/fsapi";
53
54 protected bool m_Enabled = false;
55
39 public FreeswitchServiceBase(IConfigSource config) : base(config) 56 public FreeswitchServiceBase(IConfigSource config) : base(config)
40 { 57 {
41 // 58 //
@@ -44,7 +61,24 @@ namespace OpenSim.Services.FreeswitchService
44 IConfig freeswitchConfig = config.Configs["FreeswitchService"]; 61 IConfig freeswitchConfig = config.Configs["FreeswitchService"];
45 if (freeswitchConfig != null) 62 if (freeswitchConfig != null)
46 { 63 {
47 // Read config here !! 64 m_freeSwitchDefaultWellKnownIP = freeswitchConfig.GetString("ServerAddress", String.Empty);
65 if (m_freeSwitchDefaultWellKnownIP == String.Empty)
66 {
67 m_log.Error("[FREESWITCH]: No FreeswitchServerAddress given, can't continue");
68 return;
69 }
70
71 m_freeSwitchRealm = freeswitchConfig.GetString("Realm", m_freeSwitchDefaultWellKnownIP);
72 m_freeSwitchSIPProxy = freeswitchConfig.GetString("SIPProxy", m_freeSwitchDefaultWellKnownIP + ":5060");
73 m_freeSwitchEchoServer = freeswitchConfig.GetString("EchoServer", m_freeSwitchDefaultWellKnownIP);
74 m_freeSwitchEchoPort = freeswitchConfig.GetInt("EchoPort", m_freeSwitchEchoPort);
75 m_freeSwitchAttemptUseSTUN = freeswitchConfig.GetBoolean("AttemptSTUN", false); // This may not work
76 m_freeSwitchDefaultTimeout = freeswitchConfig.GetInt("DefaultTimeout", m_freeSwitchDefaultTimeout);
77 m_freeSwitchContext = freeswitchConfig.GetString("Context", m_freeSwitchContext);
78 m_freeSwitchServerUser = freeswitchConfig.GetString("UserName", m_freeSwitchServerUser);
79 m_freeSwitchServerPass = freeswitchConfig.GetString("Password", m_freeSwitchServerPass);
80
81 m_Enabled = true;
48 } 82 }
49 } 83 }
50 } 84 }
diff --git a/OpenSim/Services/Interfaces/IFreeswitchService.cs b/OpenSim/Services/Interfaces/IFreeswitchService.cs
index d1f635b..e7941d5 100644
--- a/OpenSim/Services/Interfaces/IFreeswitchService.cs
+++ b/OpenSim/Services/Interfaces/IFreeswitchService.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using OpenSim.Framework; 29using OpenSim.Framework;
30using System.Collections;
30 31
31namespace OpenSim.Services.Interfaces 32namespace OpenSim.Services.Interfaces
32{ 33{
33 public interface IFreeswitchService 34 public interface IFreeswitchService
34 { 35 {
35 // Place anything the connector eeds to access here! 36 Hashtable HandleDirectoryRequest(Hashtable requestBody);
37 Hashtable HandleDialplanRequest(Hashtable requestBody);
38 string GetJsonConfig();
36 } 39 }
37} 40}
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example
index 9d34854..988831f 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -580,44 +580,33 @@
580[FreeSwitchVoice] 580[FreeSwitchVoice]
581 ;; In order for this to work you need a functioning FreeSWITCH PBX set up. 581 ;; In order for this to work you need a functioning FreeSWITCH PBX set up.
582 ;; Configuration details at http://opensimulator.org/wiki/Freeswitch_Module 582 ;; Configuration details at http://opensimulator.org/wiki/Freeswitch_Module
583 ; enabled = false 583 ; Enabled = false
584 584
585 ;; FreeSWITCH server is going to contact us and ask us all sorts of things 585 ;; You need to load a local service for a standalone, and a remote service
586 ; freeswitch_server_user = freeswitch 586 ;; for a grid region. Use one of the lines below, as appropriate
587 ; freeswitch_server_pass = password 587 ; LocalServiceModule = OpenSim.Services.FreeswitchService.dll:FreeswitchService
588 ; freeswitch_api_prefix = /api 588 ; LocalServiceModule = OpenSim.Services.Connectors.dll:RemoteFreeswitchConnector
589 589
590 ;; external IP address of your OpenSim voice enabled region 590 ;; If using a remote module, specify the server URL
591 ;; note: all regions running on same OpenSim.exe will be enabled 591 ; FreeswitchServiceURL = http://my.grid.server:8003/fsapi
592 ; freeswitch_service_server = ip.address.of.your.sim 592
593 593[FreeswitchService]
594 ;; this should be the same port the region listens on 594 ;; !!!!!!!!!!!!!!!!!!!!!!!!!!!
595 ; freeswitch_service_port = 9000 595 ;; !!!!!!STANDALONE ONLY!!!!!!
596 ; freeswitch_realm = ip.address.of.freeswitch.server 596 ;; !!!!!!!!!!!!!!!!!!!!!!!!!!!
597 ; freeswitch_sip_proxy = ip.address.of.freeswitch.server:5060 597 ;; IP of your FS server
598 598 ;ServerAddress = 85.25.142.92
599 ;; STUN = Simple Traversal of UDP through NATs 599
600 ;; See http://wiki.freeswitch.org/wiki/NAT_Traversal 600 ;; All other options are - well - optional
601 ;; stun.freeswitch.org is not guaranteed to be running so use it in 601 ; Realm = "127.0.0.1"
602 ;; production at your own risk 602 ; SIPProxy = "127.0.0.1:5060"
603 ; freeswitch_attempt_stun = false 603 ; EchoServer = "127.0.0.1"
604 ; freeswitch_stun_server = ip.address.of.stun.server 604 ; EchoPort = 50505
605 ; freeswitch_echo_server = ip.address.of.freeswitch.server 605 ; AttemptSTUN = "false"
606 ; freeswitch_echo_port = 50505 606 ; DefaultTimeout = 5000
607 ; freeswitch_well_known_ip = ip.address.of.freeswitch.server 607 ; Context = "default"
608 608 ; UserName = "freeswitch"
609 ;; Type the address of your http server here, hostname is allowed. 609 ; Password = "password"
610 ;; This is provided so you can specify a hostname
611 ;; This is used by client for account verification. By default, it's the
612 ;; same as the freeswitch service server.
613 ; opensim_well_known_http_address = Address_Of_Your_SIM_HTTP_Server
614
615 ;; Timeouts
616 ; freeswitch_default_timeout = 5000
617 ; freeswitch_subscribe_retry = 120
618
619 ;; Misc
620 ; freeswitch_password_reset_url =
621 610
622[Groups] 611[Groups]
623 ;# {Enabled} {} {Enable groups?} {true false} false 612 ;# {Enabled} {} {Enable groups?} {true false} false
diff --git a/bin/Robust.ini.example b/bin/Robust.ini.example
index bc87ac2..b12e05b 100644
--- a/bin/Robust.ini.example
+++ b/bin/Robust.ini.example
@@ -69,6 +69,19 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003
69; * This is the configuration for the freeswitch server in grid mode 69; * This is the configuration for the freeswitch server in grid mode
70[FreeswitchService] 70[FreeswitchService]
71 LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService" 71 LocalServiceModule = "OpenSim.Services.FreeswitchService.dll:FreeswitchService"
72 ;; IP of your FS server
73 ; ServerAddress = 127.0.0.1
74
75 ;; All other options are - well - optional
76 ; Realm = "127.0.0.1"
77 ; SIPProxy = "127.0.0.1:5060"
78 ; EchoServer = "127.0.0.1"
79 ; EchoPort = 50505
80 ; AttemptSTUN = "false"
81 ; DefaultTimeout = 5000
82 ; Context = "default"
83 ; UserName = "freeswitch"
84 ; Password = "password"
72 85
73; * This is the new style authentication service. Currently, only MySQL 86; * This is the new style authentication service. Currently, only MySQL
74; * is implemented. "Realm" is the table that is used for user lookup. 87; * is implemented. "Realm" is the table that is used for user lookup.
diff --git a/prebuild.xml b/prebuild.xml
index ac003d9..00be4f9 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -1023,6 +1023,7 @@
1023 <ReferencePath>../../../bin/</ReferencePath> 1023 <ReferencePath>../../../bin/</ReferencePath>
1024 <Reference name="System"/> 1024 <Reference name="System"/>
1025 <Reference name="OpenMetaverseTypes" path="../../../bin/"/> 1025 <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
1026 <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
1026 <Reference name="OpenMetaverse" path="../../../bin/"/> 1027 <Reference name="OpenMetaverse" path="../../../bin/"/>
1027 <Reference name="OpenSim.Framework"/> 1028 <Reference name="OpenSim.Framework"/>
1028 <Reference name="OpenSim.Framework.Console"/> 1029 <Reference name="OpenSim.Framework.Console"/>