aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs785
1 files changed, 386 insertions, 399 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
index 4528714..69239b1 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs
@@ -32,6 +32,8 @@ using System.IO;
32using System.Net; 32using System.Net;
33using System.Net.Sockets; 33using System.Net.Sockets;
34using System.Reflection; 34using System.Reflection;
35using System.Text;
36using System.Text.RegularExpressions;
35using System.Threading; 37using System.Threading;
36using log4net; 38using log4net;
37using Nini.Config; 39using Nini.Config;
@@ -51,60 +53,59 @@ namespace OpenSim.Region.ClientStack.LindenUDP
51 /// A shim around LLUDPServer that implements the IClientNetworkServer interface 53 /// A shim around LLUDPServer that implements the IClientNetworkServer interface
52 /// </summary> 54 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "LLUDPServerShim")]
54 public sealed class LLUDPServerShim : INonSharedRegionModule 56 public class LLUDPServerShim : INonSharedRegionModule
55 { 57 {
56 private bool m_Enabled = true; 58 protected IConfigSource m_Config;
57 private IConfigSource m_Config; 59 protected LLUDPServer m_udpServer;
58 LLUDPServer m_udpServer;
59 60
60 #region INonSharedRegionModule 61 #region INonSharedRegionModule
61 public string Name 62 public virtual string Name
62 { 63 {
63 get { return "LLUDPServerShim"; } 64 get { return "LLUDPServerShim"; }
64 } 65 }
65 66
66 public Type ReplaceableInterface 67 public virtual Type ReplaceableInterface
67 { 68 {
68 get { return null; } 69 get { return null; }
69 } 70 }
70 71
71 public void Initialise(IConfigSource source) 72 public virtual void Initialise(IConfigSource source)
72 { 73 {
73 m_Config = source; 74 m_Config = source;
74 } 75 }
75 76
76 public void Close() 77 public virtual void Close()
77 { 78 {
78 } 79 }
79 80
80 public void AddRegion(Scene scene) 81 public virtual void AddRegion(Scene scene)
81 { 82 {
82 uint port = (uint)scene.RegionInfo.InternalEndPoint.Port; 83 uint port = (uint)scene.RegionInfo.InternalEndPoint.Port;
83 84
84 IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address; 85 IPAddress listenIP = scene.RegionInfo.InternalEndPoint.Address;
85 Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, scene.RegionInfo.m_allow_alternate_ports, m_Config, scene.AuthenticateHandler); 86 Initialise(listenIP, ref port, scene.RegionInfo.ProxyOffset, m_Config, scene.AuthenticateHandler);
86 scene.RegionInfo.InternalEndPoint.Port = (int)port; 87 scene.RegionInfo.InternalEndPoint.Port = (int)port;
87 88
88 AddScene(scene); 89 AddScene(scene);
89 } 90 }
90 91
91 public void RemoveRegion(Scene scene) 92 public virtual void RemoveRegion(Scene scene)
92 { 93 {
93 Stop(); 94 Stop();
94 } 95 }
95 96
96 public void RegionLoaded(Scene scene) 97 public virtual void RegionLoaded(Scene scene)
97 { 98 {
98 Start(); 99 Start();
99 } 100 }
100 #endregion 101 #endregion
101 102
102 public void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 103 public virtual void Initialise(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, IConfigSource configSource, AgentCircuitManager circuitManager)
103 { 104 {
104 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, allow_alternate_port, configSource, circuitManager); 105 m_udpServer = new LLUDPServer(listenIP, ref port, proxyPortOffsetParm, configSource, circuitManager);
105 } 106 }
106 107
107 public void AddScene(IScene scene) 108 public virtual void AddScene(IScene scene)
108 { 109 {
109 m_udpServer.AddScene(scene); 110 m_udpServer.AddScene(scene);
110 111
@@ -223,22 +224,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
223 StatType.Pull, 224 StatType.Pull,
224 MeasuresOfInterest.None, 225 MeasuresOfInterest.None,
225 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod, 226 stat => stat.Value = m_udpServer.AverageReceiveTicksForLastSamplePeriod,
226// stat => 227// stat =>
227// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7), 228// stat.Value = Math.Round(m_udpServer.AverageReceiveTicksForLastSamplePeriod, 7),
228 StatVerbosity.Debug)); 229 StatVerbosity.Debug));
229 } 230 }
230 231
231 public bool HandlesRegion(Location x) 232 public virtual bool HandlesRegion(Location x)
232 { 233 {
233 return m_udpServer.HandlesRegion(x); 234 return m_udpServer.HandlesRegion(x);
234 } 235 }
235 236
236 public void Start() 237 public virtual void Start()
237 { 238 {
238 m_udpServer.Start(); 239 m_udpServer.Start();
239 } 240 }
240 241
241 public void Stop() 242 public virtual void Stop()
242 { 243 {
243 m_udpServer.Stop(); 244 m_udpServer.Stop();
244 } 245 }
@@ -257,7 +258,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
257 public const int MTU = 1400; 258 public const int MTU = 1400;
258 259
259 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary> 260 /// <summary>Number of forced client logouts due to no receipt of packets before timeout.</summary>
260 public int ClientLogoutsDueToNoReceives { get; private set; } 261 public int ClientLogoutsDueToNoReceives { get; protected set; }
261 262
262 /// <summary> 263 /// <summary>
263 /// Default packet debug level given to new clients 264 /// Default packet debug level given to new clients
@@ -273,7 +274,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
273 /// <summary>The measured resolution of Environment.TickCount</summary> 274 /// <summary>The measured resolution of Environment.TickCount</summary>
274 public readonly float TickCountResolution; 275 public readonly float TickCountResolution;
275 276
276 /// <summary>Number of prim updates to put on the queue each time the 277 /// <summary>Number of prim updates to put on the queue each time the
277 /// OnQueueEmpty event is triggered for updates</summary> 278 /// OnQueueEmpty event is triggered for updates</summary>
278 public readonly int PrimUpdatesPerCallback; 279 public readonly int PrimUpdatesPerCallback;
279 280
@@ -284,54 +285,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP
284 /// <summary>Handlers for incoming packets</summary> 285 /// <summary>Handlers for incoming packets</summary>
285 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 286 //PacketEventDictionary packetEvents = new PacketEventDictionary();
286 /// <summary>Incoming packets that are awaiting handling</summary> 287 /// <summary>Incoming packets that are awaiting handling</summary>
287 private OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>(); 288 //protected OpenMetaverse.BlockingQueue<IncomingPacket> packetInbox = new OpenMetaverse.BlockingQueue<IncomingPacket>();
289
290 protected OpenSim.Framework.BlockingQueue<IncomingPacket> packetInbox = new OpenSim.Framework.BlockingQueue<IncomingPacket>();
288 291
289 /// <summary>Bandwidth throttle for this UDP server</summary> 292 /// <summary>Bandwidth throttle for this UDP server</summary>
290 public TokenBucket Throttle { get; private set; } 293 public TokenBucket Throttle { get; protected set; }
291 294
292 /// <summary>Per client throttle rates enforced by this server</summary> 295 /// <summary>Per client throttle rates enforced by this server</summary>
293 /// <remarks> 296 /// <remarks>
294 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have. 297 /// If the total rate is non-zero, then this is the maximum total throttle setting that any client can ever have.
295 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually 298 /// The other rates (resend, asset, etc.) are the defaults for a new client and can be changed (and usually
296 /// do get changed immediately). They do not need to sum to the total. 299 /// do get changed immediately). They do not need to sum to the total.
297 /// </remarks> 300 /// </remarks>
298 public ThrottleRates ThrottleRates { get; private set; } 301 public ThrottleRates ThrottleRates { get; protected set; }
299 302
300 /// <summary>Manages authentication for agent circuits</summary> 303 /// <summary>Manages authentication for agent circuits</summary>
301 private AgentCircuitManager m_circuitManager; 304 protected AgentCircuitManager m_circuitManager;
302 305
303 /// <summary>Reference to the scene this UDP server is attached to</summary> 306 /// <summary>Reference to the scene this UDP server is attached to</summary>
304 public Scene Scene { get; private set; } 307 public Scene Scene { get; protected set; }
305 308
306 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 309 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
307 private Location m_location; 310 protected Location m_location;
308 311
309 /// <summary>The size of the receive buffer for the UDP socket. This value 312 /// <summary>The size of the receive buffer for the UDP socket. This value
310 /// is passed up to the operating system and used in the system networking 313 /// is passed up to the operating system and used in the system networking
311 /// stack. Use zero to leave this value as the default</summary> 314 /// stack. Use zero to leave this value as the default</summary>
312 private int m_recvBufferSize; 315 protected int m_recvBufferSize;
313
314 /// <summary>Flag to process packets asynchronously or synchronously</summary>
315 private bool m_asyncPacketHandling;
316 316
317 /// <summary>Tracks whether or not a packet was sent each round so we know 317 /// <summary>Tracks whether or not a packet was sent each round so we know
318 /// whether or not to sleep</summary> 318 /// whether or not to sleep</summary>
319 private bool m_packetSent; 319 protected bool m_packetSent;
320 320
321 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary> 321 /// <summary>Environment.TickCount of the last time that packet stats were reported to the scene</summary>
322 private int m_elapsedMSSinceLastStatReport = 0; 322 protected int m_elapsedMSSinceLastStatReport = 0;
323 323
324 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary> 324 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
325 private int m_tickLastOutgoingPacketHandler; 325 protected double m_tickLastOutgoingPacketHandler;
326 326
327 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary> 327 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
328 private int m_elapsedMSOutgoingPacketHandler; 328 protected double m_elapsedMSOutgoingPacketHandler;
329 329
330 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary> 330 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
331 private int m_elapsed100MSOutgoingPacketHandler; 331 protected int m_elapsed100MSOutgoingPacketHandler;
332 332
333 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary> 333 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
334 private int m_elapsed500MSOutgoingPacketHandler; 334 protected int m_elapsed500MSOutgoingPacketHandler;
335 335
336 /// <summary>Flag to signal when clients should check for resends</summary> 336 /// <summary>Flag to signal when clients should check for resends</summary>
337 protected bool m_resendUnacked; 337 protected bool m_resendUnacked;
@@ -342,32 +342,38 @@ namespace OpenSim.Region.ClientStack.LindenUDP
342 /// <summary>Flag to signal when clients should send pings</summary> 342 /// <summary>Flag to signal when clients should send pings</summary>
343 protected bool m_sendPing; 343 protected bool m_sendPing;
344 344
345 /// <summary> 345 protected int m_animationSequenceNumber;
346 /// Event used to signal when queued packets are available for sending.
347 /// </summary>
348 /// <remarks>
349 /// This allows the outbound loop to only operate when there is data to send rather than continuously polling.
350 /// Some data is sent immediately and not queued. That data would not trigger this event.
351 /// </remarks>
352 private AutoResetEvent m_dataPresentEvent = new AutoResetEvent(false);
353 346
354 private Pool<IncomingPacket> m_incomingPacketPool; 347 public int NextAnimationSequenceNumber
348 {
349 get
350 {
351 m_animationSequenceNumber++;
352 if (m_animationSequenceNumber > 2147482624)
353 m_animationSequenceNumber = 1;
354 return m_animationSequenceNumber;
355 }
356 }
357
358 protected ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>> m_pendingCache = new ExpiringCache<IPEndPoint, Queue<UDPPacketBuffer>>();
359
360 protected Pool<IncomingPacket> m_incomingPacketPool;
355 361
356 /// <summary> 362 /// <summary>
357 /// Stat for number of packets in the main pool awaiting use. 363 /// Stat for number of packets in the main pool awaiting use.
358 /// </summary> 364 /// </summary>
359 private Stat m_poolCountStat; 365 protected Stat m_poolCountStat;
360 366
361 /// <summary> 367 /// <summary>
362 /// Stat for number of packets in the inbound packet pool awaiting use. 368 /// Stat for number of packets in the inbound packet pool awaiting use.
363 /// </summary> 369 /// </summary>
364 private Stat m_incomingPacketPoolStat; 370 protected Stat m_incomingPacketPoolStat;
365 371
366 private int m_defaultRTO = 0; 372 protected int m_defaultRTO = 0;
367 private int m_maxRTO = 0; 373 protected int m_maxRTO = 0;
368 private int m_ackTimeout = 0; 374 protected int m_ackTimeout = 0;
369 private int m_pausedAckTimeout = 0; 375 protected int m_pausedAckTimeout = 0;
370 private bool m_disableFacelights = false; 376 protected bool m_disableFacelights = false;
371 377
372 public Socket Server { get { return null; } } 378 public Socket Server { get { return null; } }
373 379
@@ -389,28 +395,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
389 /// <summary> 395 /// <summary>
390 /// Record how many inbound packets could not be recognized as LLUDP packets. 396 /// Record how many inbound packets could not be recognized as LLUDP packets.
391 /// </summary> 397 /// </summary>
392 public int IncomingMalformedPacketCount { get; private set; } 398 public int IncomingMalformedPacketCount { get; protected set; }
393 399
394 /// <summary> 400 /// <summary>
395 /// Record how many inbound packets could not be associated with a simulator circuit. 401 /// Record how many inbound packets could not be associated with a simulator circuit.
396 /// </summary> 402 /// </summary>
397 public int IncomingOrphanedPacketCount { get; private set; } 403 public int IncomingOrphanedPacketCount { get; protected set; }
398 404
399 /// <summary> 405 /// <summary>
400 /// Record current outgoing client for monitoring purposes. 406 /// Record current outgoing client for monitoring purposes.
401 /// </summary> 407 /// </summary>
402 private IClientAPI m_currentOutgoingClient; 408 protected IClientAPI m_currentOutgoingClient;
403 409
404 /// <summary> 410 /// <summary>
405 /// Recording current incoming client for monitoring purposes. 411 /// Recording current incoming client for monitoring purposes.
406 /// </summary> 412 /// </summary>
407 private IClientAPI m_currentIncomingClient; 413 protected IClientAPI m_currentIncomingClient;
408 414
409 /// <summary> 415 /// <summary>
410 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available 416 /// Queue some low priority but potentially high volume async requests so that they don't overwhelm available
411 /// threadpool threads. 417 /// threadpool threads.
412 /// </summary> 418 /// </summary>
413 public JobEngine IpahEngine { get; private set; } 419// public JobEngine IpahEngine { get; protected set; }
414 420
415 /// <summary> 421 /// <summary>
416 /// Run queue empty processing within a single persistent thread. 422 /// Run queue empty processing within a single persistent thread.
@@ -420,27 +426,42 @@ namespace OpenSim.Region.ClientStack.LindenUDP
420 /// connection schedule its own job in the threadpool which causes performance problems when there are many 426 /// connection schedule its own job in the threadpool which causes performance problems when there are many
421 /// connections. 427 /// connections.
422 /// </remarks> 428 /// </remarks>
423 public JobEngine OqrEngine { get; private set; } 429 public JobEngine OqrEngine { get; protected set; }
424 430
425 public LLUDPServer( 431 public LLUDPServer(
426 IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, 432 IPAddress listenIP, ref uint port, int proxyPortOffsetParm,
427 IConfigSource configSource, AgentCircuitManager circuitManager) 433 IConfigSource configSource, AgentCircuitManager circuitManager)
428 : base(listenIP, (int)port) 434 : base(listenIP, (int)port)
429 { 435 {
430 #region Environment.TickCount Measurement 436 #region Environment.TickCount Measurement
431 437
438 // Update the port with the one we actually got
439 port = (uint)Port;
440
432 // Measure the resolution of Environment.TickCount 441 // Measure the resolution of Environment.TickCount
433 TickCountResolution = 0f; 442 TickCountResolution = 0f;
434 for (int i = 0; i < 5; i++) 443 for (int i = 0; i < 10; i++)
435 { 444 {
436 int start = Environment.TickCount; 445 int start = Environment.TickCount;
437 int now = start; 446 int now = start;
438 while (now == start) 447 while (now == start)
439 now = Environment.TickCount; 448 now = Environment.TickCount;
440 TickCountResolution += (float)(now - start) * 0.2f; 449 TickCountResolution += (float)(now - start);
450 }
451 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution * 0.1f + "ms");
452
453 TickCountResolution = 0f;
454 for (int i = 0; i < 100; i++)
455 {
456 double start = Util.GetTimeStampMS();
457 double now = start;
458 while (now == start)
459 now = Util.GetTimeStampMS();
460 TickCountResolution += (float)((now - start));
441 } 461 }
442 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); 462
443 TickCountResolution = (float)Math.Ceiling(TickCountResolution); 463 TickCountResolution = (float)Math.Round(TickCountResolution * 0.01f,6,MidpointRounding.AwayFromZero);
464 m_log.Info("[LLUDPSERVER]: Average Util.GetTimeStampMS resolution: " + TickCountResolution + "ms");
444 465
445 #endregion Environment.TickCount Measurement 466 #endregion Environment.TickCount Measurement
446 467
@@ -451,7 +472,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
451 IConfig config = configSource.Configs["ClientStack.LindenUDP"]; 472 IConfig config = configSource.Configs["ClientStack.LindenUDP"];
452 if (config != null) 473 if (config != null)
453 { 474 {
454 m_asyncPacketHandling = config.GetBoolean("async_packet_handling", true);
455 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0); 475 m_recvBufferSize = config.GetInt("client_socket_rcvbuf_size", 0);
456 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0); 476 sceneThrottleBps = config.GetInt("scene_throttle_max_bps", 0);
457 477
@@ -494,24 +514,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
494 } 514 }
495 #endregion BinaryStats 515 #endregion BinaryStats
496 516
497 // FIXME: Can't add info here because don't know scene yet. 517 Throttle = new TokenBucket(null, sceneThrottleBps, sceneThrottleBps * 10e-3f);
498// m_throttle
499// = new TokenBucket(
500// string.Format("server throttle bucket for {0}", Scene.Name), null, sceneThrottleBps);
501
502 Throttle = new TokenBucket("server throttle bucket", null, 0, sceneThrottleBps);
503
504 ThrottleRates = new ThrottleRates(configSource); 518 ThrottleRates = new ThrottleRates(configSource);
505 519
506 if (usePools) 520 Random rnd = new Random(Util.EnvironmentTickCount());
507 EnablePools(); 521 m_animationSequenceNumber = rnd.Next(11474826);
522
523// if (usePools)
524// EnablePools();
525 base.DisablePools();
508 } 526 }
509 527
510 public void Start() 528 public void Start()
511 { 529 {
512 StartInbound(); 530 StartInbound();
513 StartOutbound(); 531 StartOutbound();
514 IpahEngine.Start(); 532// IpahEngine.Start();
515 OqrEngine.Start(); 533 OqrEngine.Start();
516 534
517 m_elapsedMSSinceLastStatReport = Environment.TickCount; 535 m_elapsedMSSinceLastStatReport = Environment.TickCount;
@@ -520,10 +538,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
520 public void StartInbound() 538 public void StartInbound()
521 { 539 {
522 m_log.InfoFormat( 540 m_log.InfoFormat(
523 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server in {0} mode with UsePools = {1}", 541 "[LLUDPSERVER]: Starting inbound packet processing for the LLUDP server");
524 m_asyncPacketHandling ? "asynchronous" : "synchronous", UsePools);
525 542
526 base.StartInbound(m_recvBufferSize, m_asyncPacketHandling); 543 base.StartInbound(m_recvBufferSize);
527 544
528 // This thread will process the packets received that are placed on the packetInbox 545 // This thread will process the packets received that are placed on the packetInbox
529 WorkManager.StartThread( 546 WorkManager.StartThread(
@@ -557,7 +574,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
557 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name); 574 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + Scene.Name);
558 base.StopOutbound(); 575 base.StopOutbound();
559 base.StopInbound(); 576 base.StopInbound();
560 IpahEngine.Stop(); 577// IpahEngine.Stop();
561 OqrEngine.Stop(); 578 OqrEngine.Stop();
562 } 579 }
563 580
@@ -642,7 +659,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
642 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. 659 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
643 /// </summary> 660 /// </summary>
644 /// <returns></returns> 661 /// <returns></returns>
645 private string GetWatchdogIncomingAlarmData() 662 protected string GetWatchdogIncomingAlarmData()
646 { 663 {
647 return string.Format( 664 return string.Format(
648 "Client is {0}", 665 "Client is {0}",
@@ -653,7 +670,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
653 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging. 670 /// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
654 /// </summary> 671 /// </summary>
655 /// <returns></returns> 672 /// <returns></returns>
656 private string GetWatchdogOutgoingAlarmData() 673 protected string GetWatchdogOutgoingAlarmData()
657 { 674 {
658 return string.Format( 675 return string.Format(
659 "Client is {0}", 676 "Client is {0}",
@@ -676,15 +693,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
676 693
677 Scene = (Scene)scene; 694 Scene = (Scene)scene;
678 m_location = new Location(Scene.RegionInfo.RegionHandle); 695 m_location = new Location(Scene.RegionInfo.RegionHandle);
679 696/*
680 IpahEngine 697 IpahEngine
681 = new JobEngine( 698 = new JobEngine(
682 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name), 699 string.Format("Incoming Packet Async Handling Engine ({0})", Scene.Name),
683 "INCOMING PACKET ASYNC HANDLING ENGINE"); 700 "INCOMING PACKET ASYNC HANDLING ENGINE");
684 701*/
685 OqrEngine 702 OqrEngine
686 = new JobEngine( 703 = new JobEngine(
687 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name), 704 string.Format("Outgoing Queue Refill Engine ({0})", Scene.Name),
688 "OUTGOING QUEUE REFILL ENGINE"); 705 "OUTGOING QUEUE REFILL ENGINE");
689 706
690 StatsManager.RegisterStat( 707 StatsManager.RegisterStat(
@@ -697,7 +714,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
697 scene.Name, 714 scene.Name,
698 StatType.Pull, 715 StatType.Pull,
699 MeasuresOfInterest.AverageChangeOverTime, 716 MeasuresOfInterest.AverageChangeOverTime,
700 stat => stat.Value = packetInbox.Count, 717 stat => stat.Value = packetInbox.Count(),
701 StatVerbosity.Debug)); 718 StatVerbosity.Debug));
702 719
703 // XXX: These stats are also pool stats but we register them separately since they are currently not 720 // XXX: These stats are also pool stats but we register them separately since they are currently not
@@ -710,9 +727,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
710 "clientstack", 727 "clientstack",
711 Scene.Name, 728 Scene.Name,
712 StatType.Pull, 729 StatType.Pull,
713 stat => 730 stat =>
714 { PercentageStat pstat = (PercentageStat)stat; 731 { PercentageStat pstat = (PercentageStat)stat;
715 pstat.Consequent = PacketPool.Instance.PacketsRequested; 732 pstat.Consequent = PacketPool.Instance.PacketsRequested;
716 pstat.Antecedent = PacketPool.Instance.PacketsReused; }, 733 pstat.Antecedent = PacketPool.Instance.PacketsReused; },
717 StatVerbosity.Debug)); 734 StatVerbosity.Debug));
718 735
@@ -725,8 +742,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
725 Scene.Name, 742 Scene.Name,
726 StatType.Pull, 743 StatType.Pull,
727 stat => 744 stat =>
728 { PercentageStat pstat = (PercentageStat)stat; 745 { PercentageStat pstat = (PercentageStat)stat;
729 pstat.Consequent = PacketPool.Instance.BlocksRequested; 746 pstat.Consequent = PacketPool.Instance.BlocksRequested;
730 pstat.Antecedent = PacketPool.Instance.BlocksReused; }, 747 pstat.Antecedent = PacketPool.Instance.BlocksReused; },
731 StatVerbosity.Debug)); 748 StatVerbosity.Debug));
732 749
@@ -766,7 +783,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
766 MeasuresOfInterest.AverageChangeOverTime, 783 MeasuresOfInterest.AverageChangeOverTime,
767 stat => stat.Value = GetTotalQueuedOutgoingPackets(), 784 stat => stat.Value = GetTotalQueuedOutgoingPackets(),
768 StatVerbosity.Info)); 785 StatVerbosity.Info));
769 786/*
770 StatsManager.RegisterStat( 787 StatsManager.RegisterStat(
771 new Stat( 788 new Stat(
772 "IncomingPacketAsyncRequestsWaiting", 789 "IncomingPacketAsyncRequestsWaiting",
@@ -779,7 +796,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
779 MeasuresOfInterest.None, 796 MeasuresOfInterest.None,
780 stat => stat.Value = IpahEngine.JobsWaiting, 797 stat => stat.Value = IpahEngine.JobsWaiting,
781 StatVerbosity.Debug)); 798 StatVerbosity.Debug));
782 799*/
783 StatsManager.RegisterStat( 800 StatsManager.RegisterStat(
784 new Stat( 801 new Stat(
785 "OQRERequestsWaiting", 802 "OQRERequestsWaiting",
@@ -792,14 +809,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
792 MeasuresOfInterest.None, 809 MeasuresOfInterest.None,
793 stat => stat.Value = OqrEngine.JobsWaiting, 810 stat => stat.Value = OqrEngine.JobsWaiting,
794 StatVerbosity.Debug)); 811 StatVerbosity.Debug));
795 812
796 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by 813 // We delay enabling pool stats to AddScene() instead of Initialize() so that we can distinguish pool stats by
797 // scene name 814 // scene name
798 if (UsePools) 815 if (UsePools)
799 EnablePoolStats(); 816 EnablePoolStats();
800 817
818
801 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this); 819 LLUDPServerCommands commands = new LLUDPServerCommands(MainConsole.Instance, this);
802 commands.Register(); 820 commands.Register();
821
803 } 822 }
804 823
805 public bool HandlesRegion(Location x) 824 public bool HandlesRegion(Location x)
@@ -906,9 +925,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
906 } 925 }
907 926
908 PacketPool.Instance.ReturnPacket(packet); 927 PacketPool.Instance.ReturnPacket(packet);
909
910 if (packetQueued)
911 m_dataPresentEvent.Set();
912 } 928 }
913 929
914 /// <summary> 930 /// <summary>
@@ -969,8 +985,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
969 bufferSize = dataLength; 985 bufferSize = dataLength;
970 buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); 986 buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
971 987
972 // m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" + 988 m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
973 // type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet"); 989 type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length);
974 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 990 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
975 } 991 }
976 } 992 }
@@ -979,35 +995,32 @@ namespace OpenSim.Region.ClientStack.LindenUDP
979 995
980 #region Queue or Send 996 #region Queue or Send
981 997
998 bool highPriority = false;
999
1000 if (category != ThrottleOutPacketType.Unknown && (category & ThrottleOutPacketType.HighPriority) != 0)
1001 {
1002 category = (ThrottleOutPacketType)((int)category & 127);
1003 highPriority = true;
1004 }
1005
982 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null); 1006 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, null);
983 1007
984 // If we were not provided a method for handling unacked, use the UDPServer default method 1008 // If we were not provided a method for handling unacked, use the UDPServer default method
985 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0) 1009 if ((outgoingPacket.Buffer.Data[0] & Helpers.MSG_RELIABLE) != 0)
986 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method); 1010 outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);
987 1011
988 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 1012 // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will
989 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object 1013 // continue to display the deleted object until relog. Therefore, we need to always queue a kill object
990 // packet so that it isn't sent before a queued update packet. 1014 // packet so that it isn't sent before a queued update packet.
991 bool forceQueue = (type == PacketType.KillObject);
992 1015
993// if (type == PacketType.ImprovedTerseObjectUpdate) 1016 bool requestQueue = type == PacketType.KillObject;
994// { 1017 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue, highPriority))
995// m_log.DebugFormat("Direct send ITOU to {0} in {1}", udpClient.AgentID, Scene.Name);
996// SendPacketFinal(outgoingPacket);
997// return false;
998// }
999// else
1000// {
1001 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, forceQueue))
1002 { 1018 {
1003 SendPacketFinal(outgoingPacket); 1019 SendPacketFinal(outgoingPacket);
1004 return true; 1020 return true;
1005 } 1021 }
1006 else 1022
1007 { 1023 return false;
1008 return false;
1009 }
1010// }
1011 1024
1012 #endregion Queue or Send 1025 #endregion Queue or Send
1013 } 1026 }
@@ -1048,6 +1061,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1048 pc.PingID.OldestUnacked = 0; 1061 pc.PingID.OldestUnacked = 0;
1049 1062
1050 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null); 1063 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
1064 udpClient.m_lastStartpingTimeMS = Util.EnvironmentTickCount();
1051 } 1065 }
1052 1066
1053 public void CompletePing(LLUDPClient udpClient, byte pingID) 1067 public void CompletePing(LLUDPClient udpClient, byte pingID)
@@ -1145,7 +1159,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1145 int dataLength = buffer.DataLength; 1159 int dataLength = buffer.DataLength;
1146 1160
1147 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here 1161 // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
1148 if (!isZerocoded) 1162 if (!isZerocoded && !isResend && outgoingPacket.UnackedMethod == null)
1149 { 1163 {
1150 // Keep appending ACKs until there is no room left in the buffer or there are 1164 // Keep appending ACKs until there is no room left in the buffer or there are
1151 // no more ACKs to append 1165 // no more ACKs to append
@@ -1180,7 +1194,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1180 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1); 1194 Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
1181 outgoingPacket.SequenceNumber = sequenceNumber; 1195 outgoingPacket.SequenceNumber = sequenceNumber;
1182 1196
1183 if (udpClient.ProcessUnackedSends && isReliable) 1197 if (isReliable)
1184 { 1198 {
1185 // Add this packet to the list of ACK responses we are waiting on from the server 1199 // Add this packet to the list of ACK responses we are waiting on from the server
1186 udpClient.NeedAcks.Add(outgoingPacket); 1200 udpClient.NeedAcks.Add(outgoingPacket);
@@ -1210,13 +1224,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1210 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name); 1224 outgoingPacket.SequenceNumber, isReliable, isResend, udpClient.AgentID, Scene.Name);
1211 1225
1212 // Put the UDP payload on the wire 1226 // Put the UDP payload on the wire
1213 AsyncBeginSend(buffer); 1227// AsyncBeginSend(buffer);
1228 SyncSend(buffer);
1214 1229
1215 // Keep track of when this packet was sent out (right now) 1230 // Keep track of when this packet was sent out (right now)
1216 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue; 1231 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
1217 } 1232 }
1218 1233
1219 private void RecordMalformedInboundPacket(IPEndPoint endPoint) 1234 protected void RecordMalformedInboundPacket(IPEndPoint endPoint)
1220 { 1235 {
1221// if (m_malformedCount < 100) 1236// if (m_malformedCount < 100)
1222// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString()); 1237// m_log.DebugFormat("[LLUDPSERVER]: Dropped malformed packet: " + e.ToString());
@@ -1225,7 +1240,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1225 1240
1226 if ((IncomingMalformedPacketCount % 10000) == 0) 1241 if ((IncomingMalformedPacketCount % 10000) == 0)
1227 m_log.WarnFormat( 1242 m_log.WarnFormat(
1228 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}", 1243 "[LLUDPSERVER]: Received {0} malformed packets so far, probable network attack. Last was from {1}",
1229 IncomingMalformedPacketCount, endPoint); 1244 IncomingMalformedPacketCount, endPoint);
1230 } 1245 }
1231 1246
@@ -1298,8 +1313,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1298 { 1313 {
1299 if (IncomingMalformedPacketCount < 100) 1314 if (IncomingMalformedPacketCount < 100)
1300 { 1315 {
1301 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data {2}:", 1316 m_log.WarnFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}, data as hex {2}: {3}",
1302 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null)); 1317 buffer.DataLength, buffer.RemoteEndPoint, Utils.BytesToHexString(buffer.Data, buffer.DataLength, null),
1318 Regex.Replace(Encoding.UTF8.GetString(buffer.Data, 0, buffer.DataLength), @"\p{Cc}", a=>string.Format("[{0:X2}]", (byte)a.Value[0])));
1303 } 1319 }
1304 1320
1305 RecordMalformedInboundPacket(endPoint); 1321 RecordMalformedInboundPacket(endPoint);
@@ -1311,35 +1327,62 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1311 1327
1312 #region Packet to Client Mapping 1328 #region Packet to Client Mapping
1313 1329
1314 // UseCircuitCode handling 1330 // If there is already a client for this endpoint, don't process UseCircuitCode
1315 if (packet.Type == PacketType.UseCircuitCode) 1331 IClientAPI client = null;
1332 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1316 { 1333 {
1317 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1334 // UseCircuitCode handling
1318 // buffer. 1335 if (packet.Type == PacketType.UseCircuitCode)
1319 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1336 {
1337 // And if there is a UseCircuitCode pending, also drop it
1338 lock (m_pendingCache)
1339 {
1340 if (m_pendingCache.Contains(endPoint))
1341 return;
1320 1342
1321 Util.FireAndForget(HandleUseCircuitCode, array, "LLUDPServer.HandleUseCircuitCode"); 1343 m_pendingCache.AddOrUpdate(endPoint, new Queue<UDPPacketBuffer>(), 60);
1344 }
1322 1345
1323 return; 1346 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1347 // buffer.
1348 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1349
1350 Util.FireAndForget(HandleUseCircuitCode, array);
1351
1352 return;
1353 }
1324 } 1354 }
1325 else if (packet.Type == PacketType.CompleteAgentMovement) 1355
1356 // If this is a pending connection, enqueue, don't process yet
1357 lock (m_pendingCache)
1326 { 1358 {
1327 // Send ack straight away to let the viewer know that we got it. 1359 Queue<UDPPacketBuffer> queue;
1328 SendAckImmediate(endPoint, packet.Header.Sequence); 1360 if (m_pendingCache.TryGetValue(endPoint, out queue))
1361 {
1362 //m_log.DebugFormat("[LLUDPSERVER]: Enqueued a {0} packet into the pending queue", packet.Type);
1363 queue.Enqueue(buffer);
1364 return;
1365 }
1329 1366
1330 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the 1367/*
1331 // buffer. 1368 else if (packet.Type == PacketType.CompleteAgentMovement)
1332 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet }; 1369 {
1370 // Send ack straight away to let the viewer know that we got it.
1371 SendAckImmediate(endPoint, packet.Header.Sequence);
1333 1372
1334 Util.FireAndForget( 1373 // We need to copy the endpoint so that it doesn't get changed when another thread reuses the
1335 HandleCompleteMovementIntoRegion, array, "LLUDPServer.HandleCompleteMovementIntoRegion"); 1374 // buffer.
1375 object[] array = new object[] { new IPEndPoint(endPoint.Address, endPoint.Port), packet };
1336 1376
1337 return; 1377 Util.FireAndForget(HandleCompleteMovementIntoRegion, array);
1378
1379 return;
1380 }
1381 */
1338 } 1382 }
1339 1383
1340 // Determine which agent this packet came from 1384 // Determine which agent this packet came from
1341 IClientAPI client; 1385 if (client == null || !(client is LLClientView))
1342 if (!Scene.TryGetClient(endPoint, out client) || !(client is LLClientView))
1343 { 1386 {
1344 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName); 1387 //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
1345 1388
@@ -1347,7 +1390,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1347 1390
1348 if ((IncomingOrphanedPacketCount % 10000) == 0) 1391 if ((IncomingOrphanedPacketCount % 10000) == 0)
1349 m_log.WarnFormat( 1392 m_log.WarnFormat(
1350 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}", 1393 "[LLUDPSERVER]: Received {0} orphaned packets so far. Last was from {1}",
1351 IncomingOrphanedPacketCount, endPoint); 1394 IncomingOrphanedPacketCount, endPoint);
1352 1395
1353 return; 1396 return;
@@ -1356,7 +1399,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1356 udpClient = ((LLClientView)client).UDPClient; 1399 udpClient = ((LLClientView)client).UDPClient;
1357 1400
1358 if (!udpClient.IsConnected) 1401 if (!udpClient.IsConnected)
1402 {
1403 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet for a unConnected client in " + Scene.RegionInfo.RegionName);
1359 return; 1404 return;
1405 }
1360 1406
1361 #endregion Packet to Client Mapping 1407 #endregion Packet to Client Mapping
1362 1408
@@ -1368,37 +1414,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1368 1414
1369 #region ACK Receiving 1415 #region ACK Receiving
1370 1416
1371 if (udpClient.ProcessUnackedSends) 1417 // Handle appended ACKs
1418 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
1372 { 1419 {
1373 // Handle appended ACKs 1420 // m_log.DebugFormat(
1374 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 1421 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1375 { 1422 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1376 // m_log.DebugFormat(
1377 // "[LLUDPSERVER]: Handling {0} appended acks from {1} in {2}",
1378 // packet.Header.AckList.Length, client.Name, m_scene.Name);
1379 1423
1380 for (int i = 0; i < packet.Header.AckList.Length; i++) 1424 for (int i = 0; i < packet.Header.AckList.Length; i++)
1381 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent); 1425 udpClient.NeedAcks.Acknowledge(packet.Header.AckList[i], now, packet.Header.Resent);
1382 } 1426 }
1383 1427
1384 // Handle PacketAck packets 1428 // Handle PacketAck packets
1385 if (packet.Type == PacketType.PacketAck) 1429 if (packet.Type == PacketType.PacketAck)
1386 { 1430 {
1387 PacketAckPacket ackPacket = (PacketAckPacket)packet; 1431 PacketAckPacket ackPacket = (PacketAckPacket)packet;
1388 1432
1389 // m_log.DebugFormat( 1433 // m_log.DebugFormat(
1390 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}", 1434 // "[LLUDPSERVER]: Handling {0} packet acks for {1} in {2}",
1391 // ackPacket.Packets.Length, client.Name, m_scene.Name); 1435 // ackPacket.Packets.Length, client.Name, m_scene.Name);
1392 1436
1393 for (int i = 0; i < ackPacket.Packets.Length; i++) 1437 for (int i = 0; i < ackPacket.Packets.Length; i++)
1394 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent); 1438 udpClient.NeedAcks.Acknowledge(ackPacket.Packets[i].ID, now, packet.Header.Resent);
1395 1439
1396 // We don't need to do anything else with PacketAck packets 1440 // We don't need to do anything else with PacketAck packets
1397 return;
1398 }
1399 }
1400 else if (packet.Type == PacketType.PacketAck)
1401 {
1402 return; 1441 return;
1403 } 1442 }
1404 1443
@@ -1442,7 +1481,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1442 { 1481 {
1443 if (packet.Header.Resent) 1482 if (packet.Header.Resent)
1444 m_log.DebugFormat( 1483 m_log.DebugFormat(
1445 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}", 1484 "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
1446 packet.Header.Sequence, packet.Type, client.Name); 1485 packet.Header.Sequence, packet.Type, client.Name);
1447 else 1486 else
1448 m_log.WarnFormat( 1487 m_log.WarnFormat(
@@ -1459,24 +1498,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1459 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length); 1498 LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
1460 #endregion BinaryStats 1499 #endregion BinaryStats
1461 1500
1462 if (packet.Type == PacketType.AgentUpdate)
1463 {
1464 if (DiscardInboundAgentUpdates)
1465 return;
1466 1501
1467 ((LLClientView)client).TotalAgentUpdates++; 1502//AgentUpdate removed from here
1468 1503
1469 AgentUpdatePacket agentUpdate = (AgentUpdatePacket)packet;
1470
1471 LLClientView llClient = client as LLClientView;
1472 if (agentUpdate.AgentData.SessionID != client.SessionId
1473 || agentUpdate.AgentData.AgentID != client.AgentId
1474 || !(llClient == null || llClient.CheckAgentUpdateSignificance(agentUpdate.AgentData)) )
1475 {
1476 PacketPool.Instance.ReturnPacket(packet);
1477 return;
1478 }
1479 }
1480 1504
1481 #region Ping Check Handling 1505 #region Ping Check Handling
1482 1506
@@ -1497,7 +1521,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1497 } 1521 }
1498 else if (packet.Type == PacketType.CompletePingCheck) 1522 else if (packet.Type == PacketType.CompletePingCheck)
1499 { 1523 {
1500 // We don't currently track client ping times 1524 int t = Util.EnvironmentTickCountSubtract(udpClient.m_lastStartpingTimeMS);
1525 int c = udpClient.m_pingMS;
1526 c = 800 * c + 200 * t;
1527 c /= 1000;
1528 udpClient.m_pingMS = c;
1501 return; 1529 return;
1502 } 1530 }
1503 1531
@@ -1517,7 +1545,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1517 incomingPacket = new IncomingPacket((LLClientView)client, packet); 1545 incomingPacket = new IncomingPacket((LLClientView)client, packet);
1518 } 1546 }
1519 1547
1520 packetInbox.Enqueue(incomingPacket); 1548// if (incomingPacket.Packet.Type == PacketType.AgentUpdate ||
1549// incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1550 if (incomingPacket.Packet.Type == PacketType.ChatFromViewer)
1551 packetInbox.PriorityEnqueue(incomingPacket);
1552 else
1553 packetInbox.Enqueue(incomingPacket);
1554
1521 } 1555 }
1522 1556
1523 #region BinaryStats 1557 #region BinaryStats
@@ -1627,14 +1661,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1627 1661
1628 #endregion BinaryStats 1662 #endregion BinaryStats
1629 1663
1630 private void HandleUseCircuitCode(object o) 1664 protected void HandleUseCircuitCode(object o)
1631 { 1665 {
1632 IPEndPoint endPoint = null; 1666 IPEndPoint endPoint = null;
1633 IClientAPI client = null; 1667 IClientAPI client = null;
1634 1668
1635 try 1669 try
1636 { 1670 {
1637 // DateTime startTime = DateTime.Now; 1671// DateTime startTime = DateTime.Now;
1638 object[] array = (object[])o; 1672 object[] array = (object[])o;
1639 endPoint = (IPEndPoint)array[0]; 1673 endPoint = (IPEndPoint)array[0];
1640 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1]; 1674 UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
@@ -1642,10 +1676,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1642 m_log.DebugFormat( 1676 m_log.DebugFormat(
1643 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}", 1677 "[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
1644 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint); 1678 uccp.CircuitCode.Code, Scene.RegionInfo.RegionName, endPoint);
1645 1679
1646 AuthenticateResponse sessionInfo; 1680 AuthenticateResponse sessionInfo;
1647 if (IsClientAuthorized(uccp, out sessionInfo)) 1681 if (IsClientAuthorized(uccp, out sessionInfo))
1648 { 1682 {
1683 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1684
1649 // Begin the process of adding the client to the simulator 1685 // Begin the process of adding the client to the simulator
1650 client 1686 client
1651 = AddClient( 1687 = AddClient(
@@ -1654,20 +1690,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1654 uccp.CircuitCode.SessionID, 1690 uccp.CircuitCode.SessionID,
1655 endPoint, 1691 endPoint,
1656 sessionInfo); 1692 sessionInfo);
1657 1693
1694 // This will be true if the client is new, e.g. not
1695 // an existing child agent, and there is no circuit data
1696 if (client != null && aCircuit == null)
1697 {
1698 Scene.CloseAgent(client.AgentId, true);
1699 return;
1700 }
1701
1702 // Now we know we can handle more data
1703 Thread.Sleep(200);
1704
1705 // Obtain the pending queue and remove it from the cache
1706 Queue<UDPPacketBuffer> queue = null;
1707
1708 lock (m_pendingCache)
1709 {
1710 if (!m_pendingCache.TryGetValue(endPoint, out queue))
1711 {
1712 m_log.DebugFormat("[LLUDPSERVER]: Client created but no pending queue present");
1713 return;
1714
1715 }
1716 m_pendingCache.Remove(endPoint);
1717 }
1718
1719 m_log.DebugFormat("[LLUDPSERVER]: Client created, processing pending queue, {0} entries", queue.Count);
1720
1721 // Reinject queued packets
1722 while (queue.Count > 0)
1723 {
1724 UDPPacketBuffer buf = queue.Dequeue();
1725 PacketReceived(buf);
1726 }
1727
1728 queue = null;
1729
1658 // Send ack straight away to let the viewer know that the connection is active. 1730 // Send ack straight away to let the viewer know that the connection is active.
1659 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use 1731 // The client will be null if it already exists (e.g. if on a region crossing the client sends a use
1660 // circuit code to the existing child agent. This is not particularly obvious. 1732 // circuit code to the existing child agent. This is not particularly obvious.
1661 SendAckImmediate(endPoint, uccp.Header.Sequence); 1733 SendAckImmediate(endPoint, uccp.Header.Sequence);
1662 1734
1663 // We only want to send initial data to new clients, not ones which are being converted from child to root. 1735 // We only want to send initial data to new clients, not ones which are being converted from child to root.
1664 if (client != null) 1736 if (client != null)
1665 { 1737 {
1666 AgentCircuitData aCircuit = Scene.AuthenticateHandler.GetAgentCircuitData(uccp.CircuitCode.Code);
1667 bool tp = (aCircuit.teleportFlags > 0); 1738 bool tp = (aCircuit.teleportFlags > 0);
1668 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from 1739 // Let's delay this for TP agents, otherwise the viewer doesn't know where to get resources from
1669 if (!tp && !client.SceneAgent.SentInitialDataToClient) 1740 if (!tp)
1670 client.SceneAgent.SendInitialDataToClient(); 1741 client.SceneAgent.SendInitialDataToMe();
1671 } 1742 }
1672 } 1743 }
1673 else 1744 else
@@ -1675,11 +1746,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1675 // Don't create clients for unauthorized requesters. 1746 // Don't create clients for unauthorized requesters.
1676 m_log.WarnFormat( 1747 m_log.WarnFormat(
1677 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}", 1748 "[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
1749
1678 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint); 1750 uccp.CircuitCode.ID, Scene.RegionInfo.RegionName, uccp.CircuitCode.Code, endPoint);
1751
1752 lock (m_pendingCache)
1753 m_pendingCache.Remove(endPoint);
1679 } 1754 }
1680 1755
1681 // m_log.DebugFormat( 1756 // m_log.DebugFormat(
1682 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms", 1757 // "[LLUDPSERVER]: Handling UseCircuitCode request from {0} took {1}ms",
1683 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds); 1758 // buffer.RemoteEndPoint, (DateTime.Now - startTime).Milliseconds);
1684 1759
1685 } 1760 }
@@ -1694,8 +1769,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1694 e.StackTrace); 1769 e.StackTrace);
1695 } 1770 }
1696 } 1771 }
1697 1772/*
1698 private void HandleCompleteMovementIntoRegion(object o) 1773 protected void HandleCompleteMovementIntoRegion(object o)
1699 { 1774 {
1700 IPEndPoint endPoint = null; 1775 IPEndPoint endPoint = null;
1701 IClientAPI client = null; 1776 IClientAPI client = null;
@@ -1711,9 +1786,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1711 1786
1712 // Determine which agent this packet came from 1787 // Determine which agent this packet came from
1713 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination 1788 // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
1714 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode 1789 // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
1715 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these 1790 // and then CompleteAgentMovement immediately without waiting for an ack. As we are now handling these
1716 // packets asynchronously, we need to account for this thread proceeding more quickly than the 1791 // packets asynchronously, we need to account for this thread proceeding more quickly than the
1717 // UseCircuitCode thread. 1792 // UseCircuitCode thread.
1718 int count = 40; 1793 int count = 40;
1719 while (count-- > 0) 1794 while (count-- > 0)
@@ -1735,7 +1810,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1735 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too 1810 // manager but the SceneAgent has not yet been set in Scene.AddNewAgent(). If we are too
1736 // eager, then the new ScenePresence may not have registered a listener for this messsage 1811 // eager, then the new ScenePresence may not have registered a listener for this messsage
1737 // before we try to process it. 1812 // before we try to process it.
1738 // XXX: A better long term fix may be to add the SceneAgent before the client is added to 1813 // XXX: A better long term fix may be to add the SceneAgent before the client is added to
1739 // the client manager 1814 // the client manager
1740 m_log.DebugFormat( 1815 m_log.DebugFormat(
1741 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.", 1816 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
@@ -1749,7 +1824,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1749 else 1824 else
1750 { 1825 {
1751 m_log.DebugFormat( 1826 m_log.DebugFormat(
1752 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.", 1827 "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
1753 endPoint, Scene.Name); 1828 endPoint, Scene.Name);
1754 } 1829 }
1755 1830
@@ -1804,6 +1879,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1804 e.StackTrace); 1879 e.StackTrace);
1805 } 1880 }
1806 } 1881 }
1882*/
1807 1883
1808 /// <summary> 1884 /// <summary>
1809 /// Send an ack immediately to the given endpoint. 1885 /// Send an ack immediately to the given endpoint.
@@ -1814,7 +1890,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1814 /// </remarks> 1890 /// </remarks>
1815 /// <param name="remoteEndpoint"></param> 1891 /// <param name="remoteEndpoint"></param>
1816 /// <param name="sequenceNumber"></param> 1892 /// <param name="sequenceNumber"></param>
1817 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) 1893 protected void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
1818 { 1894 {
1819 PacketAckPacket ack = new PacketAckPacket(); 1895 PacketAckPacket ack = new PacketAckPacket();
1820 ack.Header.Reliable = false; 1896 ack.Header.Reliable = false;
@@ -1835,10 +1911,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1835 1911
1836 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); 1912 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
1837 1913
1838 AsyncBeginSend(buffer); 1914// AsyncBeginSend(buffer);
1915 SyncSend(buffer);
1839 } 1916 }
1840 1917
1841 private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) 1918 protected bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
1842 { 1919 {
1843 UUID agentID = useCircuitCode.CircuitCode.ID; 1920 UUID agentID = useCircuitCode.CircuitCode.ID;
1844 UUID sessionID = useCircuitCode.CircuitCode.SessionID; 1921 UUID sessionID = useCircuitCode.CircuitCode.SessionID;
@@ -1861,6 +1938,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1861 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo) 1938 uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
1862 { 1939 {
1863 IClientAPI client = null; 1940 IClientAPI client = null;
1941 bool createNew = false;
1864 1942
1865 // We currently synchronize this code across the whole scene to avoid issues such as 1943 // We currently synchronize this code across the whole scene to avoid issues such as
1866 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done 1944 // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done
@@ -1869,14 +1947,28 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1869 { 1947 {
1870 if (!Scene.TryGetClient(agentID, out client)) 1948 if (!Scene.TryGetClient(agentID, out client))
1871 { 1949 {
1950 createNew = true;
1951 }
1952 else
1953 {
1954 if (client.SceneAgent == null)
1955 {
1956 Scene.CloseAgent(agentID, true);
1957 createNew = true;
1958 }
1959 }
1960
1961 if (createNew)
1962 {
1872 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); 1963 LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, Throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
1873 1964
1965
1874 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); 1966 client = new LLClientView(Scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
1875 client.OnLogout += LogoutHandler; 1967 client.OnLogout += LogoutHandler;
1876 client.DebugPacketLevel = DefaultClientPacketDebugLevel; 1968 client.DebugPacketLevel = DefaultClientPacketDebugLevel;
1877 1969
1878 ((LLClientView)client).DisableFacelights = m_disableFacelights; 1970 ((LLClientView)client).DisableFacelights = m_disableFacelights;
1879 1971
1880 client.Start(); 1972 client.Start();
1881 } 1973 }
1882 } 1974 }
@@ -1893,56 +1985,55 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1893 /// </remarks> 1985 /// </remarks>
1894 /// <param name='client'></param> 1986 /// <param name='client'></param>
1895 /// <param name='timeoutTicks'></param> 1987 /// <param name='timeoutTicks'></param>
1896 private void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks) 1988 protected void DeactivateClientDueToTimeout(LLClientView client, int timeoutTicks)
1897 { 1989 {
1898 lock (client.CloseSyncLock) 1990 lock (client.CloseSyncLock)
1899 { 1991 {
1900 ClientLogoutsDueToNoReceives++; 1992 ClientLogoutsDueToNoReceives++;
1901 1993
1902 m_log.WarnFormat( 1994 if (client.SceneAgent != null)
1903 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.", 1995 {
1904 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name); 1996 m_log.WarnFormat(
1905 1997 "[LLUDPSERVER]: No packets received from {0} agent of {1} for {2}ms in {3}. Disconnecting.",
1906 if (!client.SceneAgent.IsChildAgent) 1998 client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, timeoutTicks, Scene.Name);
1907 client.Kick("Simulator logged you out due to connection timeout."); 1999
2000 if (!client.SceneAgent.IsChildAgent)
2001 client.Kick("Simulator logged you out due to connection timeout.");
2002 }
1908 } 2003 }
1909 2004
1910 Scene.CloseAgent(client.AgentId, true); 2005 if (!Scene.CloseAgent(client.AgentId, true))
2006 client.Close(true,true);
1911 } 2007 }
1912 2008
1913 private void IncomingPacketHandler() 2009 protected void IncomingPacketHandler()
1914 { 2010 {
1915 Thread.CurrentThread.Priority = ThreadPriority.Highest; 2011 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1916 2012 IncomingPacket incomingPacket;
1917 // Set this culture for the thread that incoming packets are received 2013 // Set this culture for the thread that incoming packets are received
1918 // on to en-US to avoid number parsing issues 2014 // on to en-US to avoid number parsing issues
1919 Culture.SetCurrentCulture(); 2015 Culture.SetCurrentCulture();
1920 2016
1921 while (IsRunningInbound) 2017 while (IsRunningInbound)
1922 { 2018 {
2019 Scene.ThreadAlive(1);
1923 try 2020 try
1924 { 2021 {
1925 IncomingPacket incomingPacket = null; 2022 incomingPacket = packetInbox.Dequeue(250);
1926
1927 /*
1928 // HACK: This is a test to try and rate limit packet handling on Mono.
1929 // If it works, a more elegant solution can be devised
1930 if (Util.FireAndForgetCount() < 2)
1931 {
1932 //m_log.Debug("[LLUDPSERVER]: Incoming packet handler is sleeping");
1933 Thread.Sleep(30);
1934 }
1935 */
1936 2023
1937 if (packetInbox.Dequeue(100, ref incomingPacket)) 2024 if (incomingPacket != null && IsRunningInbound)
1938 { 2025 {
1939 ProcessInPacket(incomingPacket);//, incomingPacket); Util.FireAndForget(ProcessInPacket, incomingPacket); 2026 ProcessInPacket(incomingPacket);
1940 2027
1941 if (UsePools) 2028 if (UsePools)
2029 {
2030 incomingPacket.Client = null;
1942 m_incomingPacketPool.ReturnObject(incomingPacket); 2031 m_incomingPacketPool.ReturnObject(incomingPacket);
2032 }
2033 incomingPacket = null;
1943 } 2034 }
1944 } 2035 }
1945 catch (Exception ex) 2036 catch(Exception ex)
1946 { 2037 {
1947 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex); 2038 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
1948 } 2039 }
@@ -1950,14 +2041,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1950 Watchdog.UpdateThread(); 2041 Watchdog.UpdateThread();
1951 } 2042 }
1952 2043
1953 if (packetInbox.Count > 0) 2044 if (packetInbox.Count() > 0)
1954 m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count + " packets"); 2045 m_log.Warn("[LLUDPSERVER]: IncomingPacketHandler is shutting down, dropping " + packetInbox.Count() + " packets");
1955 packetInbox.Clear(); 2046 packetInbox.Clear();
1956 2047
1957 Watchdog.RemoveThread(); 2048 Watchdog.RemoveThread();
1958 } 2049 }
1959 2050
1960 private void OutgoingPacketHandler() 2051 protected void OutgoingPacketHandler()
1961 { 2052 {
1962 Thread.CurrentThread.Priority = ThreadPriority.Highest; 2053 Thread.CurrentThread.Priority = ThreadPriority.Highest;
1963 2054
@@ -1971,6 +2062,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1971 2062
1972 while (base.IsRunningOutbound) 2063 while (base.IsRunningOutbound)
1973 { 2064 {
2065 Scene.ThreadAlive(2);
2066
2067
1974 try 2068 try
1975 { 2069 {
1976 m_packetSent = false; 2070 m_packetSent = false;
@@ -1982,19 +2076,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
1982 m_sendPing = false; 2076 m_sendPing = false;
1983 2077
1984 // Update elapsed time 2078 // Update elapsed time
1985 int thisTick = Environment.TickCount & Int32.MaxValue; 2079 double thisTick = Util.GetTimeStampMS();
1986 if (m_tickLastOutgoingPacketHandler > thisTick)
1987 m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
1988 else
1989 m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
1990 2080
2081 // update some 1ms resolution chained timers
2082 m_elapsedMSOutgoingPacketHandler += thisTick - m_tickLastOutgoingPacketHandler;
1991 m_tickLastOutgoingPacketHandler = thisTick; 2083 m_tickLastOutgoingPacketHandler = thisTick;
1992 2084
1993 // Check for pending outgoing resends every 100ms 2085 // Check for pending outgoing resends every 100ms
1994 if (m_elapsedMSOutgoingPacketHandler >= 100) 2086 if (m_elapsedMSOutgoingPacketHandler >= 100.0)
1995 { 2087 {
1996 m_resendUnacked = true; 2088 m_resendUnacked = true;
1997 m_elapsedMSOutgoingPacketHandler = 0; 2089 m_elapsedMSOutgoingPacketHandler = 0.0;
1998 m_elapsed100MSOutgoingPacketHandler += 1; 2090 m_elapsed100MSOutgoingPacketHandler += 1;
1999 } 2091 }
2000 2092
@@ -2012,15 +2104,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2012 m_sendPing = true; 2104 m_sendPing = true;
2013 m_elapsed500MSOutgoingPacketHandler = 0; 2105 m_elapsed500MSOutgoingPacketHandler = 0;
2014 } 2106 }
2015
2016 #endregion Update Timers 2107 #endregion Update Timers
2017 2108
2018 // Use this for emergency monitoring -- bug hunting
2019 //if (m_scene.EmergencyMonitoring)
2020 // clientPacketHandler = MonitoredClientOutgoingPacketHandler;
2021 //else
2022 // clientPacketHandler = ClientOutgoingPacketHandler;
2023
2024 // Handle outgoing packets, resends, acknowledgements, and pings for each 2109 // Handle outgoing packets, resends, acknowledgements, and pings for each
2025 // client. m_packetSent will be set to true if a packet is sent 2110 // client. m_packetSent will be set to true if a packet is sent
2026 Scene.ForEachClient(clientPacketHandler); 2111 Scene.ForEachClient(clientPacketHandler);
@@ -2029,13 +2114,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2029 2114
2030 // If nothing was sent, sleep for the minimum amount of time before a 2115 // If nothing was sent, sleep for the minimum amount of time before a
2031 // token bucket could get more tokens 2116 // token bucket could get more tokens
2032 //if (!m_packetSent) 2117
2033 // Thread.Sleep((int)TickCountResolution); 2118 if(Scene.GetNumberOfClients() == 0)
2034 // 2119 {
2035 // Instead, now wait for data present to be explicitly signalled. Evidence so far is that with 2120 Thread.Sleep(100);
2036 // modern mono it reduces CPU base load since there is no more continuous polling. 2121 }
2037 if (!m_packetSent) 2122 else if (!m_packetSent)
2038 m_dataPresentEvent.WaitOne(100); 2123// Thread.Sleep((int)TickCountResolution); outch this is bad on linux
2124 Thread.Sleep(15); // match the 16ms of windows7, dont ask 16 or win may decide to do 32ms.
2039 2125
2040 Watchdog.UpdateThread(); 2126 Watchdog.UpdateThread();
2041 } 2127 }
@@ -2061,7 +2147,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2061 2147
2062 if (udpClient.IsConnected) 2148 if (udpClient.IsConnected)
2063 { 2149 {
2064 if (udpClient.ProcessUnackedSends && m_resendUnacked) 2150 if (m_resendUnacked)
2065 HandleUnacked(llClient); 2151 HandleUnacked(llClient);
2066 2152
2067 if (m_sendAcks) 2153 if (m_sendAcks)
@@ -2086,160 +2172,61 @@ namespace OpenSim.Region.ClientStack.LindenUDP
2086 #region Emergency Monitoring 2172 #region Emergency Monitoring
2087 // Alternative packet handler fuull of instrumentation 2173 // Alternative packet handler fuull of instrumentation
2088 // Handy for hunting bugs 2174 // Handy for hunting bugs
2089 private Stopwatch watch1 = new Stopwatch(); 2175 protected Stopwatch watch1 = new Stopwatch();
2090 private Stopwatch watch2 = new Stopwatch(); 2176 protected Stopwatch watch2 = new Stopwatch();
2091 2177
2092 private float avgProcessingTicks = 0; 2178 protected float avgProcessingTicks = 0;
2093 private float avgResendUnackedTicks = 0; 2179 protected float avgResendUnackedTicks = 0;
2094 private float avgSendAcksTicks = 0; 2180 protected float avgSendAcksTicks = 0;
2095 private float avgSendPingTicks = 0; 2181 protected float avgSendPingTicks = 0;
2096 private float avgDequeueTicks = 0; 2182 protected float avgDequeueTicks = 0;
2097 private long nticks = 0; 2183 protected long nticks = 0;
2098 private long nticksUnack = 0; 2184 protected long nticksUnack = 0;
2099 private long nticksAck = 0; 2185 protected long nticksAck = 0;
2100 private long nticksPing = 0; 2186 protected long nticksPing = 0;
2101 private int npacksSent = 0; 2187 protected int npacksSent = 0;
2102 private int npackNotSent = 0; 2188 protected int npackNotSent = 0;
2103 2189
2104 /// <summary> 2190 /// <summary>
2105 /// Number of inbound packets processed since startup. 2191 /// Number of inbound packets processed since startup.
2106 /// </summary> 2192 /// </summary>
2107 public long IncomingPacketsProcessed { get; private set; } 2193 public long IncomingPacketsProcessed { get; protected set; }
2108
2109 private void MonitoredClientOutgoingPacketHandler(IClientAPI client)
2110 {
2111 nticks++;
2112 watch1.Start();
2113 m_currentOutgoingClient = client;
2114
2115 try
2116 {
2117 if (client is LLClientView)
2118 {
2119 LLClientView llClient = (LLClientView)client;
2120 LLUDPClient udpClient = llClient.UDPClient;
2121 2194
2122 if (udpClient.IsConnected) 2195 #endregion
2123 {
2124 if (m_resendUnacked)
2125 {
2126 nticksUnack++;
2127 watch2.Start();
2128
2129 HandleUnacked(llClient);
2130
2131 watch2.Stop();
2132 avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
2133 watch2.Reset();
2134 }
2135
2136 if (m_sendAcks)
2137 {
2138 nticksAck++;
2139 watch2.Start();
2140
2141 SendAcks(udpClient);
2142
2143 watch2.Stop();
2144 avgSendAcksTicks = (nticksAck - 1) / (float)nticksAck * avgSendAcksTicks + (watch2.ElapsedTicks / (float)nticksAck);
2145 watch2.Reset();
2146 }
2147
2148 if (m_sendPing)
2149 {
2150 nticksPing++;
2151 watch2.Start();
2152
2153 SendPing(udpClient);
2154 2196
2155 watch2.Stop(); 2197 protected void ProcessInPacket(IncomingPacket incomingPacket)
2156 avgSendPingTicks = (nticksPing - 1) / (float)nticksPing * avgSendPingTicks + (watch2.ElapsedTicks / (float)nticksPing); 2198 {
2157 watch2.Reset(); 2199 Packet packet = incomingPacket.Packet;
2158 } 2200 LLClientView client = incomingPacket.Client;
2159 2201
2160 watch2.Start(); 2202 if(!client.IsActive)
2161 // Dequeue any outgoing packets that are within the throttle limits 2203 return;
2162 if (udpClient.DequeueOutgoing())
2163 {
2164 m_packetSent = true;
2165 npacksSent++;
2166 }
2167 else
2168 {
2169 npackNotSent++;
2170 }
2171 2204
2172 watch2.Stop(); 2205 m_currentIncomingClient = client;
2173 avgDequeueTicks = (nticks - 1) / (float)nticks * avgDequeueTicks + (watch2.ElapsedTicks / (float)nticks);
2174 watch2.Reset();
2175 2206
2176 } 2207 try
2177 else
2178 {
2179 m_log.WarnFormat("[LLUDPSERVER]: Client is not connected");
2180 }
2181 }
2182 }
2183 catch (Exception ex)
2184 { 2208 {
2185 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name + 2209 // Process this packet
2186 " threw an exception: " + ex.Message, ex); 2210 client.ProcessInPacket(packet);
2187 } 2211 }
2188 watch1.Stop(); 2212 catch(ThreadAbortException)
2189 avgProcessingTicks = (nticks - 1) / (float)nticks * avgProcessingTicks + (watch1.ElapsedTicks / (float)nticks);
2190 watch1.Reset();
2191
2192 // reuse this -- it's every ~100ms
2193 if (Scene.EmergencyMonitoring && nticks % 100 == 0)
2194 { 2213 {
2195 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})", 2214 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2196 avgProcessingTicks, avgResendUnackedTicks, avgSendAcksTicks, avgSendPingTicks, avgDequeueTicks, TickCountResolution, npacksSent, npackNotSent); 2215 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2197 npackNotSent = npacksSent = 0; 2216 Stop();
2198 } 2217 }
2199 2218 catch(Exception e)
2200 }
2201
2202 #endregion
2203
2204 private void ProcessInPacket(IncomingPacket incomingPacket)
2205 {
2206 Packet packet = incomingPacket.Packet;
2207 LLClientView client = incomingPacket.Client;
2208
2209 if (client.IsActive)
2210 { 2219 {
2211 m_currentIncomingClient = client; 2220 // Don't let a failure in an individual client thread crash the whole sim.
2212 2221 m_log.Error(
2213 try 2222 string.Format(
2214 { 2223 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2215 // Process this packet 2224 client.Name,packet.Type),
2216 client.ProcessInPacket(packet); 2225 e);
2217 }
2218 catch (ThreadAbortException)
2219 {
2220 // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
2221 m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
2222 Stop();
2223 }
2224 catch (Exception e)
2225 {
2226 // Don't let a failure in an individual client thread crash the whole sim.
2227 m_log.Error(
2228 string.Format(
2229 "[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
2230 client.Name, packet.Type),
2231 e);
2232 }
2233 finally
2234 {
2235 m_currentIncomingClient = null;
2236 }
2237 } 2226 }
2238 else 2227 finally
2239 { 2228 {
2240 m_log.DebugFormat( 2229 m_currentIncomingClient = null;
2241 "[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
2242 packet.Type, client.Name, Scene.RegionInfo.RegionName);
2243 } 2230 }
2244 2231
2245 IncomingPacketsProcessed++; 2232 IncomingPacketsProcessed++;