aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs421
1 files changed, 263 insertions, 158 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 545a0bc..a9f4b2c 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -39,6 +39,8 @@ using OpenSim.Framework.Statistics;
39using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
40using OpenMetaverse; 40using OpenMetaverse;
41 41
42using TokenBucket = OpenSim.Region.ClientStack.LindenUDP.TokenBucket;
43
42namespace OpenSim.Region.ClientStack.LindenUDP 44namespace OpenSim.Region.ClientStack.LindenUDP
43{ 45{
44 /// <summary> 46 /// <summary>
@@ -89,8 +91,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
89 /// </summary> 91 /// </summary>
90 public class LLUDPServer : OpenSimUDPBase 92 public class LLUDPServer : OpenSimUDPBase
91 { 93 {
94 /// <summary>Maximum transmission unit, or UDP packet size, for the LLUDP protocol</summary>
95 public const int MTU = 1400;
96
92 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 97 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
93 98
99 /// <summary>The measured resolution of Environment.TickCount</summary>
100 public readonly float TickCountResolution;
101
94 /// <summary>Handlers for incoming packets</summary> 102 /// <summary>Handlers for incoming packets</summary>
95 //PacketEventDictionary packetEvents = new PacketEventDictionary(); 103 //PacketEventDictionary packetEvents = new PacketEventDictionary();
96 /// <summary>Incoming packets that are awaiting handling</summary> 104 /// <summary>Incoming packets that are awaiting handling</summary>
@@ -104,20 +112,35 @@ namespace OpenSim.Region.ClientStack.LindenUDP
104 /// <summary>Manages authentication for agent circuits</summary> 112 /// <summary>Manages authentication for agent circuits</summary>
105 private AgentCircuitManager m_circuitManager; 113 private AgentCircuitManager m_circuitManager;
106 /// <summary>Reference to the scene this UDP server is attached to</summary> 114 /// <summary>Reference to the scene this UDP server is attached to</summary>
107 private IScene m_scene; 115 private Scene m_scene;
108 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary> 116 /// <summary>The X/Y coordinates of the scene this UDP server is attached to</summary>
109 private Location m_location; 117 private Location m_location;
110 /// <summary>The measured resolution of Environment.TickCount</summary>
111 private float m_tickCountResolution;
112 /// <summary>The size of the receive buffer for the UDP socket. This value 118 /// <summary>The size of the receive buffer for the UDP socket. This value
113 /// is passed up to the operating system and used in the system networking 119 /// is passed up to the operating system and used in the system networking
114 /// stack. Use zero to leave this value as the default</summary> 120 /// stack. Use zero to leave this value as the default</summary>
115 private int m_recvBufferSize; 121 private int m_recvBufferSize;
116 /// <summary>Flag to process packets asynchronously or synchronously</summary> 122 /// <summary>Flag to process packets asynchronously or synchronously</summary>
117 private bool m_asyncPacketHandling; 123 private bool m_asyncPacketHandling;
124 /// <summary>Tracks whether or not a packet was sent each round so we know
125 /// whether or not to sleep</summary>
126 private bool m_packetSent;
127
128 /// <summary>Environment.TickCount of the last time the outgoing packet handler executed</summary>
129 private int m_tickLastOutgoingPacketHandler;
130 /// <summary>Keeps track of the number of elapsed milliseconds since the last time the outgoing packet handler looped</summary>
131 private int m_elapsedMSOutgoingPacketHandler;
132 /// <summary>Keeps track of the number of 100 millisecond periods elapsed in the outgoing packet handler executed</summary>
133 private int m_elapsed100MSOutgoingPacketHandler;
134 /// <summary>Keeps track of the number of 500 millisecond periods elapsed in the outgoing packet handler executed</summary>
135 private int m_elapsed500MSOutgoingPacketHandler;
136
137 /// <summary>Flag to signal when clients should check for resends</summary>
138 private bool m_resendUnacked;
139 /// <summary>Flag to signal when clients should send ACKs</summary>
140 private bool m_sendAcks;
141 /// <summary>Flag to signal when clients should send pings</summary>
142 private bool m_sendPing;
118 143
119 /// <summary>The measured resolution of Environment.TickCount</summary>
120 public float TickCountResolution { get { return m_tickCountResolution; } }
121 public Socket Server { get { return null; } } 144 public Socket Server { get { return null; } }
122 145
123 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager) 146 public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
@@ -126,16 +149,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP
126 #region Environment.TickCount Measurement 149 #region Environment.TickCount Measurement
127 150
128 // Measure the resolution of Environment.TickCount 151 // Measure the resolution of Environment.TickCount
129 m_tickCountResolution = 0f; 152 TickCountResolution = 0f;
130 for (int i = 0; i < 5; i++) 153 for (int i = 0; i < 5; i++)
131 { 154 {
132 int start = Environment.TickCount; 155 int start = Environment.TickCount;
133 int now = start; 156 int now = start;
134 while (now == start) 157 while (now == start)
135 now = Environment.TickCount; 158 now = Environment.TickCount;
136 m_tickCountResolution += (float)(now - start) * 0.2f; 159 TickCountResolution += (float)(now - start) * 0.2f;
137 } 160 }
138 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms"); 161 m_log.Info("[LLUDPSERVER]: Average Environment.TickCount resolution: " + TickCountResolution + "ms");
162 TickCountResolution = (float)Math.Ceiling(TickCountResolution);
139 163
140 #endregion Environment.TickCount Measurement 164 #endregion Environment.TickCount Measurement
141 165
@@ -181,15 +205,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
181 205
182 public void AddScene(IScene scene) 206 public void AddScene(IScene scene)
183 { 207 {
184 if (m_scene == null) 208 if (m_scene != null)
185 { 209 {
186 m_scene = scene; 210 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene");
187 m_location = new Location(m_scene.RegionInfo.RegionHandle); 211 return;
188 } 212 }
189 else 213
214 if (!(scene is Scene))
190 { 215 {
191 m_log.Error("[LLUDPSERVER]: AddScene() called on an LLUDPServer that already has a scene"); 216 m_log.Error("[LLUDPSERVER]: AddScene() called with an unrecognized scene type " + scene.GetType());
217 return;
192 } 218 }
219
220 m_scene = (Scene)scene;
221 m_location = new Location(m_scene.RegionInfo.RegionHandle);
193 } 222 }
194 223
195 public bool HandlesRegion(Location x) 224 public bool HandlesRegion(Location x)
@@ -267,38 +296,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP
267 { 296 {
268 int dataLength = data.Length; 297 int dataLength = data.Length;
269 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0; 298 bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
299 bool doCopy = true;
270 300
271 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum. 301 // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
272 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting 302 // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
273 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here 303 // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
274 // to accomodate for both common scenarios and provide ample room for ACK appending in both 304 // to accomodate for both common scenarios and provide ample room for ACK appending in both
275 int bufferSize = (dataLength > 180) ? Packet.MTU : 200; 305 int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;
276 306
277 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize); 307 UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);
278 308
279 // Zerocode if needed 309 // Zerocode if needed
280 if (doZerocode) 310 if (doZerocode)
281 { 311 {
282 try { dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data); } 312 try
313 {
314 dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
315 doCopy = false;
316 }
283 catch (IndexOutOfRangeException) 317 catch (IndexOutOfRangeException)
284 { 318 {
285 // The packet grew larger than the bufferSize while zerocoding. 319 // The packet grew larger than the bufferSize while zerocoding.
286 // Remove the MSG_ZEROCODED flag and send the unencoded data 320 // Remove the MSG_ZEROCODED flag and send the unencoded data
287 // instead 321 // instead
288 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". Removing MSG_ZEROCODED flag"); 322 m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
323 " and BufferLength=" + buffer.Data.Length + ". Removing MSG_ZEROCODED flag");
289 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED); 324 data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);
290 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
291 } 325 }
292 } 326 }
293 else 327
328 // If the packet data wasn't already copied during zerocoding, copy it now
329 if (doCopy)
294 { 330 {
295 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength); 331 if (dataLength <= buffer.Data.Length)
332 {
333 Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
334 }
335 else
336 {
337 m_log.Error("[LLUDPSERVER]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
338 type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet");
339 return;
340 }
296 } 341 }
342
297 buffer.DataLength = dataLength; 343 buffer.DataLength = dataLength;
298 344
299 #region Queue or Send 345 #region Queue or Send
300 346
301 // Look up the UDPClient this is going to
302 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category); 347 OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category);
303 348
304 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 349 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
@@ -338,57 +383,54 @@ namespace OpenSim.Region.ClientStack.LindenUDP
338 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); 383 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
339 pc.Header.Reliable = false; 384 pc.Header.Reliable = false;
340 385
341 OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
342
343 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; 386 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
344 pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; 387 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
388 pc.PingID.OldestUnacked = 0;
345 389
346 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); 390 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
347 } 391 }
348 392
349 public void ResendUnacked(LLUDPClient udpClient) 393 public void ResendUnacked(LLUDPClient udpClient)
350 { 394 {
351 if (udpClient.IsConnected && udpClient.NeedAcks.Count > 0) 395 if (!udpClient.IsConnected)
396 return;
397
398 // Disconnect an agent if no packets are received for some time
399 //FIXME: Make 60 an .ini setting
400 if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60)
352 { 401 {
353 // Disconnect an agent if no packets are received for some time 402 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
354 //FIXME: Make 60 an .ini setting
355 if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60)
356 {
357 m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
358 403
359 RemoveClient(udpClient); 404 RemoveClient(udpClient);
360 return; 405 return;
361 } 406 }
362 407
363 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO 408 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
364 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO); 409 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
365 410
366 if (expiredPackets != null) 411 if (expiredPackets != null)
367 { 412 {
368 // Resend packets 413 m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
369 for (int i = 0; i < expiredPackets.Count; i++)
370 {
371 OutgoingPacket outgoingPacket = expiredPackets[i];
372 414
373 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed", 415 // Resend packets
374 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount); 416 for (int i = 0; i < expiredPackets.Count; i++)
417 {
418 OutgoingPacket outgoingPacket = expiredPackets[i];
375 419
376 // Set the resent flag 420 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
377 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 421 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
378 outgoingPacket.Category = ThrottleOutPacketType.Resend;
379 422
380 // The TickCount will be set to the current time when the packet 423 // Set the resent flag
381 // is actually sent out again 424 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
382 outgoingPacket.TickCount = 0; 425 outgoingPacket.Category = ThrottleOutPacketType.Resend;
383 426
384 // Bump up the resend count on this packet 427 // Bump up the resend count on this packet
385 Interlocked.Increment(ref outgoingPacket.ResendCount); 428 Interlocked.Increment(ref outgoingPacket.ResendCount);
386 //Interlocked.Increment(ref Stats.ResentPackets); 429 //Interlocked.Increment(ref Stats.ResentPackets);
387 430
388 // Requeue or resend the packet 431 // Requeue or resend the packet
389 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 432 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
390 SendPacketFinal(outgoingPacket); 433 SendPacketFinal(outgoingPacket);
391 }
392 } 434 }
393 } 435 }
394 } 436 }
@@ -409,9 +451,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
409 if (!udpClient.IsConnected) 451 if (!udpClient.IsConnected)
410 return; 452 return;
411 453
412 // Keep track of when this packet was sent out (right now)
413 outgoingPacket.TickCount = Environment.TickCount;
414
415 #region ACK Appending 454 #region ACK Appending
416 455
417 int dataLength = buffer.DataLength; 456 int dataLength = buffer.DataLength;
@@ -464,6 +503,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
464 503
465 // Put the UDP payload on the wire 504 // Put the UDP payload on the wire
466 AsyncBeginSend(buffer); 505 AsyncBeginSend(buffer);
506
507 // Keep track of when this packet was sent out (right now)
508 outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
467 } 509 }
468 510
469 protected override void PacketReceived(UDPPacketBuffer buffer) 511 protected override void PacketReceived(UDPPacketBuffer buffer)
@@ -506,14 +548,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP
506 // UseCircuitCode handling 548 // UseCircuitCode handling
507 if (packet.Type == PacketType.UseCircuitCode) 549 if (packet.Type == PacketType.UseCircuitCode)
508 { 550 {
509 AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); 551 Util.FireAndForget(
552 delegate(object o)
553 {
554 IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
555
556 // Begin the process of adding the client to the simulator
557 AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint);
558
559 // Acknowledge the UseCircuitCode packet
560 SendAckImmediate(remoteEndPoint, packet.Header.Sequence);
561 }
562 );
563 return;
510 } 564 }
511 565
512 // Determine which agent this packet came from 566 // Determine which agent this packet came from
513 IClientAPI client; 567 IClientAPI client;
514 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView)) 568 if (!m_scene.ClientManager.TryGetValue(address, out client) || !(client is LLClientView))
515 { 569 {
516 m_log.Warn("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + 570 m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address +
517 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients"); 571 " in " + m_scene.RegionInfo.RegionName + ", currently tracking " + m_scene.ClientManager.Count + " clients");
518 return; 572 return;
519 } 573 }
@@ -528,19 +582,16 @@ namespace OpenSim.Region.ClientStack.LindenUDP
528 // Stats tracking 582 // Stats tracking
529 Interlocked.Increment(ref udpClient.PacketsReceived); 583 Interlocked.Increment(ref udpClient.PacketsReceived);
530 584
531 #region ACK Receiving 585 int now = Environment.TickCount & Int32.MaxValue;
532
533 int now = Environment.TickCount;
534 udpClient.TickLastPacketReceived = now; 586 udpClient.TickLastPacketReceived = now;
535 587
588 #region ACK Receiving
589
536 // Handle appended ACKs 590 // Handle appended ACKs
537 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 591 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
538 { 592 {
539 lock (udpClient.NeedAcks.SyncRoot) 593 for (int i = 0; i < packet.Header.AckList.Length; i++)
540 { 594 udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent);
541 for (int i = 0; i < packet.Header.AckList.Length; i++)
542 AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
543 }
544 } 595 }
545 596
546 // Handle PacketAck packets 597 // Handle PacketAck packets
@@ -548,11 +599,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP
548 { 599 {
549 PacketAckPacket ackPacket = (PacketAckPacket)packet; 600 PacketAckPacket ackPacket = (PacketAckPacket)packet;
550 601
551 lock (udpClient.NeedAcks.SyncRoot) 602 for (int i = 0; i < ackPacket.Packets.Length; i++)
552 { 603 udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent);
553 for (int i = 0; i < ackPacket.Packets.Length; i++) 604
554 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent); 605 // We don't need to do anything else with PacketAck packets
555 } 606 return;
556 } 607 }
557 608
558 #endregion ACK Receiving 609 #endregion ACK Receiving
@@ -560,20 +611,22 @@ namespace OpenSim.Region.ClientStack.LindenUDP
560 #region ACK Sending 611 #region ACK Sending
561 612
562 if (packet.Header.Reliable) 613 if (packet.Header.Reliable)
614 {
563 udpClient.PendingAcks.Enqueue(packet.Header.Sequence); 615 udpClient.PendingAcks.Enqueue(packet.Header.Sequence);
564 616
565 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out, 617 // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
566 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove 618 // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
567 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to 619 // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
568 // client.BytesSinceLastACK. Lockless thread safety 620 // client.BytesSinceLastACK. Lockless thread safety
569 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0); 621 int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
570 bytesSinceLastACK += buffer.DataLength; 622 bytesSinceLastACK += buffer.DataLength;
571 if (bytesSinceLastACK > Packet.MTU * 2) 623 if (bytesSinceLastACK > LLUDPServer.MTU * 2)
572 { 624 {
573 bytesSinceLastACK -= Packet.MTU * 2; 625 bytesSinceLastACK -= LLUDPServer.MTU * 2;
574 SendAcks(udpClient); 626 SendAcks(udpClient);
627 }
628 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
575 } 629 }
576 Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
577 630
578 #endregion ACK Sending 631 #endregion ACK Sending
579 632
@@ -593,16 +646,47 @@ namespace OpenSim.Region.ClientStack.LindenUDP
593 646
594 #endregion Incoming Packet Accounting 647 #endregion Incoming Packet Accounting
595 648
596 // Don't bother clogging up the queue with PacketAck packets that are already handled here 649 #region Ping Check Handling
597 if (packet.Type != PacketType.PacketAck) 650
651 if (packet.Type == PacketType.StartPingCheck)
598 { 652 {
599 // Inbox insertion 653 // We don't need to do anything else with ping checks
600 packetInbox.Enqueue(new IncomingPacket(udpClient, packet)); 654 StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
655
656 CompletePingCheckPacket completePing = new CompletePingCheckPacket();
657 completePing.PingID.PingID = startPing.PingID.PingID;
658 SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false);
659 return;
601 } 660 }
661 else if (packet.Type == PacketType.CompletePingCheck)
662 {
663 // We don't currently track client ping times
664 return;
665 }
666
667 #endregion Ping Check Handling
668
669 // Inbox insertion
670 packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
602 } 671 }
603 672
604 protected override void PacketSent(UDPPacketBuffer buffer, int bytesSent) 673 private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
605 { 674 {
675 PacketAckPacket ack = new PacketAckPacket();
676 ack.Header.Reliable = false;
677 ack.Packets = new PacketAckPacket.PacketsBlock[1];
678 ack.Packets[0] = new PacketAckPacket.PacketsBlock();
679 ack.Packets[0].ID = sequenceNumber;
680
681 byte[] packetData = ack.ToBytes();
682 int length = packetData.Length;
683
684 UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length);
685 buffer.DataLength = length;
686
687 Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length);
688
689 AsyncBeginSend(buffer);
606 } 690 }
607 691
608 private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) 692 private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo)
@@ -672,33 +756,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP
672 client.Close(); 756 client.Close();
673 } 757 }
674 758
675 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
676 {
677 OutgoingPacket ackedPacket;
678 if (client.NeedAcks.RemoveUnsafe(ack, out ackedPacket) && !fromResend)
679 {
680 // Update stats
681 Interlocked.Add(ref client.UnackedBytes, -ackedPacket.Buffer.DataLength);
682
683 // Calculate the round-trip time for this packet and its ACK
684 int rtt = currentTime - ackedPacket.TickCount;
685 if (rtt > 0)
686 client.UpdateRoundTrip(rtt);
687 }
688 }
689
690 private void IncomingPacketHandler() 759 private void IncomingPacketHandler()
691 { 760 {
692 // Set this culture for the thread that incoming packets are received 761 // Set this culture for the thread that incoming packets are received
693 // on to en-US to avoid number parsing issues 762 // on to en-US to avoid number parsing issues
694 Culture.SetCurrentCulture(); 763 Culture.SetCurrentCulture();
695 764
696 IncomingPacket incomingPacket = null;
697
698 while (base.IsRunning) 765 while (base.IsRunning)
699 { 766 {
700 if (packetInbox.Dequeue(100, ref incomingPacket)) 767 try
701 Util.FireAndForget(ProcessInPacket, incomingPacket); 768 {
769 IncomingPacket incomingPacket = null;
770
771 if (packetInbox.Dequeue(100, ref incomingPacket))
772 Util.FireAndForget(ProcessInPacket, incomingPacket);
773 }
774 catch (Exception ex)
775 {
776 m_log.Error("[LLUDPSERVER]: Error in the incoming packet handler loop: " + ex.Message, ex);
777 }
702 } 778 }
703 779
704 if (packetInbox.Count > 0) 780 if (packetInbox.Count > 0)
@@ -712,68 +788,97 @@ namespace OpenSim.Region.ClientStack.LindenUDP
712 // on to en-US to avoid number parsing issues 788 // on to en-US to avoid number parsing issues
713 Culture.SetCurrentCulture(); 789 Culture.SetCurrentCulture();
714 790
715 int now = Environment.TickCount;
716 int elapsedMS = 0;
717 int elapsed100MS = 0;
718 int elapsed500MS = 0;
719
720 while (base.IsRunning) 791 while (base.IsRunning)
721 { 792 {
722 bool resendUnacked = false; 793 try
723 bool sendAcks = false; 794 {
724 bool sendPings = false; 795 m_packetSent = false;
725 bool packetSent = false;
726 796
727 elapsedMS += Environment.TickCount - now; 797 #region Update Timers
728 798
729 // Check for pending outgoing resends every 100ms 799 m_resendUnacked = false;
730 if (elapsedMS >= 100) 800 m_sendAcks = false;
731 { 801 m_sendPing = false;
732 resendUnacked = true; 802
733 elapsedMS -= 100; 803 // Update elapsed time
734 ++elapsed100MS; 804 int thisTick = Environment.TickCount & Int32.MaxValue;
805 if (m_tickLastOutgoingPacketHandler > thisTick)
806 m_elapsedMSOutgoingPacketHandler += ((Int32.MaxValue - m_tickLastOutgoingPacketHandler) + thisTick);
807 else
808 m_elapsedMSOutgoingPacketHandler += (thisTick - m_tickLastOutgoingPacketHandler);
809
810 m_tickLastOutgoingPacketHandler = thisTick;
811
812 // Check for pending outgoing resends every 100ms
813 if (m_elapsedMSOutgoingPacketHandler >= 100)
814 {
815 m_resendUnacked = true;
816 m_elapsedMSOutgoingPacketHandler = 0;
817 m_elapsed100MSOutgoingPacketHandler += 1;
818 }
819
820 // Check for pending outgoing ACKs every 500ms
821 if (m_elapsed100MSOutgoingPacketHandler >= 5)
822 {
823 m_sendAcks = true;
824 m_elapsed100MSOutgoingPacketHandler = 0;
825 m_elapsed500MSOutgoingPacketHandler += 1;
826 }
827
828 // Send pings to clients every 5000ms
829 if (m_elapsed500MSOutgoingPacketHandler >= 10)
830 {
831 m_sendPing = true;
832 m_elapsed500MSOutgoingPacketHandler = 0;
833 }
834
835 #endregion Update Timers
836
837 // Handle outgoing packets, resends, acknowledgements, and pings for each
838 // client. m_packetSent will be set to true if a packet is sent
839 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler);
840
841 // If nothing was sent, sleep for the minimum amount of time before a
842 // token bucket could get more tokens
843 if (!m_packetSent)
844 Thread.Sleep((int)TickCountResolution);
735 } 845 }
736 // Check for pending outgoing ACKs every 500ms 846 catch (Exception ex)
737 if (elapsed100MS >= 5)
738 { 847 {
739 sendAcks = true; 848 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler loop threw an exception: " + ex.Message, ex);
740 elapsed100MS = 0;
741 ++elapsed500MS;
742 } 849 }
743 // Send pings to clients every 5000ms 850 }
744 if (elapsed500MS >= 10) 851 }
852
853 private void ClientOutgoingPacketHandler(IClientAPI client)
854 {
855 try
856 {
857 if (client is LLClientView)
745 { 858 {
746 sendPings = true; 859 LLUDPClient udpClient = ((LLClientView)client).UDPClient;
747 elapsed500MS = 0;
748 }
749 860
750 m_scene.ClientManager.ForEach( 861 if (udpClient.IsConnected)
751 delegate(IClientAPI client)
752 { 862 {
753 if (client is LLClientView) 863 if (m_resendUnacked)
754 { 864 ResendUnacked(udpClient);
755 LLUDPClient udpClient = ((LLClientView)client).UDPClient; 865
756 866 if (m_sendAcks)
757 if (udpClient.IsConnected) 867 SendAcks(udpClient);
758 { 868
759 if (udpClient.DequeueOutgoing()) 869 if (m_sendPing)
760 packetSent = true; 870 SendPing(udpClient);
761 if (resendUnacked)
762 ResendUnacked(udpClient);
763 if (sendAcks)
764 {
765 SendAcks(udpClient);
766 udpClient.SendPacketStats();
767 }
768 if (sendPings)
769 SendPing(udpClient);
770 }
771 }
772 }
773 );
774 871
775 if (!packetSent) 872 // Dequeue any outgoing packets that are within the throttle limits
776 Thread.Sleep(20); 873 if (udpClient.DequeueOutgoing())
874 m_packetSent = true;
875 }
876 }
877 }
878 catch (Exception ex)
879 {
880 m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
881 " threw an exception: " + ex.Message, ex);
777 } 882 }
778 } 883 }
779 884