aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs190
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
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.IO;
30using System.Net; 31using System.Net;
31using System.Net.Sockets; 32using System.Net.Sockets;
32using System.Reflection; 33using 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)