コード例 #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];
                TokenBucket bucket = m_throttleCategories[category];

                if (bucket.RemoveTokens(packet.Buffer.DataLength))
                {
                    // Enough tokens were removed from the bucket, the packet will not be queued
                    return(false);
                }
                else
                {
                    // Not enough tokens in the bucket, queue this packet
                    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 void TestReportCriticalPacketDrop(OutgoingPacket packet)
 {
     lock (_dropReportLock)
     {
         if (DateTime.Now - _lastDropReport > TimeSpan.FromSeconds(MIN_DROP_REPORT_INTERVAL))
         {
             _lastDropReport = DateTime.Now;
             m_log.WarnFormat("[LLUDP] Reliable packets are being dropped for {0} due to overfilled outbound queue. Last packet type {1}",
                              AgentID, packet.Type);
         }
     }
 }
コード例 #3
0
        public void ResendUnacked(LLUDPClient udpClient)
        {
            if (!udpClient.IsConnected)
            {
                return;
            }

            // Disconnect an agent if no packets are received for some time
            //FIXME: Make 60 an .ini setting
            if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60)
            {
                m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);

                RemoveClient(udpClient);
                return;
            }

            // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
            List <OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);

            if (expiredPackets != null)
            {
                //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);

                // Exponential backoff of the retransmission timeout
                udpClient.BackoffRTO();

                // Resend packets
                for (int i = 0; i < expiredPackets.Count; i++)
                {
                    OutgoingPacket outgoingPacket = expiredPackets[i];

                    //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
                    //    outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);

                    // Set the resent flag
                    outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
                    outgoingPacket.Category       = ThrottleOutPacketType.Resend;

                    // Bump up the resend count on this packet
                    Interlocked.Increment(ref outgoingPacket.ResendCount);
                    //Interlocked.Increment(ref Stats.ResentPackets);

                    // Requeue or resend the packet
                    if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
                    {
                        SendPacketFinal(outgoingPacket);
                    }
                }
            }
        }
コード例 #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
        void AsyncEndSend(IAsyncResult result)
        {
            OutgoingPacket packet = (OutgoingPacket)result.AsyncState;

            try
            {
                m_udpSocket.EndSendTo(result);
            }
            catch (SocketException) { }
            catch (ObjectDisposedException) { }
            finally
            {
                this.SendCompleted(packet);
            }
        }
コード例 #6
0
ファイル: LLUDPClient.cs プロジェクト: ssatguru/opensim
        /// <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);
            }
        }
コード例 #7
0
ファイル: LLUDPClient.cs プロジェクト: kow/Aurora-Sim
        public bool EnqueueOutgoing(OutgoingPacket packet)
        {
            int category = (int)packet.Category;
            int prio;

            if (category >= 0 && category < m_packetOutboxes.Length )  
            {
                //All packets are enqueued, except those that don't have a queue
                prio = MapCatsToPriority[category];
                m_outbox.Enqueue(prio, (object)packet);
                return true;
            }
            else
            {
                // all known packs should have a known
                // We don't have a token bucket for this category, so it will not be queued
                return false;
            }
        }
コード例 #8
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);
            }
        }
コード例 #9
0
        public void AsyncBeginSend(OutgoingPacket packet)
        {
            if (!m_shutdownFlag)
            {
                try
                {
                    packet.AddRef();

                    m_udpSocket.BeginSendTo(
                        packet.Buffer,
                        0,
                        packet.DataSize,
                        SocketFlags.None,
                        packet.Destination,
                        AsyncEndSend,
                        packet);
                }
                catch (SocketException) { }
                catch (ObjectDisposedException) { }
            }
        }
