diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 190 |
1 files changed, 167 insertions, 23 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index 74d3262..0b05ed9 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.IO; | ||
30 | using System.Net; | 31 | using System.Net; |
31 | using System.Net.Sockets; | 32 | using System.Net.Sockets; |
32 | using System.Reflection; | 33 | using System.Reflection; |
@@ -118,13 +119,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
118 | /// <summary></summary> | 119 | /// <summary></summary> |
119 | //private UDPClientCollection m_clients = new UDPClientCollection(); | 120 | //private UDPClientCollection m_clients = new UDPClientCollection(); |
120 | /// <summary>Bandwidth throttle for this UDP server</summary> | 121 | /// <summary>Bandwidth throttle for this UDP server</summary> |
121 | private TokenBucket m_throttle; | 122 | protected TokenBucket m_throttle; |
122 | /// <summary>Bandwidth throttle rates for this UDP server</summary> | 123 | /// <summary>Bandwidth throttle rates for this UDP server</summary> |
123 | private ThrottleRates m_throttleRates; | 124 | protected ThrottleRates m_throttleRates; |
124 | /// <summary>Manages authentication for agent circuits</summary> | 125 | /// <summary>Manages authentication for agent circuits</summary> |
125 | private AgentCircuitManager m_circuitManager; | 126 | private AgentCircuitManager m_circuitManager; |
126 | /// <summary>Reference to the scene this UDP server is attached to</summary> | 127 | /// <summary>Reference to the scene this UDP server is attached to</summary> |
127 | private Scene m_scene; | 128 | protected Scene m_scene; |
128 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> | 129 | /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> |
129 | private Location m_location; | 130 | private Location m_location; |
130 | /// <summary>The size of the receive buffer for the UDP socket. This value | 131 | /// <summary>The size of the receive buffer for the UDP socket. This value |
@@ -153,6 +154,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
153 | /// <summary>Flag to signal when clients should send pings</summary> | 154 | /// <summary>Flag to signal when clients should send pings</summary> |
154 | private bool m_sendPing; | 155 | private bool m_sendPing; |
155 | 156 | ||
157 | private int m_defaultRTO = 0; | ||
158 | private int m_maxRTO = 0; | ||
159 | |||
156 | public Socket Server { get { return null; } } | 160 | public Socket Server { get { return null; } } |
157 | 161 | ||
158 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) | 162 | public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) |
@@ -189,6 +193,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
189 | AvatarTerseUpdatesPerPacket = config.GetInt("AvatarTerseUpdatesPerPacket", 10); | 193 | AvatarTerseUpdatesPerPacket = config.GetInt("AvatarTerseUpdatesPerPacket", 10); |
190 | PrimFullUpdatesPerPacket = config.GetInt("PrimFullUpdatesPerPacket", 100); | 194 | PrimFullUpdatesPerPacket = config.GetInt("PrimFullUpdatesPerPacket", 100); |
191 | TextureSendLimit = config.GetInt("TextureSendLimit", 20); | 195 | TextureSendLimit = config.GetInt("TextureSendLimit", 20); |
196 | |||
197 | m_defaultRTO = config.GetInt("DefaultRTO", 0); | ||
198 | m_maxRTO = config.GetInt("MaxRTO", 0); | ||
192 | } | 199 | } |
193 | else | 200 | else |
194 | { | 201 | { |
@@ -198,6 +205,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
198 | TextureSendLimit = 20; | 205 | TextureSendLimit = 20; |
199 | } | 206 | } |
200 | 207 | ||
208 | #region BinaryStats | ||
209 | config = configSource.Configs["Statistics.Binary"]; | ||
210 | m_shouldCollectStats = false; | ||
211 | if (config != null) | ||
212 | { | ||
213 | if (config.Contains("enabled") && config.GetBoolean("enabled")) | ||
214 | { | ||
215 | if (config.Contains("collect_packet_headers")) | ||
216 | m_shouldCollectStats = config.GetBoolean("collect_packet_headers"); | ||
217 | if (config.Contains("packet_headers_period_seconds")) | ||
218 | { | ||
219 | binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds")); | ||
220 | } | ||
221 | if (config.Contains("stats_dir")) | ||
222 | { | ||
223 | binStatsDir = config.GetString("stats_dir"); | ||
224 | } | ||
225 | } | ||
226 | else | ||
227 | { | ||
228 | m_shouldCollectStats = false; | ||
229 | } | ||
230 | } | ||
231 | #endregion BinaryStats | ||
232 | |||
201 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); | 233 | m_throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps); |
202 | m_throttleRates = new ThrottleRates(configSource); | 234 | m_throttleRates = new ThrottleRates(configSource); |
203 | } | 235 | } |
@@ -247,8 +279,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
247 | 279 | ||
248 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) | 280 | public void BroadcastPacket(Packet packet, ThrottleOutPacketType category, bool sendToPausedAgents, bool allowSplitting) |
249 | { | 281 | { |
250 | // CoarseLocationUpdate packets cannot be split in an automated way | 282 | // CoarseLocationUpdate and AvatarGroupsReply packets cannot be split in an automated way |
251 | if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting) | 283 | if ((packet.Type == PacketType.CoarseLocationUpdate || packet.Type == PacketType.AvatarGroupsReply) && allowSplitting) |
252 | allowSplitting = false; | 284 | allowSplitting = false; |
253 | 285 | ||
254 | if (allowSplitting && packet.HasVariableBlocks) | 286 | if (allowSplitting && packet.HasVariableBlocks) |
@@ -256,8 +288,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
256 | byte[][] datas = packet.ToBytesMultiple(); | 288 | byte[][] datas = packet.ToBytesMultiple(); |
257 | int packetCount = datas.Length; | 289 | int packetCount = datas.Length; |
258 | 290 | ||
259 | //if (packetCount > 1) | 291 | if (packetCount < 1) |
260 | // m_log.Debug("[LLUDPSERVER]: Split " + packet.Type + " packet into " + packetCount + " packets"); | 292 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); |
261 | 293 | ||
262 | for (int i = 0; i < packetCount; i++) | 294 | for (int i = 0; i < packetCount; i++) |
263 | { | 295 | { |
@@ -295,8 +327,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
295 | byte[][] datas = packet.ToBytesMultiple(); | 327 | byte[][] datas = packet.ToBytesMultiple(); |
296 | int packetCount = datas.Length; | 328 | int packetCount = datas.Length; |
297 | 329 | ||
298 | //if (packetCount > 1) | 330 | if (packetCount < 1) |
299 | // m_log.Debug("[LLUDPSERVER]: Split " + packet.Type + " packet into " + packetCount + " packets"); | 331 | m_log.Error("[LLUDPSERVER]: Failed to split " + packet.Type + " with estimated length " + packet.Length); |
300 | 332 | ||
301 | for (int i = 0; i < packetCount; i++) | 333 | for (int i = 0; i < packetCount; i++) |
302 | { | 334 | { |
@@ -353,9 +385,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
353 | } | 385 | } |
354 | else | 386 | else |
355 | { | 387 | { |
356 | m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | 388 | bufferSize = dataLength; |
357 | type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | 389 | buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); |
358 | return; | 390 | |
391 | // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + | ||
392 | // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); | ||
393 | Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); | ||
359 | } | 394 | } |
360 | } | 395 | } |
361 | 396 | ||
@@ -364,6 +399,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
364 | #region Queue or Send | 399 | #region Queue or Send |
365 | 400 | ||
366 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); | 401 | OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); |
402 | outgoingPacket.Type = type; | ||
367 | 403 | ||
368 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) | 404 | if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) |
369 | SendPacketFinal(outgoingPacket); | 405 | SendPacketFinal(outgoingPacket); |
@@ -409,6 +445,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
409 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); | 445 | SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); |
410 | } | 446 | } |
411 | 447 | ||
448 | public void CompletePing(LLUDPClient udpClient, byte pingID) | ||
449 | { | ||
450 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); | ||
451 | completePing.PingID.PingID = pingID; | ||
452 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); | ||
453 | } | ||
454 | |||
412 | public void ResendUnacked(LLUDPClient udpClient) | 455 | public void ResendUnacked(LLUDPClient udpClient) |
413 | { | 456 | { |
414 | if (!udpClient.IsConnected) | 457 | if (!udpClient.IsConnected) |
@@ -429,7 +472,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
429 | 472 | ||
430 | if (expiredPackets != null) | 473 | if (expiredPackets != null) |
431 | { | 474 | { |
432 | m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); | 475 | //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO); |
433 | 476 | ||
434 | // Exponential backoff of the retransmission timeout | 477 | // Exponential backoff of the retransmission timeout |
435 | udpClient.BackoffRTO(); | 478 | udpClient.BackoffRTO(); |
@@ -468,6 +511,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
468 | byte flags = buffer.Data[0]; | 511 | byte flags = buffer.Data[0]; |
469 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; | 512 | bool isResend = (flags & Helpers.MSG_RESENT) != 0; |
470 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; | 513 | bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0; |
514 | bool sendSynchronous = false; | ||
471 | LLUDPClient udpClient = outgoingPacket.Client; | 515 | LLUDPClient udpClient = outgoingPacket.Client; |
472 | 516 | ||
473 | if (!udpClient.IsConnected) | 517 | if (!udpClient.IsConnected) |
@@ -523,9 +567,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
523 | if (isReliable) | 567 | if (isReliable) |
524 | Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); | 568 | Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength); |
525 | 569 | ||
526 | // Put the UDP payload on the wire | 570 | //Some packet types need to be sent synchonously. |
527 | AsyncBeginSend(buffer); | 571 | //Sorry, i know it's not optimal, but until the LL client |
572 | //manages packets correctly and re-orders them as required, this is necessary. | ||
528 | 573 | ||
574 | if (outgoingPacket.Type == PacketType.ImprovedTerseObjectUpdate | ||
575 | || outgoingPacket.Type == PacketType.ChatFromSimulator | ||
576 | || outgoingPacket.Type == PacketType.ObjectUpdate | ||
577 | || outgoingPacket.Type == PacketType.LayerData) | ||
578 | { | ||
579 | sendSynchronous = true; | ||
580 | } | ||
581 | |||
582 | // Put the UDP payload on the wire | ||
583 | if (sendSynchronous == true) | ||
584 | { | ||
585 | SyncBeginSend(buffer); | ||
586 | } | ||
587 | else | ||
588 | { | ||
589 | AsyncBeginSend(buffer); | ||
590 | } | ||
529 | // Keep track of when this packet was sent out (right now) | 591 | // Keep track of when this packet was sent out (right now) |
530 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; | 592 | outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; |
531 | } | 593 | } |
@@ -585,7 +647,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
585 | IClientAPI client; | 647 | IClientAPI client; |
586 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) | 648 | if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView)) |
587 | { | 649 | { |
588 | m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); | 650 | //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); |
589 | return; | 651 | return; |
590 | } | 652 | } |
591 | 653 | ||
@@ -663,16 +725,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
663 | 725 | ||
664 | #endregion Incoming Packet Accounting | 726 | #endregion Incoming Packet Accounting |
665 | 727 | ||
728 | #region BinaryStats | ||
729 | LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); | ||
730 | #endregion BinaryStats | ||
731 | |||
666 | #region Ping Check Handling | 732 | #region Ping Check Handling |
667 | 733 | ||
668 | if (packet.Type == PacketType.StartPingCheck) | 734 | if (packet.Type == PacketType.StartPingCheck) |
669 | { | 735 | { |
670 | // We don't need to do anything else with ping checks | 736 | // We don't need to do anything else with ping checks |
671 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; | 737 | StartPingCheckPacket startPing = (StartPingCheckPacket)packet; |
672 | 738 | CompletePing(udpClient, startPing.PingID.PingID); | |
673 | CompletePingCheckPacket completePing = new CompletePingCheckPacket(); | ||
674 | completePing.PingID.PingID = startPing.PingID.PingID; | ||
675 | SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false); | ||
676 | return; | 739 | return; |
677 | } | 740 | } |
678 | else if (packet.Type == PacketType.CompletePingCheck) | 741 | else if (packet.Type == PacketType.CompletePingCheck) |
@@ -687,6 +750,87 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
687 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); | 750 | packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); |
688 | } | 751 | } |
689 | 752 | ||
753 | #region BinaryStats | ||
754 | |||
755 | public class PacketLogger | ||
756 | { | ||
757 | public DateTime StartTime; | ||
758 | public string Path = null; | ||
759 | public System.IO.BinaryWriter Log = null; | ||
760 | } | ||
761 | |||
762 | public static PacketLogger PacketLog; | ||
763 | |||
764 | protected static bool m_shouldCollectStats = false; | ||
765 | // Number of seconds to log for | ||
766 | static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300); | ||
767 | static object binStatsLogLock = new object(); | ||
768 | static string binStatsDir = ""; | ||
769 | |||
770 | public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size) | ||
771 | { | ||
772 | if (!m_shouldCollectStats) return; | ||
773 | |||
774 | // Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size | ||
775 | |||
776 | // Put the incoming bit into the least significant bit of the flags byte | ||
777 | if (incoming) | ||
778 | flags |= 0x01; | ||
779 | else | ||
780 | flags &= 0xFE; | ||
781 | |||
782 | // Put the flags byte into the most significant bits of the type integer | ||
783 | uint type = (uint)packetType; | ||
784 | type |= (uint)flags << 24; | ||
785 | |||
786 | // m_log.Debug("1 LogPacketHeader(): Outside lock"); | ||
787 | lock (binStatsLogLock) | ||
788 | { | ||
789 | DateTime now = DateTime.Now; | ||
790 | |||
791 | // m_log.Debug("2 LogPacketHeader(): Inside lock. now is " + now.Ticks); | ||
792 | try | ||
793 | { | ||
794 | if (PacketLog == null || (now > PacketLog.StartTime + binStatsMaxFilesize)) | ||
795 | { | ||
796 | if (PacketLog != null && PacketLog.Log != null) | ||
797 | { | ||
798 | PacketLog.Log.Close(); | ||
799 | } | ||
800 | |||
801 | // First log file or time has expired, start writing to a new log file | ||
802 | PacketLog = new PacketLogger(); | ||
803 | PacketLog.StartTime = now; | ||
804 | PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() : "") | ||
805 | + String.Format("packets-{0}.log", now.ToString("yyyyMMddHHmmss")); | ||
806 | PacketLog.Log = new BinaryWriter(File.Open(PacketLog.Path, FileMode.Append, FileAccess.Write)); | ||
807 | } | ||
808 | |||
809 | // Serialize the data | ||
810 | byte[] output = new byte[18]; | ||
811 | Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8); | ||
812 | Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4); | ||
813 | Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4); | ||
814 | Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2); | ||
815 | |||
816 | // Write the serialized data to disk | ||
817 | if (PacketLog != null && PacketLog.Log != null) | ||
818 | PacketLog.Log.Write(output); | ||
819 | } | ||
820 | catch (Exception ex) | ||
821 | { | ||
822 | m_log.Error("Packet statistics gathering failed: " + ex.Message, ex); | ||
823 | if (PacketLog.Log != null) | ||
824 | { | ||
825 | PacketLog.Log.Close(); | ||
826 | } | ||
827 | PacketLog = null; | ||
828 | } | ||
829 | } | ||
830 | } | ||
831 | |||
832 | #endregion BinaryStats | ||
833 | |||
690 | private void HandleUseCircuitCode(object o) | 834 | private void HandleUseCircuitCode(object o) |
691 | { | 835 | { |
692 | object[] array = (object[])o; | 836 | object[] array = (object[])o; |
@@ -759,10 +903,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
759 | } | 903 | } |
760 | } | 904 | } |
761 | 905 | ||
762 | private void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) | 906 | protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) |
763 | { | 907 | { |
764 | // Create the LLUDPClient | 908 | // Create the LLUDPClient |
765 | LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint); | 909 | LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); |
766 | IClientAPI existingClient; | 910 | IClientAPI existingClient; |
767 | 911 | ||
768 | if (!m_scene.TryGetClient(agentID, out existingClient)) | 912 | if (!m_scene.TryGetClient(agentID, out existingClient)) |
@@ -976,7 +1120,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
976 | } | 1120 | } |
977 | } | 1121 | } |
978 | 1122 | ||
979 | private void LogoutHandler(IClientAPI client) | 1123 | protected void LogoutHandler(IClientAPI client) |
980 | { | 1124 | { |
981 | client.SendLogoutPacket(); | 1125 | client.SendLogoutPacket(); |
982 | if (client.IsActive) | 1126 | if (client.IsActive) |