diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index 51606b4ee8..556942cca7 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -741,22 +741,19 @@ namespace OpenSim.Framework string Name { get; } /// - /// True if the client is active (sending and receiving new UDP messages). False if the client is closing. + /// True if the client is active (sending and receiving new UDP messages). False if the client is being closed. /// bool IsActive { get; set; } /// - /// Set if the client is closing due to a logout request or because of too much time since last ack. + /// Set if the client is closing due to a logout request /// /// /// Do not use this flag if you want to know if the client is closing, since it will not be set in other /// circumstances (e.g. if a child agent is closed or the agent is kicked off the simulator). Use IsActive - /// instead. + /// instead with a IClientAPI.SceneAgent.IsChildAgent check if necessary. /// /// Only set for root agents. - /// - /// TODO: Too much time since last ack should probably be a separate property, or possibly part of a state - /// machine. /// bool IsLoggingOut { get; set; } diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index 2036f61f22..37d29439a6 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs @@ -555,15 +555,17 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (udpClient.IsPaused) timeoutTicks = m_pausedAckTimeout; - if (!client.IsLoggingOut && + if (client.IsActive && (Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks) { - m_log.WarnFormat( - "[LLUDPSERVER]: Ack timeout for {0} {1}, disconnecting", - client.Name, client.AgentId); + // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even + // though it's set later on by LLClientView.Close() + client.IsActive = false; - StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); - LogoutClientDueToTimeout(client); + // Fire this out on a different thread so that we don't hold up outgoing packet processing for + // everybody else if this is being called due to an ack timeout. + // This is the same as processing as the async process of a logout request. + Util.FireAndForget(o => DeactivateClientDueToTimeout(client)); return; } @@ -792,7 +794,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP Interlocked.Increment(ref udpClient.PacketsReceived); int now = Environment.TickCount & Int32.MaxValue; - udpClient.TickLastPacketReceived = now; +// udpClient.TickLastPacketReceived = now; #region ACK Receiving @@ -1113,30 +1115,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP return client; } - private void RemoveClient(IClientAPI client) + /// + /// Deactivates the client if we don't receive any packets within a certain amount of time (default 60 seconds). + /// + /// + /// If a connection is active then we will always receive packets even if nothing else is happening, due to + /// regular client pings. + /// + /// + private void DeactivateClientDueToTimeout(IClientAPI client) { - // We must set IsLoggingOut synchronously so that we can stop the packet loop reinvoking this method. - client.IsLoggingOut = true; + // We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even + // though it's set later on by LLClientView.Close() + client.IsActive = false; - // Fire this out on a different thread so that we don't hold up outgoing packet processing for - // everybody else if this is being called due to an ack timeout. - // This is the same as processing as the async process of a logout request. - Util.FireAndForget(o => client.Close()); - } + m_log.WarnFormat( + "[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}", + client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName); - private void LogoutClientDueToTimeout(IClientAPI client) - { - // We must set IsLoggingOut synchronously so that we can stop the packet loop reinvoking this method. - client.IsLoggingOut = true; + StatsManager.SimExtraStats.AddAbnormalClientThreadTermination(); - // Fire this out on a different thread so that we don't hold up outgoing packet processing for - // everybody else if this is being called due to an ack timeout. - // This is the same as processing as the async process of a logout request. - Util.FireAndForget( - o => - { if (!client.SceneAgent.IsChildAgent) - client.Kick("Simulator logged you out due to connection timeout"); - client.Close(); }); + if (!client.SceneAgent.IsChildAgent) + client.Kick("Simulator logged you out due to connection timeout"); + + client.Close(); } private void IncomingPacketHandler() @@ -1450,8 +1452,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP protected void LogoutHandler(IClientAPI client) { client.SendLogoutPacket(); + if (!client.IsLoggingOut) - RemoveClient(client); + { + client.IsLoggingOut = true; + client.Close(); + } } } } \ No newline at end of file