diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | 785 |
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; | |||
32 | using System.Net; | 32 | using System.Net; |
33 | using System.Net.Sockets; | 33 | using System.Net.Sockets; |
34 | using System.Reflection; | 34 | using System.Reflection; |
35 | using System.Text; | ||
36 | using System.Text.RegularExpressions; | ||
35 | using System.Threading; | 37 | using System.Threading; |
36 | using log4net; | 38 | using log4net; |
37 | using Nini.Config; | 39 | using 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++; |