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.cs420
1 files changed, 219 insertions, 201 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index c356f02..545a0bc 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -96,7 +96,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
96 /// <summary>Incoming packets that are awaiting handling</summary> 96 /// <summary>Incoming packets that are awaiting handling</summary>
97 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 97 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
98 /// <summary></summary> 98 /// <summary></summary>
99 private UDPClientCollection clients = new UDPClientCollection(); 99 //private UDPClientCollection m_clients = new UDPClientCollection();
100 /// <summary>Bandwidth throttle for this UDP server</summary> 100 /// <summary>Bandwidth throttle for this UDP server</summary>
101 private TokenBucket m_throttle; 101 private TokenBucket m_throttle;
102 /// <summary>Bandwidth throttle rates for this UDP server</summary> 102 /// <summary>Bandwidth throttle rates for this UDP server</summary>
@@ -109,13 +109,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
109 private Location m_location; 109 private Location m_location;
110 /// <summary>The measured resolution of Environment.TickCount</summary> 110 /// <summary>The measured resolution of Environment.TickCount</summary>
111 private float m_tickCountResolution; 111 private float m_tickCountResolution;
112 /// <summary>The size of the receive buffer for the UDP socket. This value
113 /// is passed up to the operating system and used in the system networking
114 /// stack. Use zero to leave this value as the default</summary>
115 private int m_recvBufferSize;
116 /// <summary>Flag to process packets asynchronously or synchronously</summary>
117 private bool m_asyncPacketHandling;
112 118
113 /// <summary>The measured resolution of Environment.TickCount</summary> 119 /// <summary>The measured resolution of Environment.TickCount</summary>
114 public float TickCountResolution { get { return m_tickCountResolution; } } 120 public float TickCountResolution { get { return m_tickCountResolution; } }
115 public Socket Server { get { return null; } } 121 public Socket Server { get { return null; } }
116 122
117 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 123 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
118 : base((int)port) 124 : base(listenIP, (int)port)
119 { 125 {
120 #region Environment.TickCount Measurement 126 #region Environment.TickCount Measurement
121 127
@@ -134,18 +140,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
134 #endregion Environment.TickCount Measurement 140 #endregion Environment.TickCount Measurement
135 141
136 m_circuitManager = circuitManager; 142 m_circuitManager = circuitManager;
143 int sceneThrottleBps = 0;
137 144
138 // TODO: Config support for throttling the entire connection 145 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
139 m_throttle = new TokenBucket(null, 0, 0); 146 if (config != null)
147 {
148 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", false);
149 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
150 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
151 }
152
153 m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps);
140 m_throttleRates = new ThrottleRates(configSource); 154 m_throttleRates = new ThrottleRates(configSource);
141 } 155 }
142 156
143 public new void Start() 157 public void Start()
144 { 158 {
145 if (m_scene == null) 159 if (m_scene == null)
146 throw new InvalidOperationException("Cannot LLUDPServer.Start() without an IScene reference"); 160 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
161
162 m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode");
147 163
148 base.Start(); 164 base.Start(m_recvBufferSize, m_asyncPacketHandling);
149 165
150 // Start the incoming packet processing thread 166 // Start the incoming packet processing thread
151 Thread incomingThread = new Thread(IncomingPacketHandler); 167 Thread incomingThread = new Thread(IncomingPacketHandler);
@@ -181,24 +197,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 return x == m_location; 197 return x == m_location;
182 } 198 }
183 199
184 public void RemoveClient(IClientAPI client)
185 {
186 m_scene.ClientManager.Remove(client.CircuitCode);
187 client.Close(false);
188
189 LLUDPClient udpClient;
190 if (clients.TryGetValue(client.AgentId, out udpClient))
191 {
192 m_log.Debug("[LLUDPSERVER]: Removing LLUDPClient for " + client.Name + " in " + m_scene.RegionInfo.RegionName);
193 udpClient.Shutdown();
194 clients.Remove(client.AgentId, udpClient.RemoteEndPoint);
195 }
196 else
197 {
198 m_log.Warn("[LLUDPSERVER]: Failed to remove LLUDPClient for " + client.Name);
199 }
200 }
201
202 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) 200 public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting)
203 { 201 {
204 // CoarseLocationUpdate packets cannot be split in an automated way 202 // CoarseLocationUpdate packets cannot be split in an automated way
@@ -216,30 +214,29 @@ namespace OpenSim.Region.ClientStack.LindenUDP
216 for (int i = 0; i < packetCount; i++) 214 for (int i = 0; i < packetCount; i++)
217 { 215 {
218 byte[] data = datas[i]; 216 byte[] data = datas[i];
219 clients.ForEach( 217 m_scene.ClientManager.ForEach(
220 delegate(LLUDPClient client) 218 delegate(IClientAPI client)
221 { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); 219 {
220 if (client is LLClientView)
221 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
222 }
223 );
222 } 224 }
223 } 225 }
224 else 226 else
225 { 227 {
226 byte[] data = packet.ToBytes(); 228 byte[] data = packet.ToBytes();
227 clients.ForEach( 229 m_scene.ClientManager.ForEach(
228 delegate(LLUDPClient client) 230 delegate(IClientAPI client)
229 { SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); }); 231 {
232 if (client is LLClientView)
233 SendPacketData(((LLClientView)client).UDPClient, data, packet.Type, category);
234 }
235 );
230 } 236 }
231 } 237 }
232 238
233 public void SendPacket(UUID agentID, Packet packet, ThrottleOutPacketType category, bool allowSplitting) 239 public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
234 {
235 LLUDPClient client;
236 if (clients.TryGetValue(agentID, out client))
237 SendPacket(client, packet, category, allowSplitting);
238 else
239 m_log.Warn("[LLUDPSERVER]: Attempted to send a packet to unknown agentID " + agentID);
240 }
241
242 public void SendPacket(LLUDPClient client, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
243 { 240 {
244 // CoarseLocationUpdate packets cannot be split in an automated way 241 // CoarseLocationUpdate packets cannot be split in an automated way
245 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) 242 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
@@ -256,25 +253,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
256 for (int i = 0; i < packetCount; i++) 253 for (int i = 0; i < packetCount; i++)
257 { 254 {
258 byte[] data = datas[i]; 255 byte[] data = datas[i];
259 SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); 256 SendPacketData(udpClient, data, packet.Type, category);
260 } 257 }
261 } 258 }
262 else 259 else
263 { 260 {
264 byte[] data = packet.ToBytes(); 261 byte[] data = packet.ToBytes();
265 SendPacketData(client, data, data.Length, packet.Type, packet.Header.Zerocoded, category); 262 SendPacketData(udpClient, data, packet.Type, category);
266 } 263 }
267 } 264 }
268 265
269 public void SendPacketData(LLUDPClient client, byte[] data, int dataLength, PacketType type, bool doZerocode, ThrottleOutPacketType category) 266 public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
270 { 267 {
268 int dataLength = data.Length;
269 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
270
271 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. 271 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
272 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting 272 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
273 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here 273 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
274 // to accomodate for both common scenarios and provide ample room for ACK appending in both 274 // to accomodate for both common scenarios and provide ample room for ACK appending in both
275 int bufferSize = (dataLength > 180) ? Packet.MTU : 200; 275 int bufferSize = (dataLength > 180) ? Packet.MTU : 200;
276 276
277 UDPPacketBuffer buffer = new UDPPacketBuffer(client.RemoteEndPoint, bufferSize); 277 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
278 278
279 // Zerocode if needed 279 // Zerocode if needed
280 if (doZerocode) 280 if (doZerocode)
@@ -285,17 +285,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 // The packet grew larger than the bufferSize while zerocoding. 285 // The packet grew larger than the bufferSize while zerocoding.
286 // Remove the MSG_ZEROCODED flag and send the unencoded data 286 // Remove the MSG_ZEROCODED flag and send the unencoded data
287 // instead 287 // instead
288 m_log.Info("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding. Removing MSG_ZEROCODED flag"); 288 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag");
289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); 289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
290 //
291 buffer = new UDPPacketBuffer(client.RemoteEndPoint, dataLength);
292 //
293 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 290 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
294 } 291 }
295 } 292 }
296 else 293 else
297 { 294 {
298 // ??? will it fit?
299 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 295 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
300 } 296 }
301 buffer.DataLength = dataLength; 297 buffer.DataLength = dataLength;
@@ -303,7 +299,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
303 #region Queue or Send 299 #region Queue or Send
304 300
305 // Look up the UDPClient this is going to 301 // Look up the UDPClient this is going to
306 OutgoingPacket outgoingPacket = new OutgoingPacket(client, buffer, category); 302 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
307 303
308 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 304 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
309 SendPacketFinal(outgoingPacket); 305 SendPacketFinal(outgoingPacket);
@@ -311,18 +307,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 #endregion Queue or Send 307 #endregion Queue or Send
312 } 308 }
313 309
314 public void SendAcks(LLUDPClient client) 310 public void SendAcks(LLUDPClient udpClient)
315 { 311 {
316 uint ack; 312 uint ack;
317 313
318 if (client.PendingAcks.Dequeue(out ack)) 314 if (udpClient.PendingAcks.Dequeue(out ack))
319 { 315 {
320 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>(); 316 List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
321 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock(); 317 PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock();
322 block.ID = ack; 318 block.ID = ack;
323 blocks.Add(block); 319 blocks.Add(block);
324 320
325 while (client.PendingAcks.Dequeue(out ack)) 321 while (udpClient.PendingAcks.Dequeue(out ack))
326 { 322 {
327 block = new PacketAckPacket.PacketsBlock(); 323 block = new PacketAckPacket.PacketsBlock();
328 block.ID = ack; 324 block.ID = ack;
@@ -333,22 +329,39 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 packet.Header.Reliable = false; 329 packet.Header.Reliable = false;
334 packet.Packets = blocks.ToArray(); 330 packet.Packets = blocks.ToArray();
335 331
336 SendPacket(client, packet, ThrottleOutPacketType.Unknown, true); 332 SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
337 } 333 }
338 } 334 }
339 335
340 public void SendPing(LLUDPClient client) 336 public void SendPing(LLUDPClient udpClient)
341 { 337 {
342 IClientAPI api = client.ClientAPI; 338 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
343 if (api != null) 339 pc.Header.Reliable = false;
344 api.SendStartPingCheck(client.CurrentPingSequence++); 340
341 OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
342
343 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
344 pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0;
345
346 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
345 } 347 }
346 348
347 public void ResendUnacked(LLUDPClient client) 349 public void ResendUnacked(LLUDPClient udpClient)
348 { 350 {
349 if (client.NeedAcks.Count > 0) 351 if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0)
350 { 352 {
351 List<OutgoingPacket> expiredPackets = client.NeedAcks.GetExpiredPackets(client.RTO); 353 // Disconnect an agent if no packets are received for some time
354 //FIXME: Make 60 an .ini setting
355 if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
356 {
357 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
358
359 RemoveClient(udpClient);
360 return;
361 }
362
363 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
364 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
352 365
353 if (expiredPackets != null) 366 if (expiredPackets != null)
354 { 367 {
@@ -357,54 +370,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
357 { 370 {
358 OutgoingPacket outgoingPacket = expiredPackets[i]; 371 OutgoingPacket outgoingPacket = expiredPackets[i];
359 372
360 // FIXME: Make this an .ini setting 373 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
361 if (outgoingPacket.ResendCount < 3) 374 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
362 {
363 //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed",
364 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount));
365
366 // Set the resent flag
367 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
368 outgoingPacket.Category = ThrottleOutPacketType.Resend;
369 375
370 // The TickCount will be set to the current time when the packet 376 // Set the resent flag
371 // is actually sent out again 377 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
372 outgoingPacket.TickCount = 0; 378 outgoingPacket.Category = ThrottleOutPacketType.Resend;
373 379
374 // Bump up the resend count on this packet 380 // The TickCount will be set to the current time when the packet
375 Interlocked.Increment(ref outgoingPacket.ResendCount); 381 // is actually sent out again
376 //Interlocked.Increment(ref Stats.ResentPackets); 382 outgoingPacket.TickCount = 0;
377 383
378 // Queue or (re)send the packet 384 // Bump up the resend count on this packet
379 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 385 Interlocked.Increment(ref outgoingPacket.ResendCount);
380 SendPacketFinal(outgoingPacket); 386 //Interlocked.Increment(ref Stats.ResentPackets);
381 }
382 else
383 {
384 m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
385 outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
386 387
387 lock (client.NeedAcks.SyncRoot) 388 // Requeue or resend the packet
388 client.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber); 389 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
389 390 SendPacketFinal(outgoingPacket);
390 //Interlocked.Increment(ref Stats.DroppedPackets);
391
392 // Disconnect an agent if no packets are received for some time
393 //FIXME: Make 60 an .ini setting
394 if (Environment.TickCount - client.TickLastPacketReceived > 1000 * 60)
395 {
396 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + client.ClientAPI.Name);
397
398 RemoveClient(client.ClientAPI);
399 return;
400 }
401 }
402 } 391 }
403 } 392 }
404 } 393 }
405 } 394 }
406 395
407 public void Flush() 396 public void Flush(LLUDPClient udpClient)
408 { 397 {
409 // FIXME: Implement? 398 // FIXME: Implement?
410 } 399 }
@@ -415,7 +404,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
415 byte flags = buffer.Data[0]; 404 byte flags = buffer.Data[0];
416 bool isResend = (flags & Helpers.MSG_RESENT) != 0; 405 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
417 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; 406 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
418 LLUDPClient client = outgoingPacket.Client; 407 LLUDPClient udpClient = outgoingPacket.Client;
408
409 if (!udpClient.IsConnected)
410 return;
419 411
420 // Keep track of when this packet was sent out (right now) 412 // Keep track of when this packet was sent out (right now)
421 outgoingPacket.TickCount = Environment.TickCount; 413 outgoingPacket.TickCount = Environment.TickCount;
@@ -424,11 +416,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
424 416
425 int dataLength = buffer.DataLength; 417 int dataLength = buffer.DataLength;
426 418
427 // Keep appending ACKs until there is no room left in the packet or there are 419 // Keep appending ACKs until there is no room left in the buffer or there are
428 // no more ACKs to append 420 // no more ACKs to append
429 uint ackCount = 0; 421 uint ackCount = 0;
430 uint ack; 422 uint ack;
431 while (dataLength + 5 < buffer.Data.Length && client.PendingAcks.Dequeue(out ack)) 423 while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.Dequeue(out ack))
432 { 424 {
433 Utils.UIntToBytesBig(ack, buffer.Data, dataLength); 425 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
434 dataLength += 4; 426 dataLength += 4;
@@ -447,24 +439,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
447 439
448 #endregion ACK Appending 440 #endregion ACK Appending
449 441
442 #region Sequence Number Assignment
443
450 if (!isResend) 444 if (!isResend)
451 { 445 {
452 // Not a resend, assign a new sequence number 446 // Not a resend, assign a new sequence number
453 uint sequenceNumber = (uint)Interlocked.Increment(ref client.CurrentSequence); 447 uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.CurrentSequence);
454 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); 448 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
455 outgoingPacket.SequenceNumber = sequenceNumber; 449 outgoingPacket.SequenceNumber = sequenceNumber;
456 450
457 if (isReliable) 451 if (isReliable)
458 { 452 {
459 // Add this packet to the list of ACK responses we are waiting on from the server 453 // Add this packet to the list of ACK responses we are waiting on from the server
460 client.NeedAcks.Add(outgoingPacket); 454 udpClient.NeedAcks.Add(outgoingPacket);
461 } 455 }
462 } 456 }
463 457
458 #endregion Sequence Number Assignment
459
464 // Stats tracking 460 // Stats tracking
465 Interlocked.Increment(ref client.PacketsSent); 461 Interlocked.Increment(ref udpClient.PacketsSent);
466 if (isReliable) 462 if (isReliable)
467 Interlocked.Add(ref client.UnackedBytes, outgoingPacket.Buffer.DataLength); 463 Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
468 464
469 // Put the UDP payload on the wire 465 // Put the UDP payload on the wire
470 AsyncBeginSend(buffer); 466 AsyncBeginSend(buffer);
@@ -473,10 +469,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
473 protected override void PacketReceived(UDPPacketBuffer buffer) 469 protected override void PacketReceived(UDPPacketBuffer buffer)
474 { 470 {
475 // Debugging/Profiling 471 // Debugging/Profiling
476 //try { Thread.CurrentThread.Name = "PacketReceived (" + scene.RegionName + ")"; } 472 //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
477 //catch (Exception) { } 473 //catch (Exception) { }
478 474
479 LLUDPClient client = null; 475 LLUDPClient udpClient = null;
480 Packet packet = null; 476 Packet packet = null;
481 int packetEnd = buffer.DataLength - 1; 477 int packetEnd = buffer.DataLength - 1;
482 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 478 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint;
@@ -491,61 +487,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
491 } 487 }
492 catch (MalformedDataException) 488 catch (MalformedDataException)
493 { 489 {
494 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", 490 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}",
495 Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 491 buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
496 } 492 }
497 493
498 // Fail-safe check 494 // Fail-safe check
499 if (packet == null) 495 if (packet == null)
500 { 496 {
501 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); 497 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength +
498 " bytes long from " + buffer.RemoteEndPoint);
502 return; 499 return;
503 } 500 }
504 501
505 //Stats.RecvBytes += (ulong)buffer.DataLength;
506 //++Stats.RecvPackets;
507
508 #endregion Decoding 502 #endregion Decoding
509 503
510 #region UseCircuitCode Handling 504 #region Packet to Client Mapping
511 505
506 // UseCircuitCode handling
512 if (packet.Type == PacketType.UseCircuitCode) 507 if (packet.Type == PacketType.UseCircuitCode)
513 { 508 {
514 UseCircuitCodePacket useCircuitCode = (UseCircuitCodePacket)packet; 509 AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint);
515 IClientAPI newuser;
516 uint circuitCode = useCircuitCode.CircuitCode.Code;
517
518 // Check if the client is already established
519 if (!m_scene.ClientManager.TryGetClient(circuitCode, out newuser))
520 {
521 AddNewClient(useCircuitCode, (IPEndPoint)buffer.RemoteEndPoint);
522 }
523 } 510 }
524 511
525 // Determine which agent this packet came from 512 // Determine which agent this packet came from
526 if (!clients.TryGetValue(address, out client)) 513 IClientAPI client;
514 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
527 { 515 {
528 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 516 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
517 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
529 return; 518 return;
530 } 519 }
531 520
532 #endregion UseCircuitCode Handling 521 udpClient = ((LLClientView)client).UDPClient;
522
523 if (!udpClient.IsConnected)
524 return;
525
526 #endregion Packet to Client Mapping
533 527
534 // Stats tracking 528 // Stats tracking
535 Interlocked.Increment(ref client.PacketsReceived); 529 Interlocked.Increment(ref udpClient.PacketsReceived);
536 530
537 #region ACK Receiving 531 #region ACK Receiving
538 532
539 int now = Environment.TickCount; 533 int now = Environment.TickCount;
540 client.TickLastPacketReceived = now; 534 udpClient.TickLastPacketReceived = now;
541 535
542 // Handle appended ACKs 536 // Handle appended ACKs
543 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 537 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
544 { 538 {
545 lock (client.NeedAcks.SyncRoot) 539 lock (udpClient.NeedAcks.SyncRoot)
546 { 540 {
547 for (int i = 0; i < packet.Header.AckList.Length; i++) 541 for (int i = 0; i < packet.Header.AckList.Length; i++)
548 AcknowledgePacket(client, packet.Header.AckList[i], now, packet.Header.Resent); 542 AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
549 } 543 }
550 } 544 }
551 545
@@ -554,10 +548,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
554 { 548 {
555 PacketAckPacket ackPacket = (PacketAckPacket)packet; 549 PacketAckPacket ackPacket = (PacketAckPacket)packet;
556 550
557 lock (client.NeedAcks.SyncRoot) 551 lock (udpClient.NeedAcks.SyncRoot)
558 { 552 {
559 for (int i = 0; i < ackPacket.Packets.Length; i++) 553 for (int i = 0; i < ackPacket.Packets.Length; i++)
560 AcknowledgePacket(client, ackPacket.Packets[i].ID, now, packet.Header.Resent); 554 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
561 } 555 }
562 } 556 }
563 557
@@ -566,27 +560,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
566 #region ACK Sending 560 #region ACK Sending
567 561
568 if (packet.Header.Reliable) 562 if (packet.Header.Reliable)
569 client.PendingAcks.Enqueue((uint)packet.Header.Sequence); 563 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
570 564
571 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 565 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
572 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove 566 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
573 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to 567 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
574 // client.BytesSinceLastACK. Lockless thread safety 568 // client.BytesSinceLastACK. Lockless thread safety
575 int bytesSinceLastACK = Interlocked.Exchange(ref client.BytesSinceLastACK, 0); 569 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
576 bytesSinceLastACK += buffer.DataLength; 570 bytesSinceLastACK += buffer.DataLength;
577 if (bytesSinceLastACK > Packet.MTU * 2) 571 if (bytesSinceLastACK > Packet.MTU * 2)
578 { 572 {
579 bytesSinceLastACK -= Packet.MTU * 2; 573 bytesSinceLastACK -= Packet.MTU * 2;
580 SendAcks(client); 574 SendAcks(udpClient);
581 } 575 }
582 Interlocked.Add(ref client.BytesSinceLastACK, bytesSinceLastACK); 576 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
583 577
584 #endregion ACK Sending 578 #endregion ACK Sending
585 579
586 #region Incoming Packet Accounting 580 #region Incoming Packet Accounting
587 581
588 // Check the archive of received reliable packet IDs to see whether we already received this packet 582 // Check the archive of received reliable packet IDs to see whether we already received this packet
589 if (packet.Header.Reliable && !client.PacketArchive.TryEnqueue(packet.Header.Sequence)) 583 if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
590 { 584 {
591 if (packet.Header.Resent) 585 if (packet.Header.Resent)
592 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type); 586 m_log.Debug("[LLUDPSERVER]: Received a resend of already processed packet #" + packet.Header.Sequence + ", type: " + packet.Type);
@@ -603,7 +597,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
603 if (packet.Type != PacketType.PacketAck) 597 if (packet.Type != PacketType.PacketAck)
604 { 598 {
605 // Inbox insertion 599 // Inbox insertion
606 packetInbox.Enqueue(new IncomingPacket(client, packet)); 600 packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
607 } 601 }
608 } 602 }
609 603
@@ -623,53 +617,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
623 617
624 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint) 618 private void AddNewClient(UseCircuitCodePacket useCircuitCode, IPEndPoint remoteEndPoint)
625 { 619 {
626 //Slave regions don't accept new clients 620 UUID agentID = useCircuitCode.CircuitCode.ID;
621 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
622 uint circuitCode = useCircuitCode.CircuitCode.Code;
623
627 if (m_scene.RegionStatus != RegionStatus.SlaveScene) 624 if (m_scene.RegionStatus != RegionStatus.SlaveScene)
628 { 625 {
629 AuthenticateResponse sessionInfo; 626 AuthenticateResponse sessionInfo;
630 bool isNewCircuit = !clients.ContainsKey(remoteEndPoint); 627 if (IsClientAuthorized(useCircuitCode, out sessionInfo))
631
632 if (!IsClientAuthorized(useCircuitCode, out sessionInfo))
633 { 628 {
634 m_log.WarnFormat( 629 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
635 "[CONNECTION FAILURE]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
636 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
637 return;
638 } 630 }
639 631 else
640 if (isNewCircuit)
641 { 632 {
642 UUID agentID = useCircuitCode.CircuitCode.ID; 633 // Don't create circuits for unauthorized clients
643 UUID sessionID = useCircuitCode.CircuitCode.SessionID; 634 m_log.WarnFormat(
644 uint circuitCode = useCircuitCode.CircuitCode.Code; 635 "[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
645 636 useCircuitCode.CircuitCode.ID, useCircuitCode.CircuitCode.Code, remoteEndPoint);
646 AddClient(circuitCode, agentID, sessionID, remoteEndPoint, sessionInfo);
647 } 637 }
648 } 638 }
639 else
640 {
641 // Slave regions don't accept new clients
642 m_log.Debug("[LLUDPSERVER]: Slave region " + m_scene.RegionInfo.RegionName + " ignoring UseCircuitCode packet");
643 }
649 } 644 }
650 645
651 private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 646 private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
652 { 647 {
653 // Create the LLUDPClient 648 // Create the LLUDPClient
654 LLUDPClient client = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); 649 LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint);
655
656 // Create the LLClientView
657 LLClientView clientApi = new LLClientView(remoteEndPoint, m_scene, this, client, sessionInfo, agentID, sessionID, circuitCode);
658 clientApi.OnViewerEffect += m_scene.ClientManager.ViewerEffectHandler;
659 clientApi.OnLogout += LogoutHandler;
660 clientApi.OnConnectionClosed += RemoveClient;
661
662 // Start the IClientAPI
663 m_scene.ClientManager.Add(circuitCode, clientApi);
664 clientApi.Start();
665 650
666 // Give LLUDPClient a reference to IClientAPI 651 if (!m_scene.ClientManager.ContainsKey(agentID))
667 client.ClientAPI = clientApi; 652 {
653 // Create the LLClientView
654 LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
655 client.OnLogout += LogoutHandler;
668 656
669 // Add the new client to our list of tracked clients 657 // Start the IClientAPI
670 clients.Add(agentID, client.RemoteEndPoint, client); 658 client.Start();
659 }
660 else
661 {
662 m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
663 udpClient.AgentID, remoteEndPoint, circuitCode);
664 }
665 }
671 666
672 m_log.DebugFormat("[LLUDPSERVER]: Added new client {0} to region {1}", agentID, m_scene.RegionInfo.RegionName); 667 private void RemoveClient(LLUDPClient udpClient)
668 {
669 // Remove this client from the scene
670 IClientAPI client;
671 if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
672 client.Close();
673 } 673 }
674 674
675 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend) 675 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
@@ -747,20 +747,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
747 elapsed500MS = 0; 747 elapsed500MS = 0;
748 } 748 }
749 749
750 clients.ForEach( 750 m_scene.ClientManager.ForEach(
751 delegate(LLUDPClient client) 751 delegate(IClientAPI client)
752 { 752 {
753 if (client.DequeueOutgoing()) 753 if (client is LLClientView)
754 packetSent = true;
755 if (resendUnacked)
756 ResendUnacked(client);
757 if (sendAcks)
758 { 754 {
759 SendAcks(client); 755 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
760 client.SendPacketStats(); 756
757 if (udpClient.IsConnected)
758 {
759 if (udpClient.DequeueOutgoing())
760 packetSent = true;
761 if (resendUnacked)
762 ResendUnacked(udpClient);
763 if (sendAcks)
764 {
765 SendAcks(udpClient);
766 udpClient.SendPacketStats();
767 }
768 if (sendPings)
769 SendPing(udpClient);
770 }
761 } 771 }
762 if (sendPings)
763 SendPing(client);
764 } 772 }
765 ); 773 );
766 774
@@ -773,38 +781,48 @@ namespace OpenSim.Region.ClientStack.LindenUDP
773 { 781 {
774 IncomingPacket incomingPacket = (IncomingPacket)state; 782 IncomingPacket incomingPacket = (IncomingPacket)state;
775 Packet packet = incomingPacket.Packet; 783 Packet packet = incomingPacket.Packet;
776 LLUDPClient client = incomingPacket.Client; 784 LLUDPClient udpClient = incomingPacket.Client;
785 IClientAPI client;
777 786
778 // Sanity check 787 // Sanity check
779 if (packet == null || client == null || client.ClientAPI == null) 788 if (packet == null || udpClient == null)
780 { 789 {
781 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"", 790 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
782 packet, client, (client != null) ? client.ClientAPI : null); 791 packet, udpClient);
783 } 792 }
784 793
785 try 794 // Make sure this client is still alive
786 { 795 if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
787 // Process this packet
788 client.ClientAPI.ProcessInPacket(packet);
789 }
790 catch (ThreadAbortException)
791 { 796 {
792 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down 797 try
793 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server"); 798 {
794 Stop(); 799 // Process this packet
800 client.ProcessInPacket(packet);
801 }
802 catch (ThreadAbortException)
803 {
804 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
805 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
806 Stop();
807 }
808 catch (Exception e)
809 {
810 // Don't let a failure in an individual client thread crash the whole sim.
811 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
812 m_log.Error(e.Message, e);
813 }
795 } 814 }
796 catch (Exception e) 815 else
797 { 816 {
798 // Don't let a failure in an individual client thread crash the whole sim. 817 m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
799 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type);
800 m_log.Error(e.Message, e);
801 } 818 }
802 } 819 }
803 820
804 private void LogoutHandler(IClientAPI client) 821 private void LogoutHandler(IClientAPI client)
805 { 822 {
806 client.SendLogoutPacket(); 823 client.SendLogoutPacket();
807 RemoveClient(client); 824 if (client.IsActive)
825 RemoveClient(((LLClientView)client).UDPClient);
808 } 826 }
809 } 827 }
810} 828}