Tracks state for a client UDP connection and provides client-specific methods
        public void SendAcks(LLUDPClient udpClient)
        {
            uint ack;

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

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

                PacketAckPacket packet = new PacketAckPacket();
                packet.Header.Reliable = false;
                packet.Packets         = blocks.ToArray();

                SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true);
            }
        }
        public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
        {
            // 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)
                {
                    m_log.Error("[LLUDPSERVER]: 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.Type, category);
                }
            }
            else
            {
                byte[] data = packet.ToBytes();
                SendPacketData(udpClient, data, packet.Type, category);
            }
        }
 /// <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>
 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
 {
     Client        = client;
     Buffer        = buffer;
     Category      = category;
     UnackedMethod = method;
 }
 public RexClientViewCompatible(EndPoint remoteEP, Scene scene,
     LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse authenSessions, UUID agentId,
     UUID sessionId, uint circuitCode)
     : base(remoteEP, scene, udpServer, udpClient, authenSessions, agentId,
            sessionId, circuitCode)
 {
 }
        public void CompletePing(LLUDPClient udpClient, byte pingID)
        {
            CompletePingCheckPacket completePing = new CompletePingCheckPacket();

            completePing.PingID.PingID = pingID;
            SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false);
        }
Exemple #6
0
        public bool QueueRequest(LLUDPClient client, ThrottleOutPacketTypeFlags categories)
        {
            if (m_requestQueue.Count < m_requestQueue.BoundedCapacity)
            {
//                m_log.DebugFormat(
//                    "[OUTGOING QUEUE REFILL ENGINE]: Adding request for categories {0} for {1} in {2}",
//                    categories, client.AgentID, m_udpServer.Scene.Name);

                m_requestQueue.Add(new RefillRequest(client, categories));

                if (!m_warnOverMaxQueue)
                {
                    m_warnOverMaxQueue = true;
                }

                return(true);
            }
            else
            {
                if (m_warnOverMaxQueue)
                {
                    m_log.WarnFormat(
                        "[OUTGOING QUEUE REFILL ENGINE]: Request queue at maximum capacity, not recording request from {0} in {1}",
                        client.AgentID, m_udpServer.Scene.Name);

                    m_warnOverMaxQueue = false;
                }

                return(false);
            }
        }
 /// <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>
 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category, UnackedPacketMethod method)
 {
     Client = client;
     Buffer = buffer;
     Category = category;
     UnackedMethod = method;
 }
 public RexClientViewLegacy(EndPoint remoteEP, Scene scene,
     LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse authenSessions, UUID agentId,
     UUID sessionId, uint circuitCode)
     : base(remoteEP, scene, udpServer, udpClient, authenSessions, agentId,
            sessionId, circuitCode)
 {
     AddGenericPacketHandler("RexSkypeStore", HandleOnSkypeStore);
 }
Exemple #9
0
 public NaaliClientView(EndPoint remoteEP, Scene scene,
     LLUDPServer udpServer, LLUDPClient udpClient, AuthenticateResponse authenSessions, UUID agentId,
     UUID sessionId, uint circuitCode)
     : base(remoteEP, scene, udpServer, udpClient, authenSessions, agentId,
            sessionId, circuitCode)
 {
     OnBinaryGenericMessage -= base.RexClientView_BinaryGenericMessage;
     OnBinaryGenericMessage += ng_BinaryGenericMessage;
 }
 /// <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;
 }
 /// <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>
 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;
 }
        private void RemoveClient(LLUDPClient udpClient)
        {
            // Remove this client from the scene
            IClientAPI client;

            if (m_scene.TryGetClient(udpClient.AgentID, out client))
            {
                client.IsLoggingOut = true;
                client.Close();
            }
        }
        public void SendPing(LLUDPClient udpClient)
        {
            StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);

            pc.Header.Reliable = false;

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

            SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false);
        }
        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);
                    }
                }
            }
        }
