aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs')
-rw-r--r--OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs143
1 files changed, 45 insertions, 98 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
index 7d5c11e..a8ce102 100644
--- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
+++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs
@@ -121,12 +121,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
121 private int m_recvBufferSize; 121 private int m_recvBufferSize;
122 /// <summary>Flag to process packets asynchronously or synchronously</summary> 122 /// <summary>Flag to process packets asynchronously or synchronously</summary>
123 private bool m_asyncPacketHandling; 123 private bool m_asyncPacketHandling;
124 /// <summary>Track the minimum amount of time needed to send the next packet in the 124 /// <summary>Tracks whether or not a packet was sent each round so we know
125 /// OutgoingPacketHandler loop so we know when to sleep</summary> 125 /// whether or not to sleep</summary>
126 private int m_minTimeout = Int32.MaxValue; 126 private bool m_packetSent;
127 /// <summary>EventWaitHandle to signify the outgoing packet handler thread that
128 /// there is more work to do</summary>
129 private EventWaitHandle m_outgoingWaitHandle;
130 127
131 public Socket Server { get { return null; } } 128 public Socket Server { get { return null; } }
132 129
@@ -174,8 +171,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
174 171
175 base.Start(m_recvBufferSize, m_asyncPacketHandling); 172 base.Start(m_recvBufferSize, m_asyncPacketHandling);
176 173
177 m_outgoingWaitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
178
179 // Start the incoming packet processing thread 174 // Start the incoming packet processing thread
180 Thread incomingThread = new Thread(IncomingPacketHandler); 175 Thread incomingThread = new Thread(IncomingPacketHandler);
181 incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")"; 176 incomingThread.Name = "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")";
@@ -190,8 +185,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
190 { 185 {
191 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName); 186 m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
192 base.Stop(); 187 base.Stop();
193
194 m_outgoingWaitHandle.Close();
195 } 188 }
196 189
197 public void AddScene(IScene scene) 190 public void AddScene(IScene scene)
@@ -374,10 +367,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
374 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck); 367 StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
375 pc.Header.Reliable = false; 368 pc.Header.Reliable = false;
376 369
377 OutgoingPacket oldestPacket = udpClient.NeedAcks.GetOldest();
378
379 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++; 370 pc.PingID.PingID = (byte)udpClient.CurrentPingSequence++;
380 pc.PingID.OldestUnacked = (oldestPacket != null) ? oldestPacket.SequenceNumber : 0; 371 // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
372 pc.PingID.OldestUnacked = 0;
381 373
382 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false); 374 SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
383 } 375 }
@@ -397,39 +389,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
397 return; 389 return;
398 } 390 }
399 391
400 if (udpClient.NeedAcks.Count > 0) 392 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
393 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
394
395 if (expiredPackets != null)
401 { 396 {
402 // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO 397 m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
403 List<OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);
404 398
405 if (expiredPackets != null) 399 // Resend packets
400 for (int i = 0; i < expiredPackets.Count; i++)
406 { 401 {
407 m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID); 402 OutgoingPacket outgoingPacket = expiredPackets[i];
408 403
409 // Resend packets 404 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
410 for (int i = 0; i < expiredPackets.Count; i++) 405 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
411 {
412 OutgoingPacket outgoingPacket = expiredPackets[i];
413
414 //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
415 // outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
416 406
417 // Set the resent flag 407 // Set the resent flag
418 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT); 408 outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
419 outgoingPacket.Category = ThrottleOutPacketType.Resend; 409 outgoingPacket.Category = ThrottleOutPacketType.Resend;
420 410
421 // The TickCount will be set to the current time when the packet 411 // The TickCount will be set to the current time when the packet
422 // is actually sent out again 412 // is actually sent out again
423 outgoingPacket.TickCount = 0; 413 outgoingPacket.TickCount = 0;
424 414
425 // Bump up the resend count on this packet 415 // Bump up the resend count on this packet
426 Interlocked.Increment(ref outgoingPacket.ResendCount); 416 Interlocked.Increment(ref outgoingPacket.ResendCount);
427 //Interlocked.Increment(ref Stats.ResentPackets); 417 //Interlocked.Increment(ref Stats.ResentPackets);
428 418
429 // Requeue or resend the packet 419 // Requeue or resend the packet
430 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket)) 420 if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
431 SendPacketFinal(outgoingPacket); 421 SendPacketFinal(outgoingPacket);
432 }
433 } 422 }
434 } 423 }
435 } 424 }
@@ -577,11 +566,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
577 // Handle appended ACKs 566 // Handle appended ACKs
578 if (packet.Header.AppendedAcks && packet.Header.AckList != null) 567 if (packet.Header.AppendedAcks && packet.Header.AckList != null)
579 { 568 {
580 lock (udpClient.NeedAcks.SyncRoot) 569 for (int i = 0; i < packet.Header.AckList.Length; i++)
581 { 570 udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent);
582 for (int i = 0; i < packet.Header.AckList.Length; i++)
583 AcknowledgePacket(udpClient, packet.Header.AckList[i], now, packet.Header.Resent);
584 }
585 } 571 }
586 572
587 // Handle PacketAck packets 573 // Handle PacketAck packets
@@ -589,11 +575,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
589 { 575 {
590 PacketAckPacket ackPacket = (PacketAckPacket)packet; 576 PacketAckPacket ackPacket = (PacketAckPacket)packet;
591 577
592 lock (udpClient.NeedAcks.SyncRoot) 578 for (int i = 0; i < ackPacket.Packets.Length; i++)
593 { 579 udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent);
594 for (int i = 0; i < ackPacket.Packets.Length; i++)
595 AcknowledgePacket(udpClient, ackPacket.Packets[i].ID, now, packet.Header.Resent);
596 }
597 580
598 // We don't need to do anything else with PacketAck packets 581 // We don't need to do anything else with PacketAck packets
599 return; 582 return;
@@ -734,21 +717,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
734 client.Close(); 717 client.Close();
735 } 718 }
736 719
737 private void AcknowledgePacket(LLUDPClient client, uint ack, int currentTime, bool fromResend)
738 {
739 OutgoingPacket ackedPacket;
740 if (client.NeedAcks.RemoveUnsafe(ack, out ackedPacket) && !fromResend)
741 {
742 // Update stats
743 Interlocked.Add(ref client.UnackedBytes, -ackedPacket.Buffer.DataLength);
744
745 // Calculate the round-trip time for this packet and its ACK
746 int rtt = currentTime - ackedPacket.TickCount;
747 if (rtt > 0)
748 client.UpdateRoundTrip(rtt);
749 }
750 }
751
752 private void IncomingPacketHandler() 720 private void IncomingPacketHandler()
753 { 721 {
754 // Set this culture for the thread that incoming packets are received 722 // Set this culture for the thread that incoming packets are received
@@ -775,11 +743,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
775 packetInbox.Clear(); 743 packetInbox.Clear();
776 } 744 }
777 745
778 public bool SignalOutgoingPacketHandler()
779 {
780 return m_outgoingWaitHandle.Set();
781 }
782
783 private void OutgoingPacketHandler() 746 private void OutgoingPacketHandler()
784 { 747 {
785 // Set this culture for the thread that outgoing packets are sent 748 // Set this culture for the thread that outgoing packets are sent
@@ -790,28 +753,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
790 { 753 {
791 try 754 try
792 { 755 {
793 m_minTimeout = Int32.MaxValue; 756 m_packetSent = false;
794 757
795 // Handle outgoing packets, resends, acknowledgements, and pings for each 758 // Handle outgoing packets, resends, acknowledgements, and pings for each
796 // client. m_minTimeout will be set to 0 if more packets are waiting in the 759 // client. m_packetSent will be set to true if a packet is sent
797 // queues with bandwidth to spare, or the number of milliseconds we need to
798 // wait before at least one packet can be sent to a client
799 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler); 760 m_scene.ClientManager.ForEachSync(ClientOutgoingPacketHandler);
800 761
801 // Can't wait for a negative amount of time, and put a 100ms ceiling on our 762 // If a packet was sent, only do a minimum length context switch to allow
802 // maximum wait time 763 // other parts of the code to do work. If nothing was sent, sleep for the
803 m_minTimeout = Utils.Clamp(m_minTimeout, 0, 100); 764 // minimum amount of time before a token bucket could get more tokens
804 765 if (m_packetSent)
805 if (m_minTimeout > 0) 766 Thread.Sleep(0);
806 { 767 else
807 // Don't bother waiting for a shorter interval than our TickCountResolution 768 Thread.Sleep((int)TickCountResolution);
808 // since the token buckets wouldn't update anyways
809 m_minTimeout = Math.Max(m_minTimeout, (int)TickCountResolution);
810
811 // Wait for someone to signal that packets are ready to be sent, or for our
812 // sleep interval to expire
813 m_outgoingWaitHandle.WaitOne(m_minTimeout);
814 }
815 } 769 }
816 catch (Exception ex) 770 catch (Exception ex)
817 { 771 {
@@ -841,7 +795,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
841 if (udpClient.ElapsedMSOutgoingPacketHandler >= 100) 795 if (udpClient.ElapsedMSOutgoingPacketHandler >= 100)
842 { 796 {
843 ResendUnacked(udpClient); 797 ResendUnacked(udpClient);
844 udpClient.ElapsedMSOutgoingPacketHandler -= 100; 798 udpClient.ElapsedMSOutgoingPacketHandler = 0;
845 udpClient.Elapsed100MSOutgoingPacketHandler += 1; 799 udpClient.Elapsed100MSOutgoingPacketHandler += 1;
846 } 800 }
847 801
@@ -849,7 +803,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
849 if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5) 803 if (udpClient.Elapsed100MSOutgoingPacketHandler >= 5)
850 { 804 {
851 SendAcks(udpClient); 805 SendAcks(udpClient);
852 udpClient.Elapsed100MSOutgoingPacketHandler -= 5; 806 udpClient.Elapsed100MSOutgoingPacketHandler = 0;
853 udpClient.Elapsed500MSOutgoingPacketHandler += 1; 807 udpClient.Elapsed500MSOutgoingPacketHandler += 1;
854 } 808 }
855 809
@@ -857,19 +811,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
857 if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10) 811 if (udpClient.Elapsed500MSOutgoingPacketHandler >= 10)
858 { 812 {
859 SendPing(udpClient); 813 SendPing(udpClient);
860 udpClient.Elapsed500MSOutgoingPacketHandler -= 10; 814 udpClient.Elapsed500MSOutgoingPacketHandler = 0;
861 } 815 }
862 816
863 // Dequeue any outgoing packets that are within the throttle limits 817 // Dequeue any outgoing packets that are within the throttle limits
864 // and get the minimum time we would have to sleep before this client 818 if (udpClient.DequeueOutgoing())
865 // could send a packet out 819 m_packetSent = true;
866 int minTimeoutThisLoop = udpClient.DequeueOutgoing();
867
868 // Although this is not thread safe, it is cheaper than locking and the
869 // worst that will happen is we sleep for slightly longer than the
870 // minimum necessary interval
871 if (minTimeoutThisLoop < m_minTimeout)
872 m_minTimeout = minTimeoutThisLoop;
873 } 820 }
874 821
875 udpClient.TickLastOutgoingPacketHandler = thisTick; 822 udpClient.TickLastOutgoingPacketHandler = thisTick;