Reinsert client.SceneAgent checks into LLUDPServer.HandleCompleteMovementIntoRegion() to fix race condition regression in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100)

This check is necessary to close a race condition where the CompleteAgentMovement processing could proceed when the UseCircuitCode thread had added the client to the client manager but before the ScenePresence had registered to process the CompleteAgentMovement message.
This is most probably why the message appeared to get lost on a proportion of entity transfers.
A better long term solution may be to set the IClientAPI.SceneAgent property before the client is added to the manager.
varregion
Justin Clark-Casey (justincc) 2013-09-25 18:45:56 +01:00
parent 732554be04
commit 32ddfc2740
2 changed files with 29 additions and 11 deletions

View File

@ -1692,6 +1692,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
endPoint = (IPEndPoint)array[0]; endPoint = (IPEndPoint)array[0];
CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1]; CompleteAgentMovementPacket packet = (CompleteAgentMovementPacket)array[1];
m_log.DebugFormat(
"[LLUDPSERVER]: Handling CompleteAgentMovement request from {0} in {1}", endPoint, m_scene.Name);
// Determine which agent this packet came from // Determine which agent this packet came from
// We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination // We need to wait here because in when using the OpenSimulator V2 teleport protocol to travel to a destination
// simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode // simulator with no existing child presence, the viewer (at least LL 3.3.4) will send UseCircuitCode
@ -1703,24 +1706,36 @@ namespace OpenSim.Region.ClientStack.LindenUDP
{ {
if (m_scene.TryGetClient(endPoint, out client)) if (m_scene.TryGetClient(endPoint, out client))
{ {
if (client.IsActive) if (!client.IsActive)
{
break;
}
else
{ {
// This check exists to catch a condition where the client has been closed by another thread // This check exists to catch a condition where the client has been closed by another thread
// but has not yet been removed from the client manager (and possibly a new connection has // but has not yet been removed from the client manager (and possibly a new connection has
// not yet been established). // not yet been established).
m_log.DebugFormat( m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} for {1} in {2} but client is not active. Waiting.", "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active yet. Waiting.",
endPoint, client.Name, m_scene.Name); endPoint, client.Name, m_scene.Name);
} }
else if (client.SceneAgent == null)
{
// This check exists to catch a condition where the new client has been added to the client
// manager but the SceneAgent has not yet been set in Scene.AddNewClient(). If we are too
// eager, then the new ScenePresence may not have registered a listener for this messsage
// before we try to process it.
// XXX: A better long term fix may be to add the SceneAgent before the client is added to
// the client manager
m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client SceneAgent not set yet. Waiting.",
endPoint, client.Name, m_scene.Name);
}
else
{
break;
}
} }
else else
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} in {1} but no client exists. Waiting.", "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} in {1} but no client exists yet. Waiting.",
endPoint, m_scene.Name); endPoint, m_scene.Name);
} }
@ -1730,19 +1745,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (client == null) if (client == null)
{ {
m_log.DebugFormat( m_log.DebugFormat(
"[LLUDPSERVER]: No client found for CompleteMovementIntoRegion from {0} in {1} after wait. Dropping.", "[LLUDPSERVER]: No client found for CompleteAgentMovement from {0} in {1} after wait. Dropping.",
endPoint, m_scene.Name); endPoint, m_scene.Name);
return; return;
} }
else if (!client.IsActive) else if (!client.IsActive || client.SceneAgent == null)
{ {
// This check exists to catch a condition where the client has been closed by another thread // This check exists to catch a condition where the client has been closed by another thread
// but has not yet been removed from the client manager. // but has not yet been removed from the client manager.
// The packet could be simply ignored but it is useful to know if this condition occurred for other debugging // The packet could be simply ignored but it is useful to know if this condition occurred for other debugging
// purposes. // purposes.
m_log.DebugFormat( m_log.DebugFormat(
"[LLUDPSERVER]: Received a CompleteMovementIntoRegion from {0} for {1} in {2} but client is not active after wait. Dropping.", "[LLUDPSERVER]: Received a CompleteAgentMovement from {0} for {1} in {2} but client is not active after wait. Dropping.",
endPoint, client.Name, m_scene.Name); endPoint, client.Name, m_scene.Name);
return; return;
@ -1767,7 +1782,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
catch (Exception e) catch (Exception e)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[LLUDPSERVER]: CompleteMovementIntoRegion handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}", "[LLUDPSERVER]: CompleteAgentMovement handling from endpoint {0}, client {1} {2} failed. Exception {3}{4}",
endPoint != null ? endPoint.ToString() : "n/a", endPoint != null ? endPoint.ToString() : "n/a",
client != null ? client.Name : "unknown", client != null ? client.Name : "unknown",
client != null ? client.AgentId.ToString() : "unknown", client != null ? client.AgentId.ToString() : "unknown",

View File

@ -2863,6 +2863,9 @@ namespace OpenSim.Region.Framework.Scenes
// We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the
// client is for a root or child agent. // client is for a root or child agent.
// XXX: This may be better set for a new client before that client is added to the client manager.
// But need to know what happens in the case where a ScenePresence is already present (and if this
// actually occurs).
client.SceneAgent = sp; client.SceneAgent = sp;
// This is currently also being done earlier in NewUserConnection for real users to see if this // This is currently also being done earlier in NewUserConnection for real users to see if this