Exemple #15
0
        private void RemoveClient(LLUDPClient udpClient)
        {
            // Remove this client from the scene
            IClientAPI client;

            if (m_scene.TryGetClient(udpClient.AgentID, out client))
            {
                client.IsLoggingOut = true;
                IEntityTransferModule transferModule = m_scene.RequestModuleInterface <IEntityTransferModule> ();
                if (transferModule != null)
                {
                    transferModule.IncomingCloseAgent(m_scene, udpClient.AgentID);
                }
            }
        }
        private void HandleThrottleGetCommand(string module, string[] args)
        {
            if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
            {
                return;
            }

            bool all = args.Length == 4;
            bool one = args.Length == 6;

            if (!all && !one)
            {
                MainConsole.Instance.Output(
                    "Usage: debug lludp throttles get [<avatar-first-name> <avatar-last-name>]");
                return;
            }

            string firstName = null;
            string lastName  = null;

            if (one)
            {
                firstName = args[4];
                lastName  = args[5];
            }

            m_udpServer.Scene.ForEachScenePresence(sp =>
            {
                if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
                {
                    m_console.Output(
                        "Status for {0} ({1}) in {2}",
                        sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);

                    LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;

                    ConsoleDisplayList cdl = new ConsoleDisplayList();
                    cdl.AddRow("adaptive", udpClient.FlowThrottle.AdaptiveEnabled);
                    cdl.AddRow("current", string.Format("{0} kbps", udpClient.FlowThrottle.DripRate * 8 / 1000));
                    cdl.AddRow("request", string.Format("{0} kbps", udpClient.FlowThrottle.RequestedDripRate * 8 / 1000));
                    cdl.AddRow("max", string.Format("{0} kbps", udpClient.FlowThrottle.MaxDripRate * 8 / 1000));

                    m_console.Output(cdl.ToString());
                }
            });
        }
        /// <summary>
        /// Does an early check to see if this queue empty callback is already
        /// running, then asynchronously firing the event
        /// </summary>
        /// <param name="categories">Throttle categories to fire the callback for</param>
        private void BeginFireQueueEmpty(ThrottleOutPacketTypeFlags categories)
        {
            if (!QueueEmptyRunning && HasUpdates(categories) && OnQueueEmpty != null)
            {
                double start = Util.GetTimeStampMS();
                if (start < m_nextOnQueueEmpty)
                {
                    return;
                }

                QueueEmptyRunning  = true;
                m_nextOnQueueEmpty = start + MIN_CALLBACK_MS;

                // Asynchronously run the callback
                if (m_udpServer.OqrEngine.IsRunning)
                {
                    LLUDPClient udpcli = this;
                    ThrottleOutPacketTypeFlags cats = categories;
                    Action <LLUDPClient, ThrottleOutPacketTypeFlags> act = delegate
                    {
                        QueueEmpty callback = udpcli.OnQueueEmpty;
                        if (callback != null)
                        {
                            try
                            {
                                callback(cats);
                            }
                            catch { }

                            if (callback != null)
                            {
                                udpcli.QueueEmptyRunning = false;
                            }
                        }
                        udpcli   = null;
                        callback = null;
                    };

                    m_udpServer.OqrEngine.QueueJob(AgentID.ToString(), () => act(udpcli, cats));
                }
                else
                {
                    Util.FireAndForget(FireQueueEmpty, categories, "LLUDPClient.BeginFireQueueEmpty");
                }
            }
        }
        private void HandleClientSetCommand(string module, string[] args)
        {
            if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
            {
                return;
            }

            if (args.Length != 6 && args.Length != 8)
            {
                MainConsole.Instance.OutputFormat("Usage: debug lludp client set <param> <value> [<avatar-first-name> <avatar-last-name>]");
                return;
            }

            string param    = args[4];
            string rawValue = args[5];

            string name = null;

            if (args.Length == 8)
            {
                name = string.Format("{0} {1}", args[6], args[7]);
            }

            if (param == "process-unacked-sends")
            {
                bool newValue;

                if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
                {
                    return;
                }

                m_udpServer.Scene.ForEachScenePresence(
                    sp =>
                {
                    if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
                    {
                        LLUDPClient udpClient         = ((LLClientView)sp.ControllingClient).UDPClient;
                        udpClient.ProcessUnackedSends = newValue;

                        m_console.OutputFormat("{0} set to {1} for {2} in {3}", param, newValue, sp.Name, m_udpServer.Scene.Name);
                    }
                });
            }
        }
