Tracks state for a client UDP connection and provides client-specific methods
コード例 #1
0
 /// <summary>
 ///     Default constructor
 /// </summary>
 /// <param name="client">Reference to the client this packet is destined for</param>
 /// <param name="buffer">
 ///     Serialized packet data. If the flags or sequence number
 ///     need to be updated, they will be injected directly into this binary buffer
 /// </param>
 /// <param name="category">Throttling category for this packet</param>
 /// <param name="resendMethod">The delegate to be called if this packet is determined to be unacknowledged</param>
 /// <param name="finishedMethod">The delegate to be called when this packet is sent</param>
 /// <param name="packet"></param>
 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer,
                       ThrottleOutPacketType category, UnackedPacketMethod resendMethod,
                       UnackedPacketMethod finishedMethod, Packet packet)
 {
     Client         = client;
     Buffer         = buffer;
     Category       = category;
     UnackedMethod  = resendMethod;
     FinishedMethod = finishedMethod;
     Packet         = packet;
 }
コード例 #2
0
 /// <summary>
 ///     Default constructor
 /// </summary>
 /// <param name="client">Reference to the client this packet is destined for</param>
 /// <param name="buffer">
 ///     Serialized packet data. If the flags or sequence number
 ///     need to be updated, they will be injected directly into this binary buffer
 /// </param>
 /// <param name="category">Throttling category for this packet</param>
 /// <param name="resendMethod">The delegate to be called if this packet is determined to be unacknowledged</param>
 /// <param name="finishedMethod">The delegate to be called when this packet is sent</param>
 /// <param name="packet"></param>
 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer,
                       ThrottleOutPacketType category, UnackedPacketMethod resendMethod,
                       UnackedPacketMethod finishedMethod, Packet packet)
 {
     Client = client;
     Buffer = buffer;
     Category = category;
     UnackedMethod = resendMethod;
     FinishedMethod = finishedMethod;
     Packet = packet;
 }
コード例 #3
0
 /// <summary>
 ///     Default constructor
 /// </summary>
 /// <param name="client">Reference to the client this packet came from</param>
 /// <param name="packet">Packet data</param>
 public IncomingPacket(LLUDPClient client, Packet packet)
 {
     Client = client;
     Packet = packet;
 }
コード例 #4
0
        public void SendPing(LLUDPClient udpClient)
        {
            StartPingCheckPacket pc = (StartPingCheckPacket) PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
            pc.Header.Reliable = false;

            pc.PingID.PingID = udpClient.CurrentPingSequence++;
            // We *could* get OldestUnacked, but it would hurt performance and not provide any benefit
            pc.PingID.OldestUnacked = 0;

            SendPacket(udpClient, pc, ThrottleOutPacketType.OutBand, false, null, null);
        }
コード例 #5
0
        public void SendPacketData(LLUDPClient udpClient, byte[] data, Packet packet, ThrottleOutPacketType category,
                                   UnackedPacketMethod resendMethod, UnackedPacketMethod finishedMethod)
        {
            int dataLength = data.Length;
            bool doZerocode = (data[0] & Helpers.MSG_ZEROCODED) != 0;
            bool doCopy = true;

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

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

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

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

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

            buffer.DataLength = dataLength;

            #region Queue or Send

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

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

            #endregion Queue or Send
        }
コード例 #6
0
        public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting,
                               UnackedPacketMethod resendMethod, UnackedPacketMethod finishedMethod)
        {
            // CoarseLocationUpdate packets cannot be split in an automated way
            if (packet.Type == PacketType.CoarseLocationUpdate && allowSplitting)
                allowSplitting = false;

            if (allowSplitting && packet.HasVariableBlocks)
            {
                byte[][] datas = packet.ToBytesMultiple();
                int packetCount = datas.Length;

                if (packetCount < 1)
                    MainConsole.Instance.Error("[LLUDP Server]: Failed to split " + packet.Type +
                                               " with estimated length " + packet.Length);

                for (int i = 0; i < packetCount; i++)
                {
                    byte[] data = datas[i];
                    SendPacketData(udpClient, data, packet, category, resendMethod, finishedMethod);
                }
            }
            else
            {
                byte[] data = packet.ToBytes();
                SendPacketData(udpClient, data, packet, category, resendMethod, finishedMethod);
            }
        }
