diff options
Diffstat (limited to '')
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 |