diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 120 |
1 files changed, 86 insertions, 34 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 545a0bc..74175d0 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -89,6 +89,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
89 | /// </summary> | 89 | /// </summary> |
90 | public class LLUDPServer : OpenSimUDPBase | 90 | public class LLUDPServer : OpenSimUDPBase |
91 | { | 91 | { |
92 | /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary> | ||
93 | public const int MTU = 1400; | ||
94 | |||
92 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 95 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
93 | 96 | ||
94 | /// <summary>Handlers for incoming packets</summary> | 97 | /// <summary>Handlers for incoming packets</summary> |
@@ -104,7 +107,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
104 | /// <summary>Manages authentication for agent circuits</summary> | 107 | /// <summary>Manages authentication for agent circuits</summary> |
105 | private AgentCircuitManager m_circuitManager; | 108 | private AgentCircuitManager m_circuitManager; |
106 | /// <summary>Reference to the scene this UDP server is attached to</summary> | 109 | /// <summary>Reference to the scene this UDP server is attached to</summary> |
107 | private IScene m_scene; | 110 | private Scene m_scene; |
108 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> | 111 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> |
109 | private Location m_location; | 112 | private Location m_location; |
110 | /// <summary>The measured resolution of Environment.TickCount</summary> | 113 | /// <summary>The measured resolution of Environment.TickCount</summary> |
@@ -181,15 +184,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
181 | 184 | ||
182 | public void AddScene(IScene scene) | 185 | public void AddScene(IScene scene) |
183 | { | 186 | { |
184 | if (m_scene == null) | 187 | if (m_scene != null) |
185 | { | 188 | { |
186 | m_scene = scene; | 189 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); |
187 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | 190 | return; |
188 | } | 191 | } |
189 | else | 192 | |
193 | if (!(scene is Scene)) | ||
190 | { | 194 | { |
191 | m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); | 195 | m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType()); |
196 | return; | ||
192 | } | 197 | } |
198 | |||
199 | m_scene = (Scene)scene; | ||
200 | m_location = new Location(m_scene.RegionInfo.RegionHandle); | ||
193 | } | 201 | } |
194 | 202 | ||
195 | public bool HandlesRegion(Location x) | 203 | public bool HandlesRegion(Location x) |
@@ -267,38 +275,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
267 | { | 275 | { |
268 | int dataLength = data.Length; | 276 | int dataLength = data.Length; |
269 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; | 277 | bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; |
278 | bool doCopy = true; | ||
270 | 279 | ||
271 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. | 280 | // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. |
272 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting | 281 | // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting |
273 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here | 282 | // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here |
274 | // to accomodate for both common scenarios and provide ample room for ACK appending in both | 283 | // to accomodate for both common scenarios and provide ample room for ACK appending in both |
275 | int bufferSize = (dataLength > 180) ? Packet.MTU : 200; | 284 | int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200; |
276 | 285 | ||
277 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); | 286 | UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
278 | 287 | ||
279 | // Zerocode if needed | 288 | // Zerocode if needed |
280 | if (doZerocode) | 289 | if (doZerocode) |
281 | { | 290 | { |
282 | try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); } | 291 | try |
292 | { | ||
293 | dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); | ||
294 | doCopy = false; | ||
295 | } | ||
283 | catch (IndexOutOfRangeException) | 296 | catch (IndexOutOfRangeException) |
284 | { | 297 | { |
285 | // The packet grew larger than the bufferSize while zerocoding. | 298 | // The packet grew larger than the bufferSize while zerocoding. |
286 | // Remove the MSG_ZEROCODED flag and send the unencoded data | 299 | // Remove the MSG_ZEROCODED flag and send the unencoded data |
287 | // instead | 300 | // instead |
288 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); | 301 | m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength + |
302 | " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag"); | ||
289 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); | 303 | data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); |
290 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
291 | } | 304 | } |
292 | } | 305 | } |
293 | else | 306 | |
307 | // If the packet data wasn't already copied during zerocoding, copy it now | ||
308 | if (doCopy) | ||
294 | { | 309 | { |
295 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | 310 | if (dataLength <= buffer.Data.Length) |
311 | { | ||
312 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | ||
317 | type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | ||
318 | return; | ||
319 | } | ||
296 | } | 320 | } |
321 | |||
297 | buffer.DataLength = dataLength; | 322 | buffer.DataLength = dataLength; |
298 | 323 | ||
299 | #region Queue or Send | 324 | #region Queue or Send |
300 | 325 | ||
301 | // Look up the UDPClient this is going to | ||
302 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); | 326 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
303 | 327 | ||
304 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 328 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
@@ -513,7 +537,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
513 | IClientAPI client; | 537 | IClientAPI client; |
514 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) | 538 | if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) |
515 | { | 539 | { |
516 | m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + | 540 | m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + |
517 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); | 541 | " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); |
518 | return; | 542 | return; |
519 | } | 543 | } |
@@ -553,6 +577,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
553 | for (int i = 0; i < ackPacket.Packets.Length; i++) | 577 | for (int i = 0; i < ackPacket.Packets.Length; i++) |
554 | AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); | 578 | AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); |
555 | } | 579 | } |
580 | |||
581 | // We don't need to do anything else with PacketAck packets | ||
582 | return; | ||
556 | } | 583 | } |
557 | 584 | ||
558 | #endregion ACK Receiving | 585 | #endregion ACK Receiving |
@@ -560,20 +587,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
560 | #region ACK Sending | 587 | #region ACK Sending |
561 | 588 | ||
562 | if (packet.Header.Reliable) | 589 | if (packet.Header.Reliable) |
590 | { | ||
563 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); | 591 | udpClient.PendingAcks.Enqueue(packet.Header.Sequence); |
564 | 592 | ||
565 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, | 593 | // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, |
566 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove | 594 | // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove |
567 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to | 595 | // 2*MTU bytes from the value and send ACKs, and finally add the local value back to |
568 | // client.BytesSinceLastACK. Lockless thread safety | 596 | // client.BytesSinceLastACK. Lockless thread safety |
569 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); | 597 | int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); |
570 | bytesSinceLastACK += buffer.DataLength; | 598 | bytesSinceLastACK += buffer.DataLength; |
571 | if (bytesSinceLastACK > Packet.MTU * 2) | 599 | if (bytesSinceLastACK > LLUDPServer.MTU * 2) |
572 | { | 600 | { |
573 | bytesSinceLastACK -= Packet.MTU * 2; | 601 | bytesSinceLastACK -= LLUDPServer.MTU * 2; |
574 | SendAcks(udpClient); | 602 | SendAcks(udpClient); |
603 | } | ||
604 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); | ||
575 | } | 605 | } |
576 | Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK); | ||
577 | 606 | ||
578 | #endregion ACK Sending | 607 | #endregion ACK Sending |
579 | 608 | ||
@@ -593,12 +622,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
593 | 622 | ||
594 | #endregion Incoming Packet Accounting | 623 | #endregion Incoming Packet Accounting |
595 | 624 | ||
596 | // Don't bother clogging up the queue with PacketAck packets that are already handled here | 625 | #region Ping Check Handling |
597 | if (packet.Type != PacketType.PacketAck) | 626 | |
627 | if (packet.Type == PacketType.StartPingCheck) | ||
628 | { | ||
629 | // We don't need to do anything else with ping checks | ||
630 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; | ||
631 | |||
632 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); | ||
633 | completePing.PingID.PingID = startPing.PingID.PingID; | ||
634 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); | ||
635 | return; | ||
636 | } | ||
637 | else if (packet.Type == PacketType.CompletePingCheck) | ||
598 | { | 638 | { |
599 | // Inbox insertion | 639 | // We don't currently track client ping times |
600 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); | 640 | return; |
601 | } | 641 | } |
642 | |||
643 | #endregion Ping Check Handling | ||
644 | |||
645 | // Inbox insertion | ||
646 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); | ||
602 | } | 647 | } |
603 | 648 | ||
604 | protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) | 649 | protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) |
@@ -693,12 +738,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
693 | // on to en-US to avoid number parsing issues | 738 | // on to en-US to avoid number parsing issues |
694 | Culture.SetCurrentCulture(); | 739 | Culture.SetCurrentCulture(); |
695 | 740 | ||
696 | IncomingPacket incomingPacket = null; | ||
697 | |||
698 | while (base.IsRunning) | 741 | while (base.IsRunning) |
699 | { | 742 | { |
700 | if (packetInbox.Dequeue(100, ref incomingPacket)) | 743 | IncomingPacket incomingPacket = null; |
701 | Util.FireAndForget(ProcessInPacket, incomingPacket); | 744 | |
745 | try | ||
746 | { | ||
747 | if (packetInbox.Dequeue(100, ref incomingPacket)) | ||
748 | Util.FireAndForget(ProcessInPacket, incomingPacket); | ||
749 | } | ||
750 | catch (Exception ex) | ||
751 | { | ||
752 | m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); | ||
753 | } | ||
702 | } | 754 | } |
703 | 755 | ||
704 | if (packetInbox.Count > 0) | 756 | if (packetInbox.Count > 0) |
@@ -747,7 +799,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
747 | elapsed500MS = 0; | 799 | elapsed500MS = 0; |
748 | } | 800 | } |
749 | 801 | ||
750 | m_scene.ClientManager.ForEach( | 802 | m_scene.ClientManager.ForEachSync( |
751 | delegate(IClientAPI client) | 803 | delegate(IClientAPI client) |
752 | { | 804 | { |
753 | if (client is LLClientView) | 805 | if (client is LLClientView) |