Exemple #19
0
        protected override void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
        {
            // Create the LLUDPClient
            LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
            IClientAPI existingClient;

            if (!m_scene.TryGetClient(agentID, out existingClient))
            {
                // Create the LLClientView
                LLClientView client = CreateNewClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
                client.OnLogout += LogoutHandler;

                // Start the IClientAPI
                client.Start();
            }
            else
            {
                m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
                    udpClient.AgentID, remoteEndPoint, circuitCode);
            }
        }
Exemple #20
0
        protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
        {
            // Create the LLUDPClient
            LLUDPClient udpClient = new LLUDPClient(this, m_throttleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
            IClientAPI  existingClient;

            if (!m_scene.TryGetClient(agentID, out existingClient))
            {
                // Create the LLClientView
                LLClientView client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
                client.OnLogout += LogoutHandler;

                // Start the IClientAPI
                client.Start();
            }
            else
            {
                m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
                                 udpClient.AgentID, remoteEndPoint, circuitCode);
            }
        }
        private void ProcessInPacket(object state)
        {
            IncomingPacket incomingPacket = (IncomingPacket)state;
            Packet         packet         = incomingPacket.Packet;
            LLUDPClient    udpClient      = incomingPacket.Client;
            IClientAPI     client;

            // Sanity check
            if (packet == null || udpClient == null)
            {
                m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
                                 packet, udpClient);
            }

            // Make sure this client is still alive
            if (m_scene.TryGetClient(udpClient.AgentID, out client))
            {
                try
                {
                    // Process this packet
                    client.ProcessInPacket(packet);
                }
                catch (ThreadAbortException)
                {
                    // If something is trying to abort the packet processing thread, take that as a hint that it's time to shut down
                    m_log.Info("[LLUDPSERVER]: Caught a thread abort, shutting down the LLUDP server");
                    Stop();
                }
                catch (Exception e)
                {
                    // Don't let a failure in an individual client thread crash the whole sim.
                    m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
                    m_log.Error(e.Message, e);
                }
            }
            else
            {
                m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
            }
        }
