aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
diff options
context:
space:
mode:
authorJohn Hurliman2009-10-13 18:56:54 -0700
committerJohn Hurliman2009-10-13 18:56:54 -0700
commite8c1e69a0dbab1a7db894eeff6b052bbd350a8f5 (patch)
tree6d29a3bae418c1c5a06e3f1b8ad4a59db57a8d9e /OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
parent* Consolidated adding / removing ClientManager IClientAPIs to two places in S... (diff)
downloadopensim-SC-e8c1e69a0dbab1a7db894eeff6b052bbd350a8f5.zip
opensim-SC-e8c1e69a0dbab1a7db894eeff6b052bbd350a8f5.tar.gz
opensim-SC-e8c1e69a0dbab1a7db894eeff6b052bbd350a8f5.tar.bz2
opensim-SC-e8c1e69a0dbab1a7db894eeff6b052bbd350a8f5.tar.xz
* Copied LocklessQueue.cs into OpenSim.Framework and added the .Count property and .Clear() method
* Changed the way the QueueEmpty callback is fired. It will be fired asynchronously as soon as an empty queue is detected (this can happen immediately following a dequeue), and will not be fired again until at least one packet is dequeued from that queue. This will give callbacks advanced notice of an empty queue and prevent callbacks from stacking up while the queue is empty * Added LLUDPClient.IsConnected checks in several places to prevent unwanted network activity after a client disconnects * Prevent LLClientView.Close() from being called twice every disconnect * Removed the packet resend limit and improved the client timeout check
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs50
1 files changed, 41 insertions, 9 deletions
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}