diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 175 |
1 files changed, 91 insertions, 84 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 69e53f6..af62d9c 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -115,7 +115,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
115 | /// <summary>Circuit code that this client is connected on</summary> | 115 | /// <summary>Circuit code that this client is connected on</summary> |
116 | public readonly uint CircuitCode; | 116 | public readonly uint CircuitCode; |
117 | /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> | 117 | /// <summary>Sequence numbers of packets we've received (for duplicate checking)</summary> |
118 | public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(256); | 118 | public IncomingPacketHistoryCollection PacketArchive = new IncomingPacketHistoryCollection(1024); |
119 | 119 | ||
120 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | 120 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> |
121 | public UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | 121 | public UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); |
@@ -123,6 +123,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
123 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 123 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
124 | public DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>(); | 124 | public DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>(); |
125 | 125 | ||
126 | public int AckStalls; | ||
127 | |||
126 | /// <summary>Current packet sequence number</summary> | 128 | /// <summary>Current packet sequence number</summary> |
127 | public int CurrentSequence; | 129 | public int CurrentSequence; |
128 | /// <summary>Current ping sequence number</summary> | 130 | /// <summary>Current ping sequence number</summary> |
@@ -185,7 +187,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
185 | private byte[] m_packedThrottles; | 187 | private byte[] m_packedThrottles; |
186 | 188 | ||
187 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC | 189 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC |
188 | private int m_maxRTO = 10000; | 190 | private int m_maxRTO = 3000; |
191 | private int m_minRTO = 250; | ||
189 | public bool m_deliverPackets = true; | 192 | public bool m_deliverPackets = true; |
190 | 193 | ||
191 | private float m_burstTime; | 194 | private float m_burstTime; |
@@ -538,46 +541,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
538 | /// true if the packet has been queued, | 541 | /// true if the packet has been queued, |
539 | /// false if the packet has not been queued and should be sent immediately. | 542 | /// false if the packet has not been queued and should be sent immediately. |
540 | /// </returns> | 543 | /// </returns> |
541 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) | 544 | public bool EnqueueOutgoing(OutgoingPacket packet) |
542 | { | 545 | { |
543 | return EnqueueOutgoing(packet, forceQueue, false); | 546 | return EnqueueOutgoing(packet, false); |
544 | } | 547 | } |
545 | 548 | ||
546 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority) | 549 | public bool EnqueueOutgoing(OutgoingPacket packet, bool highPriority) |
547 | { | 550 | { |
548 | int category = (int)packet.Category; | 551 | int category = (int)packet.Category; |
549 | 552 | ||
550 | if (category >= 0 && category < m_packetOutboxes.Length) | 553 | if (category >= 0 && category < m_packetOutboxes.Length) |
551 | { | 554 | { |
552 | DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; | 555 | DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
553 | 556 | queue.Enqueue(packet, highPriority); | |
554 | if (forceQueue || m_deliverPackets == false) | 557 | return true; |
555 | { | ||
556 | queue.Enqueue(packet, highPriority); | ||
557 | return true; | ||
558 | } | ||
559 | |||
560 | // need to enqueue if queue is not empty | ||
561 | if (queue.Count > 0 || m_nextPackets[category] != null) | ||
562 | { | ||
563 | queue.Enqueue(packet, highPriority); | ||
564 | return true; | ||
565 | } | ||
566 | |||
567 | // check bandwidth | ||
568 | TokenBucket bucket = m_throttleCategories[category]; | ||
569 | if (bucket.CheckTokens(packet.Buffer.DataLength)) | ||
570 | { | ||
571 | // enough tokens so it can be sent imediatly by caller | ||
572 | bucket.RemoveTokens(packet.Buffer.DataLength); | ||
573 | return false; | ||
574 | } | ||
575 | else | ||
576 | { | ||
577 | // Force queue specified or not enough tokens in the bucket, queue this packet | ||
578 | queue.Enqueue(packet, highPriority); | ||
579 | return true; | ||
580 | } | ||
581 | } | 558 | } |
582 | else | 559 | else |
583 | { | 560 | { |
@@ -608,33 +585,84 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
608 | 585 | ||
609 | OutgoingPacket packet = null; | 586 | OutgoingPacket packet = null; |
610 | DoubleLocklessQueue<OutgoingPacket> queue; | 587 | DoubleLocklessQueue<OutgoingPacket> queue; |
611 | TokenBucket bucket; | ||
612 | bool packetSent = false; | 588 | bool packetSent = false; |
613 | ThrottleOutPacketTypeFlags emptyCategories = 0; | 589 | ThrottleOutPacketTypeFlags emptyCategories = 0; |
614 | 590 | ||
615 | //string queueDebugOutput = String.Empty; // Serious debug business | 591 | //string queueDebugOutput = String.Empty; // Serious debug business |
592 | // do resends | ||
616 | 593 | ||
617 | for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++) | 594 | packet = m_nextPackets[0]; |
595 | if (packet != null) | ||
596 | { | ||
597 | if (packet.Buffer != null) | ||
598 | { | ||
599 | if (m_throttleCategories[0].RemoveTokens(packet.Buffer.DataLength)) | ||
600 | { | ||
601 | // Send the packet | ||
602 | m_udpServer.SendPacketFinal(packet); | ||
603 | packetSent = true; | ||
604 | m_nextPackets[0] = null; | ||
605 | } | ||
606 | } | ||
607 | else | ||
608 | m_nextPackets[0] = null; | ||
609 | } | ||
610 | else | ||
611 | { | ||
612 | queue = m_packetOutboxes[0]; | ||
613 | if (queue != null) | ||
614 | { | ||
615 | if(queue.Dequeue(out packet)) | ||
616 | { | ||
617 | // A packet was pulled off the queue. See if we have | ||
618 | // enough tokens in the bucket to send it out | ||
619 | if (packet.Buffer != null) | ||
620 | { | ||
621 | if (m_throttleCategories[0].RemoveTokens(packet.Buffer.DataLength)) | ||
622 | { | ||
623 | // Send the packet | ||
624 | m_udpServer.SendPacketFinal(packet); | ||
625 | packetSent = true; | ||
626 | } | ||
627 | else | ||
628 | { | ||
629 | // Save the dequeued packet for the next iteration | ||
630 | m_nextPackets[0] = packet; | ||
631 | } | ||
632 | } | ||
633 | } | ||
634 | } | ||
635 | else | ||
636 | { | ||
637 | m_packetOutboxes[0] = new DoubleLocklessQueue<OutgoingPacket>(); | ||
638 | } | ||
639 | } | ||
640 | |||
641 | if(NeedAcks.Count() > 50) | ||
642 | { | ||
643 | Interlocked.Increment(ref AckStalls); | ||
644 | return true; | ||
645 | } | ||
646 | |||
647 | for (int i = 1; i < THROTTLE_CATEGORY_COUNT; i++) | ||
618 | { | 648 | { |
619 | bucket = m_throttleCategories[i]; | ||
620 | //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business | 649 | //queueDebugOutput += m_packetOutboxes[i].Count + " "; // Serious debug business |
621 | 650 | ||
622 | if (m_nextPackets[i] != null) | 651 | packet = m_nextPackets[i]; |
652 | if (packet != null) | ||
623 | { | 653 | { |
624 | // This bucket was empty the last time we tried to send a packet, | 654 | if(packet.Buffer == null) |
625 | // leaving a dequeued packet still waiting to be sent out. Try to | ||
626 | // send it again | ||
627 | OutgoingPacket nextPacket = m_nextPackets[i]; | ||
628 | if(nextPacket.Buffer == null) | ||
629 | { | 655 | { |
630 | if (m_packetOutboxes[i].Count < 5) | 656 | if (m_packetOutboxes[i].Count < 5) |
631 | emptyCategories |= CategoryToFlag(i); | 657 | emptyCategories |= CategoryToFlag(i); |
658 | m_nextPackets[i] = null; | ||
632 | continue; | 659 | continue; |
633 | } | 660 | } |
634 | if (bucket.RemoveTokens(nextPacket.Buffer.DataLength)) | 661 | |
662 | if (m_throttleCategories[i].RemoveTokens(packet.Buffer.DataLength)) | ||
635 | { | 663 | { |
636 | // Send the packet | 664 | // Send the packet |
637 | m_udpServer.SendPacketFinal(nextPacket); | 665 | m_udpServer.SendPacketFinal(packet); |
638 | m_nextPackets[i] = null; | 666 | m_nextPackets[i] = null; |
639 | packetSent = true; | 667 | packetSent = true; |
640 | 668 | ||
@@ -647,55 +675,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
647 | // No dequeued packet waiting to be sent, try to pull one off | 675 | // No dequeued packet waiting to be sent, try to pull one off |
648 | // this queue | 676 | // this queue |
649 | queue = m_packetOutboxes[i]; | 677 | queue = m_packetOutboxes[i]; |
650 | if (queue != null) | 678 | if(queue.Dequeue(out packet)) |
651 | { | 679 | { |
652 | bool success = false; | 680 | if (packet.Buffer == null) |
653 | try | ||
654 | { | ||
655 | success = queue.Dequeue(out packet); | ||
656 | } | ||
657 | catch | ||
658 | { | 681 | { |
659 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); | 682 | // packet canceled elsewhere (by a ack for example) |
683 | if (queue.Count < 5) | ||
684 | emptyCategories |= CategoryToFlag(i); | ||
685 | continue; | ||
660 | } | 686 | } |
661 | if (success) | 687 | |
688 | if (m_throttleCategories[i].RemoveTokens(packet.Buffer.DataLength)) | ||
662 | { | 689 | { |
663 | // A packet was pulled off the queue. See if we have | 690 | // Send the packet |
664 | // enough tokens in the bucket to send it out | 691 | m_udpServer.SendPacketFinal(packet); |
665 | if(packet.Buffer == null) | 692 | packetSent = true; |
666 | { | 693 | if (queue.Count < 5) |
667 | // packet canceled elsewhere (by a ack for example) | 694 | emptyCategories |= CategoryToFlag(i); |
668 | if (queue.Count < 5) | ||
669 | emptyCategories |= CategoryToFlag(i); | ||
670 | } | ||
671 | else | ||
672 | { | ||
673 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
674 | { | ||
675 | // Send the packet | ||
676 | m_udpServer.SendPacketFinal(packet); | ||
677 | packetSent = true; | ||
678 | |||
679 | if (queue.Count < 5) | ||
680 | emptyCategories |= CategoryToFlag(i); | ||
681 | } | ||
682 | else | ||
683 | { | ||
684 | // Save the dequeued packet for the next iteration | ||
685 | m_nextPackets[i] = packet; | ||
686 | } | ||
687 | } | ||
688 | } | 695 | } |
689 | else | 696 | else |
690 | { | 697 | { |
691 | // No packets in this queue. Fire the queue empty callback | 698 | // Save the dequeued packet for the next iteration |
692 | // if it has not been called recently | 699 | m_nextPackets[i] = packet; |
693 | emptyCategories |= CategoryToFlag(i); | ||
694 | } | 700 | } |
695 | } | 701 | } |
696 | else | 702 | else |
697 | { | 703 | { |
698 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); | 704 | // No packets in this queue. Fire the queue empty callback |
705 | // if it has not been called recently | ||
699 | emptyCategories |= CategoryToFlag(i); | 706 | emptyCategories |= CategoryToFlag(i); |
700 | } | 707 | } |
701 | } | 708 | } |
@@ -718,8 +725,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
718 | p *= 5; | 725 | p *= 5; |
719 | if( p> m_maxRTO) | 726 | if( p> m_maxRTO) |
720 | p = m_maxRTO; | 727 | p = m_maxRTO; |
721 | else if(p < m_defaultRTO) | 728 | else if(p < m_minRTO) |
722 | p = m_defaultRTO; | 729 | p = m_minRTO; |
723 | 730 | ||
724 | m_RTO = p; | 731 | m_RTO = p; |
725 | } | 732 | } |