From 3b972417167e2c5d3aa7b2d390a5be68e5509dc5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 20 Aug 2012 20:24:54 +0100 Subject: Add --force flag to "kick user" console command to allow bypassing of recent race condition checks. This is to allow a second attempt to remove an avatar even if "show connections" shows them as already inactive (i.e. close has already been attempted once). You should only attempt --force if a normal kick fails. This is partly for diagnostics as we have seen some connections occasionally remain on lbsa plaza even if they are registered as inactive. This is not a permanent solution and may not work anyway - the ultimate solution is to stop this problem from happening in the first place. --- OpenSim/Framework/IClientAPI.cs | 14 +++++++++++++ OpenSim/Region/Application/OpenSim.cs | 24 +++++++++++++++------- .../Caps/EventQueue/Tests/EventQueueTests.cs | 2 +- .../Region/ClientStack/Linden/UDP/LLClientView.cs | 14 ++++++++----- .../Attachments/Tests/AttachmentsModuleTests.cs | 4 ++-- .../EntityTransfer/EntityTransferModule.cs | 2 +- .../Simulation/LocalSimulationConnector.cs | 2 +- OpenSim/Region/Framework/Scenes/Scene.cs | 9 +++++--- .../Scenes/Tests/ScenePresenceAgentTests.cs | 2 +- .../Server/IRCClientView.cs | 5 +++++ .../Region/OptionalModules/World/NPC/NPCAvatar.cs | 5 +++++ .../Shared/Api/Implementation/OSSL_Api.cs | 4 ++-- OpenSim/Tests/Common/Mock/TestClient.cs | 5 +++++ prebuild.xml | 1 + 14 files changed, 70 insertions(+), 23 deletions(-) diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index d5952c4..8a63bff 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1033,7 +1033,21 @@ namespace OpenSim.Framework void InPacket(object NewPack); void ProcessInPacket(Packet NewPack); + + /// + /// Close this client + /// void Close(); + + /// + /// Close this client + /// + /// + /// If true, attempts the close without checking active status. You do not want to try this except as a last + /// ditch attempt where Active == false but the ScenePresence still exists. + /// + void Close(bool force); + void Kick(string message); /// diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 6bbab35..1fc11f5 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -35,6 +35,7 @@ using System.Text; using System.Text.RegularExpressions; using System.Timers; using log4net; +using NDesk.Options; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; @@ -310,8 +311,11 @@ namespace OpenSim "Change the scale of a named prim", HandleEditScale); m_console.Commands.AddCommand("Users", false, "kick user", - "kick user [message]", - "Kick a user off the simulator", KickUserCommand); + "kick user [--force] [message]", + "Kick a user off the simulator", + "The --force option will kick the user without any checks to see whether it's already in the process of closing\n" + + "Only use this option if you are sure the avatar is inactive and a normal kick user operation does not removed them", + KickUserCommand); m_console.Commands.AddCommand("Users", false, "show users", "show users [full]", @@ -453,11 +457,17 @@ namespace OpenSim /// name of avatar to kick private void KickUserCommand(string module, string[] cmdparams) { - if (cmdparams.Length < 4) + bool force = false; + + OptionSet options = new OptionSet().Add("f|force", delegate (string v) { force = v != null; }); + + List mainParams = options.Parse(cmdparams); + + if (mainParams.Count < 4) return; string alert = null; - if (cmdparams.Length > 4) + if (mainParams.Count > 4) alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4)); IList agents = SceneManager.GetCurrentSceneAvatars(); @@ -466,8 +476,8 @@ namespace OpenSim { RegionInfo regionInfo = presence.Scene.RegionInfo; - if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) && - presence.Lastname.ToLower().Contains(cmdparams[3].ToLower())) + if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) && + presence.Lastname.ToLower().Contains(mainParams[3].ToLower())) { MainConsole.Instance.Output( String.Format( @@ -480,7 +490,7 @@ namespace OpenSim else presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); - presence.Scene.IncomingCloseAgent(presence.UUID); + presence.Scene.IncomingCloseAgent(presence.UUID, force); } } diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs index cd70410..d604cf6 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/Tests/EventQueueTests.cs @@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests UUID spId = TestHelpers.ParseTail(0x1); SceneHelpers.AddScenePresence(m_scene, spId); - m_scene.IncomingCloseAgent(spId); + m_scene.IncomingCloseAgent(spId, false); // TODO: Add more assertions for the other aspects of event queues Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs index 22b3d35..148d0e0 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs @@ -487,16 +487,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP #region Client Methods - /// - /// Close down the client view - /// public void Close() { + Close(false); + } + + public void Close(bool force) + { // We lock here to prevent race conditions between two threads calling close simultaneously (e.g. // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection. lock (CloseSyncLock) { - if (!IsActive) + // We still perform a force close inside the sync lock since this is intended to attempt close where + // there is some unidentified connection problem, not where we have issues due to deadlock + if (!IsActive && !force) return; IsActive = false; @@ -11989,7 +11993,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP { Kick(reason); Thread.Sleep(1000); - Close(); + Disconnect(); } public void Disconnect() diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs index 6e7a414..5d82d2c 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/Tests/AttachmentsModuleTests.cs @@ -461,7 +461,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; - scene.IncomingCloseAgent(presence.UUID); + scene.IncomingCloseAgent(presence.UUID, false); // Check that we can't retrieve this attachment from the scene. Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); @@ -641,4 +641,4 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests // Assert.That(presence.HasAttachments(), Is.True, "Presence has not received new objects"); // } } -} \ No newline at end of file +} diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 46738f6..c63b0a4 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs @@ -644,7 +644,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer // an agent cannot teleport back to this region if it has teleported away. Thread.Sleep(2000); - sp.Scene.IncomingCloseAgent(sp.UUID); + sp.Scene.IncomingCloseAgent(sp.UUID, false); } else { diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs index 09a3bd6..1e52d37 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Simulation/LocalSimulationConnector.cs @@ -312,7 +312,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // s.RegionInfo.RegionName, destination.RegionHandle); - Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id); }); + Util.FireAndForget(delegate { m_scenes[destination.RegionID].IncomingCloseAgent(id, false); }); return true; } diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index 40cfb72..b2592d4 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs @@ -4083,16 +4083,19 @@ namespace OpenSim.Region.Framework.Scenes /// /// Tell a single agent to disconnect from the region. /// - /// /// - public bool IncomingCloseAgent(UUID agentID) + /// + /// Force the agent to close even if it might be in the middle of some other operation. You do not want to + /// force unless you are absolutely sure that the agent is dead and a normal close is not working. + /// + public bool IncomingCloseAgent(UUID agentID, bool force) { //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); if (presence != null) { - presence.ControllingClient.Close(); + presence.ControllingClient.Close(force); return true; } diff --git a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs index 5758869..5faf131 100644 --- a/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs +++ b/OpenSim/Region/Framework/Scenes/Tests/ScenePresenceAgentTests.cs @@ -141,7 +141,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests TestScene scene = new SceneHelpers().SetupScene(); ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); - scene.IncomingCloseAgent(sp.UUID); + scene.IncomingCloseAgent(sp.UUID, false); Assert.That(scene.GetScenePresence(sp.UUID), Is.Null); Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs index bae25cd..e93bd7c 100644 --- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs +++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs @@ -886,6 +886,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server public void Close() { + Close(false); + } + + public void Close(bool force) + { Disconnect(); } diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs index 67989ba..a8e4d90 100644 --- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs @@ -901,6 +901,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC public void Close() { + Close(false); + } + + public void Close(bool force) + { // Remove ourselves from the scene m_scene.RemoveClient(AgentId, false); } diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs index 859ee93..8b6f76b 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/OSSL_Api.cs @@ -2881,7 +2881,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api avatar.SpeedModifier = (float)SpeedModifier; } - public void osKickAvatar(string FirstName,string SurName,string alert) + public void osKickAvatar(string FirstName, string SurName, string alert) { CheckThreatLevel(ThreatLevel.Severe, "osKickAvatar"); m_host.AddScriptLPS(1); @@ -2895,7 +2895,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api sp.ControllingClient.Kick(alert); // ...and close on our side - sp.Scene.IncomingCloseAgent(sp.UUID); + sp.Scene.IncomingCloseAgent(sp.UUID, false); } }); } diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs index 89c4f11..bb8b935 100644 --- a/OpenSim/Tests/Common/Mock/TestClient.cs +++ b/OpenSim/Tests/Common/Mock/TestClient.cs @@ -934,6 +934,11 @@ namespace OpenSim.Tests.Common.Mock public void Close() { + Close(false); + } + + public void Close(bool force) + { // Fire the callback for this connection closing // This is necesary to get the presence detector to notice that a client has logged out. if (OnConnectionClosed != null) diff --git a/prebuild.xml b/prebuild.xml index b4f4464..1765899 100644 --- a/prebuild.xml +++ b/prebuild.xml @@ -1760,6 +1760,7 @@ + -- cgit v1.1