コード例 #10
0
ファイル: LLUDPClient.cs プロジェクト: kow/Aurora-Sim
        public bool Dequeue(out OutgoingPacket pack)
            {
            object o;
            int i = nlevels;

            while (--i >= 0) // go down levels looking for data
                {
                if (queues[i].Dequeue(out o))
                    {
                    if (o is OutgoingPacket)
                        {
                        pack = (OutgoingPacket)o;
                        Interlocked.Decrement(ref count);
                        return true;
                        }
                    // else  do call to a funtion that will return the packet or whatever
                    }
                }
               
            pack=null;
            return false;
            }
コード例 #11
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, bool forceQueue)
        {
            int category = (int)packet.Category;

            if (category >= 0 && category < m_packetOutboxes.Length)
            {
                ThreadedClasses.NonblockingQueue <OutgoingPacket> queue = m_packetOutboxes[category];
                TokenBucket bucket = m_throttleCategories[category];

                // Don't send this packet if there is already a packet waiting in the queue
                // even if we have the tokens to send it, tokens should go to the already
                // queued packets
                if (queue.Count > 0)
                {
                    queue.Enqueue(packet);
                    return(true);
                }


                if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
                {
                    // Enough tokens were removed from the bucket, the packet will not be queued
                    return(false);
                }
                else
                {
                    // Force queue specified or not enough tokens in the bucket, queue this packet
                    queue.Enqueue(packet);
                    return(true);
                }
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return(false);
            }
        }
コード例 #12
0
        public bool Dequeue(out OutgoingPacket pack)
        {
            int i = nlevels;

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

            pack = null;
            return(false);
        }
コード例 #13
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, bool forceQueue)
 {
     return(EnqueueOutgoing(packet, forceQueue, false));
 }
コード例 #14
0
ファイル: LLUDPServer.cs プロジェクト: digitalmystic/halcyon
        private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber)
        {
            PacketAckPacket ack = new PacketAckPacket();
            ack.Header.Reliable = false;
            ack.Packets = new PacketAckPacket.PacketsBlock[1];
            ack.Packets[0] = new PacketAckPacket.PacketsBlock();
            ack.Packets[0].ID = sequenceNumber;

            byte[] packetData = ack.ToBytes();
            int length = packetData.Length;

            OutgoingPacket outgoingPacket = new OutgoingPacket(null, packetData, 0, length, 
                remoteEndpoint, false, PacketType.PacketAck);

            AsyncBeginSend(outgoingPacket);
        }
