aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs468
1 files changed, 418 insertions, 50 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index d6513c5..9a4abd4 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -37,6 +37,7 @@ using log4net;
37using Nini.Config; 37using Nini.Config;
38using OpenMetaverse.Packets; 38using OpenMetaverse.Packets;
39using OpenSim.Framework; 39using OpenSim.Framework;
40using OpenSim.Framework.Console;
40using OpenSim.Framework.Monitoring; 41using OpenSim.Framework.Monitoring;
41using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
42using OpenMetaverse; 43using OpenMetaverse;
@@ -69,6 +70,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
69 public void AddScene(IScene scene) 70 public void AddScene(IScene scene)
70 { 71 {
71 m_udpServer.AddScene(scene); 72 m_udpServer.AddScene(scene);
73
74 StatsManager.RegisterStat(
75 new Stat(
76 "IncomingPacketsProcessedCount",
77 "Number of inbound UDP packets processed",
78 "Number of inbound UDP packets processed",
79 "",
80 "clientstack",
81 scene.Name,
82 StatType.Pull,
83 MeasuresOfInterest.AverageChangeOverTime,
84 stat => stat.Value = m_udpServer.IncomingPacketsProcessed,
85 StatVerbosity.Debug));
72 } 86 }
73 87
74 public bool HandlesRegion(Location x) 88 public bool HandlesRegion(Location x)
@@ -100,9 +114,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
100 114
101 /// <summary>The measured resolution of Environment.TickCount</summary> 115 /// <summary>The measured resolution of Environment.TickCount</summary>
102 public readonly float TickCountResolution; 116 public readonly float TickCountResolution;
117
103 /// <summary>Number of prim updates to put on the queue each time the 118 /// <summary>Number of prim updates to put on the queue each time the
104 /// OnQueueEmpty event is triggered for updates</summary> 119 /// OnQueueEmpty event is triggered for updates</summary>
105 public readonly int PrimUpdatesPerCallback; 120 public readonly int PrimUpdatesPerCallback;
121
106 /// <summary>Number of texture packets to put on the queue each time the 122 /// <summary>Number of texture packets to put on the queue each time the
107 /// OnQueueEmpty event is triggered for textures</summary> 123 /// OnQueueEmpty event is triggered for textures</summary>
108 public readonly int TextureSendLimit; 124 public readonly int TextureSendLimit;
@@ -124,28 +140,37 @@ namespace OpenSim.Region.ClientStack.LindenUDP
124 140
125 /// <summary>Manages authentication for agent circuits</summary> 141 /// <summary>Manages authentication for agent circuits</summary>
126 private AgentCircuitManager m_circuitManager; 142 private AgentCircuitManager m_circuitManager;
143
127 /// <summary>Reference to the scene this UDP server is attached to</summary> 144 /// <summary>Reference to the scene this UDP server is attached to</summary>
128 protected Scene m_scene; 145 protected Scene m_scene;
146
129 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 147 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
130 private Location m_location; 148 private Location m_location;
149
131 /// <summary>The size of the receive buffer for the UDP socket. This value 150 /// <summary>The size of the receive buffer for the UDP socket. This value
132 /// is passed up to the operating system and used in the system networking 151 /// is passed up to the operating system and used in the system networking
133 /// stack. Use zero to leave this value as the default</summary> 152 /// stack. Use zero to leave this value as the default</summary>
134 private int m_recvBufferSize; 153 private int m_recvBufferSize;
154
135 /// <summary>Flag to process packets asynchronously or synchronously</summary> 155 /// <summary>Flag to process packets asynchronously or synchronously</summary>
136 private bool m_asyncPacketHandling; 156 private bool m_asyncPacketHandling;
157
137 /// <summary>Tracks whether or not a packet was sent each round so we know 158 /// <summary>Tracks whether or not a packet was sent each round so we know
138 /// whether or not to sleep</summary> 159 /// whether or not to sleep</summary>
139 private bool m_packetSent; 160 private bool m_packetSent;
140 161
141 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 162 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
142 private int m_elapsedMSSinceLastStatReport = 0; 163 private int m_elapsedMSSinceLastStatReport = 0;
164
143 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 165 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
144 private int m_tickLastOutgoingPacketHandler; 166 private int m_tickLastOutgoingPacketHandler;
167
145 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 168 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
146 private int m_elapsedMSOutgoingPacketHandler; 169 private int m_elapsedMSOutgoingPacketHandler;
170
147 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 171 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
148 private int m_elapsed100MSOutgoingPacketHandler; 172 private int m_elapsed100MSOutgoingPacketHandler;
173
149 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 174 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
150 private int m_elapsed500MSOutgoingPacketHandler; 175 private int m_elapsed500MSOutgoingPacketHandler;
151 176
@@ -159,6 +184,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
159 protected bool m_sendPing; 184 protected bool m_sendPing;
160 185
161 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>(); 186 private ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
187 private Pool<IncomingPacket> m_incomingPacketPool;
188
189 /// <summary>
190 /// Stat for number of packets in the main pool awaiting use.
191 /// </summary>
192 private Stat m_poolCountStat;
193
194 /// <summary>
195 /// Stat for number of packets in the inbound packet pool awaiting use.
196 /// </summary>
197 private Stat m_incomingPacketPoolStat;
162 198
163 private int m_defaultRTO = 0; 199 private int m_defaultRTO = 0;
164 private int m_maxRTO = 0; 200 private int m_maxRTO = 0;
@@ -180,7 +216,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
180 /// </summary> 216 /// </summary>
181 private IClientAPI m_currentIncomingClient; 217 private IClientAPI m_currentIncomingClient;
182 218
183 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 219 public LLUDPServer(
220 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port,
221 IConfigSource configSource, AgentCircuitManager circuitManager)
184 : base(listenIP, (int)port) 222 : base(listenIP, (int)port)
185 { 223 {
186 #region Environment.TickCount Measurement 224 #region Environment.TickCount Measurement
@@ -202,6 +240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
202 240
203 m_circuitManager = circuitManager; 241 m_circuitManager = circuitManager;
204 int sceneThrottleBps = 0; 242 int sceneThrottleBps = 0;
243 bool usePools = false;
205 244
206 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 245 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
207 if (config != null) 246 if (config != null)
@@ -227,6 +266,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
227 m_pausedAckTimeout = 1000 * 300; // 5 minutes 266 m_pausedAckTimeout = 1000 * 300; // 5 minutes
228 } 267 }
229 268
269 // FIXME: This actually only needs to be done once since the PacketPool is shared across all servers.
270 // However, there is no harm in temporarily doing it multiple times.
271 IConfig packetConfig = configSource.Configs["PacketPool"];
272 if (packetConfig != null)
273 {
274 PacketPool.Instance.RecyclePackets = packetConfig.GetBoolean("RecyclePackets", true);
275 PacketPool.Instance.RecycleDataBlocks = packetConfig.GetBoolean("RecycleDataBlocks", true);
276 usePools = packetConfig.GetBoolean("RecycleBaseUDPPackets", usePools);
277 }
278
230 #region BinaryStats 279 #region BinaryStats
231 config = configSource.Configs["Statistics.Binary"]; 280 config = configSource.Configs["Statistics.Binary"];
232 m_shouldCollectStats = false; 281 m_shouldCollectStats = false;
@@ -254,20 +303,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
254 303
255 m_throttle = new TokenBucket(null, sceneThrottleBps); 304 m_throttle = new TokenBucket(null, sceneThrottleBps);
256 ThrottleRates = new ThrottleRates(configSource); 305 ThrottleRates = new ThrottleRates(configSource);
306
307 if (usePools)
308 EnablePools();
257 } 309 }
258 310
259 public void Start() 311 public void Start()
260 { 312 {
261 if (m_scene == null) 313 StartInbound();
262 throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference"); 314 StartOutbound();
315
316 m_elapsedMSSinceLastStatReport = Environment.TickCount;
317 }
263 318
319 private void StartInbound()
320 {
264 m_log.InfoFormat( 321 m_log.InfoFormat(
265 "[LLUDPSERVER]: Starting the LLUDP server in {0} mode", 322 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}",
266 m_asyncPacketHandling ? "asynchronous" : "synchronous"); 323 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
267 324
268 base.Start(m_recvBufferSize, m_asyncPacketHandling); 325 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling);
269 326
270 // Start the packet processing threads 327 // This thread will process the packets received that are placed on the packetInbox
271 Watchdog.StartThread( 328 Watchdog.StartThread(
272 IncomingPacketHandler, 329 IncomingPacketHandler,
273 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName), 330 string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
@@ -276,6 +333,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
276 true, 333 true,
277 GetWatchdogIncomingAlarmData, 334 GetWatchdogIncomingAlarmData,
278 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 335 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
336 }
337
338 private new void StartOutbound()
339 {
340 m_log.Info("[LLUDPSERVER]: Starting outbound packet processing for the LLUDP server");
341
342 base.StartOutbound();
279 343
280 Watchdog.StartThread( 344 Watchdog.StartThread(
281 OutgoingPacketHandler, 345 OutgoingPacketHandler,
@@ -285,8 +349,90 @@ namespace OpenSim.Region.ClientStack.LindenUDP
285 true, 349 true,
286 GetWatchdogOutgoingAlarmData, 350 GetWatchdogOutgoingAlarmData,
287 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS); 351 Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
352 }
288 353
289 m_elapsedMSSinceLastStatReport = Environment.TickCount; 354 public void Stop()
355 {
356 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
357 base.StopOutbound();
358 base.StopInbound();
359 }
360
361 protected override bool EnablePools()
362 {
363 if (!UsePools)
364 {
365 base.EnablePools();
366
367 m_incomingPacketPool = new Pool<IncomingPacket>(() => new IncomingPacket(), 500);
368
369 return true;
370 }
371
372 return false;
373 }
374
375 protected override bool DisablePools()
376 {
377 if (UsePools)
378 {
379 base.DisablePools();
380
381 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
382
383 // We won't null out the pool to avoid a race condition with code that may be in the middle of using it.
384
385 return true;
386 }
387
388 return false;
389 }
390
391 /// <summary>
392 /// This is a seperate method so that it can be called once we have an m_scene to distinguish different scene
393 /// stats.
394 /// </summary>
395 private void EnablePoolStats()
396 {
397 m_poolCountStat
398 = new Stat(
399 "UDPPacketBufferPoolCount",
400 "Objects within the UDPPacketBuffer pool",
401 "The number of objects currently stored within the UDPPacketBuffer pool",
402 "",
403 "clientstack",
404 m_scene.Name,
405 StatType.Pull,
406 stat => stat.Value = Pool.Count,
407 StatVerbosity.Debug);
408
409 StatsManager.RegisterStat(m_poolCountStat);
410
411 m_incomingPacketPoolStat
412 = new Stat(
413 "IncomingPacketPoolCount",
414 "Objects within incoming packet pool",
415 "The number of objects currently stored within the incoming packet pool",
416 "",
417 "clientstack",
418 m_scene.Name,
419 StatType.Pull,
420 stat => stat.Value = m_incomingPacketPool.Count,
421 StatVerbosity.Debug);
422
423 StatsManager.RegisterStat(m_incomingPacketPoolStat);
424 }
425
426 /// <summary>
427 /// Disables pool stats.
428 /// </summary>
429 private void DisablePoolStats()
430 {
431 StatsManager.DeregisterStat(m_poolCountStat);
432 m_poolCountStat = null;
433
434 StatsManager.DeregisterStat(m_incomingPacketPoolStat);
435 m_incomingPacketPoolStat = null;
290 } 436 }
291 437
292 /// <summary> 438 /// <summary>
@@ -311,12 +457,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
311 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none"); 457 m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
312 } 458 }
313 459
314 public new void Stop()
315 {
316 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
317 base.Stop();
318 }
319
320 public void AddScene(IScene scene) 460 public void AddScene(IScene scene)
321 { 461 {
322 if (m_scene != null) 462 if (m_scene != null)
@@ -333,6 +473,182 @@ namespace OpenSim.Region.ClientStack.LindenUDP
333 473
334 m_scene = (Scene)scene; 474 m_scene = (Scene)scene;
335 m_location = new Location(m_scene.RegionInfo.RegionHandle); 475 m_location = new Location(m_scene.RegionInfo.RegionHandle);
476
477 // XXX: These stats are also pool stats but we register them separately since they are currently not
478 // turned on and off by EnablePools()/DisablePools()
479 StatsManager.RegisterStat(
480 new PercentageStat(
481 "PacketsReused",
482 "Packets reused",
483 "Number of packets reused out of all requests to the packet pool",
484 "clientstack",
485 m_scene.Name,
486 StatType.Pull,
487 stat =>
488 { PercentageStat pstat = (PercentageStat)stat;
489 pstat.Consequent = PacketPool.Instance.PacketsRequested;
490 pstat.Antecedent = PacketPool.Instance.PacketsReused; },
491 StatVerbosity.Debug));
492
493 StatsManager.RegisterStat(
494 new PercentageStat(
495 "PacketDataBlocksReused",
496 "Packet data blocks reused",
497 "Number of data blocks reused out of all requests to the packet pool",
498 "clientstack",
499 m_scene.Name,
500 StatType.Pull,
501 stat =>
502 { PercentageStat pstat = (PercentageStat)stat;
503 pstat.Consequent = PacketPool.Instance.BlocksRequested;
504 pstat.Antecedent = PacketPool.Instance.BlocksReused; },
505 StatVerbosity.Debug));
506
507 StatsManager.RegisterStat(
508 new Stat(
509 "PacketsPoolCount",
510 "Objects within the packet pool",
511 "The number of objects currently stored within the packet pool",
512 "",
513 "clientstack",
514 m_scene.Name,
515 StatType.Pull,
516 stat => stat.Value = PacketPool.Instance.PacketsPooled,
517 StatVerbosity.Debug));
518
519 StatsManager.RegisterStat(
520 new Stat(
521 "PacketDataBlocksPoolCount",
522 "Objects within the packet data block pool",
523 "The number of objects currently stored within the packet data block pool",
524 "",
525 "clientstack",
526 m_scene.Name,
527 StatType.Pull,
528 stat => stat.Value = PacketPool.Instance.BlocksPooled,
529 StatVerbosity.Debug));
530
531 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
532 // scene name
533 if (UsePools)
534 EnablePoolStats();
535
536 MainConsole.Instance.Commands.AddCommand(
537 "Debug",
538 false,
539 "debug lludp start",
540 "debug lludp start <in|out|all>",
541 "Control LLUDP packet processing.",
542 "No effect if packet processing has already started.\n"
543 + "in - start inbound processing.\n"
544 + "out - start outbound processing.\n"
545 + "all - start in and outbound processing.\n",
546 HandleStartCommand);
547
548 MainConsole.Instance.Commands.AddCommand(
549 "Debug",
550 false,
551 "debug lludp stop",
552 "debug lludp stop <in|out|all>",
553 "Stop LLUDP packet processing.",
554 "No effect if packet processing has already stopped.\n"
555 + "in - stop inbound processing.\n"
556 + "out - stop outbound processing.\n"
557 + "all - stop in and outbound processing.\n",
558 HandleStopCommand);
559
560 MainConsole.Instance.Commands.AddCommand(
561 "Debug",
562 false,
563 "debug lludp pool",
564 "debug lludp pool <on|off>",
565 "Turn object pooling within the lludp component on or off.",
566 HandlePoolCommand);
567
568 MainConsole.Instance.Commands.AddCommand(
569 "Debug",
570 false,
571 "debug lludp status",
572 "debug lludp status",
573 "Return status of LLUDP packet processing.",
574 HandleStatusCommand);
575 }
576
577 private void HandleStartCommand(string module, string[] args)
578 {
579 if (args.Length != 4)
580 {
581 MainConsole.Instance.Output("Usage: debug lludp start <in|out|all>");
582 return;
583 }
584
585 string subCommand = args[3];
586
587 if (subCommand == "in" || subCommand == "all")
588 StartInbound();
589
590 if (subCommand == "out" || subCommand == "all")
591 StartOutbound();
592 }
593
594 private void HandleStopCommand(string module, string[] args)
595 {
596 if (args.Length != 4)
597 {
598 MainConsole.Instance.Output("Usage: debug lludp stop <in|out|all>");
599 return;
600 }
601
602 string subCommand = args[3];
603
604 if (subCommand == "in" || subCommand == "all")
605 StopInbound();
606
607 if (subCommand == "out" || subCommand == "all")
608 StopOutbound();
609 }
610
611 private void HandlePoolCommand(string module, string[] args)
612 {
613 if (args.Length != 4)
614 {
615 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
616 return;
617 }
618
619 string enabled = args[3];
620
621 if (enabled == "on")
622 {
623 if (EnablePools())
624 {
625 EnablePoolStats();
626 MainConsole.Instance.OutputFormat("Packet pools enabled on {0}", m_scene.Name);
627 }
628 }
629 else if (enabled == "off")
630 {
631 if (DisablePools())
632 {
633 DisablePoolStats();
634 MainConsole.Instance.OutputFormat("Packet pools disabled on {0}", m_scene.Name);
635 }
636 }
637 else
638 {
639 MainConsole.Instance.Output("Usage: debug lludp pool <on|off>");
640 }
641 }
642
643 private void HandleStatusCommand(string module, string[] args)
644 {
645 MainConsole.Instance.OutputFormat(
646 "IN LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningInbound ? "enabled" : "disabled");
647
648 MainConsole.Instance.OutputFormat(
649 "OUT LLUDP packet processing for {0} is {1}", m_scene.Name, IsRunningOutbound ? "enabled" : "disabled");
650
651 MainConsole.Instance.OutputFormat("LLUDP pools in {0} are {1}", m_scene.Name, UsePools ? "on" : "off");
336 } 652 }
337 653
338 public bool HandlesRegion(Location x) 654 public bool HandlesRegion(Location x)
@@ -416,6 +732,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
416 byte[] data = packet.ToBytes(); 732 byte[] data = packet.ToBytes();
417 SendPacketData(udpClient, data, packet.Type, category, method); 733 SendPacketData(udpClient, data, packet.Type, category, method);
418 } 734 }
735
736 PacketPool.Instance.ReturnPacket(packet);
419 } 737 }
420 738
421 /// <summary> 739 /// <summary>
@@ -700,7 +1018,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
700 LLUDPClient udpClient = null; 1018 LLUDPClient udpClient = null;
701 Packet packet = null; 1019 Packet packet = null;
702 int packetEnd = buffer.DataLength - 1; 1020 int packetEnd = buffer.DataLength - 1;
703 IPEndPoint address = (IPEndPoint)buffer.RemoteEndPoint; 1021 IPEndPoint endPoint = (IPEndPoint)buffer.RemoteEndPoint;
704 1022
705 #region Decoding 1023 #region Decoding
706 1024
@@ -710,7 +1028,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}", 1028// "[LLUDPSERVER]: Dropping undersized packet with {0} bytes received from {1} in {2}",
711// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName); 1029// buffer.DataLength, buffer.RemoteEndPoint, m_scene.RegionInfo.RegionName);
712 1030
713 return; // Drop undersizd packet 1031 return; // Drop undersized packet
714 } 1032 }
715 1033
716 int headerLen = 7; 1034 int headerLen = 7;
@@ -733,7 +1051,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
733 1051
734 try 1052 try
735 { 1053 {
736 packet = Packet.BuildPacket(buffer.Data, ref packetEnd, 1054// packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
1055// // Only allocate a buffer for zerodecoding if the packet is zerocoded
1056// ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
1057 // If OpenSimUDPBase.UsePool == true (which is currently separate from the PacketPool) then we
1058 // assume that packet construction does not retain a reference to byte[] buffer.Data (instead, all
1059 // bytes are copied out).
1060 packet = PacketPool.Instance.GetPacket(buffer.Data, ref packetEnd,
737 // Only allocate a buffer for zerodecoding if the packet is zerocoded 1061 // Only allocate a buffer for zerodecoding if the packet is zerocoded
738 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null); 1062 ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
739 } 1063 }
@@ -748,11 +1072,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
748 1072
749 return; // Drop short packet 1073 return; // Drop short packet
750 } 1074 }
751 catch(Exception e) 1075 catch (Exception e)
752 { 1076 {
753 if (m_malformedCount < 100) 1077 if (m_malformedCount < 100)
754 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1078 m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
1079
755 m_malformedCount++; 1080 m_malformedCount++;
1081
756 if ((m_malformedCount % 100000) == 0) 1082 if ((m_malformedCount % 100000) == 0)
757 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount); 1083 m_log.DebugFormat("[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack.", m_malformedCount);
758 } 1084 }
@@ -772,7 +1098,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
772 1098
773 // If there is already a client for this endpoint, don't process UseCircuitCode 1099 // If there is already a client for this endpoint, don't process UseCircuitCode
774 IClientAPI client = null; 1100 IClientAPI client = null;
775 if (!m_scene.TryGetClient(address, out client)) 1101 if (!m_scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
776 { 1102 {
777 // UseCircuitCode handling 1103 // UseCircuitCode handling
778 if (packet.Type == PacketType.UseCircuitCode) 1104 if (packet.Type == PacketType.UseCircuitCode)
@@ -780,13 +1106,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
780 // And if there is a UseCircuitCode pending, also drop it 1106 // And if there is a UseCircuitCode pending, also drop it
781 lock (m_pendingCache) 1107 lock (m_pendingCache)
782 { 1108 {
783 if (m_pendingCache.Contains(address)) 1109 if (m_pendingCache.Contains(endPoint))
784 return; 1110 return;
785 1111
786 m_pendingCache.AddOrUpdate(address, new Queue<UDPPacketBuffer>(), 60); 1112 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
787 } 1113 }
788 1114
789 object[] array = new object[] { buffer, packet }; 1115 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1116 // buffer.
1117 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
790 1118
791 Util.FireAndForget(HandleUseCircuitCode, array); 1119 Util.FireAndForget(HandleUseCircuitCode, array);
792 1120
@@ -798,7 +1126,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
798 lock (m_pendingCache) 1126 lock (m_pendingCache)
799 { 1127 {
800 Queue<UDPPacketBuffer> queue; 1128 Queue<UDPPacketBuffer> queue;
801 if (m_pendingCache.TryGetValue(address, out queue)) 1129 if (m_pendingCache.TryGetValue(endPoint, out queue))
802 { 1130 {
803 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type); 1131 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
804 queue.Enqueue(buffer); 1132 queue.Enqueue(buffer);
@@ -834,6 +1162,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
834 // Handle appended ACKs 1162 // Handle appended ACKs
835 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 1163 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
836 { 1164 {
1165// m_log.DebugFormat(
1166// "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1167// packet.Header.AckList.Length, client.Name, m_scene.Name);
1168
837 for (int i = 0; i < packet.Header.AckList.Length; i++) 1169 for (int i = 0; i < packet.Header.AckList.Length; i++)
838 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); 1170 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
839 } 1171 }
@@ -843,6 +1175,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
843 { 1175 {
844 PacketAckPacket ackPacket = (PacketAckPacket)packet; 1176 PacketAckPacket ackPacket = (PacketAckPacket)packet;
845 1177
1178// m_log.DebugFormat(
1179// "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1180// ackPacket.Packets.Length, client.Name, m_scene.Name);
1181
846 for (int i = 0; i < ackPacket.Packets.Length; i++) 1182 for (int i = 0; i < ackPacket.Packets.Length; i++)
847 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); 1183 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
848 1184
@@ -856,6 +1192,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
856 1192
857 if (packet.Header.Reliable) 1193 if (packet.Header.Reliable)
858 { 1194 {
1195// m_log.DebugFormat(
1196// "[LLUDPSERVER]: Adding ack request for {0} {1} from {2} in {3}",
1197// packet.Type, packet.Header.Sequence, client.Name, m_scene.Name);
1198
859 udpClient.PendingAcks.Enqueue(packet.Header.Sequence); 1199 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
860 1200
861 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 1201 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
@@ -902,6 +1242,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
902 1242
903 if (packet.Type == PacketType.StartPingCheck) 1243 if (packet.Type == PacketType.StartPingCheck)
904 { 1244 {
1245// m_log.DebugFormat("[LLUDPSERVER]: Handling ping from {0} in {1}", client.Name, m_scene.Name);
1246
905 // We don't need to do anything else with ping checks 1247 // We don't need to do anything else with ping checks
906 StartPingCheckPacket startPing = (StartPingCheckPacket)packet; 1248 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
907 CompletePing(udpClient, startPing.PingID.PingID); 1249 CompletePing(udpClient, startPing.PingID.PingID);
@@ -921,13 +1263,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
921 1263
922 #endregion Ping Check Handling 1264 #endregion Ping Check Handling
923 1265
1266 IncomingPacket incomingPacket;
1267
924 // Inbox insertion 1268 // Inbox insertion
925 if (packet.Type == PacketType.AgentUpdate || 1269 if (UsePools)
926 packet.Type == PacketType.ChatFromViewer) 1270 {
927 packetInbox.EnqueueHigh(new IncomingPacket((LLClientView)client, packet)); 1271 incomingPacket = m_incomingPacketPool.GetObject();
1272 incomingPacket.Client = (LLClientView)client;
1273 incomingPacket.Packet = packet;
1274 }
1275 else
1276 {
1277 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1278 }
1279
1280 if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1281 incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1282 packetInbox.EnqueueHigh(incomingPacket);
928 else 1283 else
929 packetInbox.EnqueueLow(new IncomingPacket((LLClientView)client, packet)); 1284 packetInbox.EnqueueLow(incomingPacket);
930// packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
931 } 1285 }
932 1286
933 #region BinaryStats 1287 #region BinaryStats
@@ -1013,21 +1367,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1013 1367
1014 private void HandleUseCircuitCode(object o) 1368 private void HandleUseCircuitCode(object o)
1015 { 1369 {
1016 IPEndPoint remoteEndPoint = null; 1370 IPEndPoint endPoint = null;
1017 IClientAPI client = null; 1371 IClientAPI client = null;
1018 1372
1019 try 1373 try
1020 { 1374 {
1021 // DateTime startTime = DateTime.Now; 1375 // DateTime startTime = DateTime.Now;
1022 object[] array = (object[])o; 1376 object[] array = (object[])o;
1023 UDPPacketBuffer buffer = (UDPPacketBuffer)array[0]; 1377 endPoint = (IPEndPoint)array[0];
1024 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1378 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
1025 1379
1026 m_log.DebugFormat( 1380 m_log.DebugFormat(
1027 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1381 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1028 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint); 1382 uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, endPoint);
1029
1030 remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
1031 1383
1032 AuthenticateResponse sessionInfo; 1384 AuthenticateResponse sessionInfo;
1033 if (IsClientAuthorized(uccp, out sessionInfo)) 1385 if (IsClientAuthorized(uccp, out sessionInfo))
@@ -1038,13 +1390,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1038 uccp.CircuitCode.Code, 1390 uccp.CircuitCode.Code,
1039 uccp.CircuitCode.ID, 1391 uccp.CircuitCode.ID,
1040 uccp.CircuitCode.SessionID, 1392 uccp.CircuitCode.SessionID,
1041 remoteEndPoint, 1393 endPoint,
1042 sessionInfo); 1394 sessionInfo);
1043 1395
1044 // Send ack straight away to let the viewer know that the connection is active. 1396 // Send ack straight away to let the viewer know that the connection is active.
1045 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1397 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1046 // circuit code to the existing child agent. This is not particularly obvious. 1398 // circuit code to the existing child agent. This is not particularly obvious.
1047 SendAckImmediate(remoteEndPoint, uccp.Header.Sequence); 1399 SendAckImmediate(endPoint, uccp.Header.Sequence);
1048 1400
1049 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1401 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1050 if (client != null) 1402 if (client != null)
@@ -1058,12 +1410,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1058 1410
1059 lock (m_pendingCache) 1411 lock (m_pendingCache)
1060 { 1412 {
1061 if (!m_pendingCache.TryGetValue(remoteEndPoint, out queue)) 1413 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1062 { 1414 {
1063 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present"); 1415 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1064 return; 1416 return;
1065 } 1417 }
1066 m_pendingCache.Remove(remoteEndPoint); 1418 m_pendingCache.Remove(endPoint);
1067 } 1419 }
1068 1420
1069 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count); 1421 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
@@ -1081,9 +1433,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1081 // Don't create clients for unauthorized requesters. 1433 // Don't create clients for unauthorized requesters.
1082 m_log.WarnFormat( 1434 m_log.WarnFormat(
1083 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1435 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1084 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint); 1436 uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1085 lock (m_pendingCache) 1437 lock (m_pendingCache)
1086 m_pendingCache.Remove(remoteEndPoint); 1438 m_pendingCache.Remove(endPoint);
1087 } 1439 }
1088 1440
1089 // m_log.DebugFormat( 1441 // m_log.DebugFormat(
@@ -1095,7 +1447,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1095 { 1447 {
1096 m_log.ErrorFormat( 1448 m_log.ErrorFormat(
1097 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", 1449 "[LLUDPSERVER]: UseCircuitCode handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
1098 remoteEndPoint != null ? remoteEndPoint.ToString() : "n/a", 1450 endPoint != null ? endPoint.ToString() : "n/a",
1099 client != null ? client.Name : "unknown", 1451 client != null ? client.Name : "unknown",
1100 client != null ? client.AgentId.ToString() : "unknown", 1452 client != null ? client.AgentId.ToString() : "unknown",
1101 e.Message, 1453 e.Message,
@@ -1160,20 +1512,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1160 { 1512 {
1161 IClientAPI client = null; 1513 IClientAPI client = null;
1162 1514
1163 // In priciple there shouldn't be more than one thread here, ever. 1515 // We currently synchronize this code across the whole scene to avoid issues such as
1164 // But in case that happens, we need to synchronize this piece of code 1516 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
1165 // because it's too important 1517 // consistently, this lock could probably be removed.
1166 lock (this) 1518 lock (this)
1167 { 1519 {
1168 if (!m_scene.TryGetClient(agentID, out client)) 1520 if (!m_scene.TryGetClient(agentID, out client))
1169 { 1521 {
1170 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1522 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1171 1523
1172 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1524 client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1173 client.OnLogout += LogoutHandler; 1525 client.OnLogout += LogoutHandler;
1174 1526
1175 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1527 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1176 1528
1177 client.Start(); 1529 client.Start();
1178 } 1530 }
1179 } 1531 }
@@ -1212,7 +1564,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1212 // on to en-US to avoid number parsing issues 1564 // on to en-US to avoid number parsing issues
1213 Culture.SetCurrentCulture(); 1565 Culture.SetCurrentCulture();
1214 1566
1215 while (base.IsRunning) 1567 while (IsRunningInbound)
1216 { 1568 {
1217 m_scene.ThreadAlive(1); 1569 m_scene.ThreadAlive(1);
1218 try 1570 try
@@ -1228,7 +1580,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1228 } 1580 }
1229 1581
1230 if (packetInbox.Dequeue(100, ref incomingPacket)) 1582 if (packetInbox.Dequeue(100, ref incomingPacket))
1583 {
1231 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); 1584 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket);
1585
1586 if (UsePools)
1587 m_incomingPacketPool.ReturnObject(incomingPacket);
1588 }
1232 } 1589 }
1233 catch (Exception ex) 1590 catch (Exception ex)
1234 { 1591 {
@@ -1255,7 +1612,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1255 // Action generic every round 1612 // Action generic every round
1256 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler; 1613 Action<IClientAPI> clientPacketHandler = ClientOutgoingPacketHandler;
1257 1614
1258 while (base.IsRunning) 1615 while (base.IsRunningOutbound)
1259 { 1616 {
1260 m_scene.ThreadAlive(2); 1617 m_scene.ThreadAlive(2);
1261 try 1618 try
@@ -1383,6 +1740,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1383 private int npacksSent = 0; 1740 private int npacksSent = 0;
1384 private int npackNotSent = 0; 1741 private int npackNotSent = 0;
1385 1742
1743 /// <summary>
1744 /// Number of inbound packets processed since startup.
1745 /// </summary>
1746 public long IncomingPacketsProcessed { get; private set; }
1747
1386 private void MonitoredClientOutgoingPacketHandler(IClientAPI client) 1748 private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
1387 { 1749 {
1388 nticks++; 1750 nticks++;
@@ -1442,7 +1804,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1442 npacksSent++; 1804 npacksSent++;
1443 } 1805 }
1444 else 1806 else
1807 {
1445 npackNotSent++; 1808 npackNotSent++;
1809 }
1446 1810
1447 watch2.Stop(); 1811 watch2.Stop();
1448 avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks); 1812 avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
@@ -1450,7 +1814,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1450 1814
1451 } 1815 }
1452 else 1816 else
1817 {
1453 m_log.WarnFormat("[LLUDPSERVER]: Client is not connected"); 1818 m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
1819 }
1454 } 1820 }
1455 } 1821 }
1456 catch (Exception ex) 1822 catch (Exception ex)
@@ -1514,6 +1880,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1514// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}", 1880// "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
1515// packet.Type, client.Name, m_scene.RegionInfo.RegionName); 1881// packet.Type, client.Name, m_scene.RegionInfo.RegionName);
1516// } 1882// }
1883
1884 IncomingPacketsProcessed++;
1517 } 1885 }
1518 1886
1519 protected void LogoutHandler(IClientAPI client) 1887 protected void LogoutHandler(IClientAPI client)
@@ -1523,7 +1891,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1523 if (!client.IsLoggingOut) 1891 if (!client.IsLoggingOut)
1524 { 1892 {
1525 client.IsLoggingOut = true; 1893 client.IsLoggingOut = true;
1526 client.Close(false); 1894 client.Close(false, false);
1527 } 1895 }
1528 } 1896 }
1529 } 1897 }