示例#1
0
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="server">Reference to the UDP server this client is connected to</param>
        /// <param name="rates">Default throttling rates and maximum throttle limits</param>
        /// <param name="parentThrottle">Parent HTB (hierarchical token bucket)
        /// that the child throttles will be governed by</param>
        /// <param name="circuitCode">Circuit code for this connection</param>
        /// <param name="agentID">AgentID for the connected agent</param>
        /// <param name="remoteEndPoint">Remote endpoint for this connection</param>
        /// <param name="defaultRTO">
        /// Default retransmission timeout for unacked packets.  The RTO will never drop
        /// beyond this number.
        /// </param>
        /// <param name="maxRTO">
        /// The maximum retransmission timeout for unacked packets.  The RTO will never exceed this number.
        /// </param>
        public LLUDPClient(
            LLUDPServer server, ThrottleRates rates, TokenBucket parentThrottle, uint circuitCode, UUID agentID,
            IPEndPoint remoteEndPoint, int defaultRTO, int maxRTO)
        {
            AgentID        = agentID;
            RemoteEndPoint = remoteEndPoint;
            CircuitCode    = circuitCode;
            m_udpServer    = server;
            if (defaultRTO != 0)
            {
                m_defaultRTO = defaultRTO;
            }
            if (maxRTO != 0)
            {
                m_maxRTO = maxRTO;
            }

            m_burstTime = rates.BrustTime;
            float m_burst = rates.ClientMaxRate * m_burstTime;

            // Create a token bucket throttle for this client that has the scene token bucket as a parent
            m_throttleClient = new AdaptiveTokenBucket(parentThrottle, rates.ClientMaxRate, m_burst, rates.AdaptiveThrottlesEnabled);

            // Create an array of token buckets for this clients different throttle categories
            m_throttleCategories = new TokenBucket[THROTTLE_CATEGORY_COUNT];

            m_burst = rates.Total * rates.BrustTime;

            for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
            {
                ThrottleOutPacketType type = (ThrottleOutPacketType)i;

                // Initialize the packet outboxes, where packets sit while they are waiting for tokens
                m_packetOutboxes[i] = new DoubleLocklessQueue <OutgoingPacket>();
                // Initialize the token buckets that control the throttling for each category
                //m_throttleCategories[i] = new TokenBucket(m_throttleClient, rates.GetRate(type), m_burst);
                float rate  = rates.GetRate(type);
                float burst = rate * rates.BrustTime;
                m_throttleCategories[i] = new TokenBucket(m_throttleClient, rate, burst);
            }

            // Default the retransmission timeout to one second
            m_RTO = m_defaultRTO;

            // Initialize this to a sane value to prevent early disconnects
            TickLastPacketReceived = Environment.TickCount & Int32.MaxValue;
            m_pingMS = (int)(3.0 * server.TickCountResolution); // so filter doesnt start at 0;
        }
示例#2
0
        /// <summary>
        /// Queue an outgoing packet if appropriate.
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="forceQueue">Always queue the packet if at all possible.</param>
        /// <returns>
        /// true if the packet has been queued,
        /// false if the packet has not been queued and should be sent immediately.
        /// </returns>
        public bool EnqueueOutgoing(OutgoingPacket packet)
        {
            int category = (int)packet.Category;

            if (category >= 0 && category < m_packetOutboxes.Length)
            {
                DoubleLocklessQueue <OutgoingPacket> queue = m_packetOutboxes[category];
                queue.Enqueue(packet, false);
                return(true);
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return(false);
            }
        }
示例#3
0
        public bool EnqueueOutgoing(OutgoingPacket packet, bool forceQueue, bool highPriority)
        {
            int category = (int)packet.Category;

            if (category >= 0 && category < m_packetOutboxes.Length)
            {
                DoubleLocklessQueue <OutgoingPacket> queue = m_packetOutboxes[category];

                if (m_deliverPackets == false)
                {
                    queue.Enqueue(packet, highPriority);
                    return(true);
                }

                TokenBucket bucket = m_throttleCategories[category];

                // Don't send this packet if queue is not empty
                if (queue.Count > 0 || m_nextPackets[category] != null)
                {
                    queue.Enqueue(packet, highPriority);
                    return(true);
                }

                if (!forceQueue && bucket.CheckTokens(packet.Buffer.DataLength))
                {
                    // enough tokens so it can be sent imediatly by caller
                    bucket.RemoveTokens(packet.Buffer.DataLength);
                    return(false);
                }
                else
                {
                    // Force queue specified or not enough tokens in the bucket, queue this packet
                    queue.Enqueue(packet, highPriority);
                    return(true);
                }
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return(false);
            }
        }
