Holds a reference to the LLUDPClient this packet is destined for, along with the serialized packet data, sequence number (if this is a resend), number of times this packet has been resent, the time of the last resend, and the throttling category for this packet
コード例 #1
0
        public bool EnqueueOutgoing(OutgoingPacket packet)
        {
            int category = (int)packet.Category;

            if (category >= 0 && category < (int)ThrottleOutPacketType.Count)
            {
                //All packets are enqueued, except those that don't have a queue
                int prio = MapCatsToPriority[category];
                m_outbox.Enqueue(prio, packet);
                return(true);
            }
            // We don't have a token bucket for this category,
            //  so it will not be queued and sent immediately
            return(false);
        }
コード例 #2
0
        public bool Dequeue(out OutgoingPacket pack)
        {
            int i = nlevels;

            while (--i >= 0) // go down levels looking for data
            {
                object o;
                if (!queues[i].TryDequeue(out o))
                {
                    continue;
                }
                if (!(o is OutgoingPacket))
                {
                    continue;
                }
                pack = (OutgoingPacket)o;
                Interlocked.Decrement(ref Count);
                return(true);
                // else  do call to a function that will return the packet or whatever
            }

            pack = null;
            return(false);
        }
コード例 #3
0
        /// <summary>
        ///     tries to send queued packets
        /// </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(int MaxNPacks)
        {
            bool packetSent = false;

            for (int i = 0; i < MaxNPacks; i++)
            {
                OutgoingPacket packet;
                if (m_nextOutPacket != null)
                {
                    packet = m_nextOutPacket;
                    if (m_throttle.RemoveTokens(packet.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal(packet);
                        m_nextOutPacket = null;
                        packetSent = true;
                    }
                }

                // No dequeued packet waiting to be sent, try to pull one off
                // this queue
                else if (m_outbox.Dequeue(out packet))
                {
                    MainConsole.Instance.Format(Level.All, AgentID + " - " + packet.Packet.Type);
                    // A packet was pulled off the queue. See if we have
                    // enough tokens in the bucket to send it out
                    if (packet.Category == ThrottleOutPacketType.OutBand ||
                        m_throttle.RemoveTokens(packet.Buffer.DataLength))
                    {
                        packetSent = true;
                        //Send the packet
                        PacketsCounts[(int) packet.Category] += packet.Packet.Length;
                        m_udpServer.SendPacketFinal(packet);
                        PacketsSent++;
                    }
                    else
                    {
                        m_nextOutPacket = packet;
                        break;
                    }
                }
                else
                    break;
            }

            if (packetSent)
            {
                if (m_throttle.MaxBurst < TotalRateRequested)
                {
                    float tmp = m_throttle.MaxBurst*1.005f;
                    m_throttle.DripRate = (int) tmp;
                    m_throttle.MaxBurst = (int) tmp;
                }
            }

            if (m_nextOnQueueEmpty != 0 && Util.EnvironmentTickCountSubtract(m_nextOnQueueEmpty) >= 0)
            {
                // Use a value of 0 to signal that FireQueueEmpty is running
                m_nextOnQueueEmpty = 0;
                // Asynchronously run the callback
                int ptmp = m_outbox.queues[MapCatsToPriority[(int) ThrottleOutPacketType.Task]].Count;
                int atmp = m_outbox.queues[MapCatsToPriority[(int) ThrottleOutPacketType.AvatarInfo]].Count;
                int ttmp = m_outbox.queues[MapCatsToPriority[(int) ThrottleOutPacketType.Texture]].Count;
                int[] arg = {ptmp, atmp, ttmp};
                Util.FireAndForget(FireQueueEmpty, arg);
            }

            return packetSent;
        }
コード例 #4
0
        public bool EnqueueOutgoing(OutgoingPacket packet)
        {
            int category = (int) packet.Category;

            if (category >= 0 && category < (int) ThrottleOutPacketType.Count)
            {
                //All packets are enqueued, except those that don't have a queue
                int prio = MapCatsToPriority[category];
                m_outbox.Enqueue(prio, packet);
                return true;
            }

            // We don't have a token bucket for this category,
            //  so it will not be queued and sent immediately
            return false;
        }
コード例 #5
0
        public bool Dequeue(out OutgoingPacket pack)
        {
            int i = nlevels;

            while (--i >= 0) // go down levels looking for data
            {
                object o;
                if (!queues[i].TryDequeue(out o)) continue;
                if (!(o is OutgoingPacket)) continue;
                pack = (OutgoingPacket) o;
                Interlocked.Decrement(ref Count);
                return true;
                // else  do call to a function that will return the packet or whatever
            }

            pack = null;
            return false;
        }
コード例 #6
0
 /// <summary>
 ///     Add an unacked packet to the collection
 /// </summary>
 /// <param name="packet">Packet that is awaiting acknowledgement</param>
 /// <returns>
 ///     True if the packet was successfully added, false if the
 ///     packet already existed in the collection
 /// </returns>
 /// <remarks>
 ///     This does not immediately add the ACK to the collection,
 ///     it only queues it so it can be added in a thread-safe way later
 /// </remarks>
 public void Add(OutgoingPacket packet)
 {
     m_pendingAdds.Enqueue(packet);
 }
コード例 #7
0
        /// <summary>
        ///     Actually send a packet to a client.
        /// </summary>
        /// <param name="outgoingPacket"></param>
        internal void SendPacketFinal(OutgoingPacket outgoingPacket)
        {
            UDPPacketBuffer buffer = outgoingPacket.Buffer;
            byte flags = buffer.Data[0];
            bool isResend = (flags & Helpers.MSG_RESENT) != 0;
            bool isReliable = (flags & Helpers.MSG_RELIABLE) != 0;
            bool isZerocoded = (flags & Helpers.MSG_ZEROCODED) != 0;
            LLUDPClient udpClient = outgoingPacket.Client;

            if (!udpClient.IsConnected)
                return;

            #region ACK Appending

            int dataLength = buffer.DataLength;

            // NOTE: I'm seeing problems with some viewers when ACKs are appended to zerocoded packets so I've disabled that here
            if (!isZerocoded)
            {
                // Keep appending ACKs until there is no room left in the buffer or there are
                // no more ACKs to append
                uint ackCount = 0;
                uint ack;
                while (dataLength + 5 < buffer.Data.Length && udpClient.PendingAcks.TryDequeue(out ack))
                {
                    Utils.UIntToBytesBig(ack, buffer.Data, dataLength);
                    dataLength += 4;
                    ++ackCount;
                }

                if (ackCount > 0)
                {
                    // Set the last byte of the packet equal to the number of appended ACKs
                    buffer.Data[dataLength++] = (byte) ackCount;
                    // Set the appended ACKs flag on this packet
                    buffer.Data[0] = (byte) (buffer.Data[0] | Helpers.MSG_APPENDED_ACKS);
                }
            }

            buffer.DataLength = dataLength;

            #endregion ACK Appending

            #region Sequence Number Assignment

            bool canBeRemoved = false;
            if (!isResend)
            {
                // Not a resend, assign a new sequence number
                uint sequenceNumber = (uint) Interlocked.Increment(ref udpClient.CurrentSequence);
                Utils.UIntToBytesBig(sequenceNumber, buffer.Data, 1);
                outgoingPacket.SequenceNumber = sequenceNumber;

                if (isReliable)
                {
                    // Add this packet to the list of ACK responses we are waiting on from the server
                    udpClient.NeedAcks.Add(outgoingPacket);
                    Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);
                }
                else
                    canBeRemoved = true;
            }

            #endregion Sequence Number Assignment

            // Stats tracking
            Interlocked.Increment(ref udpClient.PacketsSent);
            //            if (isReliable)
            //                Interlocked.Add(ref udpClient.UnackedBytes, outgoingPacket.Buffer.DataLength);

            // Put the UDP payload on the wire
            //            AsyncBeginSend(buffer);

            SyncSend(buffer);

            // Keep track of when this packet was sent out (right now)
            outgoingPacket.TickCount = Environment.TickCount & int.MaxValue;

            if (outgoingPacket.FinishedMethod != null)
                outgoingPacket.FinishedMethod(outgoingPacket);

            if (canBeRemoved)
                outgoingPacket.Destroy(1);
        }
