EnqueueOutgoing() 공개 메소드

public EnqueueOutgoing ( OpenSim.Region.ClientStack.LindenUDP.OutgoingPacket packet ) : bool
packet OpenSim.Region.ClientStack.LindenUDP.OutgoingPacket
리턴 bool
예제 #1
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)
            {
                IClientAPI client;
                if (m_scene.TryGetClient(udpClient.AgentID, out client))
                {
                    if (client.IsActive)   // to prevent duplicate reporting
                        m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);

                    RemoveClient(client);
                }
                return;
            }

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

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

                // Exponential backoff of the retransmission timeout
                if ((expiredPackets.Key & UnackedPacketCollection.ResendReason.TimeoutExpired) != 0) udpClient.BackoffRTO();

                var packetList = expiredPackets.Value;

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

                    /*m_log.DebugFormat("[LLUDPSERVER]: {0} Resending packet #{1} (attempt {2}), {3}ms have passed",
                        (expiredPackets.Key & UnackedPacketCollection.ResendReason.FastRetransmit) != 0 ? "(Fast)" : "",
                        outgoingPacket.SequenceNumber, outgoingPacket.ResendCount, Environment.TickCount - outgoingPacket.TickCount);
                    */

                    // Set the resent flag
                    outgoingPacket.Buffer[0] = (byte)(outgoingPacket.Buffer[0] | Helpers.MSG_RESENT);
                    outgoingPacket.Category = (int) 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 (!udpClient.EnqueueOutgoing(outgoingPacket))
                        SendPacketFinal(outgoingPacket);
                }

                /*
                if (packetList.Count != 0)
                {
                    m_log.DebugFormat("[LLUDPSERVER]: {0} Resent {1} packet(s) for {2}",
                        (expiredPackets.Key & UnackedPacketCollection.ResendReason.FastRetransmit) != 0 ? "(Fast)" : "",
                        packetList.Count, udpClient.AgentID);
                }*/
            }
        }
예제 #2
0
        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
        }