aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJohn Hurliman2009-10-06 12:13:16 -0700
committerJohn Hurliman2009-10-06 12:13:16 -0700
commit61b537215328499155c58f46e6338d459aba87ec (patch)
treed410fa5de01aeeacc6c66c23a886a2ae3e5248cc
parent* Try/catch around EndInvoke() when Util.FireAndForget() returns to catch exc... (diff)
downloadopensim-SC-61b537215328499155c58f46e6338d459aba87ec.zip
opensim-SC-61b537215328499155c58f46e6338d459aba87ec.tar.gz
opensim-SC-61b537215328499155c58f46e6338d459aba87ec.tar.bz2
opensim-SC-61b537215328499155c58f46e6338d459aba87ec.tar.xz
* Added missing references to prebuild.xml and commented out the LindenUDP tests until a new test harness is written
* Clients are no longer disconnected when a packet handler crashes. We'll see how this works out in practice * Added documentation and cleanup, getting ready for the first public push * Deleted an old LLUDP file
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs17
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs128
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs56
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs103
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs14
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs23
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs49
-rw-r--r--prebuild.xml4
8 files changed, 199 insertions, 195 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs
index dc0d62a..90b3ede 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/IncomingPacket.cs
@@ -32,11 +32,26 @@ using OpenMetaverse.Packets;
32 32
33namespace OpenSim.Region.ClientStack.LindenUDP 33namespace OpenSim.Region.ClientStack.LindenUDP
34{ 34{
35 public struct IncomingPacket 35 /// <summary>
36 /// Holds a reference to a <seealso cref="LLUDPClient"/> and a <seealso cref="Packet"/>
37 /// for incoming packets
38 /// </summary>
39 public sealed class IncomingPacket
36 { 40 {
37 /// <summary>Client this packet came from</summary> 41 /// <summary>Client this packet came from</summary>
38 public LLUDPClient Client; 42 public LLUDPClient Client;
39 /// <summary>Packet data that has been received</summary> 43 /// <summary>Packet data that has been received</summary>
40 public Packet Packet; 44 public Packet Packet;
45
46 /// <summary>
47 /// Default constructor
48 /// </summary>
49 /// <param name="client">Reference to the client this packet came from</param>
50 /// <param name="packet">Packet data</param>
51 public IncomingPacket(LLUDPClient client, Packet packet)
52 {
53 Client = client;
54 Packet = packet;
55 }
41 } 56 }
42} 57}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs
deleted file mode 100644
index 52effc5..0000000
--- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs
+++ /dev/null
@@ -1,128 +0,0 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
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 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28namespace OpenSim.Region.ClientStack.LindenUDP
29{
30 public class LLPacketThrottle
31 {
32 private readonly int m_maxAllowableThrottle;
33 private readonly int m_minAllowableThrottle;
34 private int m_currentThrottle;
35 private const int m_throttleTimeDivisor = 7;
36 private int m_currentBitsSent;
37 private int m_throttleBits;
38
39 /// <value>
40 /// Value with which to multiply all the throttle fields
41 /// </value>
42 private float m_throttleMultiplier;
43
44 public int Max
45 {
46 get { return m_maxAllowableThrottle; }
47 }
48
49 public int Min
50 {
51 get { return m_minAllowableThrottle; }
52 }
53
54 public int Current
55 {
56 get { return m_currentThrottle; }
57 }
58
59 /// <summary>
60 /// Constructor.
61 /// </summary>
62 /// <param name="min"></param>
63 /// <param name="max"></param>
64 /// <param name="throttle"></param>
65 /// <param name="throttleMultiplier">
66 /// A parameter that's ends up multiplying all throttle settings. An alternative solution would have been
67 /// to multiply all the parameters by this before giving them to the constructor. But doing it this way
68 /// represents the fact that the multiplier is a hack that pumps data to clients much faster than the actual
69 /// settings that we are given.
70 /// </param>
71 public LLPacketThrottle(int min, int max, int throttle, float throttleMultiplier)
72 {
73 m_throttleMultiplier = throttleMultiplier;
74 m_maxAllowableThrottle = max;
75 m_minAllowableThrottle = min;
76 m_currentThrottle = throttle;
77 m_currentBitsSent = 0;
78
79 CalcBits();
80 }
81
82 /// <summary>
83 /// Calculate the actual throttle required.
84 /// </summary>
85 private void CalcBits()
86 {
87 m_throttleBits = (int)((float)m_currentThrottle * m_throttleMultiplier / (float)m_throttleTimeDivisor);
88 }
89
90 public void Reset()
91 {
92 m_currentBitsSent = 0;
93 }
94
95 public bool UnderLimit()
96 {
97 return m_currentBitsSent < m_throttleBits;
98 }
99
100 public int AddBytes(int bytes)
101 {
102 m_currentBitsSent += bytes * 8;
103 return m_currentBitsSent;
104 }
105
106 public int Throttle
107 {
108 get { return m_currentThrottle; }
109 set
110 {
111 if (value < m_minAllowableThrottle)
112 {
113 m_currentThrottle = m_minAllowableThrottle;
114 }
115 else if (value > m_maxAllowableThrottle)
116 {
117 m_currentThrottle = m_maxAllowableThrottle;
118 }
119 else
120 {
121 m_currentThrottle = value;
122 }
123
124 CalcBits();
125 }
126 }
127 }
128}
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
index f2e76d3..871e8e8 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs
@@ -33,16 +33,40 @@ using OpenMetaverse;
33 33
34namespace OpenSim.Region.ClientStack.LindenUDP 34namespace OpenSim.Region.ClientStack.LindenUDP
35{ 35{
36 #region Delegates
37
38 /// <summary>
39 /// Fired when updated networking stats are produced for this client
40 /// </summary>
41 /// <param name="inPackets">Number of incoming packets received since this
42 /// event was last fired</param>
43 /// <param name="outPackets">Number of outgoing packets sent since this
44 /// event was last fired</param>
45 /// <param name="unAckedBytes">Current total number of bytes in packets we
46 /// are waiting on ACKs for</param>
36 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes); 47 public delegate void PacketStats(int inPackets, int outPackets, int unAckedBytes);
48 /// <summary>
49 /// Fired when the queue for a packet category is empty. This event can be
50 /// hooked to put more data on the empty queue
51 /// </summary>
52 /// <param name="category">Category of the packet queue that is empty</param>
37 public delegate void QueueEmpty(ThrottleOutPacketType category); 53 public delegate void QueueEmpty(ThrottleOutPacketType category);
38 54
39 public class LLUDPClient 55 #endregion Delegates
56
57 /// <summary>
58 /// Tracks state for a client UDP connection and provides client-specific methods
59 /// </summary>
60 public sealed class LLUDPClient
40 { 61 {
41 /// <summary>The number of packet categories to throttle on. If a throttle category is added 62 /// <summary>The number of packet categories to throttle on. If a throttle category is added
42 /// or removed, this number must also change</summary> 63 /// or removed, this number must also change</summary>
43 const int THROTTLE_CATEGORY_COUNT = 7; 64 const int THROTTLE_CATEGORY_COUNT = 7;
44 65
66 /// <summary>Fired when updated networking stats are produced for this client</summary>
45 public event PacketStats OnPacketStats; 67 public event PacketStats OnPacketStats;
68 /// <summary>Fired when the queue for a packet category is empty. This event can be
69 /// hooked to put more data on the empty queue</summary>
46 public event QueueEmpty OnQueueEmpty; 70 public event QueueEmpty OnQueueEmpty;
47 71
48 /// <summary>AgentID for this client</summary> 72 /// <summary>AgentID for this client</summary>
@@ -115,6 +139,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
115 /// <summary>A reference to the LLUDPServer that is managing this client</summary> 139 /// <summary>A reference to the LLUDPServer that is managing this client</summary>
116 private readonly LLUDPServer udpServer; 140 private readonly LLUDPServer udpServer;
117 141
142 /// <summary>
143 /// Default constructor
144 /// </summary>
145 /// <param name="server">Reference to the UDP server this client is connected to</param>
146 /// <param name="rates">Default throttling rates and maximum throttle limits</param>
147 /// <param name="parentThrottle">Parent HTB (hierarchical token bucket)
148 /// that the child throttles will be governed by</param>
149 /// <param name="circuitCode">Circuit code for this connection</param>
150 /// <param name="agentID">AgentID for the connected agent</param>
151 /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
118 public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint) 152 public LLUDPClient(LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID, IPEndPoint remoteEndPoint)
119 { 153 {
120 udpServer = server; 154 udpServer = server;
@@ -144,14 +178,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
144 RTO = 3000; 178 RTO = 3000;
145 } 179 }
146 180
181 /// <summary>
182 /// Shuts down this client connection
183 /// </summary>
147 public void Shutdown() 184 public void Shutdown()
148 { 185 {
186 // TODO: Do we need to invalidate the circuit?
149 IsConnected = false; 187 IsConnected = false;
150 } 188 }
151 189
190 /// <summary>
191 /// Gets information about this client connection
192 /// </summary>
193 /// <returns>Information about the client connection</returns>
152 public ClientInfo GetClientInfo() 194 public ClientInfo GetClientInfo()
153 { 195 {
154 // TODO: This data structure is wrong in so many ways 196 // TODO: This data structure is wrong in so many ways. Locking and copying the entire lists
197 // of pending and needed ACKs for every client every time some method wants information about
198 // this connection is a recipe for poor performance
155 ClientInfo info = new ClientInfo(); 199 ClientInfo info = new ClientInfo();
156 info.pendingAcks = new Dictionary<uint, uint>(); 200 info.pendingAcks = new Dictionary<uint, uint>();
157 info.needAck = new Dictionary<uint, byte[]>(); 201 info.needAck = new Dictionary<uint, byte[]>();
@@ -169,8 +213,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
169 return info; 213 return info;
170 } 214 }
171 215
216 /// <summary>
217 /// Modifies the UDP throttles
218 /// </summary>
219 /// <param name="info">New throttling values</param>
172 public void SetClientInfo(ClientInfo info) 220 public void SetClientInfo(ClientInfo info)
173 { 221 {
222 // TODO: Allowing throttles to be manually set from this function seems like a reasonable
223 // idea. On the other hand, letting external code manipulate our ACK accounting is not
224 // going to happen
225 throw new NotImplementedException();
174 } 226 }
175 227
176 public string GetStats() 228 public string GetStats()
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 38890da..c0a84a8 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -41,7 +41,10 @@ using OpenMetaverse;
41 41
42namespace OpenSim.Region.ClientStack.LindenUDP 42namespace OpenSim.Region.ClientStack.LindenUDP
43{ 43{
44 public class LLUDPServerShim : IClientNetworkServer 44 /// <summary>
45 /// A shim around LLUDPServer that implements the IClientNetworkServer interface
46 /// </summary>
47 public sealed class LLUDPServerShim : IClientNetworkServer
45 { 48 {
46 LLUDPServer m_udpServer; 49 LLUDPServer m_udpServer;
47 50
@@ -80,6 +83,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
80 } 83 }
81 } 84 }
82 85
86 /// <summary>
87 /// The LLUDP server for a region. This handles incoming and outgoing
88 /// packets for all UDP connections to the region
89 /// </summary>
83 public class LLUDPServer : UDPBase 90 public class LLUDPServer : UDPBase
84 { 91 {
85 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 92 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
@@ -152,6 +159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
152 159
153 public new void Stop() 160 public new void Stop()
154 { 161 {
162 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
155 base.Stop(); 163 base.Stop();
156 } 164 }
157 165
@@ -591,11 +599,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
591 if (packet.Type != PacketType.PacketAck) 599 if (packet.Type != PacketType.PacketAck)
592 { 600 {
593 // Inbox insertion 601 // Inbox insertion
594 IncomingPacket incomingPacket; 602 packetInbox.Enqueue(new IncomingPacket(client, packet));
595 incomingPacket.Client = client;
596 incomingPacket.Packet = packet;
597
598 packetInbox.Enqueue(incomingPacket);
599 } 603 }
600 } 604 }
601 605
@@ -683,7 +687,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
683 // on to en-US to avoid number parsing issues 687 // on to en-US to avoid number parsing issues
684 Culture.SetCurrentCulture(); 688 Culture.SetCurrentCulture();
685 689
686 IncomingPacket incomingPacket = default(IncomingPacket); 690 IncomingPacket incomingPacket = null;
687 691
688 while (base.IsRunning) 692 while (base.IsRunning)
689 { 693 {
@@ -696,59 +700,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
696 packetInbox.Clear(); 700 packetInbox.Clear();
697 } 701 }
698 702
699 private void ProcessInPacket(object state)
700 {
701 IncomingPacket incomingPacket = (IncomingPacket)state;
702 Packet packet = incomingPacket.Packet;
703 LLUDPClient client = incomingPacket.Client;
704
705 if (packet != null && client != null)
706 {
707 try
708 {
709 client.ClientAPI.ProcessInPacket(packet);
710 }
711 catch (ThreadAbortException)
712 {
713 throw;
714 }
715 catch (Exception e)
716 {
717 if (StatsManager.SimExtraStats != null)
718 StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
719
720 // Don't let a failure in an individual client thread crash the whole sim.
721 m_log.ErrorFormat("[LLUDPSERVER]: Client thread for {0} crashed. Logging them out", client.AgentID);
722 m_log.Error(e.Message, e);
723
724 try
725 {
726 // Make an attempt to alert the user that their session has crashed
727 AgentAlertMessagePacket alert = client.ClientAPI.BuildAgentAlertPacket(
728 "Unfortunately the session for this client on the server has crashed.\n" +
729 "Any further actions taken will not be processed.\n" +
730 "Please relog", true);
731
732 SendPacket(client, alert, ThrottleOutPacketType.Unknown, false);
733
734 // TODO: There may be a better way to do this. Perhaps kick? Not sure this propogates notifications to
735 // listeners yet, though.
736 client.ClientAPI.SendLogoutPacket();
737 RemoveClient(client.ClientAPI);
738 }
739 catch (ThreadAbortException)
740 {
741 throw;
742 }
743 catch (Exception e2)
744 {
745 m_log.Error("[LLUDPSERVER]: Further exception thrown on forced session logout for " + client.AgentID);
746 m_log.Error(e2.Message, e2);
747 }
748 }
749 }
750 }
751
752 private void OutgoingPacketHandler() 703 private void OutgoingPacketHandler()
753 { 704 {
754 // Set this culture for the thread that outgoing packets are sent 705 // Set this culture for the thread that outgoing packets are sent
@@ -812,6 +763,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
812 } 763 }
813 } 764 }
814 765
766 private void ProcessInPacket(object state)
767 {
768 IncomingPacket incomingPacket = (IncomingPacket)state;
769 Packet packet = incomingPacket.Packet;
770 LLUDPClient client = incomingPacket.Client;
771
772 // Sanity check
773 if (packet == null || client == null || client.ClientAPI == null)
774 {
775 m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", Client=\"{1}\", Client.ClientAPI=\"{2}\"",
776 packet, client, (client != null) ? client.ClientAPI : null);
777 }
778
779 try
780 {
781 // Process this packet
782 client.ClientAPI.ProcessInPacket(packet);
783 }
784 catch (ThreadAbortException)
785 {
786 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
787 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
788 Stop();
789 }
790 catch (Exception e)
791 {
792 // Don't let a failure in an individual client thread crash the whole sim.
793 m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", client.AgentID, packet.Type);
794 m_log.Error(e.Message, e);
795 }
796 }
797
815 private void LogoutHandler(IClientAPI client) 798 private void LogoutHandler(IClientAPI client)
816 { 799 {
817 client.SendLogoutPacket(); 800 client.SendLogoutPacket();
diff --git a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
index 69b0c5f..1a1a1cb 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs
@@ -31,6 +31,13 @@ using OpenMetaverse;
31 31
32namespace OpenSim.Region.ClientStack.LindenUDP 32namespace OpenSim.Region.ClientStack.LindenUDP
33{ 33{
34 /// <summary>
35 /// Holds a reference to the <seealso cref="LLUDPClient"/> this packet is
36 /// destined for, along with the serialized packet data, sequence number
37 /// (if this is a resend), number of times this packet has been resent,
38 /// the time of the last resend, and the throttling category for this
39 /// packet
40 /// </summary>
34 public sealed class OutgoingPacket 41 public sealed class OutgoingPacket
35 { 42 {
36 /// <summary>Client this packet is destined for</summary> 43 /// <summary>Client this packet is destined for</summary>
@@ -46,6 +53,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
46 /// <summary>Category this packet belongs to</summary> 53 /// <summary>Category this packet belongs to</summary>
47 public ThrottleOutPacketType Category; 54 public ThrottleOutPacketType Category;
48 55
56 /// <summary>
57 /// Default constructor
58 /// </summary>
59 /// <param name="client">Reference to the client this packet is destined for</param>
60 /// <param name="buffer">Serialized packet data. If the flags or sequence number
61 /// need to be updated, they will be injected directly into this binary buffer</param>
62 /// <param name="category">Throttling category for this packet</param>
49 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category) 63 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category)
50 { 64 {
51 Client = client; 65 Client = client;
diff --git a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
index ffa20d5..858a03c 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs
@@ -30,24 +30,47 @@ using Nini.Config;
30 30
31namespace OpenSim.Region.ClientStack.LindenUDP 31namespace OpenSim.Region.ClientStack.LindenUDP
32{ 32{
33 /// <summary>
34 /// Holds drip rates and maximum burst rates for throttling with hierarchical
35 /// token buckets. The maximum burst rates set here are hard limits and can
36 /// not be overridden by client requests
37 /// </summary>
33 public sealed class ThrottleRates 38 public sealed class ThrottleRates
34 { 39 {
40 /// <summary>Drip rate for resent packets</summary>
35 public int Resend; 41 public int Resend;
42 /// <summary>Drip rate for terrain packets</summary>
36 public int Land; 43 public int Land;
44 /// <summary>Drip rate for wind packets</summary>
37 public int Wind; 45 public int Wind;
46 /// <summary>Drip rate for cloud packets</summary>
38 public int Cloud; 47 public int Cloud;
48 /// <summary>Drip rate for task (state and transaction) packets</summary>
39 public int Task; 49 public int Task;
50 /// <summary>Drip rate for texture packets</summary>
40 public int Texture; 51 public int Texture;
52 /// <summary>Drip rate for asset packets</summary>
41 public int Asset; 53 public int Asset;
42 54
55 /// <summary>Maximum burst rate for resent packets</summary>
43 public int ResendLimit; 56 public int ResendLimit;
57 /// <summary>Maximum burst rate for land packets</summary>
44 public int LandLimit; 58 public int LandLimit;
59 /// <summary>Maximum burst rate for wind packets</summary>
45 public int WindLimit; 60 public int WindLimit;
61 /// <summary>Maximum burst rate for cloud packets</summary>
46 public int CloudLimit; 62 public int CloudLimit;
63 /// <summary>Maximum burst rate for task (state and transaction) packets</summary>
47 public int TaskLimit; 64 public int TaskLimit;
65 /// <summary>Maximum burst rate for texture packets</summary>
48 public int TextureLimit; 66 public int TextureLimit;
67 /// <summary>Maximum burst rate for asset packets</summary>
49 public int AssetLimit; 68 public int AssetLimit;
50 69
70 /// <summary>
71 /// Default constructor
72 /// </summary>
73 /// <param name="config">Config source to load defaults from</param>
51 public ThrottleRates(IConfigSource config) 74 public ThrottleRates(IConfigSource config)
52 { 75 {
53 try 76 try
diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
index 16c0035..b7df84d 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs
@@ -32,19 +32,34 @@ using OpenMetaverse;
32 32
33namespace OpenSim.Region.ClientStack.LindenUDP 33namespace OpenSim.Region.ClientStack.LindenUDP
34{ 34{
35 /// <summary>
36 /// Special collection that is optimized for tracking unacknowledged packets
37 /// </summary>
35 public sealed class UnackedPacketCollection 38 public sealed class UnackedPacketCollection
36 { 39 {
40 /// <summary>Synchronization primitive. A lock must be acquired on this
41 /// object before calling any of the unsafe methods</summary>
37 public object SyncRoot = new object(); 42 public object SyncRoot = new object();
38 43
39 SortedDictionary<uint, OutgoingPacket> packets; 44 /// <summary>Holds the actual unacked packet data, sorted by sequence number</summary>
45 private SortedDictionary<uint, OutgoingPacket> packets = new SortedDictionary<uint, OutgoingPacket>();
40 46
47 /// <summary>Gets the total number of unacked packets</summary>
41 public int Count { get { return packets.Count; } } 48 public int Count { get { return packets.Count; } }
42 49
50 /// <summary>
51 /// Default constructor
52 /// </summary>
43 public UnackedPacketCollection() 53 public UnackedPacketCollection()
44 { 54 {
45 packets = new SortedDictionary<uint, OutgoingPacket>();
46 } 55 }
47 56
57 /// <summary>
58 /// Add an unacked packet to the collection
59 /// </summary>
60 /// <param name="packet">Packet that is awaiting acknowledgement</param>
61 /// <returns>True if the packet was successfully added, false if the
62 /// packet already existed in the collection</returns>
48 public bool Add(OutgoingPacket packet) 63 public bool Add(OutgoingPacket packet)
49 { 64 {
50 lock (SyncRoot) 65 lock (SyncRoot)
@@ -58,11 +73,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
58 } 73 }
59 } 74 }
60 75
76 /// <summary>
77 /// Removes a packet from the collection without attempting to obtain a
78 /// lock first
79 /// </summary>
80 /// <param name="sequenceNumber">Sequence number of the packet to remove</param>
81 /// <returns>True if the packet was found and removed, otherwise false</returns>
61 public bool RemoveUnsafe(uint sequenceNumber) 82 public bool RemoveUnsafe(uint sequenceNumber)
62 { 83 {
63 return packets.Remove(sequenceNumber); 84 return packets.Remove(sequenceNumber);
64 } 85 }
65 86
87 /// <summary>
88 /// Removes a packet from the collection without attempting to obtain a
89 /// lock first
90 /// </summary>
91 /// <param name="sequenceNumber">Sequence number of the packet to remove</param>
92 /// <param name="packet">Returns the removed packet</param>
93 /// <returns>True if the packet was found and removed, otherwise false</returns>
66 public bool RemoveUnsafe(uint sequenceNumber, out OutgoingPacket packet) 94 public bool RemoveUnsafe(uint sequenceNumber, out OutgoingPacket packet)
67 { 95 {
68 if (packets.TryGetValue(sequenceNumber, out packet)) 96 if (packets.TryGetValue(sequenceNumber, out packet))
@@ -74,6 +102,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
74 return false; 102 return false;
75 } 103 }
76 104
105 /// <summary>
106 /// Gets the packet with the lowest sequence number
107 /// </summary>
108 /// <returns>The packet with the lowest sequence number, or null if the
109 /// collection is empty</returns>
77 public OutgoingPacket GetOldest() 110 public OutgoingPacket GetOldest()
78 { 111 {
79 lock (SyncRoot) 112 lock (SyncRoot)
@@ -83,7 +116,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
83 } 116 }
84 } 117 }
85 118
86 public List<OutgoingPacket> GetExpiredPackets(int timeout) 119 /// <summary>
120 /// Returns a list of all of the packets with a TickCount older than
121 /// the specified timeout
122 /// </summary>
123 /// <param name="timeoutMS">Number of ticks (milliseconds) before a
124 /// packet is considered expired</param>
125 /// <returns>A list of all expired packets according to the given
126 /// expiration timeout</returns>
127 public List<OutgoingPacket> GetExpiredPackets(int timeoutMS)
87 { 128 {
88 List<OutgoingPacket> expiredPackets = null; 129 List<OutgoingPacket> expiredPackets = null;
89 130
@@ -95,7 +136,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
95 if (packet.TickCount == 0) 136 if (packet.TickCount == 0)
96 continue; 137 continue;
97 138
98 if (now - packet.TickCount >= timeout) 139 if (now - packet.TickCount >= timeoutMS)
99 { 140 {
100 if (expiredPackets == null) 141 if (expiredPackets == null)
101 expiredPackets = new List<OutgoingPacket>(); 142 expiredPackets = new List<OutgoingPacket>();
diff --git a/prebuild.xml b/prebuild.xml
index f863ab6..f35dcc3 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -131,6 +131,7 @@
131 131
132 <ReferencePath>../../bin/</ReferencePath> 132 <ReferencePath>../../bin/</ReferencePath>
133 <Reference name="System"/> 133 <Reference name="System"/>
134 <Reference name="System.Core"/>
134 <Reference name="System.Xml"/> 135 <Reference name="System.Xml"/>
135 <Reference name="System.Data"/> 136 <Reference name="System.Data"/>
136 <Reference name="System.Drawing"/> 137 <Reference name="System.Drawing"/>
@@ -1755,6 +1756,7 @@
1755 1756
1756 <ReferencePath>../../../../bin/</ReferencePath> 1757 <ReferencePath>../../../../bin/</ReferencePath>
1757 <Reference name="System"/> 1758 <Reference name="System"/>
1759 <Reference name="System.Core"/>
1758 <Reference name="System.Xml"/> 1760 <Reference name="System.Xml"/>
1759 <Reference name="OpenMetaverseTypes.dll"/> 1761 <Reference name="OpenMetaverseTypes.dll"/>
1760 <Reference name="OpenMetaverse.StructuredData.dll"/> 1762 <Reference name="OpenMetaverse.StructuredData.dll"/>
@@ -3695,6 +3697,7 @@
3695 </Files> 3697 </Files>
3696 </Project> 3698 </Project>
3697 3699
3700 <!-- Commented for now until new unit tests are written for the new LLUDP implementation
3698 <Project frameworkVersion="v3_5" name="OpenSim.Region.ClientStack.LindenUDP.Tests" path="OpenSim/Region/ClientStack/LindenUDP/Tests" type="Library"> 3701 <Project frameworkVersion="v3_5" name="OpenSim.Region.ClientStack.LindenUDP.Tests" path="OpenSim/Region/ClientStack/LindenUDP/Tests" type="Library">
3699 <Configuration name="Debug"> 3702 <Configuration name="Debug">
3700 <Options> 3703 <Options>
@@ -3728,6 +3731,7 @@
3728 <Match pattern="*.cs" recurse="false"/> 3731 <Match pattern="*.cs" recurse="false"/>
3729 </Files> 3732 </Files>
3730 </Project> 3733 </Project>
3734 -->
3731 3735
3732 <Project frameworkVersion="v3_5" name="OpenSim.Region.ScriptEngine.Tests" path="OpenSim/Region/ScriptEngine" type="Library"> 3736 <Project frameworkVersion="v3_5" name="OpenSim.Region.ScriptEngine.Tests" path="OpenSim/Region/ScriptEngine" type="Library">
3733 <Configuration name="Debug"> 3737 <Configuration name="Debug">