Exemple #22
0
        private void ClientOutgoingPacketHandler(IClientAPI client)
        {
            try
            {
                if (client is LLClientView)
                {
                    LLUDPClient udpClient = ((LLClientView)client).UDPClient;

                    if (udpClient.IsConnected)
                    {
                        if (m_resendUnacked)
                        {
                            ResendUnacked(udpClient);
                        }

                        if (m_sendAcks)
                        {
                            SendAcks(udpClient);
                        }

                        if (m_sendPing)
                        {
                            SendPing(udpClient);
                        }

                        // Dequeue any outgoing packets that are within the throttle limits
                        if (udpClient.DequeueOutgoing(4)) // limit number of packets for each client per call
                        {
                            m_packetSent = true;
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
                            " threw an exception: " + ex.Message, ex);
                return;
            }
        }
Exemple #23
0
 protected LLClientView CreateNewClientView(EndPoint remoteEP, Scene scene, LLUDPServer udpServer, LLUDPClient udpClient,
     AuthenticateResponse sessionInfo, OpenMetaverse.UUID agentId, OpenMetaverse.UUID sessionId, uint circuitCode)
 {
     switch (m_clientToSpawn.ToLower())
     {
         case "ng":
         case "naali":
             return new NaaliClientView(remoteEP, scene, udpServer, udpClient,
                           sessionInfo, agentId, sessionId, circuitCode);
         case "0.4":
         case "0.40":
         case "0.41":
         case "legacy":
             return new RexClientViewLegacy(remoteEP, scene, udpServer, udpClient,
                           sessionInfo, agentId, sessionId, circuitCode);
         case "default":
         case "compatible":
         default:
             return new RexClientViewCompatible(remoteEP, scene, udpServer, udpClient,
                           sessionInfo, agentId, sessionId, circuitCode);
     }
 }
        private void HandleClientGetCommand(string module, string[] args)
        {
            if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
            {
                return;
            }

            if (args.Length != 4 && args.Length != 6)
            {
                MainConsole.Instance.OutputFormat("Usage: debug lludp client get [<avatar-first-name> <avatar-last-name>]");
                return;
            }

            string name = null;

            if (args.Length == 6)
            {
                name = string.Format("{0} {1}", args[4], args[5]);
            }

            m_udpServer.Scene.ForEachScenePresence(
                sp =>
            {
                if ((name == null || sp.Name == name) && sp.ControllingClient is LLClientView)
                {
                    LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;

                    m_console.OutputFormat(
                        "Client debug parameters for {0} ({1}) in {2}",
                        sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);

                    ConsoleDisplayList cdl = new ConsoleDisplayList();
                    cdl.AddRow("process-unacked-sends", udpClient.ProcessUnackedSends);

                    m_console.Output(cdl.ToString());
                }
            });
        }
Exemple #25
0
        private void ProcessInPacket(object state)
        {
            IncomingPacket incomingPacket = (IncomingPacket)state;
            Packet         packet         = incomingPacket.Packet;
            LLUDPClient    udpClient      = incomingPacket.Client;
            IClientAPI     client;

            // Sanity check
            if (packet == null || udpClient == null)
            {
                m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
                                 packet, udpClient);
            }

            // Make sure this client is still alive
            if (m_scene.TryGetClient(udpClient.AgentID, out client))
            {
                try
                {
                    // Process this packet
                    client.ProcessInPacket(packet);
                }
                catch (Exception e)
                {
                    if (e.Message == "Closing")
                    {
                        // Don't let a failure in an individual client thread crash the whole sim.
                        m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
                        m_log.Error(e.Message, e);
                    }
                }
            }
            else
            {
                m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
            }
        }
Exemple #26
0
        protected virtual bool AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AgentCircuitData 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;

                client.DisableFacelights = m_disableFacelights;

                // Start the IClientAPI
                m_scene.AddNewClient(client);
            }
            else
            {
                m_log.DebugFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode ({0}) from {1} at {2} ",
                                  circuitCode, agentID, remoteEndPoint);
            }
            return(true);
        }
        private void HandleThrottleSetCommand(string module, string[] args)
        {
            if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
            {
                return;
            }

            bool all = args.Length == 6;
            bool one = args.Length == 8;

            if (!all && !one)
            {
                MainConsole.Instance.Output(
                    "Usage: debug lludp throttles set <param> <value> [<avatar-first-name> <avatar-last-name>]");
                return;
            }

            string param    = args[4];
            string rawValue = args[5];

            string firstName = null;
            string lastName  = null;

            if (one)
            {
                firstName = args[6];
                lastName  = args[7];
            }

            if (param == "adaptive")
            {
                bool newValue;
                if (!ConsoleUtil.TryParseConsoleBool(MainConsole.Instance, rawValue, out newValue))
                {
                    return;
                }

                m_udpServer.Scene.ForEachScenePresence(sp =>
                {
                    if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
                    {
                        MainConsole.Instance.Output(
                            "Setting param {0} to {1} for {2} ({3}) in {4}",
                            param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);

                        LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
                        udpClient.FlowThrottle.AdaptiveEnabled = newValue;
                        //                        udpClient.FlowThrottle.MaxDripRate = 0;
                        //                        udpClient.FlowThrottle.AdjustedDripRate = 0;
                    }
                });
            }
            else if (param == "request")
            {
                int newValue;
                if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
                {
                    return;
                }

                int newCurrentThrottleKbps = newValue * 1000 / 8;

                m_udpServer.Scene.ForEachScenePresence(sp =>
                {
                    if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
                    {
                        MainConsole.Instance.Output(
                            "Setting param {0} to {1} for {2} ({3}) in {4}",
                            param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);

                        LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
                        udpClient.FlowThrottle.RequestedDripRate = newCurrentThrottleKbps;
                    }
                });
            }
            else if (param == "max")
            {
                int newValue;
                if (!ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, rawValue, out newValue))
                {
                    return;
                }

                int newThrottleMaxKbps = newValue * 1000 / 8;

                m_udpServer.Scene.ForEachScenePresence(sp =>
                {
                    if (all || (sp.Firstname == firstName && sp.Lastname == lastName))
                    {
                        MainConsole.Instance.Output(
                            "Setting param {0} to {1} for {2} ({3}) in {4}",
                            param, newValue, sp.Name, sp.IsChildAgent ? "child" : "root", m_udpServer.Scene.Name);

                        LLUDPClient udpClient = ((LLClientView)sp.ControllingClient).UDPClient;
                        udpClient.FlowThrottle.MaxDripRate = newThrottleMaxKbps;
                    }
                });
            }
        }
