aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs370
1 files changed, 0 insertions, 370 deletions
diff --git a/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs b/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs
deleted file mode 100644
index aa8764d..0000000
--- a/OpenSim/Region/Environment/Modules/VoiceChat/VoiceChatServer.cs
+++ /dev/null
@@ -1,370 +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 OpenSim 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 System;
29using System.Collections.Generic;
30using System.Text;
31using System.Threading;
32using System.Net.Sockets;
33using System.Net;
34using OpenSim.Region.Environment.Scenes;
35using OpenSim.Framework;
36using OpenSim.Region.Environment.Modules;
37using OpenSim.Region.Environment.Interfaces;
38using Nini;
39using libsecondlife;
40
41namespace OpenSim.Region.Environment.Modules.VoiceChat
42{
43 public class VoiceChatServer : IRegionModule
44 {
45 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
46
47 int m_dummySocketPort = 53134;
48
49 Thread m_listenerThread;
50 Thread m_mainThread;
51 List<Scene> m_scenes = new List<Scene>();
52 Socket m_server;
53 Socket m_selectCancel;
54 bool m_enabled = false;
55
56 Dictionary<Socket, VoiceClient> m_clients = new Dictionary<Socket,VoiceClient>();
57 Dictionary<LLUUID, VoiceClient> m_uuidToClient = new Dictionary<LLUUID,VoiceClient>();
58
59
60 #region IRegionModule Members
61
62 public void Initialise(Scene scene, Nini.Config.IConfigSource source)
63 {
64 try
65 {
66 m_enabled = source.Configs["Voice"].GetBoolean("enabled", m_enabled);
67 }
68 catch (Exception)
69 { }
70
71 if (m_enabled)
72 {
73 if (!m_scenes.Contains(scene))
74 m_scenes.Add(scene);
75
76 scene.EventManager.OnNewClient += NewClient;
77 scene.EventManager.OnRemovePresence += RemovePresence;
78 }
79 }
80
81 public void PostInitialise()
82 {
83 if (m_enabled != true)
84 return;
85
86 try
87 {
88 CreateListeningSocket();
89 }
90 catch (Exception)
91 {
92 m_log.Error("[VOICECHAT]: Unable to start listening");
93 return;
94 }
95
96 m_listenerThread = new Thread(new ThreadStart(ListenIncomingConnections));
97 m_listenerThread.IsBackground = true;
98 m_listenerThread.Start();
99
100 m_mainThread = new Thread(new ThreadStart(RunVoiceChat));
101 m_mainThread.IsBackground = true;
102 m_mainThread.Start();
103
104 Thread.Sleep(500);
105 m_selectCancel = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
106 m_selectCancel.Connect("localhost", m_dummySocketPort);
107 }
108
109 public void Close()
110 {
111 throw new NotImplementedException();
112 }
113
114 public string Name
115 {
116 get { return "VoiceChatModule"; }
117 }
118
119 public bool IsSharedModule
120 {
121 get { return true; } // I think we can share this one.
122 }
123
124 #endregion
125
126 public void NewClient(IClientAPI client)
127 {
128 m_log.Info("[VOICECHAT]: New client: " + client.AgentId);
129 lock (m_uuidToClient)
130 {
131 m_uuidToClient[client.AgentId] = null;
132 }
133 }
134
135 public void RemovePresence(LLUUID uuid)
136 {
137 lock (m_uuidToClient)
138 {
139 if (m_uuidToClient.ContainsKey(uuid))
140 {
141 if (m_uuidToClient[uuid] != null)
142 {
143 RemoveClient(m_uuidToClient[uuid].m_socket);
144 }
145 m_uuidToClient.Remove(uuid);
146 }
147 else
148 {
149 m_log.Error("[VOICECHAT]: Presence not found on RemovePresence: " + uuid);
150 }
151 }
152 }
153
154 public bool AddClient(VoiceClient client, LLUUID uuid)
155 {
156 lock (m_uuidToClient)
157 {
158 if (m_uuidToClient.ContainsKey(uuid))
159 {
160 if (m_uuidToClient[uuid] != null) {
161 m_log.Warn("[VOICECHAT]: Multiple login attempts for " + uuid);
162 return false;
163 }
164 m_uuidToClient[uuid] = client;
165 return true;
166 }
167 }
168 return false;
169 }
170
171 public void RemoveClient(Socket socket)
172 {
173 m_log.Info("[VOICECHAT]: Removing client");
174 lock(m_clients)
175 {
176 VoiceClient client = m_clients[socket];
177
178 lock(m_uuidToClient)
179 {
180 if (m_uuidToClient.ContainsKey(client.m_clientId))
181 {
182 m_uuidToClient[client.m_clientId] = null;
183 }
184 }
185
186 m_clients.Remove(socket);
187 client.m_socket.Close();
188 }
189 }
190
191 protected void CreateListeningSocket()
192 {
193 IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 12000);
194 m_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
195 m_server.Bind(listenEndPoint);
196 m_server.Listen(50);
197 }
198
199 void ListenIncomingConnections()
200 {
201 m_log.Info("[VOICECHAT]: Listening connections...");
202 //ServerStatus.ReportThreadName("VoiceChat: Connection listener");
203
204 byte[] dummyBuffer = new byte[1];
205
206 while (true)
207 {
208 try
209 {
210 Socket connection = m_server.Accept();
211 lock (m_clients)
212 {
213 m_clients[connection] = new VoiceClient(connection, this);
214 m_selectCancel.Send(dummyBuffer);
215 m_log.Info("[VOICECHAT]: Voicechat connection from " + connection.RemoteEndPoint.ToString());
216 }
217 }
218 catch (SocketException e)
219 {
220 m_log.Error("[VOICECHAT]: During accept: " + e.ToString());
221 }
222 }
223 }
224
225 Socket ListenLoopbackSocket()
226 {
227 IPEndPoint listenEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), m_dummySocketPort);
228 Socket dummyListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
229 dummyListener.Bind(listenEndPoint);
230 dummyListener.Listen(1);
231 Socket socket = dummyListener.Accept();
232 dummyListener.Close();
233 return socket;
234 }
235
236 void RunVoiceChat()
237 {
238 m_log.Info("[VOICECHAT]: Connection handler started...");
239 //ServerStatus.ReportThreadName("VoiceChat: Connection handler");
240
241 //Listen a loopback socket for aborting select call
242 Socket dummySocket = ListenLoopbackSocket();
243
244 List<Socket> sockets = new List<Socket>();
245 byte[] buffer = new byte[65536];
246
247 while (true)
248 {
249 if (m_clients.Count == 0)
250 {
251 Thread.Sleep(100);
252 continue;
253 }
254
255 lock (m_clients)
256 {
257 foreach (Socket s in m_clients.Keys)
258 {
259 sockets.Add(s);
260 }
261 }
262 sockets.Add(dummySocket);
263
264 try
265 {
266 Socket.Select(sockets, null, null, 200000);
267 }
268 catch (SocketException e)
269 {
270 m_log.Warn("[VOICECHAT]: " + e.Message);
271 }
272
273 foreach (Socket s in sockets)
274 {
275 try
276 {
277 if (s.RemoteEndPoint != dummySocket.RemoteEndPoint)
278 {
279 ReceiveFromSocket(s, buffer);
280 }
281 else
282 {
283 //Receive data and check if there was an error with select abort socket
284 if (s.Receive(buffer) <= 0)
285 {
286 //Just give a warning for now
287 m_log.Error("[VOICECHAT]: Select abort socket was closed");
288 }
289 }
290 }
291 catch(ObjectDisposedException)
292 {
293 m_log.Warn("[VOICECHAT]: Connection has been already closed");
294 }
295 catch (Exception e)
296 {
297 m_log.Error("[VOICECHAT]: Exception: " + e.Message);
298
299 RemoveClient(s);
300 }
301 }
302
303 sockets.Clear();
304 }
305 }
306
307 private void ReceiveFromSocket( Socket s, byte[] buffer )
308 {
309 int byteCount = s.Receive(buffer);
310 if (byteCount <= 0)
311 {
312 m_log.Info("[VOICECHAT]: Connection lost to " + s.RemoteEndPoint);
313 lock (m_clients)
314 {
315 RemoveClient(s);
316 }
317 }
318 else
319 {
320 //ServerStatus.ReportInPacketTcp(byteCount);
321 lock (m_clients)
322 {
323 if (m_clients.ContainsKey(s))
324 {
325 m_clients[s].OnDataReceived(buffer, byteCount);
326 }
327 else
328 {
329 m_log.Warn("[VOICECHAT]: Got data from " + s.RemoteEndPoint +
330 ", but source is not a valid voice client");
331 }
332 }
333 }
334 }
335
336 public LLVector3 getScenePresencePosition(LLUUID clientID)
337 {
338 foreach (Scene scene in m_scenes)
339 {
340 ScenePresence x;
341 if ((x = scene.GetScenePresence(clientID)) != null)
342 {
343 return x.AbsolutePosition + new LLVector3(Constants.RegionSize * scene.RegionInfo.RegionLocX,
344 Constants.RegionSize * scene.RegionInfo.RegionLocY, 0);
345 }
346 }
347 return LLVector3.Zero;
348 }
349
350 public void BroadcastVoice(VoicePacket packet)
351 {
352 libsecondlife.LLVector3 origPos = getScenePresencePosition(packet.m_clientId);
353
354 byte[] bytes = packet.GetBytes();
355 foreach (VoiceClient client in m_clients.Values)
356 {
357 if (client.IsEnabled() && client.m_clientId != packet.m_clientId &&
358 client.m_authenticated && client.IsCodecSupported(packet.m_codec))
359 {
360 LLVector3 presenceLoc = getScenePresencePosition(client.m_clientId);
361
362 if (presenceLoc != LLVector3.Zero && Util.GetDistanceTo(presenceLoc, origPos) < 20)
363 {
364 client.SendTo(bytes);
365 }
366 }
367 }
368 }
369 }
370}