aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Framework/ClientManager.cs23
-rw-r--r--OpenSim/Framework/LocklessQueue.cs130
-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
7 files changed, 242 insertions, 94 deletions
diff --git a/OpenSim/Framework/ClientManager.cs b/OpenSim/Framework/ClientManager.cs
index fd5f87f..367bc6a 100644
--- a/OpenSim/Framework/ClientManager.cs
+++ b/OpenSim/Framework/ClientManager.cs
@@ -121,20 +121,10 @@ namespace OpenSim.Framework
121 /// <summary> 121 /// <summary>
122 /// Remove a client from the collection 122 /// Remove a client from the collection
123 /// </summary> 123 /// </summary>
124 /// <param name="value">Reference to the client object</param> 124 /// <param name="key">UUID of the client to remove</param>
125 public void Remove(IClientAPI value) 125 /// <returns>True if a client was removed, or false if the given UUID
126 { 126 /// was not present in the collection</returns>
127 lock (m_writeLock) 127 public bool Remove(UUID key)
128 {
129 if (m_dict.ContainsKey(value.AgentId))
130 m_dict = m_dict.Delete(value.AgentId);
131
132 if (m_dict2.ContainsKey(value.RemoteEndPoint))
133 m_dict2 = m_dict2.Delete(value.RemoteEndPoint);
134 }
135 }
136
137 public void Remove(UUID key)
138 { 128 {
139 lock (m_writeLock) 129 lock (m_writeLock)
140 { 130 {
@@ -144,6 +134,11 @@ namespace OpenSim.Framework
144 { 134 {
145 m_dict = m_dict.Delete(key); 135 m_dict = m_dict.Delete(key);
146 m_dict2 = m_dict2.Delete(client.RemoteEndPoint); 136 m_dict2 = m_dict2.Delete(client.RemoteEndPoint);
137 return true;
138 }
139 else
140 {
141 return false;
147 } 142 }
148 } 143 }
149 } 144 }
diff --git a/OpenSim/Framework/LocklessQueue.cs b/OpenSim/Framework/LocklessQueue.cs
new file mode 100644
index 0000000..dd3d201
--- /dev/null
+++ b/OpenSim/Framework/LocklessQueue.cs
@@ -0,0 +1,130 @@
1/*
2 * Copyright (c) 2009, openmetaverse.org
3 * All rights reserved.
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 *
8 * - Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 * - Neither the name of the openmetaverse.org nor the names
11 * of its contributors may be used to endorse or promote products derived from
12 * this software without specific prior written permission.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
18 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24 * POSSIBILITY OF SUCH DAMAGE.
25 */
26
27using System;
28using System.Threading;
29
30namespace OpenSim.Framework
31{
32 public sealed class LocklessQueue<T>
33 {
34 private sealed class SingleLinkNode
35 {
36 public SingleLinkNode Next;
37 public T Item;
38 }
39
40 SingleLinkNode head;
41 SingleLinkNode tail;
42 int count;
43
44 public int Count { get { return count; } }
45
46 public LocklessQueue()
47 {
48 Init();
49 }
50
51 public void Enqueue(T item)
52 {
53 SingleLinkNode oldTail = null;
54 SingleLinkNode oldTailNext;
55
56 SingleLinkNode newNode = new SingleLinkNode();
57 newNode.Item = item;
58
59 bool newNodeWasAdded = false;
60
61 while (!newNodeWasAdded)
62 {
63 oldTail = tail;
64 oldTailNext = oldTail.Next;
65
66 if (tail == oldTail)
67 {
68 if (oldTailNext == null)
69 newNodeWasAdded = CAS(ref tail.Next, null, newNode);
70 else
71 CAS(ref tail, oldTail, oldTailNext);
72 }
73 }
74
75 CAS(ref tail, oldTail, newNode);
76 Interlocked.Increment(ref count);
77 }
78
79 public bool Dequeue(out T item)
80 {
81 item = default(T);
82 SingleLinkNode oldHead = null;
83 bool haveAdvancedHead = false;
84
85 while (!haveAdvancedHead)
86 {
87 oldHead = head;
88 SingleLinkNode oldTail = tail;
89 SingleLinkNode oldHeadNext = oldHead.Next;
90
91 if (oldHead == head)
92 {
93 if (oldHead == oldTail)
94 {
95 if (oldHeadNext == null)
96 return false;
97
98 CAS(ref tail, oldTail, oldHeadNext);
99 }
100 else
101 {
102 item = oldHeadNext.Item;
103 haveAdvancedHead = CAS(ref head, oldHead, oldHeadNext);
104 }
105 }
106 }
107
108 Interlocked.Decrement(ref count);
109 return true;
110 }
111
112 public void Clear()
113 {
114 Init();
115 }
116
117 private void Init()
118 {
119 count = 0;
120 head = tail = new SingleLinkNode();
121 }
122
123 private static bool CAS(ref SingleLinkNode location, SingleLinkNode comparand, SingleLinkNode newValue)
124 {
125 return
126 (object)comparand ==
127 (object)Interlocked.CompareExchange<SingleLinkNode>(ref location, newValue, comparand);
128 }
129 }
130} \ No newline at end of file
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