Exemple #28
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);
 }
Exemple #29
0
        public void SendAcks(LLUDPClient udpClient)
        {
            uint ack;

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

                while (udpClient.PendingAcks.Dequeue(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);
            }
        }
 /// <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;
 }
Exemple #31
0
        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);

                if (m_scene.Stats is OpenSim.Framework.Statistics.SimExtraStatsCollector)
                {
                    OpenSim.Framework.Statistics.SimExtraStatsCollector stats = m_scene.Stats as OpenSim.Framework.Statistics.SimExtraStatsCollector;
                    stats.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();

                // 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);
                }
            }
        }
Exemple #32
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;
 }
Exemple #33
0
        /// <summary>
        /// Add a client.
        /// </summary>
        /// <param name="circuitCode"></param>
        /// <param name="agentID"></param>
        /// <param name="sessionID"></param>
        /// <param name="remoteEndPoint"></param>
        /// <param name="sessionInfo"></param>
        /// <returns>The client if it was added.  Null if the client already existed.</returns>
        protected virtual IClientAPI AddClient(
            uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
        {
            IClientAPI client = null;

            // In priciple there shouldn't be more than one thread here, ever.
            // But in case that happens, we need to synchronize this piece of code
            // because it's too important
            lock (this) 
            {
                if (!m_scene.TryGetClient(agentID, out client))
                {
                    LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);

                    client = new LLClientView(remoteEndPoint, m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
                    client.OnLogout += LogoutHandler;

                    ((LLClientView)client).DisableFacelights = m_disableFacelights;

                    client.Start();
                }
            }

            return client;
        }
Exemple #34
0
        /// <summary>
        /// Start the process of sending a packet to the client.
        /// </summary>
        /// <param name="udpClient"></param>
        /// <param name="packet"></param>
        /// <param name="category"></param>
        /// <param name="allowSplitting"></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 virtual void SendPacket(
            LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting, UnackedPacketMethod method)
        {
            // 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)
                    m_log.Error("[LLUDPSERVER]: 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.Type, category, method);
                }
            }
            else
            {
                byte[] data = packet.ToBytes();
                SendPacketData(udpClient, data, packet.Type, category, method);
            }

            PacketPool.Instance.ReturnPacket(packet);

            m_dataPresentEvent.Set();
        }
Exemple #35
0
 public void Flush(LLUDPClient udpClient)
 {
     // FIXME: Implement?
 }
Exemple #36
0
        public void SendPing(LLUDPClient udpClient)
        {
            StartPingCheckPacket pc = (StartPingCheckPacket)PacketPool.Instance.GetPacket(PacketType.StartPingCheck);
            pc.Header.Reliable = false;

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

            SendPacket(udpClient, pc, ThrottleOutPacketType.Unknown, false, null);
        }
