aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs')
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs175
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 }