From 7ee422a344ff22cf988aea2355628d2dee831983 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 13:47:16 -0700 Subject: [PATCH] * Handle UseCircuitCode packets asynchronously. Adding an agent to a scene can take several seconds, and was blocking up packet handling in the meantime * Clamp retransmission timeout values between three and 10 seconds * Log outgoing time for a packet right after it is sent instead of well before * Loop through the entire UnackedPacketCollection when looking for expired packets --- .../ClientStack/LindenUDP/LLUDPClient.cs | 7 ++- .../ClientStack/LindenUDP/LLUDPServer.cs | 47 +++++++++++++++---- .../LindenUDP/UnackedPacketCollection.cs | 8 ++-- 3 files changed, 49 insertions(+), 13 deletions(-) diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs index 458e78daa0..a43197d9bf 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPClient.cs @@ -505,8 +505,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP SRTT = (1.0f - ALPHA) * SRTT + ALPHA * r; } - // Always round retransmission timeout up to two seconds - RTO = Math.Max(2000, (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR))); + RTO = (int)(SRTT + Math.Max(m_udpServer.TickCountResolution, K * RTTVAR)); + + // Clamp the retransmission timeout to manageable values + RTO = Utils.Clamp(RTO, 3000, 10000); + //m_log.Debug("[LLUDPCLIENT]: Setting agent " + this.Agent.FullName + "'s RTO to " + RTO + "ms with an RTTVAR of " + // RTTVAR + " based on new RTT of " + r + "ms"); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index a8ce102305..209c0e0712 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -381,7 +381,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Disconnect an agent if no packets are received for some time //FIXME: Make 60 an .ini setting - if (Environment.TickCount - udpClient.TickLastPacketReceived > 1000 * 60) + if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60) { m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID); @@ -439,9 +439,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!udpClient.IsConnected) return; - // Keep track of when this packet was sent out (right now) - outgoingPacket.TickCount = Environment.TickCount; - #region ACK Appending int dataLength = buffer.DataLength; @@ -494,6 +491,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP // 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; } protected override void PacketReceived(UDPPacketBuffer buffer) @@ -536,7 +536,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP // UseCircuitCode handling if (packet.Type == PacketType.UseCircuitCode) { - AddNewClient((UseCircuitCodePacket)packet, (IPEndPoint)buffer.RemoteEndPoint); + Util.FireAndForget( + delegate(object o) + { + IPEndPoint remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint; + + // Begin the process of adding the client to the simulator + AddNewClient((UseCircuitCodePacket)packet, remoteEndPoint); + + // Acknowledge the UseCircuitCode packet + SendAckImmediate(remoteEndPoint, packet.Header.Sequence); + } + ); + return; } // Determine which agent this packet came from @@ -558,11 +570,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP // Stats tracking Interlocked.Increment(ref udpClient.PacketsReceived); - #region ACK Receiving - - int now = Environment.TickCount; + int now = Environment.TickCount & Int32.MaxValue; udpClient.TickLastPacketReceived = now; + #region ACK Receiving + // Handle appended ACKs if (packet.Header.AppendedAcks && packet.Header.AckList != null) { @@ -650,6 +662,25 @@ namespace OpenSim.Region.ClientStack.LindenUDP { } + private void SendAckImmediate(IPEndPoint remoteEndpoint, uint sequenceNumber) + { + PacketAckPacket ack = new PacketAckPacket(); + ack.Header.Reliable = false; + ack.Packets = new PacketAckPacket.PacketsBlock[1]; + ack.Packets[0] = new PacketAckPacket.PacketsBlock(); + ack.Packets[0].ID = sequenceNumber; + + byte[] packetData = ack.ToBytes(); + int length = packetData.Length; + + UDPPacketBuffer buffer = new UDPPacketBuffer(remoteEndpoint, length); + buffer.DataLength = length; + + Buffer.BlockCopy(packetData, 0, buffer.Data, 0, length); + + AsyncBeginSend(buffer); + } + private bool IsClientAuthorized(UseCircuitCodePacket useCircuitCode, out AuthenticateResponse sessionInfo) { UUID agentID = useCircuitCode.CircuitCode.ID; diff --git a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs index 12f0c0a8b5..bd5fe1cab4 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/UnackedPacketCollection.cs @@ -85,6 +85,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP /// Sequence number of the packet to /// acknowledge /// Current value of Environment.TickCount + /// This does not immediately acknowledge the packet, it only + /// queues the ack so it can be handled in a thread-safe way later public void Remove(uint sequenceNumber, int currentTime, bool fromResend) { m_pendingRemoves.Enqueue(new PendingAck(sequenceNumber, currentTime, fromResend)); @@ -108,7 +110,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (m_packets.Count > 0) { - int now = Environment.TickCount; + int now = Environment.TickCount & Int32.MaxValue; foreach (OutgoingPacket packet in m_packets.Values) { @@ -123,10 +125,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP expiredPackets = new List(); expiredPackets.Add(packet); } - else + /*else { break; - } + }*/ } }