コード例 #15
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>
        ///
        /// 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).
        ///
        /// <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)
        {
            OutgoingPacket packet;
            bool           packetSent = false;

            for (int i = 0; i < MaxNPacks; i++)
            {
                if (m_nextOutPackets != null)
                {
                    OutgoingPacket nextPacket = m_nextOutPackets;
                    if (m_throttle.RemoveTokens(nextPacket.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal(nextPacket);
                        m_nextOutPackets = null;
                        packetSent       = true;
                        this.PacketsSent++;
                    }
                    else
                    {
                        int prio = MapCatsToPriority[(int)nextPacket.Category];
                        prio++;
                        if (prio > MapCatsToPriority.Length)
                        {
                            prio--;
                        }
                        m_outbox.Enqueue(prio, nextPacket);
                        m_nextOutPackets = null;
                    }
                }
                else
                {
                    // No dequeued packet waiting to be sent, try to pull one off
                    // this queue
                    if (m_outbox.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.Category == ThrottleOutPacketType.OutBand || m_throttle.RemoveTokens(packet.Buffer.DataLength))
                        {
                            // Send the packet
                            m_udpServer.SendPacketFinal(packet);
                            packetSent = true;

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

                            this.PacketsSent++;
                        }
                        else
                        {
                            m_nextOutPackets = packet;
                        }
                    }
                    else
                    {
                        break;
                    }
                }
            }

            if (m_outbox.count < 100 || m_lastEmptyUpdates > 10)
            {
                //if(m_outbox.count > 100)
                //    MainConsole.Instance.Output(m_outbox.count.ToString(), log4net.Core.Level.Alert);
                m_lastEmptyUpdates = 0;
                BeginFireQueueEmpty();
            }
            else
            {
                m_lastEmptyUpdates++;
            }

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

            /*
             *
             *           OutgoingPacket packet;
             *          OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
             *          TokenBucket bucket;
             *          bool packetSent = false;
             *          ThrottleOutPacketTypeFlags emptyCategories = 0;
             *
             *          //string queueDebugOutput = String.Empty; // Serious debug business
             *          int npacksTosent = MaxNPacks;
             *
             *          int i = m_lastthrottleCategoryChecked;
             *          for (int j = 0; j < (int)ThrottleOutPacketType.OutBand; j++) // don't check OutBand
             *          {
             *
             *              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;
             *                      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.Buffer.DataLength))
             *                      {
             *                          // Send the packet
             *                          m_udpServer.SendPacketFinal(packet);
             *                          packetSent = true;
             *                          this.PacketsSent++;
             *                      }
             *                      else
             *                      {
             *                          // Save the dequeued packet for the next iteration
             *                          m_nextPackets[i] = packet;
             *                      }
             *
             *                      // 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 (++i >= (int)ThrottleOutPacketType.OutBand)
             *                  i = 0;
             *
             *              if (--npacksTosent <= 0)
             *                  break;
             *          }
             *
             *          m_lastthrottleCategoryChecked = i;
             *
             *          // send at least one outband packet
             *
             *          if (npacksTosent <= 0)
             *              npacksTosent = 1;
             *
             *          i = (int)ThrottleOutPacketType.OutBand;
             *
             *          while (npacksTosent > 0)
             *          {
             *              //outband has no tokens checking and no throttle
             *              // 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.Buffer.DataLength))
             *                  //                            {
             *                  // Send the packet
             *                  m_udpServer.SendPacketFinal(packet);
             *                  packetSent = true;
             *                  this.PacketsSent++;
             *                  //                            }
             * //                                            else
             * //                                                {
             *                                              // Save the dequeued packet for the next iteration
             * //                                                m_nextPackets[i] = packet;
             * //                                                }
             *
             *                  // 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);
             *                  break;
             *              }
             *              npacksTosent--;
             *          }
             *
             *          if (emptyCategories != 0)
             *              BeginFireQueueEmpty(emptyCategories);
             *
             *          //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
             *          return packetSent;
             */
        }
コード例 #16
0
ファイル: LLUDPClient.cs プロジェクト: AlphaStaxLLC/taiga
        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];
                TokenBucket bucket = m_throttleCategories[category];

                if (bucket.RemoveTokens(packet.Buffer.DataLength))
                {
                    // Enough tokens were removed from the bucket, the packet will not be queued
                    return false;
                }
                else
                {
                    // Not enough tokens in the bucket, queue this packet
                    queue.Enqueue(packet);
                    return true;
                }
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return false;
            }
        }
コード例 #17
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.Output(AgentID + " - " + packet.Packet.Type, "Verbose");
                    // 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);
        }
コード例 #18
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);
     Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength);
 }
コード例 #19
0
ファイル: LLUDPClient.cs プロジェクト: samiam123/Aurora-Sim
        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;
        }
コード例 #20
0
ファイル: LLUDPServer.cs プロジェクト: digitalmystic/halcyon
 protected override void SendCompleted(OutgoingPacket packet)
 {
     packet.DecRef(_bufferPool);
 }
コード例 #21
0
 /// <summary>
 /// Called when the base is through with the given packet
 /// </summary>
 /// <param name="packet"></param>
 protected abstract void SendCompleted(OutgoingPacket packet);
コード例 #22
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()
        {
            OutgoingPacket packet;

            OpenSim.Framework.LocklessQueue <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;
                    }
                }
                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.Buffer.DataLength))
                        {
                            // Send the packet
                            m_udpServer.SendPacketFinal(packet);
                            packetSent = true;
                        }
                        else
                        {
                            // Save the dequeued packet for the next iteration
                            m_nextPackets[i] = packet;
                        }

                        // 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);
        }
