aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/FunSLUDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/FunSLUDP/LLUDPServer.cs545
1 files changed, 545 insertions, 0 deletions
diff --git a/OpenSim/Region/ClientStack/FunSLUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/FunSLUDP/LLUDPServer.cs
new file mode 100644
index 0000000..41a3197
--- /dev/null
+++ b/OpenSim/Region/ClientStack/FunSLUDP/LLUDPServer.cs
@@ -0,0 +1,545 @@
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;
30using System.Collections.Generic;
31using System.Net;
32using System.Net.Sockets;
33using System.Reflection;
34using libsecondlife.Packets;
35using log4net;
36using OpenSim.Framework;
37using OpenSim.Framework.Communications.Cache;
38using OpenSim.Region.ClientStack.LindenUDP;
39using OpenSim.Region.Environment.Scenes;
40
41namespace OpenSim.Region.ClientStack.LindenUDP
42{
43 public class LLUDPServer : LLClientStackNetworkHandler, IClientNetworkServer
44 {
45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 protected Dictionary<EndPoint, uint> clientCircuits = new Dictionary<EndPoint, uint>();
48
49 //public Dictionary<uint, EndPoint> clientCircuits_reverse = new Dictionary<uint, EndPoint>();
50 public Hashtable clientCircuits_reverse = Hashtable.Synchronized(new Hashtable());
51
52 protected Dictionary<uint, EndPoint> proxyCircuits = new Dictionary<uint, EndPoint>();
53 private Socket m_socket;
54 protected IPEndPoint ServerIncoming;
55 protected byte[] RecvBuffer = new byte[4096];
56 protected byte[] ZeroBuffer = new byte[8192];
57 protected IPEndPoint ipeSender;
58 protected EndPoint epSender;
59 protected EndPoint epProxy;
60 protected int proxyPortOffset;
61 protected AsyncCallback ReceivedData;
62 protected LLPacketServer m_packetServer;
63 protected Location m_location;
64
65 protected uint listenPort;
66 protected bool Allow_Alternate_Port;
67 protected IPAddress listenIP = IPAddress.Parse("0.0.0.0");
68 protected IScene m_localScene;
69 protected AssetCache m_assetCache;
70 protected AgentCircuitManager m_authenticateSessionsClass;
71
72 public LLPacketServer PacketServer
73 {
74 get { return m_packetServer; }
75 set { m_packetServer = value; }
76 }
77
78 public IScene LocalScene
79 {
80 set
81 {
82 m_localScene = value;
83 m_packetServer.LocalScene = m_localScene;
84 m_location = new Location(m_localScene.RegionInfo.RegionHandle);
85 }
86 }
87
88 public ulong RegionHandle
89 {
90 get { return m_location.RegionHandle; }
91 }
92
93 Socket IClientNetworkServer.Server
94 {
95 get { return m_socket; }
96 }
97
98 public bool HandlesRegion(Location x)
99 {
100 return x == m_location;
101 }
102
103 public void AddScene(Scene x)
104 {
105 LocalScene = x;
106 }
107
108 public void Start()
109 {
110 ServerListener();
111 }
112
113 public void Stop()
114 {
115 m_socket.Close();
116 }
117
118 public LLUDPServer()
119 {
120 }
121
122 public LLUDPServer(IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, AssetCache assetCache, AgentCircuitManager authenticateClass)
123 {
124 Initialise(_listenIP, ref port, proxyPortOffset, allow_alternate_port, assetCache, authenticateClass);
125 }
126
127 public void Initialise(IPAddress _listenIP, ref uint port, int proxyPortOffset, bool allow_alternate_port, AssetCache assetCache, AgentCircuitManager authenticateClass)
128 {
129 this.proxyPortOffset = proxyPortOffset;
130 listenPort = (uint) (port + proxyPortOffset);
131 listenIP = _listenIP;
132 Allow_Alternate_Port = allow_alternate_port;
133 m_assetCache = assetCache;
134 m_authenticateSessionsClass = authenticateClass;
135 CreatePacketServer();
136
137 // Return new port
138 // This because in Grid mode it is not really important what port the region listens to as long as it is correctly registered.
139 // So the option allow_alternate_ports="true" was added to default.xml
140 port = (uint)(listenPort - proxyPortOffset);
141 }
142
143 protected virtual void CreatePacketServer()
144 {
145 new LLPacketServer(this);
146 }
147
148 protected virtual void OnReceivedData(IAsyncResult result)
149 {
150 ipeSender = new IPEndPoint(listenIP, 0);
151 epSender = (EndPoint) ipeSender;
152 Packet packet = null;
153
154 int numBytes = 1;
155
156 try
157 {
158 numBytes = m_socket.EndReceiveFrom(result, ref epSender);
159 }
160 catch (SocketException e)
161 {
162 // TODO : Actually only handle those states that we have control over, re-throw everything else,
163 // TODO: implement cases as we encounter them.
164 //m_log.Error("[UDPSERVER]: Connection Error! - " + e.ToString());
165 switch (e.SocketErrorCode)
166 {
167 case SocketError.AlreadyInProgress:
168 case SocketError.NetworkReset:
169 case SocketError.ConnectionReset:
170 try
171 {
172 CloseEndPoint(epSender);
173 }
174 catch (Exception a)
175 {
176 m_log.Info("[UDPSERVER]: " + a.ToString());
177 }
178 try
179 {
180 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender,
181 ReceivedData, null);
182
183 // Ter: For some stupid reason ConnectionReset basically kills our async event structure..
184 // so therefore.. we've got to tell the server to BeginReceiveFrom again.
185 // This will happen over and over until we've gone through all packets
186 // sent to and from this particular user.
187 // Stupid I know..
188 // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method.
189 }
190 catch (SocketException)
191 {
192 }
193 break;
194 default:
195 try
196 {
197 CloseEndPoint(epSender);
198 }
199 catch (Exception)
200 {
201 //m_log.Info("[UDPSERVER]" + a.ToString());
202 }
203 try
204 {
205 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender,
206 ReceivedData, null);
207
208 // Ter: For some stupid reason ConnectionReset basically kills our async event structure..
209 // so therefore.. we've got to tell the server to BeginReceiveFrom again.
210 // This will happen over and over until we've gone through all packets
211 // sent to and from this particular user.
212 // Stupid I know..
213 // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method.
214 }
215 catch (SocketException e2)
216 {
217 m_log.Error("[UDPSERVER]: " + e2.ToString());
218 }
219
220 // Here's some reference code! :D
221 // Shutdown and restart the UDP listener! hehe
222 // Shiny
223
224 //Server.Shutdown(SocketShutdown.Both);
225 //CloseEndPoint(epSender);
226 //ServerListener();
227 break;
228 }
229
230 //return;
231 }
232 catch (ObjectDisposedException e)
233 {
234 m_log.Debug("[UDPSERVER]: " + e.ToString());
235 try
236 {
237 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender,
238 ReceivedData, null);
239
240 // Ter: For some stupid reason ConnectionReset basically kills our async event structure..
241 // so therefore.. we've got to tell the server to BeginReceiveFrom again.
242 // This will happen over and over until we've gone through all packets
243 // sent to and from this particular user.
244 // Stupid I know..
245 // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method.
246 }
247
248 catch (SocketException e2)
249 {
250 m_log.Error("[UDPSERVER]: " + e2.ToString());
251 }
252 catch (ObjectDisposedException)
253 {
254 }
255 //return;
256 }
257
258 //System.Console.WriteLine("UDPServer : recieved message from {0}", epSender.ToString());
259 epProxy = epSender;
260 if (proxyPortOffset != 0)
261 {
262 epSender = PacketPool.DecodeProxyMessage(RecvBuffer, ref numBytes);
263 }
264
265 int packetEnd = numBytes - 1;
266
267 try
268 {
269 packet = PacketPool.Instance.GetPacket(RecvBuffer, ref packetEnd, ZeroBuffer);
270 }
271 catch (Exception e)
272 {
273 m_log.Debug("[UDPSERVER]: " + e.ToString());
274 }
275
276 try
277 {
278 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null);
279 }
280 catch (SocketException)
281 {
282 try
283 {
284 CloseEndPoint(epSender);
285 }
286 catch (Exception a)
287 {
288 m_log.Info("[UDPSERVER]: " + a.ToString());
289 }
290 try
291 {
292 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender,
293 ReceivedData, null);
294
295 // Ter: For some stupid reason ConnectionReset basically kills our async event structure..
296 // so therefore.. we've got to tell the server to BeginReceiveFrom again.
297 // This will happen over and over until we've gone through all packets
298 // sent to and from this particular user.
299 // Stupid I know..
300 // but Flusing the buffer would be even more stupid... so, we're stuck with this ugly method.
301 }
302 catch (SocketException e5)
303 {
304 m_log.Error("[UDPSERVER]: " + e5.ToString());
305 }
306 }
307 catch (ObjectDisposedException)
308 {
309 }
310
311 if (packet != null)
312 {
313 try
314 {
315 // do we already have a circuit for this endpoint
316 uint circuit;
317
318 bool ret = false;
319 lock (clientCircuits)
320 {
321 ret = clientCircuits.TryGetValue(epSender, out circuit);
322 }
323 if (ret)
324 {
325 //if so then send packet to the packetserver
326 //m_log.Warn("[UDPSERVER]: ALREADY HAVE Circuit!");
327 m_packetServer.InPacket(circuit, packet);
328 }
329 else if (packet.Type == PacketType.UseCircuitCode)
330 {
331 // new client
332 m_log.Debug("[UDPSERVER]: Adding New Client");
333 AddNewClient(packet);
334
335 UseCircuitCodePacket p = (UseCircuitCodePacket)packet;
336
337 // Ack the first UseCircuitCode packet
338 PacketAckPacket ack_it = (PacketAckPacket)PacketPool.Instance.GetPacket(PacketType.PacketAck);
339 // TODO: don't create new blocks if recycling an old packet
340 ack_it.Packets = new PacketAckPacket.PacketsBlock[1];
341 ack_it.Packets[0] = new PacketAckPacket.PacketsBlock();
342 ack_it.Packets[0].ID = packet.Header.Sequence;
343 ack_it.Header.Reliable = false;
344 SendPacketTo(ack_it.ToBytes(),ack_it.ToBytes().Length,SocketFlags.None,p.CircuitCode.Code);
345 }
346 }
347 catch (Exception)
348 {
349 m_log.Error("[UDPSERVER]: Exception in processing packet.");
350 m_log.Debug("[UDPSERVER]: Adding New Client");
351 try
352 {
353 AddNewClient(packet);
354 }
355 catch (Exception e3)
356 {
357 m_log.Error("[UDPSERVER]: Adding New Client threw exception " + e3.ToString());
358 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender,
359 ReceivedData, null);
360 }
361 }
362 }
363
364 }
365
366 private void CloseEndPoint(EndPoint sender)
367 {
368 uint circuit;
369 lock (clientCircuits)
370 {
371 if (clientCircuits.TryGetValue(sender, out circuit))
372 {
373 m_packetServer.CloseCircuit(circuit);
374 }
375 }
376 }
377
378 protected virtual void AddNewClient(Packet packet)
379 {
380 //Slave regions don't accept new clients
381 if (m_localScene.Region_Status != RegionStatus.SlaveScene)
382 {
383 if (!(packet is UseCircuitCodePacket))
384 return;
385
386 UseCircuitCodePacket useCircuit = (UseCircuitCodePacket) packet;
387 lock (clientCircuits)
388 {
389 if (!clientCircuits.ContainsKey(epSender))
390 clientCircuits.Add(epSender, useCircuit.CircuitCode.Code);
391 else
392 m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding.");
393 }
394
395 // This doesn't need locking as it's synchronized data
396 if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code))
397 clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, epSender);
398 else
399 m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding.");
400
401
402 lock (proxyCircuits)
403 {
404 if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code))
405 proxyCircuits.Add(useCircuit.CircuitCode.Code, epProxy);
406 else
407 m_log.Error("[UDPSERVER]: proxyCircuits already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding.");
408 }
409
410 PacketServer.AddNewClient(epSender, useCircuit, m_assetCache, m_authenticateSessionsClass, epProxy);
411 }
412 PacketPool.Instance.ReturnPacket(packet);
413 }
414
415 public void ServerListener()
416 {
417 uint newPort = listenPort;
418 m_log.Info("[SERVER]: Opening UDP socket on " + listenIP.ToString() + " " + newPort + ".");
419
420 ServerIncoming = new IPEndPoint(listenIP, (int)newPort);
421 m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
422 m_socket.Bind(ServerIncoming);
423 // Add flags to the UDP socket to prevent "Socket forcibly closed by host"
424 // uint IOC_IN = 0x80000000;
425 // uint IOC_VENDOR = 0x18000000;
426 // uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
427 // TODO: this apparently works in .NET but not in Mono, need to sort out the right flags here.
428 // m_socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
429
430 listenPort = newPort;
431
432 m_log.Info("[SERVER]: UDP socket bound, getting ready to listen");
433
434 ipeSender = new IPEndPoint(listenIP, 0);
435 epSender = (EndPoint)ipeSender;
436 ReceivedData = new AsyncCallback(OnReceivedData);
437 m_socket.BeginReceiveFrom(RecvBuffer, 0, RecvBuffer.Length, SocketFlags.None, ref epSender, ReceivedData, null);
438
439 m_log.Info("[SERVER]: Listening on port " + newPort);
440 }
441
442 public virtual void RegisterPacketServer(LLPacketServer server)
443 {
444 m_packetServer = server;
445 }
446
447 public virtual void SendPacketTo(byte[] buffer, int size, SocketFlags flags, uint circuitcode)
448 //EndPoint packetSender)
449 {
450 // find the endpoint for this circuit
451 EndPoint sendto = null;
452 try {
453 sendto = (EndPoint)clientCircuits_reverse[circuitcode];
454 } catch {
455 // Exceptions here mean there is no circuit
456 m_log.Warn("Circuit not found, not sending packet");
457 return;
458 }
459
460 if (sendto != null)
461 {
462 //we found the endpoint so send the packet to it
463 if (proxyPortOffset != 0)
464 {
465 //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo proxy " + proxyCircuits[circuitcode].ToString() + ": client " + sendto.ToString());
466 PacketPool.EncodeProxyMessage(buffer, ref size, sendto);
467 m_socket.SendTo(buffer, size, flags, proxyCircuits[circuitcode]);
468 }
469 else
470 {
471 //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo : client " + sendto.ToString());
472 m_socket.SendTo(buffer, size, flags, sendto);
473 }
474 }
475 }
476
477 public virtual void RemoveClientCircuit(uint circuitcode)
478 {
479 EndPoint sendto = null;
480 if (clientCircuits_reverse.Contains(circuitcode))
481 {
482 sendto = (EndPoint)clientCircuits_reverse[circuitcode];
483
484 clientCircuits_reverse.Remove(circuitcode);
485
486 lock (clientCircuits)
487 {
488 if (sendto != null)
489 {
490 clientCircuits.Remove(sendto);
491 }
492 else
493 {
494 m_log.DebugFormat(
495 "[UDPSERVER]: endpoint for circuit code {0} in RemoveClientCircuit() was unexpectedly null!", circuitcode);
496 }
497 }
498 lock (proxyCircuits)
499 {
500 proxyCircuits.Remove(circuitcode);
501 }
502 }
503 }
504
505 public void RestoreClient(AgentCircuitData circuit, EndPoint userEP, EndPoint proxyEP)
506 {
507 //MainLog.Instance.Verbose("UDPSERVER", "RestoreClient");
508
509 UseCircuitCodePacket useCircuit = new UseCircuitCodePacket();
510 useCircuit.CircuitCode.Code = circuit.circuitcode;
511 useCircuit.CircuitCode.ID = circuit.AgentID;
512 useCircuit.CircuitCode.SessionID = circuit.SessionID;
513
514 lock (clientCircuits)
515 {
516 if (!clientCircuits.ContainsKey(userEP))
517 clientCircuits.Add(userEP, useCircuit.CircuitCode.Code);
518 else
519 m_log.Error("[UDPSERVER]: clientCircuits already contans entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding.");
520 }
521
522 // This data structure is synchronized, so we don't need the lock
523 if (!clientCircuits_reverse.ContainsKey(useCircuit.CircuitCode.Code))
524 clientCircuits_reverse.Add(useCircuit.CircuitCode.Code, userEP);
525 else
526 m_log.Error("[UDPSERVER]: clientCurcuits_reverse already contains entry for user " + useCircuit.CircuitCode.Code.ToString() + ". NOT adding.");
527
528 lock (proxyCircuits)
529 {
530 if (!proxyCircuits.ContainsKey(useCircuit.CircuitCode.Code))
531 {
532 proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP);
533 }
534 else
535 {
536 // re-set proxy endpoint
537 proxyCircuits.Remove(useCircuit.CircuitCode.Code);
538 proxyCircuits.Add(useCircuit.CircuitCode.Code, proxyEP);
539 }
540 }
541
542 PacketServer.AddNewClient(userEP, useCircuit, m_assetCache, m_authenticateSessionsClass, proxyEP);
543 }
544 }
545}