29 using System.Collections.Generic;
30 using System.Diagnostics;
33 using System.Net.Sockets;
34 using System.Reflection;
35 using System.Threading;
38 using OpenMetaverse.Packets;
39 using OpenSim.Framework;
40 using OpenSim.Framework.Console;
41 using OpenSim.Framework.Monitoring;
42 using OpenSim.Region.Framework.Scenes;
43 using OpenSim.Region.Framework.Interfaces;
48 namespace OpenSim.
Region.ClientStack.LindenUDP
53 [Extension(Path =
"/OpenSim/RegionModules", NodeName =
"RegionModule", Id =
"LLUDPServerShim")]
56 private bool m_Enabled =
true;
57 private IConfigSource m_Config;
60 #region INonSharedRegionModule
63 get {
return "LLUDPServerShim"; }
66 public Type ReplaceableInterface
86 scene.RegionInfo.InternalEndPoint.Port = (int)port;
102 public void Initialise(IPAddress listenIP, ref uint port,
int proxyPortOffsetParm,
bool allow_alternate_port, IConfigSource configSource,
AgentCircuitManager circuitManager)
104 m_udpServer =
new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager);
109 m_udpServer.AddScene(scene);
111 StatsManager.RegisterStat(
113 "ClientLogoutsDueToNoReceives",
114 "Number of times a client has been logged out because no packets were received before the timeout.",
121 stat => stat.Value = m_udpServer.ClientLogoutsDueToNoReceives,
124 StatsManager.RegisterStat(
126 "IncomingUDPReceivesCount",
127 "Number of UDP receives performed",
134 stat => stat.Value = m_udpServer.UdpReceives,
137 StatsManager.RegisterStat(
139 "IncomingPacketsProcessedCount",
140 "Number of inbound LL protocol packets processed",
147 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
150 StatsManager.RegisterStat(
152 "IncomingPacketsMalformedCount",
153 "Number of inbound UDP packets that could not be recognized as LL protocol packets.",
160 stat => stat.Value = m_udpServer.IncomingMalformedPacketCount,
163 StatsManager.RegisterStat(
165 "IncomingPacketsOrphanedCount",
166 "Number of inbound packets that were not initial connections packets and could not be associated with a viewer.",
173 stat => stat.Value = m_udpServer.IncomingOrphanedPacketCount,
176 StatsManager.RegisterStat(
178 "IncomingPacketsResentCount",
179 "Number of inbound packets that clients indicate are resends.",
186 stat => stat.Value = m_udpServer.IncomingPacketsResentCount,
189 StatsManager.RegisterStat(
191 "OutgoingUDPSendsCount",
192 "Number of UDP sends performed",
199 stat => stat.Value = m_udpServer.UdpSends,
202 StatsManager.RegisterStat(
204 "OutgoingPacketsResentCount",
205 "Number of packets resent because a client did not acknowledge receipt",
212 stat => stat.Value = m_udpServer.PacketsResentCount,
215 StatsManager.RegisterStat(
217 "AverageUDPProcessTime",
218 "Average number of milliseconds taken to process each incoming UDP packet in a sample.",
219 "This is for initial receive processing which is separate from the later client LL packet processing stage.",
225 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
233 return m_udpServer.HandlesRegion(x);
254 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
257 public const int MTU = 1400;
260 public int ClientLogoutsDueToNoReceives {
get;
private set; }
265 public int DefaultClientPacketDebugLevel {
get; set; }
271 public bool DiscardInboundAgentUpdates {
get; set; }
314 private int m_recvBufferSize;
317 private bool m_asyncPacketHandling;
321 private bool m_packetSent;
324 private int m_elapsedMSSinceLastStatReport = 0;
327 private int m_tickLastOutgoingPacketHandler;
330 private int m_elapsedMSOutgoingPacketHandler;
333 private int m_elapsed100MSOutgoingPacketHandler;
336 private int m_elapsed500MSOutgoingPacketHandler;
347 private int m_animationSequenceNumber;
349 public int NextAnimationSequenceNumber
353 m_animationSequenceNumber++;
354 if (m_animationSequenceNumber > 2147482624)
355 m_animationSequenceNumber = 1;
356 return m_animationSequenceNumber;
362 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache =
new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
374 private Pool<IncomingPacket> m_incomingPacketPool;
379 private Stat m_poolCountStat;
384 private Stat m_incomingPacketPoolStat;
386 private int m_defaultRTO = 0;
387 private int m_maxRTO = 0;
388 private int m_ackTimeout = 0;
389 private int m_pausedAckTimeout = 0;
390 private bool m_disableFacelights =
false;
392 public Socket Server {
get {
return null; } }
397 internal int PacketsResentCount {
get; set; }
402 internal int PacketsSentCount {
get; set; }
407 internal int IncomingPacketsResentCount {
get; set; }
412 public int IncomingMalformedPacketCount {
get;
private set; }
417 public int IncomingOrphanedPacketCount {
get;
private set; }
446 IPAddress listenIP, ref uint port,
int proxyPortOffsetParm,
bool allow_alternate_port,
448 : base(listenIP, (int)port)
450 #region Environment.TickCount Measurement
453 TickCountResolution = 0f;
454 for (
int i = 0; i < 10; i++)
456 int start = Environment.TickCount;
459 now = Environment.TickCount;
460 TickCountResolution += (float)(now - start) * 0.1f;
462 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
463 m_log.Info(
"[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution +
"ms");
465 #endregion Environment.TickCount Measurement
467 m_circuitManager = circuitManager;
468 int sceneThrottleBps = 0;
469 bool usePools =
false;
473 IConfig config = configSource.Configs[
"ClientStack.LindenUDP"];
476 m_asyncPacketHandling = config.GetBoolean(
"async_packet_handling",
true);
477 m_recvBufferSize = config.GetInt(
"client_socket_rcvbuf_size", 0);
478 sceneThrottleBps = config.GetInt(
"scene_throttle_max_bps", 0);
480 PrimUpdatesPerCallback = config.GetInt(
"PrimUpdatesPerCallback", 100);
481 TextureSendLimit = config.GetInt(
"TextureSendLimit", 20);
483 m_defaultRTO = config.GetInt(
"DefaultRTO", 0);
484 m_maxRTO = config.GetInt(
"MaxRTO", 0);
485 m_disableFacelights = config.GetBoolean(
"DisableFacelights",
false);
486 m_ackTimeout = 1000 * config.GetInt(
"AckTimeout", 60);
487 m_pausedAckTimeout = 1000 * config.GetInt(
"PausedAckTimeout", 300);
491 PrimUpdatesPerCallback = 100;
492 TextureSendLimit = 20;
493 m_ackTimeout = 1000 * 60;
494 m_pausedAckTimeout = 1000 * 300;
499 IConfig packetConfig = configSource.Configs[
"PacketPool"];
500 if (packetConfig != null)
502 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean(
"RecyclePackets",
true);
503 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean(
"RecycleDataBlocks",
true);
504 usePools = packetConfig.GetBoolean(
"RecycleBaseUDPPackets", usePools);
508 config = configSource.Configs[
"Statistics.Binary"];
509 m_shouldCollectStats =
false;
512 m_shouldCollectStats = config.GetBoolean(
"Enabled",
false);
513 binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt(
"packet_headers_period_seconds", 300));
514 binStatsDir = config.GetString(
"stats_dir",
".");
515 m_aggregatedBWStats = config.GetBoolean(
"aggregatedBWStats",
false);
517 #endregion BinaryStats
519 Throttle =
new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
522 Random rnd =
new Random(Util.EnvironmentTickCount());
523 m_animationSequenceNumber = rnd.Next(11474826);
537 m_elapsedMSSinceLastStatReport = Environment.TickCount;
543 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
544 m_asyncPacketHandling ?
"asynchronous" :
"synchronous", UsePools);
546 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
549 WorkManager.StartThread(
550 IncomingPacketHandler,
551 string.Format(
"Incoming Packets ({0})", Scene.Name),
552 ThreadPriority.Normal,
555 GetWatchdogIncomingAlarmData,
556 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
561 m_log.Info(
"[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
563 base.StartOutbound();
565 WorkManager.StartThread(
566 OutgoingPacketHandler,
567 string.Format(
"Outgoing Packets ({0})", Scene.Name),
568 ThreadPriority.Normal,
571 GetWatchdogOutgoingAlarmData,
572 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
577 m_log.Info(
"[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
590 m_incomingPacketPool =
new Pool<IncomingPacket>(() =>
new IncomingPacket(), 500);
604 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
618 protected internal void EnablePoolStats()
622 "UDPPacketBufferPoolCount",
623 "Objects within the UDPPacketBuffer pool",
624 "The number of objects currently stored within the UDPPacketBuffer pool",
629 stat => stat.Value = Pool.Count,
632 StatsManager.RegisterStat(m_poolCountStat);
634 m_incomingPacketPoolStat
636 "IncomingPacketPoolCount",
637 "Objects within incoming packet pool",
638 "The number of objects currently stored within the incoming packet pool",
643 stat => stat.Value = m_incomingPacketPool.Count,
646 StatsManager.RegisterStat(m_incomingPacketPoolStat);
652 protected internal void DisablePoolStats()
654 StatsManager.DeregisterStat(m_poolCountStat);
655 m_poolCountStat = null;
657 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
658 m_incomingPacketPoolStat = null;
665 private string GetWatchdogIncomingAlarmData()
667 return string.Format(
669 m_currentIncomingClient != null ? m_currentIncomingClient.Name :
"none");
676 private string GetWatchdogOutgoingAlarmData()
678 return string.Format(
680 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name :
"none");
687 m_log.Error(
"[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
691 if (!(scene is
Scene))
693 m_log.Error(
"[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
697 Scene = (Scene)scene;
698 m_location =
new Location(Scene.RegionInfo.RegionHandle);
702 string.Format(
"Incoming Packet Async Handling Engine ({0})", Scene.Name),
703 "INCOMING PACKET ASYNC HANDLING ENGINE");
707 string.Format(
"Outgoing Queue Refill Engine ({0})", Scene.Name),
708 "OUTGOING QUEUE REFILL ENGINE");
710 StatsManager.RegisterStat(
713 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
714 "Number of LL protocol packets waiting for the second stage of processing after initial receive.",
720 stat => stat.Value = packetInbox.Count(),
721 StatVerbosity.Debug));
725 StatsManager.RegisterStat(
729 "Number of packets reused out of all requests to the packet pool",
737 StatVerbosity.Debug));
739 StatsManager.RegisterStat(
741 "PacketDataBlocksReused",
742 "Packet data blocks reused",
743 "Number of data blocks reused out of all requests to the packet pool",
751 StatVerbosity.Debug));
753 StatsManager.RegisterStat(
756 "Objects within the packet pool",
757 "The number of objects currently stored within the packet pool",
762 stat => stat.Value = PacketPool.Instance.PacketsPooled,
765 StatsManager.RegisterStat(
767 "PacketDataBlocksPoolCount",
768 "Objects within the packet data block pool",
769 "The number of objects currently stored within the packet data block pool",
774 stat => stat.Value = PacketPool.Instance.BlocksPooled,
777 StatsManager.RegisterStat(
779 "OutgoingPacketsQueuedCount",
780 "Packets queued for outgoing send",
781 "Number of queued outgoing packets across all connections",
787 stat => stat.Value = GetTotalQueuedOutgoingPackets(),
790 StatsManager.RegisterStat(
792 "IncomingPacketAsyncRequestsWaiting",
793 "Number of incoming packets waiting for async processing in engine.",
800 stat => stat.Value = IpahEngine.JobsWaiting,
803 StatsManager.RegisterStat(
805 "OQRERequestsWaiting",
806 "Number of outgong queue refill requests waiting for processing.",
813 stat => stat.Value = OqrEngine.JobsWaiting,
829 return x == m_location;
842 total += udpClient.GetTotalPacketsQueuedCount();
903 if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
904 allowSplitting =
false;
906 bool packetQueued =
false;
908 if (allowSplitting && packet.HasVariableBlocks)
910 byte[][] datas = packet.ToBytesMultiple();
911 int packetCount = datas.Length;
914 m_log.Error(
"[LLUDPSERVER]: Failed to split " + packet.Type +
" with estimated length " + packet.Length);
916 for (
int i = 0; i < packetCount; i++)
918 byte[] data = datas[i];
919 if (!SendPacketData(udpClient, data, packet.Type, category, method))
925 byte[] data = packet.ToBytes();
926 if (!SendPacketData(udpClient, data, packet.Type, category, method))
930 PacketPool.Instance.ReturnPacket(packet);
952 int dataLength = data.Length;
953 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
962 UDPPacketBuffer buffer =
new UDPPacketBuffer(udpClient.
RemoteEndPoint, bufferSize);
969 dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
972 catch (IndexOutOfRangeException)
977 m_log.Debug(
"[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type +
". DataLength=" + dataLength +
978 " and BufferLength=" + buffer.Data.Length +
". Removing MSG_ZEROCODED flag");
979 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
986 if (dataLength <= buffer.Data.Length)
988 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
992 bufferSize = dataLength;
993 buffer =
new UDPPacketBuffer(udpClient.
RemoteEndPoint, bufferSize);
995 m_log.Error(
"[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
996 type +
", DataLength=" + dataLength +
", BufferLength=" + buffer.Data.Length);
997 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
1001 buffer.DataLength = dataLength;
1003 #region Queue or Send
1005 bool highPriority =
false;
1010 highPriority =
true;
1016 if ((outgoingPacket.
Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
1017 outgoingPacket.UnackedMethod = ((method == null) ? delegate(
OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
1023 bool requestQueue = type == PacketType.KillObject;
1026 SendPacketFinal(outgoingPacket);
1032 #endregion Queue or Send
1041 List<PacketAckPacket.PacketsBlock> blocks =
new List<PacketAckPacket.PacketsBlock>();
1042 PacketAckPacket.PacketsBlock block =
new PacketAckPacket.PacketsBlock();
1048 block =
new PacketAckPacket.PacketsBlock();
1053 PacketAckPacket packet =
new PacketAckPacket();
1054 packet.Header.Reliable =
false;
1055 packet.Packets = blocks.ToArray();
1064 pc.Header.Reliable =
false;
1068 pc.PingID.OldestUnacked = 0;
1071 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1076 CompletePingCheckPacket completePing =
new CompletePingCheckPacket();
1077 completePing.PingID.PingID = pingID;
1089 int timeoutTicks = m_ackTimeout;
1095 timeoutTicks = m_pausedAckTimeout;
1102 client.IsActive =
false;
1108 o => DeactivateClientDueToTimeout(client, timeoutTicks), null,
"LLUDPServer.DeactivateClientDueToTimeout");
1114 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
1116 if (expiredPackets != null)
1120 udpClient.BackoffRTO();
1121 for (
int i = 0; i < expiredPackets.Count; ++i)
1122 expiredPackets[i].UnackedMethod(expiredPackets[i]);
1132 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.
Buffer.Data[0] | Helpers.MSG_RESENT);
1133 outgoingPacket.Category = ThrottleOutPacketType.Resend;
1136 Interlocked.Increment(ref outgoingPacket.ResendCount);
1140 SendPacketFinal(outgoingPacket);
1154 UDPPacketBuffer buffer = outgoingPacket.Buffer;
1155 byte flags = buffer.Data[0];
1156 bool isResend = (flags & Helpers.MSG_RESENT) != 0;
1157 bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
1158 bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
1164 #region ACK Appending
1166 int dataLength = buffer.DataLength;
1169 if (!isZerocoded && !isResend && outgoingPacket.
UnackedMethod == null)
1175 while (dataLength + 5 < buffer.Data.Length && udpClient.
PendingAcks.Dequeue(out ack))
1177 Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
1185 buffer.Data[dataLength++] = (byte)ackCount;
1187 buffer.Data[0] = (byte)(buffer.Data[0] | Helpers.MSG_APPENDED_ACKS);
1191 buffer.DataLength = dataLength;
1193 #endregion ACK Appending
1195 #region Sequence Number Assignment
1200 uint sequenceNumber = (uint)Interlocked.Increment(ref udpClient.
CurrentSequence);
1201 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
1202 outgoingPacket.SequenceNumber = sequenceNumber;
1207 udpClient.NeedAcks.Add(outgoingPacket);
1212 Interlocked.Increment(ref udpClient.PacketsResent);
1216 PacketsResentCount++;
1219 #endregion Sequence Number Assignment
1222 Interlocked.Increment(ref udpClient.PacketsSent);
1230 "[LLUDPSERVER]: Sending packet #{0} (rel: {1}, res: {2}) to {3} from {4}",
1231 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1234 AsyncBeginSend(buffer);
1237 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1240 private void RecordMalformedInboundPacket(IPEndPoint endPoint)
1245 IncomingMalformedPacketCount++;
1247 if ((IncomingMalformedPacketCount % 10000) == 0)
1249 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1250 IncomingMalformedPacketCount, endPoint);
1262 Packet packet = null;
1263 int packetEnd = buffer.DataLength - 1;
1268 if (buffer.DataLength < 7)
1274 RecordMalformedInboundPacket(endPoint);
1280 if (buffer.Data[6] == 0xFF)
1282 if (buffer.Data[7] == 0xFF)
1288 if (buffer.DataLength < headerLen)
1294 RecordMalformedInboundPacket(endPoint);
1307 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
1309 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ?
new byte[4096] : null);
1313 if (IncomingMalformedPacketCount < 100)
1314 m_log.DebugFormat(
"[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1320 if (IncomingMalformedPacketCount < 100)
1322 m_log.WarnFormat(
"[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:",
1323 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
1326 RecordMalformedInboundPacket(endPoint);
1333 #region Packet to Client Mapping
1340 if (packet.Type == PacketType.UseCircuitCode)
1343 lock (m_pendingCache)
1345 if (m_pendingCache.Contains(endPoint))
1348 m_pendingCache.AddOrUpdate(endPoint,
new Queue<UDPPacketBuffer>(), 60);
1353 object[] array =
new object[] {
new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1355 Util.FireAndForget(HandleUseCircuitCode, array);
1362 lock (m_pendingCache)
1364 Queue<UDPPacketBuffer> queue;
1365 if (m_pendingCache.TryGetValue(endPoint, out queue))
1368 queue.Enqueue(buffer);
1394 IncomingOrphanedPacketCount++;
1396 if ((IncomingOrphanedPacketCount % 10000) == 0)
1398 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1399 IncomingOrphanedPacketCount, endPoint);
1404 udpClient = ((LLClientView)client).UDPClient;
1408 m_log.Debug(
"[LLUDPSERVER]: Received a " + packet.Type +
" packet for a unConnected client in " + Scene.RegionInfo.RegionName);
1412 #endregion Packet to Client Mapping
1415 Interlocked.Increment(ref udpClient.PacketsReceived);
1417 int now = Environment.TickCount & Int32.MaxValue;
1418 udpClient.TickLastPacketReceived = now;
1420 #region ACK Receiving
1423 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1429 for (
int i = 0; i < packet.Header.AckList.Length; i++)
1434 if (packet.Type == PacketType.PacketAck)
1436 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1442 for (
int i = 0; i < ackPacket.Packets.Length; i++)
1449 #endregion ACK Receiving
1453 if (packet.Header.Reliable)
1459 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
1465 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
1466 bytesSinceLastACK += buffer.DataLength;
1469 bytesSinceLastACK -= LLUDPServer.MTU * 2;
1470 SendAcks(udpClient);
1472 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
1475 #endregion ACK Sending
1477 #region Incoming Packet Accounting
1481 if (packet.Header.Resent)
1482 IncomingPacketsResentCount++;
1487 if (packet.Header.Resent)
1489 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
1490 packet.Header.Sequence, packet.Type, client.Name);
1493 "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
1494 packet.Header.Sequence, packet.Type, client.Name);
1500 #endregion Incoming Packet Accounting
1503 LogPacketHeader(
true, udpClient.
CircuitCode, 0, packet.Type, (ushort)packet.Length);
1504 #endregion BinaryStats
1510 #region Ping Check Handling
1512 if (packet.Type == PacketType.StartPingCheck)
1517 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
1518 CompletePing(udpClient, startPing.PingID.PingID);
1520 if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
1522 udpClient.SendPacketStats();
1523 m_elapsedMSSinceLastStatReport = Environment.TickCount;
1527 else if (packet.Type == PacketType.CompletePingCheck)
1529 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1530 int c = udpClient.m_pingMS;
1531 c = 800 * c + 200 * t;
1533 udpClient.m_pingMS = c;
1537 #endregion Ping Check Handling
1544 incomingPacket = m_incomingPacketPool.GetObject();
1545 incomingPacket.Client = (LLClientView)client;
1546 incomingPacket.Packet = packet;
1550 incomingPacket =
new IncomingPacket((LLClientView)client, packet);
1555 if (incomingPacket.
Packet.Type == PacketType.ChatFromViewer)
1556 packetInbox.PriorityEnqueue(incomingPacket);
1558 packetInbox.Enqueue(incomingPacket);
1567 public string Path = null;
1568 public System.IO.BinaryWriter Log = null;
1573 protected static bool m_shouldCollectStats =
false;
1575 static TimeSpan binStatsMaxFilesize = TimeSpan.FromSeconds(300);
1576 static object binStatsLogLock =
new object();
1577 static string binStatsDir =
"";
1580 static bool m_aggregatedBWStats =
false;
1581 static long m_aggregatedBytesIn = 0;
1582 static long m_aggregatedByestOut = 0;
1583 static object aggBWStatsLock =
new object();
1585 public static long AggregatedLLUDPBytesIn
1587 get {
return m_aggregatedBytesIn; }
1589 public static long AggregatedLLUDPBytesOut
1591 get {
return m_aggregatedByestOut;}
1594 public static void LogPacketHeader(
bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
1596 if (m_aggregatedBWStats)
1598 lock (aggBWStatsLock)
1601 m_aggregatedBytesIn += size;
1603 m_aggregatedByestOut += size;
1607 if (!m_shouldCollectStats)
return;
1618 uint type = (uint)packetType;
1619 type |= (uint)flags << 24;
1622 lock (binStatsLogLock)
1624 DateTime now = DateTime.Now;
1629 if (PacketLog == null || (now > PacketLog.
StartTime + binStatsMaxFilesize))
1631 if (PacketLog != null && PacketLog.
Log != null)
1633 PacketLog.Log.Close();
1638 PacketLog.StartTime = now;
1639 PacketLog.Path = (binStatsDir.Length > 0 ? binStatsDir + System.IO.Path.DirectorySeparatorChar.ToString() :
"")
1640 + String.Format(
"packets-{0}.log", now.ToString(
"yyyyMMddHHmmss"));
1641 PacketLog.Log =
new BinaryWriter(
File.Open(PacketLog.
Path, FileMode.Append, FileAccess.Write));
1645 byte[] output =
new byte[18];
1646 Buffer.BlockCopy(BitConverter.GetBytes(now.Ticks), 0, output, 0, 8);
1647 Buffer.BlockCopy(BitConverter.GetBytes(circuit), 0, output, 8, 4);
1648 Buffer.BlockCopy(BitConverter.GetBytes(type), 0, output, 12, 4);
1649 Buffer.BlockCopy(BitConverter.GetBytes(size), 0, output, 16, 2);
1652 if (PacketLog != null && PacketLog.
Log != null)
1653 PacketLog.Log.Write(output);
1655 catch (Exception ex)
1657 m_log.Error(
"Packet statistics gathering failed: " + ex.Message, ex);
1658 if (PacketLog.
Log != null)
1660 PacketLog.Log.Close();
1667 #endregion BinaryStats
1669 private void HandleUseCircuitCode(
object o)
1671 IPEndPoint endPoint = null;
1677 object[] array = (
object[])o;
1678 endPoint = (IPEndPoint)array[0];
1679 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1682 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1683 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1686 if (IsClientAuthorized(uccp, out sessionInfo))
1688 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1693 uccp.CircuitCode.Code,
1694 uccp.CircuitCode.ID,
1695 uccp.CircuitCode.SessionID,
1701 if (client != null && aCircuit == null)
1703 Scene.CloseAgent(client.AgentId,
true);
1711 Queue<UDPPacketBuffer> queue = null;
1713 lock (m_pendingCache)
1715 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1717 m_log.DebugFormat(
"[LLUDPSERVER]: Client created but no pending queue present");
1721 m_pendingCache.Remove(endPoint);
1724 m_log.DebugFormat(
"[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1727 while (queue.Count > 0)
1729 UDPPacketBuffer buf = queue.Dequeue();
1730 PacketReceived(buf);
1738 SendAckImmediate(endPoint, uccp.Header.Sequence);
1743 bool tp = (aCircuit.teleportFlags > 0);
1746 client.SceneAgent.SendInitialDataToMe();
1753 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1755 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1757 lock (m_pendingCache)
1758 m_pendingCache.Remove(endPoint);
1769 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1770 endPoint != null ? endPoint.ToString() :
"n/a",
1771 client != null ? client.Name :
"unknown",
1772 client != null ? client.AgentId.ToString() :
"unknown",
1898 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
1900 PacketAckPacket ack =
new PacketAckPacket();
1901 ack.Header.Reliable =
false;
1902 ack.Packets =
new PacketAckPacket.PacketsBlock[1];
1903 ack.Packets[0] =
new PacketAckPacket.PacketsBlock();
1904 ack.Packets[0].ID = sequenceNumber;
1906 SendAckImmediate(remoteEndpoint, ack);
1911 byte[] packetData = ack.ToBytes();
1912 int length = packetData.Length;
1914 UDPPacketBuffer buffer =
new UDPPacketBuffer(remoteEndpoint, length);
1915 buffer.DataLength = length;
1917 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
1919 AsyncBeginSend(buffer);
1922 private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out
AuthenticateResponse sessionInfo)
1924 UUID agentID = useCircuitCode.CircuitCode.ID;
1925 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
1926 uint circuitCode = useCircuitCode.CircuitCode.Code;
1928 sessionInfo = m_circuitManager.AuthenticateSession(sessionID, agentID, circuitCode);
1929 return sessionInfo.Authorised;
1942 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint,
AuthenticateResponse sessionInfo)
1945 bool createNew =
false;
1958 if (client.SceneAgent == null)
1960 Scene.CloseAgent(agentID,
true);
1970 client =
new LLClientView(
Scene,
this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1971 client.OnLogout += LogoutHandler;
1972 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1974 ((
LLClientView)client).DisableFacelights = m_disableFacelights;
1992 private void DeactivateClientDueToTimeout(
LLClientView client,
int timeoutTicks)
1996 ClientLogoutsDueToNoReceives++;
2001 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
2002 client.SceneAgent.IsChildAgent ?
"child" :
"root", client.Name, timeoutTicks, Scene.Name);
2005 client.Kick(
"Simulator logged you out due to connection timeout.");
2010 client.
Close(
true,
true);
2013 private void IncomingPacketHandler()
2015 Thread.CurrentThread.Priority = ThreadPriority.Highest;
2016 IncomingPacket incomingPacket;
2019 Culture.SetCurrentCulture();
2021 while (IsRunningInbound)
2023 Scene.ThreadAlive(1);
2026 incomingPacket = packetInbox.Dequeue(250);
2028 if (incomingPacket != null && IsRunningInbound)
2030 ProcessInPacket(incomingPacket);
2034 incomingPacket.Client = null;
2035 m_incomingPacketPool.ReturnObject(incomingPacket);
2037 incomingPacket = null;
2042 m_log.Error(
"[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
2045 Watchdog.UpdateThread();
2048 if (packetInbox.Count() > 0)
2049 m_log.Warn(
"[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count() +
" packets");
2050 packetInbox.Clear();
2052 Watchdog.RemoveThread();
2055 private void OutgoingPacketHandler()
2057 Thread.CurrentThread.Priority = ThreadPriority.Highest;
2061 Culture.SetCurrentCulture();
2065 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
2067 while (base.IsRunningOutbound)
2069 Scene.ThreadAlive(2);
2072 m_packetSent =
false;
2074 #region Update Timers
2076 m_resendUnacked =
false;
2081 int thisTick = Environment.TickCount & Int32.MaxValue;
2082 if (m_tickLastOutgoingPacketHandler > thisTick)
2083 m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
2085 m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
2087 m_tickLastOutgoingPacketHandler = thisTick;
2090 if (m_elapsedMSOutgoingPacketHandler >= 100)
2092 m_resendUnacked =
true;
2093 m_elapsedMSOutgoingPacketHandler = 0;
2094 m_elapsed100MSOutgoingPacketHandler += 1;
2098 if (m_elapsed100MSOutgoingPacketHandler >= 5)
2101 m_elapsed100MSOutgoingPacketHandler = 0;
2102 m_elapsed500MSOutgoingPacketHandler += 1;
2106 if (m_elapsed500MSOutgoingPacketHandler >= 10)
2109 m_elapsed500MSOutgoingPacketHandler = 0;
2112 #endregion Update Timers
2122 Scene.ForEachClient(clientPacketHandler);
2124 m_currentOutgoingClient = null;
2130 Thread.Sleep((int)TickCountResolution);
2135 Watchdog.UpdateThread();
2137 catch (Exception ex)
2139 m_log.Error(
"[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
2143 Watchdog.RemoveThread();
2148 m_currentOutgoingClient = client;
2154 LLClientView llClient = (LLClientView)client;
2159 if (m_resendUnacked)
2160 HandleUnacked(llClient);
2163 SendAcks(udpClient);
2166 SendPing(udpClient);
2170 m_packetSent =
true;
2174 catch (Exception ex)
2177 string.Format(
"[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
2181 #region Emergency Monitoring
2184 private Stopwatch watch1 =
new Stopwatch();
2185 private Stopwatch watch2 =
new Stopwatch();
2187 private float avgProcessingTicks = 0;
2188 private float avgResendUnackedTicks = 0;
2189 private float avgSendAcksTicks = 0;
2190 private float avgSendPingTicks = 0;
2191 private float avgDequeueTicks = 0;
2192 private long nticks = 0;
2193 private long nticksUnack = 0;
2194 private long nticksAck = 0;
2195 private long nticksPing = 0;
2196 private int npacksSent = 0;
2197 private int npackNotSent = 0;
2202 public long IncomingPacketsProcessed {
get;
private set; }
2204 private void MonitoredClientOutgoingPacketHandler(
IClientAPI client)
2208 m_currentOutgoingClient = client;
2214 LLClientView llClient = (LLClientView)client;
2219 if (m_resendUnacked)
2224 HandleUnacked(llClient);
2227 avgResendUnackedTicks = (nticksUnack - 1)/(
float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
2236 SendAcks(udpClient);
2239 avgSendAcksTicks = (nticksAck - 1) / (
float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
2248 SendPing(udpClient);
2251 avgSendPingTicks = (nticksPing - 1) / (
float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing);
2259 m_packetSent =
true;
2268 avgDequeueTicks = (nticks - 1) / (
float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
2274 m_log.WarnFormat(
"[LLUDPSERVER]: Client is not connected");
2278 catch (Exception ex)
2280 m_log.Error(
"[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
2281 " threw an exception: " + ex.Message, ex);
2284 avgProcessingTicks = (nticks - 1) / (
float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
2290 m_log.InfoFormat(
"[LLUDPSERVER]: avg processing ticks: {0} avg unacked: {1} avg acks: {2} avg ping: {3} avg dequeue: {4} (TickCountRes: {5} sent: {6} notsent: {7})",
2291 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent);
2292 npackNotSent = npacksSent = 0;
2299 private void ProcessInPacket(IncomingPacket incomingPacket)
2301 Packet packet = incomingPacket.Packet;
2302 LLClientView client = incomingPacket.Client;
2304 if(!client.IsActive)
2307 m_currentIncomingClient = client;
2312 client.ProcessInPacket(packet);
2314 catch(ThreadAbortException)
2317 m_log.Info(
"[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2325 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2326 client.Name,packet.Type),
2331 m_currentIncomingClient = null;
2334 IncomingPacketsProcessed++;
2339 client.SendLogoutPacket();
2343 client.IsLoggingOut =
true;
2344 Scene.CloseAgent(client.AgentId,
false);
virtual IClientAPI AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
Add a client.
virtual void SendAckImmediate(IPEndPoint remoteEndpoint, PacketAckPacket ack)
static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
bool IsActive
As well as it's function in IClientAPI, in LLClientView we are locking on this property in order to p...
void HandleUnacked(LLClientView client)
IClientAPI ControllingClient
const int MTU
Maximum transmission unit, or UDP packet size, for the LLUDP protocol
Packet Packet
Packet data that has been received
void AddRegion(Scene scene)
This is called whenever a Scene is added. For shared modules, this can happen several times...
OpenSim.Region.ClientStack.LindenUDP.TokenBucket TokenBucket
A hierarchical token bucket for bandwidth throttling. See http://en.wikipedia.org/wiki/Token_bucket f...
void AddScene(IScene scene)
void ClientOutgoingPacketHandler(IClientAPI client)
void ResendUnacked(OutgoingPacket outgoingPacket)
int TickLastPacketReceived
Environment.TickCount when the last packet was received for this client
Handles new client connections Constructor takes a single Packet and authenticates everything ...
void RemoveRegion(Scene scene)
This is called whenever a Scene is removed. For shared modules, this can happen several times...
bool SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
Start the process of sending a packet to the client.
void Flush(LLUDPClient udpClient)
Holds individual statistic details
bool IsChildAgent
If true, then the agent has no avatar in the scene. The agent exists to relay data from a region that...
long BlocksRequested
Number of packet blocks requested.
void Acknowledge(uint sequenceNumber, int currentTime, bool fromResend)
Marks a packet as acknowledged This method is used when an acknowledgement is received from the netwo...
readonly IPEndPoint RemoteEndPoint
The remote address of the connected client
readonly IncomingPacketHistoryCollection PacketArchive
Sequence numbers of packets we've received (for duplicate checking)
void Close()
Close down the client view
IPEndPoint InternalEndPoint
long BlocksReused
Number of packet blocks reused.
bool IsPaused
True when this connection is paused, otherwise false
void SendAcks(LLUDPClient udpClient)
bool IsConnected
True when this connection is alive, otherwise false
OpenSim.Region.ClientStack.LindenUDP.TokenBucket TokenBucket
bool TryEnqueue(uint ack)
virtual void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
Start the process of sending a packet to the client.
Tracks state for a client UDP connection and provides client-specific methods
A shim around LLUDPServer that implements the IClientNetworkServer interface
UnackedPacketMethod UnackedMethod
The delegate to be called if this packet is determined to be unacknowledged
override bool EnablePools()
readonly UnackedPacketCollection NeedAcks
Packets we have sent that need to be ACKed by the client
bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue)
Queue an outgoing packet if appropriate.
void AddScene(IScene scene)
byte CurrentPingSequence
Current ping sequence number
Circuit data for an agent. Connection information shared between regions that accept UDP connections ...
string Name
The name of this scene.
Holds a reference to a LLUDPClient, Packetand a for incoming packets
Holds drip rates and maximum burst rates for throttling with hierarchical token buckets. The maximum burst rates set here are hard limits and can not be overridden by client requests
override bool DisablePools()
static ICommandConsole Instance
readonly DoubleLocklessQueue< uint > PendingAcks
ACKs that are queued up, waiting to be sent to the client
bool DequeueOutgoing()
Loops through all of the packet queues for this client and tries to send an outgoing packet from each...
StatVerbosity
Verbosity of stat.
UDPPacketBuffer Buffer
Packet data to send
void Close()
This is the inverse to Initialise. After a Close(), this instance won't be usable anymore...
bool m_sendAcks
Flag to signal when clients should send ACKs
override void StartOutbound()
Start outbound UDP packet handling.
The LLUDP server for a region. This handles incoming and outgoing packets for all UDP connections to ...
bool IsLoggingOut
Set if the client is closing due to a logout request
readonly int PrimUpdatesPerCallback
Number of prim updates to put on the queue each time the OnQueueEmpty event is triggered for updates...
LLUDPClient Client
Client this packet is destined for
void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
Object CloseSyncLock
Used to synchronise threads when client is being closed.
int GetTotalQueuedOutgoingPackets()
static PacketPool Instance
void SendPing(LLUDPClient udpClient)
void CompletePing(LLUDPClient udpClient, byte pingID)
bool HandlesRegion(Location x)
bool HandlesRegion(Location x)
LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
int DebugDataOutLevel
Controls whether information is logged about each outbound packet immediately before it is sent...
List< ScenePresence > GetScenePresences()
Gets all the scene presences in this scene.
readonly int TextureSendLimit
Number of texture packets to put on the queue each time the OnQueueEmpty event is triggered for textu...
bool m_sendPing
Flag to signal when clients should send pings
readonly float TickCountResolution
The measured resolution of Environment.TickCount
Packet GetPacket(PacketType type)
Gets a packet of the given type.
long PacketsRequested
Number of packets requested.
bool m_allow_alternate_ports
void LogoutHandler(IClientAPI client)
System.IO.BinaryWriter Log
virtual RegionInfo RegionInfo
readonly uint CircuitCode
Circuit code that this client is connected on
static PacketLogger PacketLog
bool TryGetClient(UUID avatarID, out IClientAPI client)
AgentCircuitManager AuthenticateHandler
MeasuresOfInterest
Measures of interest for this stat.
long PacketsReused
Number of packets reused.
bool m_resendUnacked
Flag to signal when clients should check for resends
bool CloseAgent(UUID agentID, bool force, string auth_token)
Authenticated close (via network)
delegate void UnackedPacketMethod(OutgoingPacket oPacket)
void Initialise(IConfigSource source)
This is called to initialize the region module. For shared modules, this is called exactly once...
int CurrentSequence
Current packet sequence number
void RegionLoaded(Scene scene)
This will be called once for every scene loaded. In a shared module this will be multiple times in on...
Holds a reference to the LLUDPClientthis packet is destined for, along with the serialized packet dat...
override void PacketReceived(UDPPacketBuffer buffer)
This method is called when an incoming packet is received