Exemple #37
0
 private 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);
     }
 }
Exemple #38
0
        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("", MonitorModuleHelper.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();

                for (int i = 0; i < expiredPackets.Count; ++i)
                {
                    if (expiredPackets[i].UnackedMethod != null)
                        expiredPackets[i].UnackedMethod(expiredPackets[i]);
                }

                // Resend packets
                for (int i = 0; i < expiredPackets.Count; i++)
                {
                    if (expiredPackets[i].UnackedMethod != null)
                        continue; //If its not null, it has taken care of the packet sending on its own

                    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);
                }
            }
        }
Exemple #39
0
        public void HandleUnacked(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);
                StatsManager.SimExtraStats.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]: Handling " + expiredPackets.Count + " packets to " + udpClient.AgentID + ", RTO=" + udpClient.RTO);
                // Exponential backoff of the retransmission timeout
                udpClient.BackoffRTO();
                for (int i = 0; i < expiredPackets.Count; ++i)
                    expiredPackets[i].UnackedMethod(expiredPackets[i]);
            }
        }
Exemple #40
0
        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);
                    }
                }
            }
        }
        protected virtual void AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
        {
            // In priciple there shouldn't be more than one thread here, ever.
            // But in case that happens, we need to synchronize this piece of code
            // because it's too important
            lock (this) 
            {
                IClientAPI existingClient;

                if (!m_scene.TryGetClient(agentID, out existingClient))
                {
                    // Create the LLUDPClient
                    LLUDPClient udpClient = new LLUDPClient(this, 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;

                    client.DisableFacelights = m_disableFacelights;

                    // Start the IClientAPI
                    client.Start();

                }
                else
                {
                    m_log.WarnFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode from {0} at {1} for circuit {2}",
                        existingClient.AgentId, remoteEndPoint, circuitCode);
                }
            }
        }
Exemple #42
0
 public RefillRequest(LLUDPClient client, ThrottleOutPacketTypeFlags categories)
 {
     Client     = client;
     Categories = categories;
 }
Exemple #43
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("[LLUDPSERVER]: 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);
                    data = null;
                }
                datas = null;
            }
            else
            {
                byte[] data = packet.ToBytes();
                SendPacketData(udpClient, data, packet, category, resendMethod, finishedMethod);
                data = null;
            }
            packet = null;
        }
Exemple #44
0
 private void RemoveClient(LLUDPClient udpClient)
 {
     // Remove this client from the scene
     IClientAPI client;
     if (m_scene.TryGetClient(udpClient.AgentID, out client))
     {
         client.IsLoggingOut = true;
         client.Close();
     }
 }
        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
        }
Exemple #46
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 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
        }
Exemple #47
0
        public void SendPacket(LLUDPClient udpClient, Packet packet, ThrottleOutPacketType category, bool allowSplitting)
        {
            // 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)
                //    m_log.Debug("[LLUDPSERVER]: Split " + packet.Type + " packet into " + packetCount + " packets");

                for (int i = 0; i < packetCount; i++)
                {
                    byte[] data = datas[i];
                    SendPacketData(udpClient, data, packet.Type, category);
                }
            }
            else
            {
                byte[] data = packet.ToBytes();
                SendPacketData(udpClient, data, packet.Type, category);
            }
        }
Exemple #48
0
        protected virtual bool AddClient(uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AgentCircuitData 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;

                client.DisableFacelights = m_disableFacelights;

                // Start the IClientAPI
                m_scene.AddNewClient(client);
                m_currentClients.Add (client);
            }
            else
            {
                m_log.DebugFormat("[LLUDPSERVER]: Ignoring a repeated UseCircuitCode ({0}) from {1} at {2} ",
                    circuitCode, agentID, remoteEndPoint);
            }
            return true;
        }
 public void Flush(LLUDPClient udpClient)
 {
     // FIXME: Implement?
 }
