diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | 115 |
1 files changed, 90 insertions, 25 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs index 202cc62..d52ad7e 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs | |||
@@ -95,7 +95,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
95 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> | 95 | /// <summary>Packets we have sent that need to be ACKed by the client</summary> |
96 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); | 96 | public readonly UnackedPacketCollection NeedAcks = new UnackedPacketCollection(); |
97 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> | 97 | /// <summary>ACKs that are queued up, waiting to be sent to the client</summary> |
98 | public readonly OpenSim.Framework.LocklessQueue<uint> PendingAcks = new OpenSim.Framework.LocklessQueue<uint>(); | 98 | public readonly DoubleLocklessQueue<uint> PendingAcks = new DoubleLocklessQueue<uint>(); |
99 | 99 | ||
100 | /// <summary>Current packet sequence number</summary> | 100 | /// <summary>Current packet sequence number</summary> |
101 | public int CurrentSequence; | 101 | public int CurrentSequence; |
@@ -149,7 +149,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
149 | /// <summary>Throttle buckets for each packet category</summary> | 149 | /// <summary>Throttle buckets for each packet category</summary> |
150 | private readonly TokenBucket[] m_throttleCategories; | 150 | private readonly TokenBucket[] m_throttleCategories; |
151 | /// <summary>Outgoing queues for throttled packets</summary> | 151 | /// <summary>Outgoing queues for throttled packets</summary> |
152 | private readonly OpenSim.Framework.LocklessQueue<OutgoingPacket>[] m_packetOutboxes = new OpenSim.Framework.LocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; | 152 | private readonly DoubleLocklessQueue<OutgoingPacket>[] m_packetOutboxes = new DoubleLocklessQueue<OutgoingPacket>[THROTTLE_CATEGORY_COUNT]; |
153 | /// <summary>A container that can hold one packet for each outbox, used to store | 153 | /// <summary>A container that can hold one packet for each outbox, used to store |
154 | /// dequeued packets that are being held for throttling</summary> | 154 | /// dequeued packets that are being held for throttling</summary> |
155 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; | 155 | private readonly OutgoingPacket[] m_nextPackets = new OutgoingPacket[THROTTLE_CATEGORY_COUNT]; |
@@ -161,6 +161,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
161 | 161 | ||
162 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC | 162 | private int m_defaultRTO = 1000; // 1sec is the recommendation in the RFC |
163 | private int m_maxRTO = 60000; | 163 | private int m_maxRTO = 60000; |
164 | public bool m_deliverPackets = true; | ||
164 | 165 | ||
165 | private ClientInfo m_info = new ClientInfo(); | 166 | private ClientInfo m_info = new ClientInfo(); |
166 | 167 | ||
@@ -206,7 +207,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
206 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; | 207 | ThrottleOutPacketType type = (ThrottleOutPacketType)i; |
207 | 208 | ||
208 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens | 209 | // Initialize the packet outboxes, where packets sit while they are waiting for tokens |
209 | m_packetOutboxes[i] = new OpenSim.Framework.LocklessQueue<OutgoingPacket>(); | 210 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
210 | // Initialize the token buckets that control the throttling for each category | 211 | // Initialize the token buckets that control the throttling for each category |
211 | m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); | 212 | m_throttleCategories[i] = new TokenBucket(m_throttleCategory, rates.GetRate(type)); |
212 | } | 213 | } |
@@ -431,11 +432,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
431 | /// </returns> | 432 | /// </returns> |
432 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) | 433 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue) |
433 | { | 434 | { |
435 | return EnqueueOutgoing(packet, forceQueue, false); | ||
436 | } | ||
437 | |||
438 | public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority) | ||
439 | { | ||
434 | int category = (int)packet.Category; | 440 | int category = (int)packet.Category; |
435 | 441 | ||
436 | if (category >= 0 && category < m_packetOutboxes.Length) | 442 | if (category >= 0 && category < m_packetOutboxes.Length) |
437 | { | 443 | { |
438 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; | 444 | DoubleLocklessQueue<OutgoingPacket> queue = m_packetOutboxes[category]; |
445 | |||
446 | if (m_deliverPackets == false) | ||
447 | { | ||
448 | queue.Enqueue(packet, highPriority); | ||
449 | return true; | ||
450 | } | ||
451 | |||
439 | TokenBucket bucket = m_throttleCategories[category]; | 452 | TokenBucket bucket = m_throttleCategories[category]; |
440 | 453 | ||
441 | // Don't send this packet if there is already a packet waiting in the queue | 454 | // Don't send this packet if there is already a packet waiting in the queue |
@@ -443,7 +456,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
443 | // queued packets | 456 | // queued packets |
444 | if (queue.Count > 0) | 457 | if (queue.Count > 0) |
445 | { | 458 | { |
446 | queue.Enqueue(packet); | 459 | queue.Enqueue(packet, highPriority); |
447 | return true; | 460 | return true; |
448 | } | 461 | } |
449 | 462 | ||
@@ -456,7 +469,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
456 | else | 469 | else |
457 | { | 470 | { |
458 | // Force queue specified or not enough tokens in the bucket, queue this packet | 471 | // Force queue specified or not enough tokens in the bucket, queue this packet |
459 | queue.Enqueue(packet); | 472 | queue.Enqueue(packet, highPriority); |
460 | return true; | 473 | return true; |
461 | } | 474 | } |
462 | } | 475 | } |
@@ -485,8 +498,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
485 | /// <returns>True if any packets were sent, otherwise false</returns> | 498 | /// <returns>True if any packets were sent, otherwise false</returns> |
486 | public bool DequeueOutgoing() | 499 | public bool DequeueOutgoing() |
487 | { | 500 | { |
488 | OutgoingPacket packet; | 501 | if (m_deliverPackets == false) return false; |
489 | OpenSim.Framework.LocklessQueue<OutgoingPacket> queue; | 502 | |
503 | OutgoingPacket packet = null; | ||
504 | DoubleLocklessQueue<OutgoingPacket> queue; | ||
490 | TokenBucket bucket; | 505 | TokenBucket bucket; |
491 | bool packetSent = false; | 506 | bool packetSent = false; |
492 | ThrottleOutPacketTypeFlags emptyCategories = 0; | 507 | ThrottleOutPacketTypeFlags emptyCategories = 0; |
@@ -517,32 +532,49 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
517 | // No dequeued packet waiting to be sent, try to pull one off | 532 | // No dequeued packet waiting to be sent, try to pull one off |
518 | // this queue | 533 | // this queue |
519 | queue = m_packetOutboxes[i]; | 534 | queue = m_packetOutboxes[i]; |
520 | if (queue.Dequeue(out packet)) | 535 | if (queue != null) |
521 | { | 536 | { |
522 | // A packet was pulled off the queue. See if we have | 537 | bool success = false; |
523 | // enough tokens in the bucket to send it out | 538 | try |
524 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) | ||
525 | { | 539 | { |
526 | // Send the packet | 540 | success = queue.Dequeue(out packet); |
527 | m_udpServer.SendPacketFinal(packet); | ||
528 | packetSent = true; | ||
529 | } | 541 | } |
530 | else | 542 | catch |
531 | { | 543 | { |
532 | // Save the dequeued packet for the next iteration | 544 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
533 | m_nextPackets[i] = packet; | ||
534 | } | 545 | } |
535 | 546 | if (success) | |
536 | // If the queue is empty after this dequeue, fire the queue | 547 | { |
537 | // empty callback now so it has a chance to fill before we | 548 | // A packet was pulled off the queue. See if we have |
538 | // get back here | 549 | // enough tokens in the bucket to send it out |
539 | if (queue.Count == 0) | 550 | if (bucket.RemoveTokens(packet.Buffer.DataLength)) |
551 | { | ||
552 | // Send the packet | ||
553 | m_udpServer.SendPacketFinal(packet); | ||
554 | packetSent = true; | ||
555 | } | ||
556 | else | ||
557 | { | ||
558 | // Save the dequeued packet for the next iteration | ||
559 | m_nextPackets[i] = packet; | ||
560 | } | ||
561 | |||
562 | // If the queue is empty after this dequeue, fire the queue | ||
563 | // empty callback now so it has a chance to fill before we | ||
564 | // get back here | ||
565 | if (queue.Count == 0) | ||
566 | emptyCategories |= CategoryToFlag(i); | ||
567 | } | ||
568 | else | ||
569 | { | ||
570 | // No packets in this queue. Fire the queue empty callback | ||
571 | // if it has not been called recently | ||
540 | emptyCategories |= CategoryToFlag(i); | 572 | emptyCategories |= CategoryToFlag(i); |
573 | } | ||
541 | } | 574 | } |
542 | else | 575 | else |
543 | { | 576 | { |
544 | // No packets in this queue. Fire the queue empty callback | 577 | m_packetOutboxes[i] = new DoubleLocklessQueue<OutgoingPacket>(); |
545 | // if it has not been called recently | ||
546 | emptyCategories |= CategoryToFlag(i); | 578 | emptyCategories |= CategoryToFlag(i); |
547 | } | 579 | } |
548 | } | 580 | } |
@@ -683,6 +715,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
683 | 715 | ||
684 | m_isQueueEmptyRunning = false; | 716 | m_isQueueEmptyRunning = false; |
685 | } | 717 | } |
718 | internal void ForceThrottleSetting(int throttle, int setting) | ||
719 | { | ||
720 | m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ; | ||
721 | } | ||
686 | 722 | ||
687 | /// <summary> | 723 | /// <summary> |
688 | /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a | 724 | /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a |
@@ -727,4 +763,33 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
727 | } | 763 | } |
728 | } | 764 | } |
729 | } | 765 | } |
766 | |||
767 | public class DoubleLocklessQueue<T> : OpenSim.Framework.LocklessQueue<T> | ||
768 | { | ||
769 | OpenSim.Framework.LocklessQueue<T> highQueue = new OpenSim.Framework.LocklessQueue<T>(); | ||
770 | |||
771 | public override int Count | ||
772 | { | ||
773 | get | ||
774 | { | ||
775 | return base.Count + highQueue.Count; | ||
776 | } | ||
777 | } | ||
778 | |||
779 | public override bool Dequeue(out T item) | ||
780 | { | ||
781 | if (highQueue.Dequeue(out item)) | ||
782 | return true; | ||
783 | |||
784 | return base.Dequeue(out item); | ||
785 | } | ||
786 | |||
787 | public void Enqueue(T item, bool highPriority) | ||
788 | { | ||
789 | if (highPriority) | ||
790 | highQueue.Enqueue(item); | ||
791 | else | ||
792 | Enqueue(item); | ||
793 | } | ||
794 | } | ||
730 | } | 795 | } |