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.
integration
Justin Clark-Casey (justincc) 2012-08-20 20:24:54 +01:00
parent 9aec62f0ac
commit bcbd450fe4
14 changed files with 69 additions and 22 deletions

View File

@ -1033,7 +1033,21 @@ namespace OpenSim.Framework
void InPacket(object NewPack); void InPacket(object NewPack);
void ProcessInPacket(Packet NewPack); void ProcessInPacket(Packet NewPack);
/// <summary>
/// Close this client
/// </summary>
void Close(); void Close();
/// <summary>
/// Close this client
/// </summary>
/// <param name='force'>
/// 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.
/// </param>
void Close(bool force);
void Kick(string message); void Kick(string message);
/// <summary> /// <summary>

View File

@ -35,6 +35,7 @@ using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Timers; using System.Timers;
using log4net; using log4net;
using NDesk.Options;
using Nini.Config; using Nini.Config;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
@ -310,8 +311,11 @@ namespace OpenSim
"Change the scale of a named prim", HandleEditScale); "Change the scale of a named prim", HandleEditScale);
m_console.Commands.AddCommand("Users", false, "kick user", m_console.Commands.AddCommand("Users", false, "kick user",
"kick user <first> <last> [message]", "kick user <first> <last> [--force] [message]",
"Kick a user off the simulator", KickUserCommand); "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", m_console.Commands.AddCommand("Users", false, "show users",
"show users [full]", "show users [full]",
@ -453,11 +457,17 @@ namespace OpenSim
/// <param name="cmdparams">name of avatar to kick</param> /// <param name="cmdparams">name of avatar to kick</param>
private void KickUserCommand(string module, string[] cmdparams) 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<string> mainParams = options.Parse(cmdparams);
if (mainParams.Count < 4)
return; return;
string alert = null; string alert = null;
if (cmdparams.Length > 4) if (mainParams.Count > 4)
alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4)); alert = String.Format("\n{0}\n", String.Join(" ", cmdparams, 4, cmdparams.Length - 4));
IList agents = SceneManager.GetCurrentSceneAvatars(); IList agents = SceneManager.GetCurrentSceneAvatars();
@ -466,8 +476,8 @@ namespace OpenSim
{ {
RegionInfo regionInfo = presence.Scene.RegionInfo; RegionInfo regionInfo = presence.Scene.RegionInfo;
if (presence.Firstname.ToLower().Contains(cmdparams[2].ToLower()) && if (presence.Firstname.ToLower().Contains(mainParams[2].ToLower()) &&
presence.Lastname.ToLower().Contains(cmdparams[3].ToLower())) presence.Lastname.ToLower().Contains(mainParams[3].ToLower()))
{ {
MainConsole.Instance.Output( MainConsole.Instance.Output(
String.Format( String.Format(
@ -480,7 +490,7 @@ namespace OpenSim
else else
presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n"); presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n");
presence.Scene.IncomingCloseAgent(presence.UUID); presence.Scene.IncomingCloseAgent(presence.UUID, force);
} }
} }

View File

@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
UUID spId = TestHelpers.ParseTail(0x1); UUID spId = TestHelpers.ParseTail(0x1);
SceneHelpers.AddScenePresence(m_scene, spId); 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 // TODO: Add more assertions for the other aspects of event queues
Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0)); Assert.That(MainServer.Instance.GetPollServiceHandlerKeys().Count, Is.EqualTo(0));

View File

@ -487,16 +487,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP
#region Client Methods #region Client Methods
/// <summary>
/// Close down the client view
/// </summary>
public void Close() 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. // 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. // a simultaneous relog just as a client is being closed out due to no packet ack from the old connection.
lock (CloseSyncLock) 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; return;
IsActive = false; IsActive = false;
@ -11989,7 +11993,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
Kick(reason); Kick(reason);
Thread.Sleep(1000); Thread.Sleep(1000);
Close(); Disconnect();
} }
public void Disconnect() public void Disconnect()

View File

@ -461,7 +461,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
SceneObjectGroup rezzedAtt = presence.GetAttachments()[0]; 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. // Check that we can't retrieve this attachment from the scene.
Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null); Assert.That(scene.GetSceneObjectGroup(rezzedAtt.UUID), Is.Null);

View File

@ -644,7 +644,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// an agent cannot teleport back to this region if it has teleported away. // an agent cannot teleport back to this region if it has teleported away.
Thread.Sleep(2000); Thread.Sleep(2000);
sp.Scene.IncomingCloseAgent(sp.UUID); sp.Scene.IncomingCloseAgent(sp.UUID, false);
} }
else else
{ {

View File

@ -312,7 +312,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate", // "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
// s.RegionInfo.RegionName, destination.RegionHandle); // 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; return true;
} }

View File

@ -4116,16 +4116,19 @@ namespace OpenSim.Region.Framework.Scenes
/// <summary> /// <summary>
/// Tell a single agent to disconnect from the region. /// Tell a single agent to disconnect from the region.
/// </summary> /// </summary>
/// <param name="regionHandle"></param>
/// <param name="agentID"></param> /// <param name="agentID"></param>
public bool IncomingCloseAgent(UUID agentID) /// <param name="force">
/// 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.
/// </param>
public bool IncomingCloseAgent(UUID agentID, bool force)
{ {
//m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID);
ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
if (presence != null) if (presence != null)
{ {
presence.ControllingClient.Close(); presence.ControllingClient.Close(force);
return true; return true;
} }

View File

@ -141,7 +141,7 @@ namespace OpenSim.Region.Framework.Scenes.Tests
TestScene scene = new SceneHelpers().SetupScene(); TestScene scene = new SceneHelpers().SetupScene();
ScenePresence sp = SceneHelpers.AddScenePresence(scene, TestHelpers.ParseTail(0x1)); 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.GetScenePresence(sp.UUID), Is.Null);
Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null); Assert.That(scene.AuthenticateHandler.GetAgentCircuitData(sp.UUID), Is.Null);

View File

@ -885,6 +885,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
} }
public void Close() public void Close()
{
Close(false);
}
public void Close(bool force)
{ {
Disconnect(); Disconnect();
} }

View File

@ -900,6 +900,11 @@ namespace OpenSim.Region.OptionalModules.World.NPC
} }
public void Close() public void Close()
{
Close(false);
}
public void Close(bool force)
{ {
// Remove ourselves from the scene // Remove ourselves from the scene
m_scene.RemoveClient(AgentId, false); m_scene.RemoveClient(AgentId, false);

View File

@ -2891,7 +2891,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
sp.ControllingClient.Kick(alert); sp.ControllingClient.Kick(alert);
// ...and close on our side // ...and close on our side
sp.Scene.IncomingCloseAgent(sp.UUID); sp.Scene.IncomingCloseAgent(sp.UUID, false);
} }
}); });
} }

View File

@ -933,6 +933,11 @@ namespace OpenSim.Tests.Common.Mock
} }
public void Close() public void Close()
{
Close(false);
}
public void Close(bool force)
{ {
// Fire the callback for this connection closing // Fire the callback for this connection closing
// This is necesary to get the presence detector to notice that a client has logged out. // This is necesary to get the presence detector to notice that a client has logged out.

View File

@ -1760,6 +1760,7 @@
<Reference name="System.Core"/> <Reference name="System.Core"/>
<Reference name="System.Xml"/> <Reference name="System.Xml"/>
<Reference name="Mono.Addins" path="../../../bin/"/> <Reference name="Mono.Addins" path="../../../bin/"/>
<Reference name="NDesk.Options" path="../../../bin/"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/> <Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/> <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/> <Reference name="OpenMetaverse" path="../../../bin/"/>