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