diff options
author | John Hurliman | 2009-10-13 18:56:54 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-13 18:56:54 -0700 |
commit | e8c1e69a0dbab1a7db894eeff6b052bbd350a8f5 (patch) | |
tree | 6d29a3bae418c1c5a06e3f1b8ad4a59db57a8d9e /OpenSim | |
parent | * Consolidated adding / removing ClientManager IClientAPIs to two places in S... (diff) | |
download | opensim-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 'OpenSim')
-rw-r--r-- | OpenSim/Framework/ClientManager.cs | 23 | ||||
-rw-r--r-- | OpenSim/Framework/LocklessQueue.cs | 130 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs | 11 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLImageManager.cs | 6 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 50 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 107 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | 9 |
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 | |||
27 | using System; | ||
28 | using System.Threading; | ||
29 | |||
30 | namespace 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 |