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