コード例 #7
0
        public void SendAcks(LLUDPClient udpClient)
        {
            uint ack;

            if (udpClient.PendingAcks.TryDequeue(out ack))
            {
                List<PacketAckPacket.PacketsBlock> blocks = new List<PacketAckPacket.PacketsBlock>();
                PacketAckPacket.PacketsBlock block = new PacketAckPacket.PacketsBlock {ID = ack};
                blocks.Add(block);

                while (udpClient.PendingAcks.TryDequeue(out ack))
                {
                    block = new PacketAckPacket.PacketsBlock {ID = ack};
                    blocks.Add(block);
                }

                PacketAckPacket packet = (PacketAckPacket) PacketPool.Instance.GetPacket(PacketType.PacketAck);
                packet.Header.Reliable = false;
                packet.Packets = blocks.ToArray();

                SendPacket(udpClient, packet, ThrottleOutPacketType.OutBand, true, null, null);
            }
        }
コード例 #8
0
        public void ResendUnacked(LLUDPClient udpClient)
        {
            if (!udpClient.IsConnected)
                return;

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

                ILoginMonitor monitor = m_scene.RequestModuleInterface<IMonitorModule>().GetMonitor<ILoginMonitor>(null);
                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)
            {
                //MainConsole.Instance.Debug("[LLUDP Server]: Resending " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);

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

                foreach (OutgoingPacket t in expiredPackets.Where(t => t.UnackedMethod != null))
                {
                    t.UnackedMethod(t);
                }

                // Resend packets
                foreach (OutgoingPacket outgoingPacket in expiredPackets.Where(t => t.UnackedMethod == null))
                {
                    //MainConsole.Instance.DebugFormat("[LLUDP Server]: 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);
                }
            }
        }
コード例 #9
0
 public void Flush(LLUDPClient udpClient)
 {
     // FIXME: Implement?
 }
コード例 #10
0
 public void CompletePing(LLUDPClient udpClient, byte pingID)
 {
     CompletePingCheckPacket completePing =
         (CompletePingCheckPacket) PacketPool.Instance.GetPacket(PacketType.CompletePingCheck);
     completePing.PingID.PingID = pingID;
     SendPacket(udpClient, completePing, ThrottleOutPacketType.OutBand, false, null, null);
 }
コード例 #11
0
        public virtual bool AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint,
                                         AgentCircuitData sessionInfo)
        {
            MainConsole.Instance.Debug("[LLUDP Server] AddClient-" + circuitCode + "-" + agentID + "-" + sessionID + "-" +
                                       remoteEndPoint + "-" + sessionInfo);
            IScenePresence SP;
            if (!m_scene.TryGetScenePresence(agentID, out SP))
            {
                // Create the LLUDPClient
                LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID,
                                                        remoteEndPoint, m_defaultRTO, m_maxRTO);
                // Create the LLClientView
                LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID,
                                                       sessionID, circuitCode);
                client.OnLogout += LogoutHandler;

                // Start the IClientAPI
                m_scene.AddNewClient(client, null);
                m_currentClients.Add(client);
            }
            else
            {
                MainConsole.Instance.DebugFormat(
                    "[LLUDP Server]: Ignoring a repeated UseCircuitCode ({0}) from {1} at {2} ",
                    circuitCode, agentID, remoteEndPoint);
            }
            return true;
        }
コード例 #12
0
 void RemoveClient(LLUDPClient udpClient)
 {
     // Remove this client from the scene
     IClientAPI client;
     if (m_scene.ClientManager.TryGetValue(udpClient.AgentID, out client))
     {
         client.IsLoggingOut = true;
         IEntityTransferModule transferModule = m_scene.RequestModuleInterface<IEntityTransferModule>();
         if (transferModule != null)
             transferModule.IncomingCloseAgent(m_scene, udpClient.AgentID);
         RemoveClient(client);
     }
 }
コード例 #13
0
 /// <summary>
 ///     Default constructor
 /// </summary>
 /// <param name="client">Reference to the client this packet came from</param>
 /// <param name="packet">Packet data</param>
 public IncomingPacket(LLUDPClient client, Packet packet)
 {
     Client = client;
     Packet = packet;
 }