コード例 #23
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.Dequeue(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

            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);
                }
            }

            #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);

            // Keep track of when this packet was sent out (right now)
            outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
        }
コード例 #24
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 (nextPacket.Buffer == null)
                    {
                        if (m_packetOutboxes[i].Count < 5)
                        {
                            emptyCategories |= CategoryToFlag(i);
                        }
                        continue;
                    }
                    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 (packet.Buffer == null)
                            {
                                // packet canceled elsewhere (by a ack for example)
                                if (queue.Count < 5)
                                {
                                    emptyCategories |= CategoryToFlag(i);
                                }
                            }
                            else
                            {
                                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);
        }
コード例 #25
0
        public void SendPacketData(LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category)
        {
            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 accomodate for both common scenarios and provide ample room for ACK appending in both
            int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;

            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
                    m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + 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);

                    // m_log.Error("[LLUDPSERVER]: 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);

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

            #endregion Queue or Send
        }
コード例 #26
0
ファイル: LLUDPServer.cs プロジェクト: digitalmystic/halcyon
        public void SendPacketData(LLUDPClient udpClient, byte[] data, int dataLength, PacketType type, 
            ThrottleOutPacketType category, bool bufferAcquiredFromPool)
        {
            bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
            bool zeroCoded = false;
            byte[] outBuffer = null;

            // Zerocode if needed
            if (doZerocode)
            {
                // 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 accomodate for both common scenarios and provide ample room for ACK appending in both
                int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;

                try
                {
                    //zerocode and return the current buffer to the pool if necessary
                    outBuffer = _bufferPool.LeaseBytes(bufferSize);
                    dataLength = Helpers.ZeroEncode(data, dataLength, outBuffer);
                    zeroCoded = true;

                    if (bufferAcquiredFromPool)
                    {
                        _bufferPool.ReturnBytes(data);
                    }

                    //now the buffer is from a pool most definitely
                    bufferAcquiredFromPool = true;
                }
                catch (IndexOutOfRangeException)
                {
                    //TODO: Throwing an exception here needs to be revisted. I've seen an issue with
                    //70+ avatars where a very common high freq packet hits this code everytime
                    //that packet either needs to be split, or this needs to be revised to not throw
                    //and instead check the buffer size and return an error condition

                    // The packet grew larger than the bufferSize while zerocoding.
                    // Remove the MSG_ZEROCODED flag and send the unencoded data
                    // instead
                    m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + type + ". DataLength=" + dataLength +
                        " and BufferLength=" + outBuffer.Length + ". Removing MSG_ZEROCODED flag");
                    data[0] = (byte)(data[0] & ~Helpers.MSG_ZEROCODED);

                    _bufferPool.ReturnBytes(outBuffer);
                }
            }

            if (! zeroCoded)
            {
                outBuffer = data;
            }

            #region Queue or Send

            OutgoingPacket outgoingPacket = new OutgoingPacket(udpClient, outBuffer, (int)category, dataLength, 
                udpClient.RemoteEndPoint, bufferAcquiredFromPool, type);

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

            #endregion Queue or Send
        }
コード例 #27
0
ファイル: LLUDPServer.cs プロジェクト: HGExchange/Aurora-Sim
        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 accomodate 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
                    m_log.Info("[LLUDPSERVER]: 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);

                    // m_log.Error("[LLUDPSERVER]: 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
        }
コード例 #28
0
ファイル: LLUDPClient.cs プロジェクト: ssatguru/opensim
        /// <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);
        }
コード例 #29
0
ファイル: LLUDPClient.cs プロジェクト: kf6kjg/halcyon
        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;
            }
        }