Exemple #50
0
        public void SendAcks(LLUDPClient udpClient)
        {
            uint ack;

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

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

                PacketAckPacket packet = new PacketAckPacket();
                packet.Header.Reliable = false;
                packet.Packets = blocks.ToArray();

                SendPacket(udpClient, packet, ThrottleOutPacketType.Unknown, true, null);
            }
        }
        /// <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;
        }
Exemple #52
0
 public void CompletePing(LLUDPClient udpClient, byte pingID)
 {
     CompletePingCheckPacket completePing = new CompletePingCheckPacket();
     completePing.PingID.PingID = pingID;
     SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
 }
        protected override void PacketReceived(UDPPacketBuffer buffer)
        {
            // Debugging/Profiling
            //try { Thread.CurrentThread.Name = "PacketReceived (" + m_scene.RegionInfo.RegionName + ")"; }
            //catch (Exception) { }

            LLUDPClient udpClient = null;
            Packet      packet    = null;
            int         packetEnd = buffer.DataLength - 1;
            IPEndPoint  address   = (IPEndPoint)buffer.RemoteEndPoint;

            #region Decoding

            try
            {
                packet = Packet.BuildPacket(buffer.Data, ref packetEnd,
                                            // Only allocate a buffer for zerodecoding if the packet is zerocoded
                                            ((buffer.Data[0] & Helpers.MSG_ZEROCODED) != 0) ? new byte[4096] : null);
            }
            catch (MalformedDataException)
            {
            }

            // Fail-safe check
            if (packet == null)
            {
                m_log.ErrorFormat("[LLUDPSERVER]: Malformed data, cannot parse {0} byte packet from {1}:",
                                  buffer.DataLength, buffer.RemoteEndPoint);
                m_log.Error(Utils.BytesToHexString(buffer.Data, buffer.DataLength, null));
                return;
            }

            #endregion Decoding

            #region Packet to Client Mapping

            // UseCircuitCode handling
            if (packet.Type == PacketType.UseCircuitCode)
            {
                object[] array = new object[] { buffer, packet };

                if (m_asyncPacketHandling)
                {
                    Util.FireAndForget(HandleUseCircuitCode, array);
                }
                else
                {
                    HandleUseCircuitCode(array);
                }

                return;
            }

            // Determine which agent this packet came from
            IClientAPI client;
            if (!m_scene.TryGetClient(address, out client) || !(client is LLClientView))
            {
                //m_log.Debug("[LLUDPSERVER]: Received a " + packet.Type + " packet from an unrecognized source: " + address + " in " + m_scene.RegionInfo.RegionName);
                return;
            }

            udpClient = ((LLClientView)client).UDPClient;

            if (!udpClient.IsConnected)
            {
                return;
            }

            #endregion Packet to Client Mapping

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

            int now = Environment.TickCount & Int32.MaxValue;
            udpClient.TickLastPacketReceived = now;

            #region ACK Receiving

            // Handle appended ACKs
            if (packet.Header.AppendedAcks && packet.Header.AckList != null)
            {
                for (int i = 0; i < packet.Header.AckList.Length; i++)
                {
                    udpClient.NeedAcks.Remove(packet.Header.AckList[i], now, packet.Header.Resent);
                }
            }

            // Handle PacketAck packets
            if (packet.Type == PacketType.PacketAck)
            {
                PacketAckPacket ackPacket = (PacketAckPacket)packet;

                for (int i = 0; i < ackPacket.Packets.Length; i++)
                {
                    udpClient.NeedAcks.Remove(ackPacket.Packets[i].ID, now, packet.Header.Resent);
                }

                // We don't need to do anything else with PacketAck packets
                return;
            }

            #endregion ACK Receiving

            #region ACK Sending

            if (packet.Header.Reliable)
            {
                udpClient.PendingAcks.Enqueue(packet.Header.Sequence);

                // This is a somewhat odd sequence of steps to pull the client.BytesSinceLastACK value out,
                // add the current received bytes to it, test if 2*MTU bytes have been sent, if so remove
                // 2*MTU bytes from the value and send ACKs, and finally add the local value back to
                // client.BytesSinceLastACK. Lockless thread safety
                int bytesSinceLastACK = Interlocked.Exchange(ref udpClient.BytesSinceLastACK, 0);
                bytesSinceLastACK += buffer.DataLength;
                if (bytesSinceLastACK > LLUDPServer.MTU * 2)
                {
                    bytesSinceLastACK -= LLUDPServer.MTU * 2;
                    SendAcks(udpClient);
                }
                Interlocked.Add(ref udpClient.BytesSinceLastACK, bytesSinceLastACK);
            }

            #endregion ACK Sending

            #region Incoming Packet Accounting

            // Check the archive of received reliable packet IDs to see whether we already received this packet
            if (packet.Header.Reliable && !udpClient.PacketArchive.TryEnqueue(packet.Header.Sequence))
            {
                if (packet.Header.Resent)
                {
                    m_log.DebugFormat(
                        "[LLUDPSERVER]: Received a resend of already processed packet #{0}, type {1} from {2}",
                        packet.Header.Sequence, packet.Type, client.Name);
                }
                else
                {
                    m_log.WarnFormat(
                        "[LLUDPSERVER]: Received a duplicate (not marked as resend) of packet #{0}, type {1} from {2}",
                        packet.Header.Sequence, packet.Type, client.Name);
                }

                // Avoid firing a callback twice for the same packet
                return;
            }

            #endregion Incoming Packet Accounting

            #region BinaryStats
            LogPacketHeader(true, udpClient.CircuitCode, 0, packet.Type, (ushort)packet.Length);
            #endregion BinaryStats

            #region Ping Check Handling

            if (packet.Type == PacketType.StartPingCheck)
            {
                // We don't need to do anything else with ping checks
                StartPingCheckPacket startPing = (StartPingCheckPacket)packet;
                CompletePing(udpClient, startPing.PingID.PingID);

                if ((Environment.TickCount - m_elapsedMSSinceLastStatReport) >= 3000)
                {
                    udpClient.SendPacketStats();
                    m_elapsedMSSinceLastStatReport = Environment.TickCount;
                }
                return;
            }
            else if (packet.Type == PacketType.CompletePingCheck)
            {
                // We don't currently track client ping times
                return;
            }

            #endregion Ping Check Handling

            // Inbox insertion
            packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
        }
