diff options
Diffstat (limited to '')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs | 143 |
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; |