コード例 #8
0
        public void SendPacketData(LLUDPClient udpClient, byte[] data, Packet packet, ThrottleOutPacketType category,
                                   UnackedPacketMethod resendMethod, UnackedPacketMethod finishedMethod)
        {
            int dataLength = data.Length;
            bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
            bool doCopy = true;

            // Frequency analysis of outgoing packet sizes shows a large clump of packets at each end of the spectrum.
            // The vast majority of packets are less than 200 bytes, although due to asset transfers and packet splitting
            // there are a decent number of packets in the 1000-1140 byte range. We allocate one of two sizes of data here
            // to accommodate for both common scenarios and provide ample room for ACK appending in both
            int bufferSize = dataLength*2;

            UDPPacketBuffer buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);

            // Zerocode if needed
            if (doZerocode)
            {
                try
                {
                    dataLength = Helpers.ZeroEncode(data, dataLength, buffer.Data);
                    doCopy = false;
                }
                catch (IndexOutOfRangeException)
                {
                    // The packet grew larger than the bufferSize while zerocoding.
                    // Remove the MSG_ZEROCODED flag and send the unencoded data
                    // instead
                    MainConsole.Instance.Debug("[LLUDP Server]: Packet exceeded buffer size during zerocoding for " +
                                               packet.Type +
                                               ". DataLength=" + dataLength +
                                               " and BufferLength=" + buffer.Data.Length +
                                               ". Removing MSG_ZEROCODED flag");
                    data[0] = (byte) (data[0] & ~Helpers.MSG_ZEROCODED);
                }
            }

            // If the packet data wasn't already copied during zerocoding, copy it now
            if (doCopy)
            {
                if (dataLength <= buffer.Data.Length)
                {
                    Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
                }
                else
                {
                    bufferSize = dataLength;
                    buffer = new UDPPacketBuffer(udpClient.RemoteEndPoint, bufferSize);

                    // MainConsole.Instance.Error("[LLUDP Server]: Packet exceeded buffer size! This could be an indication of packet assembly not obeying the MTU. Type=" +
                    //     type + ", DataLength=" + dataLength + ", BufferLength=" + buffer.Data.Length + ". Dropping packet");
                    Buffer.BlockCopy(data, 0, buffer.Data, 0, dataLength);
                }
            }

            buffer.DataLength = dataLength;

            #region Queue or Send

            OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, buffer, category, resendMethod, finishedMethod, packet);

            if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
                SendPacketFinal(outgoingPacket);

            #endregion Queue or Send
        }