Exemple #54
0
        /// <summary>
        /// Add a client.
        /// </summary>
        /// <param name="circuitCode"></param>
        /// <param name="agentID"></param>
        /// <param name="sessionID"></param>
        /// <param name="remoteEndPoint"></param>
        /// <param name="sessionInfo"></param>
        /// <returns>The client if it was added.  Null if the client already existed.</returns>
        protected virtual IClientAPI AddClient(
            uint circuitCode, UUID agentID, UUID sessionID, IPEndPoint remoteEndPoint, AuthenticateResponse sessionInfo)
        {
            IClientAPI client = null;

            // We currently synchronize this code across the whole scene to avoid issues such as
            // http://opensimulator.org/mantis/view.php?id=5365  However, once locking per agent circuit can be done
            // consistently, this lock could probably be removed.
            lock (this)
            {
                if (!m_scene.TryGetClient(agentID, out client))
                {
                    LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO);
    
                    client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode);
                    client.OnLogout += LogoutHandler;
                    client.DebugPacketLevel = DefaultClientPacketDebugLevel;
    
                    ((LLClientView)client).DisableFacelights = m_disableFacelights;
    
                    client.Start();
                }
            }

            return client;
        }
Exemple #55
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>
 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category)
 {
     Client = client;
     Buffer = buffer;
     Category = category;
 }
Exemple #56
0
        /// <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
        }
 /// <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>
 public OutgoingPacket(LLUDPClient client, UDPPacketBuffer buffer, ThrottleOutPacketType category)
 {
     Client   = client;
     Buffer   = buffer;
     Category = category;
 }