コード例 #30
0
ファイル: LLUDPServer.cs プロジェクト: x8ball/Aurora-Sim
        public void ResendUnacked(LLUDPClient udpClient)
        {
            if (!udpClient.IsConnected)
            {
                return;
            }

            // Disconnect an agent if no packets are received for some time
            if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * ClientTimeOut && !udpClient.IsPaused)
            {
                m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);

                ILoginMonitor monitor = (ILoginMonitor)m_scene.RequestModuleInterface <IMonitorModule>().GetMonitor("", "LoginMonitor");
                if (monitor != null)
                {
                    monitor.AddAbnormalClientThreadTermination();
                }
                RemoveClient(udpClient);
                return;
            }

            // Get a list of all of the packets that have been sitting unacked longer than udpClient.RTO
            List <OutgoingPacket> expiredPackets = udpClient.NeedAcks.GetExpiredPackets(udpClient.RTO);

            if (expiredPackets != null)
            {
                //m_log.Debug("[LLUDPSERVER]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);

                // Exponential backoff of the retransmission timeout
                udpClient.BackoffRTO();

                lock (udpClient)
                {
                    udpClient.SlowDownSend();
                }

                // Resend packets
                for (int i = 0; i < expiredPackets.Count; i++)
                {
                    OutgoingPacket outgoingPacket = expiredPackets[i];

                    //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
                    //    outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);

                    // Set the resent flag
                    outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);

// resend in its original category
//                    outgoingPacket.Category = ThrottleOutPacketType.Resend;

                    // Bump up the resend count on this packet
                    Interlocked.Increment(ref outgoingPacket.ResendCount);
                    //Interlocked.Increment(ref Stats.ResentPackets);

                    // Requeue or resend the packet
                    if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket))
                    {
                        SendPacketFinal(outgoingPacket);
                    }
                }
            }
        }
コード例 #31
0
ファイル: LLUDPServer.cs プロジェクト: JeffCost/opensim
        /// <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.Dequeue(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

            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);
                }
            }
            else
            {
                Interlocked.Increment(ref udpClient.PacketsResent);
            }

            #endregion Sequence Number Assignment

            // Stats tracking
            Interlocked.Increment(ref udpClient.PacketsSent);

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

            // Keep track of when this packet was sent out (right now)
            outgoingPacket.TickCount = Environment.TickCount & Int32.MaxValue;
        }