コード例 #9
0
 /// <summary>
 ///     Add an unacked packet to the collection
 /// </summary>
 /// <param name="packet">Packet that is awaiting acknowledgement</param>
 /// <returns>
 ///     True if the packet was successfully added, false if the
 ///     packet already existed in the collection
 /// </returns>
 /// <remarks>
 ///     This does not immediately add the ACK to the collection,
 ///     it only queues it so it can be added in a thread-safe way later
 /// </remarks>
 public void Add(OutgoingPacket packet)
 {
     m_pendingAdds.Enqueue(packet);
 }
コード例 #10
0
        /// <summary>
        ///     tries to send queued packets
        /// </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(int MaxNPacks)
        {
            bool packetSent = false;

            for (int i = 0; i < MaxNPacks; i++)
            {
                OutgoingPacket packet;
                if (m_nextOutPacket != null)
                {
                    packet = m_nextOutPacket;
                    if (m_throttle.RemoveTokens(packet.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal(packet);
                        m_nextOutPacket = null;
                        packetSent      = true;
                    }
                }
                // No dequeued packet waiting to be sent, try to pull one off
                // this queue
                else if (m_outbox.Dequeue(out packet))
                {
                    MainConsole.Instance.Format(Level.All, AgentID + " - " + packet.Packet.Type);
                    // A packet was pulled off the queue. See if we have
                    // enough tokens in the bucket to send it out
                    if (packet.Category == ThrottleOutPacketType.OutBand ||
                        m_throttle.RemoveTokens(packet.Buffer.DataLength))
                    {
                        packetSent = true;
                        //Send the packet
                        PacketsCounts[(int)packet.Category] += packet.Packet.Length;
                        m_udpServer.SendPacketFinal(packet);
                        PacketsSent++;
                    }
                    else
                    {
                        m_nextOutPacket = packet;
                        break;
                    }
                }
                else
                {
                    break;
                }
            }

            if (packetSent)
            {
                if (m_throttle.MaxBurst < TotalRateRequested)
                {
                    float tmp = m_throttle.MaxBurst * 1.005f;
                    m_throttle.DripRate = (int)tmp;
                    m_throttle.MaxBurst = (int)tmp;
                }
            }


            if (m_nextOnQueueEmpty != 0 && Util.EnvironmentTickCountSubtract(m_nextOnQueueEmpty) >= 0)
            {
                // Use a value of 0 to signal that FireQueueEmpty is running
                m_nextOnQueueEmpty = 0;
                // Asynchronously run the callback
                int   ptmp = m_outbox.queues[MapCatsToPriority[(int)ThrottleOutPacketType.Task]].Count;
                int   atmp = m_outbox.queues[MapCatsToPriority[(int)ThrottleOutPacketType.AvatarInfo]].Count;
                int   ttmp = m_outbox.queues[MapCatsToPriority[(int)ThrottleOutPacketType.Texture]].Count;
                int[] arg  = { ptmp, atmp, ttmp };
                Util.FireAndForget(FireQueueEmpty, arg);
            }

            return(packetSent);
        }