diff options
author | John Hurliman | 2009-10-06 12:13:16 -0700 |
---|---|---|
committer | John Hurliman | 2009-10-06 12:13:16 -0700 |
commit | 61b537215328499155c58f46e6338d459aba87ec (patch) | |
tree | d410fa5de01aeeacc6c66c23a886a2ae3e5248cc | |
parent | * Try/catch around EndInvoke() when Util.FireAndForget() returns to catch exc... (diff) | |
download | opensim-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.cs | 17 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLPacketThrottle.cs | 128 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs | 56 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 103 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/OutgoingPacket.cs | 14 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/ThrottleRates.cs | 23 | ||||
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs | 49 | ||||
-rw-r--r-- | prebuild.xml | 4 |
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 | ||
33 | namespace OpenSim.Region.ClientStack.LindenUDP | 33 | namespace 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 | |||
28 | namespace 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 | ||
34 | namespace OpenSim.Region.ClientStack.LindenUDP | 34 | namespace 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 | ||
42 | namespace OpenSim.Region.ClientStack.LindenUDP | 42 | namespace 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 | ||
32 | namespace OpenSim.Region.ClientStack.LindenUDP | 32 | namespace 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 | ||
31 | namespace OpenSim.Region.ClientStack.LindenUDP | 31 | namespace 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 | ||
33 | namespace OpenSim.Region.ClientStack.LindenUDP | 33 | namespace 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"> |