示例#4
0
        /// <summary>
        /// Loops through all of the packet queues for this client and tries to send
        /// an outgoing packet from each, obeying the throttling bucket limits
        /// </summary>
        ///
        /// <remarks>
        /// Packet queues are inspected in ascending numerical order starting from 0.  Therefore, queues with a lower
        /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have
        /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the
        /// wind queue).
        ///
        /// This function is only called from a synchronous loop in the
        /// UDPServer so we don't need to bother making this thread safe
        /// </remarks>
        ///
        /// <returns>True if any packets were sent, otherwise false</returns>
        public bool DequeueOutgoing()
        {
//            if (m_deliverPackets == false) return false;

            OutgoingPacket packet = null;
            DoubleLocklessQueue <OutgoingPacket> queue;
            bool packetSent = false;
            ThrottleOutPacketTypeFlags emptyCategories = 0;

            //string queueDebugOutput = String.Empty; // Serious debug business
            // do resends

            packet = m_nextPackets[0];
            if (packet != null)
            {
                if (packet.Buffer != null)
                {
                    if (m_throttleCategories[0].RemoveTokens(packet.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal(packet);
                        packetSent       = true;
                        m_nextPackets[0] = null;
                    }
                }
                else
                {
                    m_nextPackets[0] = null;
                }
            }
            else
            {
                queue = m_packetOutboxes[0];
                if (queue != null)
                {
                    if (queue.Dequeue(out packet))
                    {
                        // A packet was pulled off the queue. See if we have
                        // enough tokens in the bucket to send it out
                        if (packet.Buffer != null)
                        {
                            if (m_throttleCategories[0].RemoveTokens(packet.Buffer.DataLength))
                            {
                                // Send the packet
                                m_udpServer.SendPacketFinal(packet);
                                packetSent = true;
                            }
                            else
                            {
                                // Save the dequeued packet for the next iteration
                                m_nextPackets[0] = packet;
                            }
                        }
                    }
                }
                else
                {
                    m_packetOutboxes[0] = new DoubleLocklessQueue <OutgoingPacket>();
                }
            }

            if (NeedAcks.Count() > 50)
            {
                Interlocked.Increment(ref AckStalls);
                return(true);
            }

            for (int i = 1; i < THROTTLE_CATEGORY_COUNT; i++)
            {
                //queueDebugOutput += m_packetOutboxes[i].Count + " ";  // Serious debug business

                packet = m_nextPackets[i];
                if (packet != null)
                {
                    if (packet.Buffer == null)
                    {
                        if (m_packetOutboxes[i].Count < 5)
                        {
                            emptyCategories |= CategoryToFlag(i);
                        }
                        m_nextPackets[i] = null;
                        continue;
                    }

                    if (m_throttleCategories[i].RemoveTokens(packet.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal(packet);
                        m_nextPackets[i] = null;
                        packetSent       = true;

                        if (m_packetOutboxes[i].Count < 5)
                        {
                            emptyCategories |= CategoryToFlag(i);
                        }
                    }
                }
                else
                {
                    // No dequeued packet waiting to be sent, try to pull one off
                    // this queue
                    queue = m_packetOutboxes[i];
                    if (queue.Dequeue(out packet))
                    {
                        if (packet.Buffer == null)
                        {
                            // packet canceled elsewhere (by a ack for example)
                            if (queue.Count < 5)
                            {
                                emptyCategories |= CategoryToFlag(i);
                            }
                            continue;
                        }

                        if (m_throttleCategories[i].RemoveTokens(packet.Buffer.DataLength))
                        {
                            // Send the packet
                            m_udpServer.SendPacketFinal(packet);
                            packetSent = true;
                            if (queue.Count < 5)
                            {
                                emptyCategories |= CategoryToFlag(i);
                            }
                        }
                        else
                        {
                            // Save the dequeued packet for the next iteration
                            m_nextPackets[i] = packet;
                        }
                    }
                    else
                    {
                        // No packets in this queue. Fire the queue empty callback
                        // if it has not been called recently
                        emptyCategories |= CategoryToFlag(i);
                    }
                }
            }

            if (emptyCategories != 0)
            {
                BeginFireQueueEmpty(emptyCategories);
            }

            //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
            return(packetSent);
        }
示例#5
0
        /// <summary>
        /// Loops through all of the packet queues for this client and tries to send
        /// an outgoing packet from each, obeying the throttling bucket limits
        /// </summary>
        ///
        /// <remarks>
        /// Packet queues are inspected in ascending numerical order starting from 0.  Therefore, queues with a lower
        /// ThrottleOutPacketType number will see their packet get sent first (e.g. if both Land and Wind queues have
        /// packets, then the packet at the front of the Land queue will be sent before the packet at the front of the
        /// wind queue).
        ///
        /// This function is only called from a synchronous loop in the
        /// UDPServer so we don't need to bother making this thread safe
        /// </remarks>
        ///
        /// <returns>True if any packets were sent, otherwise false</returns>
        public bool DequeueOutgoing()
        {
//            if (m_deliverPackets == false) return false;

            OutgoingPacket packet = null;
            DoubleLocklessQueue <OutgoingPacket> queue;
            TokenBucket bucket;
            bool        packetSent = false;
            ThrottleOutPacketTypeFlags emptyCategories = 0;

            //string queueDebugOutput = String.Empty; // Serious debug business

            for (int i = 0; i < THROTTLE_CATEGORY_COUNT; i++)
            {
                bucket = m_throttleCategories[i];
                //queueDebugOutput += m_packetOutboxes[i].Count + " ";  // Serious debug business

                if (m_nextPackets[i] != null)
                {
                    // This bucket was empty the last time we tried to send a packet,
                    // leaving a dequeued packet still waiting to be sent out. Try to
                    // send it again
                    OutgoingPacket nextPacket = m_nextPackets[i];
                    if (bucket.RemoveTokens(nextPacket.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal(nextPacket);
                        m_nextPackets[i] = null;
                        packetSent       = true;

                        if (m_packetOutboxes[i].Count < 5)
                        {
                            emptyCategories |= CategoryToFlag(i);
                        }
                    }
                }
                else
                {
                    // No dequeued packet waiting to be sent, try to pull one off
                    // this queue
                    queue = m_packetOutboxes[i];
                    if (queue != null)
                    {
                        bool success = false;
                        try
                        {
                            success = queue.Dequeue(out packet);
                        }
                        catch
                        {
                            m_packetOutboxes[i] = new DoubleLocklessQueue <OutgoingPacket>();
                        }
                        if (success)
                        {
                            // A packet was pulled off the queue. See if we have
                            // enough tokens in the bucket to send it out
                            if (bucket.RemoveTokens(packet.Buffer.DataLength))
                            {
                                // Send the packet
                                m_udpServer.SendPacketFinal(packet);
                                packetSent = true;

                                if (queue.Count < 5)
                                {
                                    emptyCategories |= CategoryToFlag(i);
                                }
                            }
                            else
                            {
                                // Save the dequeued packet for the next iteration
                                m_nextPackets[i] = packet;
                            }
                        }
                        else
                        {
                            // No packets in this queue. Fire the queue empty callback
                            // if it has not been called recently
                            emptyCategories |= CategoryToFlag(i);
                        }
                    }
                    else
                    {
                        m_packetOutboxes[i] = new DoubleLocklessQueue <OutgoingPacket>();
                        emptyCategories    |= CategoryToFlag(i);
                    }
                }
            }

            if (emptyCategories != 0)
            {
                BeginFireQueueEmpty(emptyCategories);
            }

            //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
            return(packetSent);
        }