From c6ffaaa959adfa4b3aa7be573be271d501173f9d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Tue, 12 Jun 2012 02:16:36 +0100 Subject: [PATCH] Set IClientAPI.IsActive = false early on client removal due to ack timeout rather than using IsLoggingOut flag. IsActive is more appropriate since unack timeout is not due to voluntary logout. This is in line with operations such as manual kick that do not set the IsLoggingOut flag. It's also slightly better race-wise since it reduces the chance of this operation clashing with another reason for client deactivation (e.g. manual kick). --- OpenSim/Framework/IClientAPI.cs | 9 +-- .../ClientStack/Linden/UDP/LLUDPServer.cs | 62 ++++++++++--------- 2 files changed, 37 insertions(+), 34 deletions(-) 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