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