aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs11
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs6
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs50
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs107
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs9
5 files changed, 103 insertions, 80 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
index 0acf6e8..ac558ff 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs
@@ -433,13 +433,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
433 // Remove ourselves from the scene 433 // Remove ourselves from the scene
434 m_scene.RemoveClient(AgentId); 434 m_scene.RemoveClient(AgentId);
435 435
436 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
437 //GC.Collect();
438 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
439
440 // FIXME: Is this still necessary?
441 //Thread.Sleep(2000);
442
443 // Shut down timers. Thread Context of this method is murky. Lock all timers 436 // Shut down timers. Thread Context of this method is murky. Lock all timers
444 if (m_avatarTerseUpdateTimer.Enabled) 437 if (m_avatarTerseUpdateTimer.Enabled)
445 lock (m_avatarTerseUpdateTimer) 438 lock (m_avatarTerseUpdateTimer)
@@ -461,6 +454,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
461 454
462 // Disable UDP handling for this client 455 // Disable UDP handling for this client
463 m_udpClient.Shutdown(); 456 m_udpClient.Shutdown();
457
458 //m_log.InfoFormat("[CLIENTVIEW] Memory pre GC {0}", System.GC.GetTotalMemory(false));
459 //GC.Collect();
460 //m_log.InfoFormat("[CLIENTVIEW] Memory post GC {0}", System.GC.GetTotalMemory(true));
464 } 461 }
465 462
466 public void Kick(string message) 463 public void Kick(string message)
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
index 8469ba6..8410ee9 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs
@@ -213,13 +213,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
213 213
214 lock (m_syncRoot) 214 lock (m_syncRoot)
215 { 215 {
216
217 if (m_priorityQueue.Count > 0) 216 if (m_priorityQueue.Count > 0)
218 { 217 {
219 try 218 try { image = m_priorityQueue.FindMax(); }
220 {
221 image = m_priorityQueue.FindMax();
222 }
223 catch (Exception) { } 219 catch (Exception) { }
224 } 220 }
225 } 221 }
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index e5b2594..b27d8d6 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -80,7 +80,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 /// <summary>Packets we have sent that need to be ACKed by the client</summary> 80 /// <summary>Packets we have sent that need to be ACKed by the client</summary>
81 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); 81 public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection();
82 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> 82 /// <summary>ACKs that are queued up, waiting to be sent to the client</summary>
83 public readonly LocklessQueue<uint> PendingAcks = new LocklessQueue<uint>(); 83 public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>();
84 84
85 /// <summary>Current packet sequence number</summary> 85 /// <summary>Current packet sequence number</summary>
86 public int CurrentSequence; 86 public int CurrentSequence;
@@ -127,13 +127,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
127 /// <summary>Throttle rate defaults and limits</summary> 127 /// <summary>Throttle rate defaults and limits</summary>
128 private readonly ThrottleRates defaultThrottleRates; 128 private readonly ThrottleRates defaultThrottleRates;
129 /// <summary>Outgoing queues for throttled packets</summary> 129 /// <summary>Outgoing queues for throttled packets</summary>
130 private readonly LocklessQueue<OutgoingPacket>[] packetOutboxes = new LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; 130 private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT];
131 /// <summary>A container that can hold one packet for each outbox, used to store 131 /// <summary>A container that can hold one packet for each outbox, used to store
132 /// dequeued packets that are being held for throttling</summary> 132 /// dequeued packets that are being held for throttling</summary>
133 private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; 133 private readonly OutgoingPacket[] nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT];
134 /// <summary>An optimization to store the length of dequeued packets being held 134 /// <summary>An optimization to store the length of dequeued packets being held
135 /// for throttling. This avoids expensive calls to Packet.Length</summary> 135 /// for throttling. This avoids expensive calls to Packet.Length</summary>
136 private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT]; 136 private readonly int[] nextPacketLengths = new int[THROTTLE_CATEGORY_COUNT];
137 /// <summary>Flags to prevent queue empty callbacks from repeatedly firing
138 /// before the callbacks have a chance to put packets in the queue</summary>
139 private readonly bool[] queueEmptySent = new bool[THROTTLE_CATEGORY_COUNT];
137 /// <summary>A reference to the LLUDPServer that is managing this client</summary> 140 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
138 private readonly LLUDPServer udpServer; 141 private readonly LLUDPServer udpServer;
139 142
@@ -156,7 +159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
156 defaultThrottleRates = rates; 159 defaultThrottleRates = rates;
157 160
158 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) 161 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
159 packetOutboxes[i] = new LocklessQueue<OutgoingPacket>(); 162 packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>();
160 163
161 throttle = new TokenBucket(parentThrottle, 0, 0); 164 throttle = new TokenBucket(parentThrottle, 0, 0);
162 throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT]; 165 throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];
@@ -182,6 +185,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
182 public void Shutdown() 185 public void Shutdown()
183 { 186 {
184 IsConnected = false; 187 IsConnected = false;
188 NeedAcks.Clear();
189 for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
190 {
191 packetOutboxes[i].Clear();
192 nextPackets[i] = null;
193 }
194 OnPacketStats = null;
195 OnQueueEmpty = null;
185 } 196 }
186 197
187 /// <summary> 198 /// <summary>
@@ -322,7 +333,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
322 333
323 if (category >= 0 && category < packetOutboxes.Length) 334 if (category >= 0 && category < packetOutboxes.Length)
324 { 335 {
325 LocklessQueue<OutgoingPacket> queue = packetOutboxes[category]; 336 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = packetOutboxes[category];
326 TokenBucket bucket = throttleCategories[category]; 337 TokenBucket bucket = throttleCategories[category];
327 338
328 if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength)) 339 if (throttleCategories[category].RemoveTokens(packet.Buffer.DataLength))
@@ -354,7 +365,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
354 public bool DequeueOutgoing() 365 public bool DequeueOutgoing()
355 { 366 {
356 OutgoingPacket packet; 367 OutgoingPacket packet;
357 LocklessQueue<OutgoingPacket> queue; 368 OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
358 TokenBucket bucket; 369 TokenBucket bucket;
359 bool packetSent = false; 370 bool packetSent = false;
360 371
@@ -382,6 +393,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
382 queue = packetOutboxes[i]; 393 queue = packetOutboxes[i];
383 if (queue.Dequeue(out packet)) 394 if (queue.Dequeue(out packet))
384 { 395 {
396 // Reset the flag for firing this queue's OnQueueEmpty callback
397 // now that we have dequeued a packet
398 queueEmptySent[i] = false;
399
385 // A packet was pulled off the queue. See if we have 400 // A packet was pulled off the queue. See if we have
386 // enough tokens in the bucket to send it out 401 // enough tokens in the bucket to send it out
387 if (bucket.RemoveTokens(packet.Buffer.DataLength)) 402 if (bucket.RemoveTokens(packet.Buffer.DataLength))
@@ -397,13 +412,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
397 nextPackets[i] = packet; 412 nextPackets[i] = packet;
398 nextPacketLengths[i] = packet.Buffer.DataLength; 413 nextPacketLengths[i] = packet.Buffer.DataLength;
399 } 414 }
415
416 // If the queue is empty after this dequeue, fire the queue
417 // empty callback now so it has a chance to fill before we
418 // get back here
419 if (queue.Count == 0)
420 FireQueueEmpty(i);
400 } 421 }
401 else 422 else
402 { 423 {
403 // No packets in this queue. Fire the queue empty callback 424 // No packets in this queue. Fire the queue empty callback
404 QueueEmpty callback = OnQueueEmpty; 425 // if it has not been called recently
405 if (callback != null) 426 FireQueueEmpty(i);
406 callback((ThrottleOutPacketType)i);
407 } 427 }
408 } 428 }
409 } 429 }
@@ -432,8 +452,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
432 452
433 // Always round retransmission timeout up to two seconds 453 // Always round retransmission timeout up to two seconds
434 RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR))); 454 RTO = Math.Max(2000, (int)(SRTT + Math.Max(G, K * RTTVAR)));
435 //Logger.Debug("Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + 455 //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " +
436 // RTTVAR + " based on new RTT of " + r + "ms"); 456 // RTTVAR + " based on new RTT of " + r + "ms");
437 } 457 }
458
459 private void FireQueueEmpty(int queueIndex)
460 {
461 if (!queueEmptySent[queueIndex])
462 {
463 queueEmptySent[queueIndex] = true;
464
465 QueueEmpty callback = OnQueueEmpty;
466 if (callback != null)
467 Util.FireAndForget(delegate(object o) { callback((ThrottleOutPacketType)(int)o); }, queueIndex);
468 }
469 }
438 } 470 }
439} 471}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 8689af3..57fee59 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -332,8 +332,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
332 332
333 public void ResendUnacked(LLUDPClient udpClient) 333 public void ResendUnacked(LLUDPClient udpClient)
334 { 334 {
335 if (udpClient.NeedAcks.Count > 0) 335 if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0)
336 { 336 {
337 // Disconnect an agent if no packets are received for some time
338 //FIXME: Make 60 an .ini setting
339 if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
340 {
341 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
342
343 RemoveClient(udpClient);
344 return;
345 }
346
347 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
337 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); 348 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
338 349
339 if (expiredPackets != null) 350 if (expiredPackets != null)
@@ -343,48 +354,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
343 { 354 {
344 OutgoingPacket outgoingPacket = expiredPackets[i]; 355 OutgoingPacket outgoingPacket = expiredPackets[i];
345 356
346 // FIXME: Make this an .ini setting 357 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
347 if (outgoingPacket.ResendCount < 3) 358 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
348 {
349 //Logger.Debug(String.Format("Resending packet #{0} (attempt {1}), {2}ms have passed",
350 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount));
351 359
352 // Set the resent flag 360 // Set the resent flag
353 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 361 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
354 outgoingPacket.Category = ThrottleOutPacketType.Resend; 362 outgoingPacket.Category = ThrottleOutPacketType.Resend;
355 363
356 // The TickCount will be set to the current time when the packet 364 // The TickCount will be set to the current time when the packet
357 // is actually sent out again 365 // is actually sent out again
358 outgoingPacket.TickCount = 0; 366 outgoingPacket.TickCount = 0;
359 367
360 // Bump up the resend count on this packet 368 // Bump up the resend count on this packet
361 Interlocked.Increment(ref outgoingPacket.ResendCount); 369 Interlocked.Increment(ref outgoingPacket.ResendCount);
362 //Interlocked.Increment(ref Stats.ResentPackets); 370 //Interlocked.Increment(ref Stats.ResentPackets);
363 371
364 // Queue or (re)send the packet 372 // Requeue or resend the packet
365 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 373 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
366 SendPacketFinal(outgoingPacket); 374 SendPacketFinal(outgoingPacket);
367 }
368 else
369 {
370 m_log.DebugFormat("[LLUDPSERVER]: Dropping packet #{0} for agent {1} after {2} failed attempts",
371 outgoingPacket.SequenceNumber, outgoingPacket.Client.RemoteEndPoint, outgoingPacket.ResendCount);
372
373 lock (udpClient.NeedAcks.SyncRoot)
374 udpClient.NeedAcks.RemoveUnsafe(outgoingPacket.SequenceNumber);
375
376 //Interlocked.Increment(ref Stats.DroppedPackets);
377
378 // Disconnect an agent if no packets are received for some time
379 //FIXME: Make 60 an .ini setting
380 if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
381 {
382 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
383
384 RemoveClient(udpClient);
385 return;
386 }
387 }
388 } 375 }
389 } 376 }
390 } 377 }
@@ -403,6 +390,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
403 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; 390 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
404 LLUDPClient udpClient = outgoingPacket.Client; 391 LLUDPClient udpClient = outgoingPacket.Client;
405 392
393 if (!udpClient.IsConnected)
394 return;
395
406 // Keep track of when this packet was sent out (right now) 396 // Keep track of when this packet was sent out (right now)
407 outgoingPacket.TickCount = Environment.TickCount; 397 outgoingPacket.TickCount = Environment.TickCount;
408 398
@@ -481,14 +471,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
481 } 471 }
482 catch (MalformedDataException) 472 catch (MalformedDataException)
483 { 473 {
484 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet:\n{0}", 474 m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse packet from {0}:\n{1}",
485 Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 475 buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
486 } 476 }
487 477
488 // Fail-safe check 478 // Fail-safe check
489 if (packet == null) 479 if (packet == null)
490 { 480 {
491 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from the incoming data"); 481 m_log.Warn("[LLUDPSERVER]: Couldn't build a message from incoming data " + buffer.DataLength +
482 " bytes long from " + buffer.RemoteEndPoint);
492 return; 483 return;
493 } 484 }
494 485
@@ -513,6 +504,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
513 504
514 udpClient = ((LLClientView)client).UDPClient; 505 udpClient = ((LLClientView)client).UDPClient;
515 506
507 if (!udpClient.IsConnected)
508 return;
509
516 #endregion Packet to Client Mapping 510 #endregion Packet to Client Mapping
517 511
518 // Stats tracking 512 // Stats tracking
@@ -643,7 +637,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
643 // Create the LLClientView 637 // Create the LLClientView
644 LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 638 LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
645 client.OnLogout += LogoutHandler; 639 client.OnLogout += LogoutHandler;
646 client.OnConnectionClosed += ConnectionClosedHandler;
647 640
648 // Start the IClientAPI 641 // Start the IClientAPI
649 client.Start(); 642 client.Start();
@@ -745,17 +738,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
745 { 738 {
746 LLUDPClient udpClient = ((LLClientView)client).UDPClient; 739 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
747 740
748 if (udpClient.DequeueOutgoing()) 741 if (udpClient.IsConnected)
749 packetSent = true;
750 if (resendUnacked)
751 ResendUnacked(udpClient);
752 if (sendAcks)
753 { 742 {
754 SendAcks(udpClient); 743 if (udpClient.DequeueOutgoing())
755 udpClient.SendPacketStats(); 744 packetSent = true;
745 if (resendUnacked)
746 ResendUnacked(udpClient);
747 if (sendAcks)
748 {
749 SendAcks(udpClient);
750 udpClient.SendPacketStats();
751 }
752 if (sendPings)
753 SendPing(udpClient);
756 } 754 }
757 if (sendPings)
758 SendPing(udpClient);
759 } 755 }
760 } 756 }
761 ); 757 );
@@ -808,14 +804,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
808 804
809 private void LogoutHandler(IClientAPI client) 805 private void LogoutHandler(IClientAPI client)
810 { 806 {
811 client.OnLogout -= LogoutHandler;
812 client.SendLogoutPacket(); 807 client.SendLogoutPacket();
813 } 808 }
814
815 private void ConnectionClosedHandler(IClientAPI client)
816 {
817 client.OnConnectionClosed -= ConnectionClosedHandler;
818 RemoveClient(((LLClientView)client).UDPClient);
819 }
820 } 809 }
821} 810}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index 195ca57..f3242c1 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -103,6 +103,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
103 } 103 }
104 104
105 /// <summary> 105 /// <summary>
106 /// Removes all elements from the collection
107 /// </summary>
108 public void Clear()
109 {
110 lock (SyncRoot)
111 packets.Clear();
112 }
113
114 /// <summary>
106 /// Gets the packet with the lowest sequence number 115 /// Gets the packet with the lowest sequence number
107 /// </summary> 116 /// </summary>
108 /// <returns>The packet with the lowest sequence number, or null if the 117 /// <returns>The packet with the lowest sequence number, or null if the