コード例 #32
0
ファイル: LLUDPClient.cs プロジェクト: kow/Aurora-Sim
        /// <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>
        /// 
        /// 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).
        /// 
        /// <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)
        {
            OutgoingPacket packet;
            bool packetSent = false;
            ThrottleOutPacketTypeFlags emptyCategories = 0;

            if (m_nextOutPackets != null)
            {
                OutgoingPacket nextPacket = m_nextOutPackets;
                if (m_throttle.RemoveTokens (nextPacket.Buffer.DataLength))
                {
                    // Send the packet
                    m_udpServer.SendPacketFinal (nextPacket);
                    m_nextOutPackets = null;
                    packetSent = true;
                    this.PacketsSent++;
                }
            }
            else
            {
                // No dequeued packet waiting to be sent, try to pull one off
                // this queue
                if (m_outbox.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.Category == ThrottleOutPacketType.OutBand || m_throttle.RemoveTokens (packet.Buffer.DataLength))
                    {
                        // Send the packet
                        m_udpServer.SendPacketFinal (packet);
                        packetSent = true;

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

                        this.PacketsSent++;
                    }
                    else
                    {
                        m_nextOutPackets = packet;
                    }
                }
                else
                {
                    emptyCategories = (ThrottleOutPacketTypeFlags)0xffff;
                }
            }

            if (m_outbox.count < 100)
            {
                emptyCategories = (ThrottleOutPacketTypeFlags)0xffff;
                BeginFireQueueEmpty (emptyCategories);
            }
            /*
                        if (emptyCategories != 0)
                            BeginFireQueueEmpty(emptyCategories);
                        else
                            {
                            int i = MapCatsToPriority[(int)ThrottleOutPacketType.Texture]; // hack to keep textures flowing for now
                            if (m_outbox.queues[i].Count < 30)
                                {
                                emptyCategories |= ThrottleOutPacketTypeFlags.Texture;
                                }
                            }
            */

            //m_log.Info("[LLUDPCLIENT]: Queues: " + queueDebugOutput); // Serious debug business
            return packetSent;
            /*
  
                         OutgoingPacket packet;
                        OpenSim.Framework.LocklessQueue<OutgoingPacket> queue;
                        TokenBucket bucket;
                        bool packetSent = false;
                        ThrottleOutPacketTypeFlags emptyCategories = 0;

                        //string queueDebugOutput = String.Empty; // Serious debug business
                        int npacksTosent = MaxNPacks;

                        int i = m_lastthrottleCategoryChecked;
                        for (int j = 0; j < (int)ThrottleOutPacketType.OutBand; j++) // don't check OutBand
                        {

                            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;
                                    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.Buffer.DataLength))
                                    {
                                        // Send the packet
                                        m_udpServer.SendPacketFinal(packet);
                                        packetSent = true;
                                        this.PacketsSent++;
                                    }
                                    else
                                    {
                                        // Save the dequeued packet for the next iteration
                                        m_nextPackets[i] = packet;
                                    }

                                    // 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 (++i >= (int)ThrottleOutPacketType.OutBand)
                                i = 0;

                            if (--npacksTosent <= 0)
                                break;
                        }

                        m_lastthrottleCategoryChecked = i;

                        // send at least one outband packet 

                        if (npacksTosent <= 0)
                            npacksTosent = 1;

                        i = (int)ThrottleOutPacketType.OutBand;

                        while (npacksTosent > 0)
                        {
                            //outband has no tokens checking and no throttle
                            // 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.Buffer.DataLength))
                                //                            {
                                // Send the packet
                                m_udpServer.SendPacketFinal(packet);
                                packetSent = true;
                                this.PacketsSent++;
                                //                            }
            //                                            else
            //                                                {
                                                            // Save the dequeued packet for the next iteration
            //                                                m_nextPackets[i] = packet;
            //                                                }

                                // 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);
                                break;
                            }
                            npacksTosent--;
                        }

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

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

        }
コード例 #33
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)
 {
     packet.AddRef();
     m_pendingAdds.Enqueue(packet);
 }
コード例 #34
0
        public void AsyncBeginSend(OutgoingPacket packet)
        {
            if (!m_shutdownFlag)
            {
                try
                {
                    packet.AddRef();

                    m_udpSocket.BeginSendTo(
                        packet.Buffer.Data,
                        0,
                        packet.DataSize,
                        SocketFlags.None,
                        packet.Destination,
                        AsyncEndSend,
                        packet);
                }
                catch (SocketException) { }
                catch (ObjectDisposedException) { }
            }
        }
コード例 #35
0
 /// <summary>
 /// Called when the base is through with the given packet
 /// </summary>
 /// <param name="packet"></param>
 protected abstract void SendCompleted(OutgoingPacket packet);
コード例 #36
0
ファイル: LLUDPClient.cs プロジェクト: szielins/opensim
        /// <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, bool forceQueue)
        {
            int category = (int)packet.Category;

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

                // Don't send this packet if there is already a packet waiting in the queue
                // even if we have the tokens to send it, tokens should go to the already
                // queued packets
                if (queue.Count > 0)
                {
                    queue.Enqueue(packet);
                    return true;
                }
                
                    
                if (!forceQueue && bucket.RemoveTokens(packet.Buffer.DataLength))
                {
                    // Enough tokens were removed from the bucket, the packet will not be queued
                    return false;
                }
                else
                {
                    // Force queue specified or not enough tokens in the bucket, queue this packet
                    queue.Enqueue(packet);
                    return true;
                }
            }
            else
            {
                // We don't have a token bucket for this category, so it will not be queued
                return false;
            }
        }
コード例 #37
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);
            }
        }
コード例 #38
0
ファイル: LLUDPClient.cs プロジェクト: samiam123/Aurora-Sim
        public bool Dequeue(out OutgoingPacket pack)
        {
            int i = nlevels;

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

            pack = null;
            return false;
        }
コード例 #39
0
ファイル: LLUDPClient.cs プロジェクト: KingMilan2006/1234
 /// <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)
 {
     return(EnqueueOutgoing(packet, false));
 }
コード例 #40
0
ファイル: LLUDPClient.cs プロジェクト: samiam123/Aurora-Sim
        /// <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.Output(AgentID + " - " + packet.Packet.Type, "Verbose");
                    // 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;
        }
コード例 #41
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);
 }
コード例 #42
0
ファイル: LLUDPClient.cs プロジェクト: kf6kjg/halcyon
 public void TestReportCriticalPacketDrop(OutgoingPacket packet)
 {
     lock (_dropReportLock)
     {
         if (DateTime.Now - _lastDropReport > TimeSpan.FromSeconds(MIN_DROP_REPORT_INTERVAL))
         {
             _lastDropReport = DateTime.Now;
             m_log.WarnFormat("[LLUDP] Reliable packets are being dropped for {0} due to overfilled outbound queue. Last packet type {1}",
                 AgentID, packet.Type);
         }
     }
 }
コード例 #43
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);
 }
コード例 #44
0
ファイル: LLUDPServer.cs プロジェクト: JeffCost/opensim
        public void ResendUnacked(OutgoingPacket outgoingPacket)
        {
            //m_log.DebugFormat("[LLUDPSERVER]: Resending packet #{0} (attempt {1}), {2}ms have passed",
            //    outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);

            // Set the resent flag
            outgoingPacket.Buffer.Data[0] = (byte)(outgoingPacket.Buffer.Data[0] | Helpers.MSG_RESENT);
            outgoingPacket.Category = ThrottleOutPacketType.Resend;

            // Bump up the resend count on this packet
            Interlocked.Increment(ref outgoingPacket.ResendCount);

            // Requeue or resend the packet
            if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, false))
                SendPacketFinal(outgoingPacket);
        }
コード例 #45
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);
     Interlocked.Add(ref packet.Client.UnackedBytes, packet.Buffer.DataLength);            
 }
コード例 #46
0
ファイル: LLUDPServer.cs プロジェクト: JeffCost/opensim
        /// <summary>
        /// Start the process of sending a packet to the client.
        /// </summary>
        /// <param name="udpClient"></param>
        /// <param name="data"></param>
        /// <param name="type"></param>
        /// <param name="category"></param>
        /// <param name="method">
        /// The method to call if the packet is not acked by the client.  If null, then a standard
        /// resend of the packet is done.
        /// </param>
        public void SendPacketData(
            LLUDPClient udpClient, byte[] data, PacketType type, ThrottleOutPacketType category, UnackedPacketMethod method)
        {
            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 accomodate for both common scenarios and provide ample room for ACK appending in both
            int bufferSize = (dataLength > 180) ? LLUDPServer.MTU : 200;

            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
                    m_log.Debug("[LLUDPSERVER]: Packet exceeded buffer size during zerocoding for " + 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);

                    // m_log.Error("[LLUDPSERVER]: 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, null);
            // If we were not provided a method for handling unacked, use the UDPServer default method
            outgoingPacket.UnackedMethod = ((method == null) ? delegate(OutgoingPacket oPacket) { ResendUnacked(oPacket); } : method);

            // If a Linden Lab 1.23.5 client receives an update packet after a kill packet for an object, it will 
            // continue to display the deleted object until relog.  Therefore, we need to always queue a kill object
            // packet so that it isn't sent before a queued update packet.
            bool requestQueue = type == PacketType.KillObject;
            if (!outgoingPacket.Client.EnqueueOutgoing(outgoingPacket, requestQueue))
                SendPacketFinal(outgoingPacket);

            #endregion Queue or Send
        }
コード例 #47
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)
 {
     packet.AddRef();
     m_pendingAdds.Enqueue(packet);
 }