Пример #1
0
        public bool EnqueueOutgoing(OutgoingPacket packet)
        {
            int category = (int)packet.Category;

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

                // Not enough tokens in the bucket, queue this packet

                //check the queue
                //Dont drop resends this can mess up the buffer pool as well as make the connection situation much worse
                if (_currentOutboundQueueSize > MAX_TOTAL_QUEUE_SIZE && (packet.Buffer[0] & Helpers.MSG_RESENT) == 0)
                {
                    //queue already has too much data in it..
                    //can we drop this packet?
                    byte flags = packet.Buffer[0];
                    bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;

                    if (!isReliable 
                        && packet.Type != PacketType.PacketAck
                        && packet.Type != PacketType.CompletePingCheck)
                    {
                        //packet is unreliable and will be dropped
                        this.TestReportPacketDrop(packet);
                        packet.DecRef(m_udpServer.ByteBufferPool);
                    }
                    else
                    {
                        if (_currentOutboundQueueSize < MAX_TOTAL_QUEUE_SIZE * 1.5)
                        {
                            this.TestReportPacketShouldDrop(packet);
                            Interlocked.Add(ref _currentOutboundQueueSize, packet.DataSize);
                            packet.AddRef();
                            queue.Enqueue(packet);
                        }
                        else
                        {
                            //this connection is in a pretty critical state and probably will never catch up.
                            //drop all packets until we start to catch up. This includes acks which will disconnect
                            //the client eventually anyways

                            this.TestReportCriticalPacketDrop(packet);
                            packet.DecRef(m_udpServer.ByteBufferPool);
                        }
                    }
                }
                else
                {
                    Interlocked.Add(ref _currentOutboundQueueSize, packet.DataSize);

                    packet.AddRef();
                    queue.Enqueue(packet);
                }

                return true;
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return false;
            }
        }
Пример #2
0
        public bool EnqueueOutgoing(OutgoingPacket packet)
        {
            int category = (int)packet.Category;

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

                // Not enough tokens in the bucket, queue this packet

                //check the queue
                //Dont drop resends this can mess up the buffer pool as well as make the connection situation much worse
                if (_currentOutboundQueueSize > MAX_TOTAL_QUEUE_SIZE && (packet.Buffer[0] & Helpers.MSG_RESENT) == 0)
                {
                    //queue already has too much data in it..
                    //can we drop this packet?
                    byte flags      = packet.Buffer[0];
                    bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;

                    if (!isReliable &&
                        packet.Type != PacketType.PacketAck &&
                        packet.Type != PacketType.CompletePingCheck)
                    {
                        //packet is unreliable and will be dropped
                        this.TestReportPacketDrop(packet);
                        packet.DecRef(m_udpServer.ByteBufferPool);
                    }
                    else
                    {
                        if (_currentOutboundQueueSize < MAX_TOTAL_QUEUE_SIZE * 1.5)
                        {
                            this.TestReportPacketShouldDrop(packet);
                            Interlocked.Add(ref _currentOutboundQueueSize, packet.DataSize);
                            packet.AddRef();
                            queue.Enqueue(packet);
                        }
                        else
                        {
                            //this connection is in a pretty critical state and probably will never catch up.
                            //drop all packets until we start to catch up. This includes acks which will disconnect
                            //the client eventually anyways

                            this.TestReportCriticalPacketDrop(packet);
                            packet.DecRef(m_udpServer.ByteBufferPool);
                        }
                    }
                }
                else
                {
                    Interlocked.Add(ref _currentOutboundQueueSize, packet.DataSize);

                    packet.AddRef();
                    queue.Enqueue(packet);
                }

                return(true);
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return(false);
            }
        }
Пример #3
0
        /// <summary>
        /// Loops through all of the packet queues for this client and tries to send
        /// any outgoing packets, obeying the throttling bucket limits
        /// </summary>
        /// <remarks>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()
        {
            OutgoingPacket packet;

            OpenSim.Framework.LocklessQueue <OutgoingPacket> queue;
            TokenBucket bucket;
            bool        packetSent = false;
            ThrottleOutPacketTypeFlags emptyCategories = 0;

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

            int randStart = _rand.Next(7);

            for (int j = 0; j < THROTTLE_CATEGORY_COUNT; j++)
            {
                int i = (j + randStart) % THROTTLE_CATEGORY_COUNT;

                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.DataSize))
                    {
                        // Send the packet
                        Interlocked.Add(ref _currentOutboundQueueSize, -nextPacket.DataSize);
                        m_udpServer.SendPacketFinal(nextPacket);
                        nextPacket.DecRef(m_udpServer.ByteBufferPool);
                        m_nextPackets[i] = null;
                        packetSent       = true;
                        this.PacketsSent++;
                    }
                }
                else
                {
                    // No dequeued packet waiting to be sent, try to pull one off
                    // this queue
                    queue = m_packetOutboxes[i];
                    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 (bucket.RemoveTokens(packet.DataSize))
                        {
                            // Send the packet
                            Interlocked.Add(ref _currentOutboundQueueSize, -packet.DataSize);
                            m_udpServer.SendPacketFinal(packet);
                            packet.DecRef(m_udpServer.ByteBufferPool);
                            packetSent = true;
                            this.PacketsSent++;
                        }
                        else
                        {
                            // Save the dequeued packet for the next iteration
                            m_nextPackets[i] = packet;
                            _emptyBucketHints.Add(i);
                        }

                        // If the queue is empty after this dequeue, fire the queue
                        // empty callback now so it has a chance to fill before we
                        // get back here
                        if (queue.Count == 0)
                        {
                            emptyCategories |= CategoryToFlag(i);
                        }
                    }
                    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);
        }
Пример #4
0
 protected override void SendCompleted(OutgoingPacket packet)
 {
     packet.DecRef(_bufferPool);
 }