diff options
author | Justin Clark-Casey (justincc) | 2012-10-10 00:26:43 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2012-10-10 00:26:43 +0100 |
commit | e76b01a201a9b2d45b56cd5dc2a207b08b4529e5 (patch) | |
tree | 81bff879c3bc3eec19ff0bde5d5029014cc8b9f4 | |
parent | minor: elaborate method doc on Scene.NewUserConnection() (diff) | |
download | opensim-SC-e76b01a201a9b2d45b56cd5dc2a207b08b4529e5.zip opensim-SC-e76b01a201a9b2d45b56cd5dc2a207b08b4529e5.tar.gz opensim-SC-e76b01a201a9b2d45b56cd5dc2a207b08b4529e5.tar.bz2 opensim-SC-e76b01a201a9b2d45b56cd5dc2a207b08b4529e5.tar.xz |
Lock on AgentCircuitData during Scene.AddClient() and RemoveClient() to prevent an inactive connection being left behind if the user closes the viewer whilst the connection is being established.
This should remove the need to run the console command "kick user --force" when these connections are left around.
3 files changed, 265 insertions, 219 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs index 594b229..0dd0904 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/EventQueue/EventQueueGetModule.cs | |||
@@ -94,7 +94,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
94 | 94 | ||
95 | //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); | 95 | //scene.CommsManager.HttpServer.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); |
96 | 96 | ||
97 | scene.EventManager.OnNewClient += OnNewClient; | 97 | // scene.EventManager.OnNewClient += OnNewClient; |
98 | 98 | ||
99 | // TODO: Leaving these open, or closing them when we | 99 | // TODO: Leaving these open, or closing them when we |
100 | // become a child is incorrect. It messes up TP in a big | 100 | // become a child is incorrect. It messes up TP in a big |
@@ -102,6 +102,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
102 | // circuit is there. | 102 | // circuit is there. |
103 | 103 | ||
104 | scene.EventManager.OnClientClosed += ClientClosed; | 104 | scene.EventManager.OnClientClosed += ClientClosed; |
105 | |||
105 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; | 106 | scene.EventManager.OnMakeChildAgent += MakeChildAgent; |
106 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; | 107 | scene.EventManager.OnRegisterCaps += OnRegisterCaps; |
107 | 108 | ||
@@ -226,16 +227,6 @@ namespace OpenSim.Region.ClientStack.Linden | |||
226 | 227 | ||
227 | #endregion | 228 | #endregion |
228 | 229 | ||
229 | private void OnNewClient(IClientAPI client) | ||
230 | { | ||
231 | //client.OnLogout += ClientClosed; | ||
232 | } | ||
233 | |||
234 | // private void ClientClosed(IClientAPI client) | ||
235 | // { | ||
236 | // ClientClosed(client.AgentId); | ||
237 | // } | ||
238 | |||
239 | private void ClientClosed(UUID agentID, Scene scene) | 230 | private void ClientClosed(UUID agentID, Scene scene) |
240 | { | 231 | { |
241 | // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); | 232 | // m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName); |
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs index d11fcbf..ab670a7 100644 --- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPServer.cs | |||
@@ -1103,20 +1103,20 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
1103 | { | 1103 | { |
1104 | IClientAPI client = null; | 1104 | IClientAPI client = null; |
1105 | 1105 | ||
1106 | // In priciple there shouldn't be more than one thread here, ever. | 1106 | // We currently synchronize this code across the whole scene to avoid issues such as |
1107 | // But in case that happens, we need to synchronize this piece of code | 1107 | // http://opensimulator.org/mantis/view.php?id=5365 However, once locking per agent circuit can be done |
1108 | // because it's too important | 1108 | // consistently, this lock could probably be removed. |
1109 | lock (this) | 1109 | lock (this) |
1110 | { | 1110 | { |
1111 | if (!m_scene.TryGetClient(agentID, out client)) | 1111 | if (!m_scene.TryGetClient(agentID, out client)) |
1112 | { | 1112 | { |
1113 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); | 1113 | LLUDPClient udpClient = new LLUDPClient(this, ThrottleRates, m_throttle, circuitCode, agentID, remoteEndPoint, m_defaultRTO, m_maxRTO); |
1114 | 1114 | ||
1115 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); | 1115 | client = new LLClientView(m_scene, this, udpClient, sessionInfo, agentID, sessionID, circuitCode); |
1116 | client.OnLogout += LogoutHandler; | 1116 | client.OnLogout += LogoutHandler; |
1117 | 1117 | ||
1118 | ((LLClientView)client).DisableFacelights = m_disableFacelights; | 1118 | ((LLClientView)client).DisableFacelights = m_disableFacelights; |
1119 | 1119 | ||
1120 | client.Start(); | 1120 | client.Start(); |
1121 | } | 1121 | } |
1122 | } | 1122 | } |
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs index ed88571..fb2decc 100644 --- a/OpenSim/Region/Framework/Scenes/Scene.cs +++ b/OpenSim/Region/Framework/Scenes/Scene.cs | |||
@@ -80,6 +80,11 @@ namespace OpenSim.Region.Framework.Scenes | |||
80 | public SynchronizeSceneHandler SynchronizeScene; | 80 | public SynchronizeSceneHandler SynchronizeScene; |
81 | 81 | ||
82 | /// <summary> | 82 | /// <summary> |
83 | /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. | ||
84 | /// </summary> | ||
85 | private object m_removeClientLock = new object(); | ||
86 | |||
87 | /// <summary> | ||
83 | /// Statistical information for this scene. | 88 | /// Statistical information for this scene. |
84 | /// </summary> | 89 | /// </summary> |
85 | public SimStatsReporter StatsReporter { get; private set; } | 90 | public SimStatsReporter StatsReporter { get; private set; } |
@@ -2709,69 +2714,89 @@ namespace OpenSim.Region.Framework.Scenes | |||
2709 | 2714 | ||
2710 | public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) | 2715 | public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type) |
2711 | { | 2716 | { |
2717 | ScenePresence sp; | ||
2718 | bool vialogin; | ||
2719 | |||
2712 | // Validation occurs in LLUDPServer | 2720 | // Validation occurs in LLUDPServer |
2721 | // | ||
2722 | // XXX: A race condition exists here where two simultaneous calls to AddNewClient can interfere with | ||
2723 | // each other. In practice, this does not currently occur in the code. | ||
2713 | AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); | 2724 | AgentCircuitData aCircuit = m_authenticateHandler.GetAgentCircuitData(client.CircuitCode); |
2714 | 2725 | ||
2715 | bool vialogin | 2726 | // We lock here on AgentCircuitData to prevent a race condition between the thread adding a new connection |
2716 | = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 | 2727 | // and a simultaneous one that removes it (as can happen if the client is closed at a particular point |
2717 | || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; | 2728 | // whilst connecting). |
2718 | 2729 | // | |
2719 | // CheckHeartbeat(); | 2730 | // It would be easier to lock across all NewUserConnection(), AddNewClient() and |
2720 | 2731 | // RemoveClient() calls for all agents, but this would allow a slow call (e.g. because of slow service | |
2721 | ScenePresence sp = GetScenePresence(client.AgentId); | 2732 | // response in some module listening to AddNewClient()) from holding up unrelated agent calls. |
2722 | 2733 | // | |
2723 | // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this | 2734 | // In practice, the lock (this) in LLUDPServer.AddNewClient() currently lock across all |
2724 | // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause | 2735 | // AddNewClient() operations (though not other ops). |
2725 | // other problems, and possible the code calling AddNewClient() should ensure that no client is already | 2736 | // In the future this can be relieved once locking per agent (not necessarily on AgentCircuitData) is improved. |
2726 | // connected. | 2737 | lock (aCircuit) |
2727 | if (sp == null) | 2738 | { |
2728 | { | 2739 | vialogin |
2729 | m_log.DebugFormat( | 2740 | = (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 |
2730 | "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", | 2741 | || (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaLogin) != 0; |
2731 | client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); | 2742 | |
2732 | 2743 | // CheckHeartbeat(); | |
2733 | m_clientManager.Add(client); | 2744 | |
2734 | SubscribeToClientEvents(client); | 2745 | sp = GetScenePresence(client.AgentId); |
2735 | |||
2736 | sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); | ||
2737 | m_eventManager.TriggerOnNewPresence(sp); | ||
2738 | |||
2739 | sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; | ||
2740 | 2746 | ||
2741 | // The first agent upon login is a root agent by design. | 2747 | // XXX: Not sure how good it is to add a new client if a scene presence already exists. Possibly this |
2742 | // For this agent we will have to rez the attachments. | 2748 | // could occur if a viewer crashes and relogs before the old client is kicked out. But this could cause |
2743 | // All other AddNewClient calls find aCircuit.child to be true. | 2749 | // other problems, and possible the code calling AddNewClient() should ensure that no client is already |
2744 | if (aCircuit.child == false) | 2750 | // connected. |
2751 | if (sp == null) | ||
2745 | { | 2752 | { |
2746 | // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to | 2753 | m_log.DebugFormat( |
2747 | // start the scripts again (since this is done in RezAttachments()). | 2754 | "[SCENE]: Adding new child scene presence {0} {1} to scene {2} at pos {3}", |
2748 | // XXX: This is convoluted. | 2755 | client.Name, client.AgentId, RegionInfo.RegionName, client.StartPos); |
2749 | sp.IsChildAgent = false; | 2756 | |
2750 | 2757 | m_clientManager.Add(client); | |
2751 | if (AttachmentsModule != null) | 2758 | SubscribeToClientEvents(client); |
2752 | Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); | 2759 | |
2760 | sp = m_sceneGraph.CreateAndAddChildScenePresence(client, aCircuit.Appearance, type); | ||
2761 | m_eventManager.TriggerOnNewPresence(sp); | ||
2762 | |||
2763 | sp.TeleportFlags = (TPFlags)aCircuit.teleportFlags; | ||
2764 | |||
2765 | // The first agent upon login is a root agent by design. | ||
2766 | // For this agent we will have to rez the attachments. | ||
2767 | // All other AddNewClient calls find aCircuit.child to be true. | ||
2768 | if (aCircuit.child == false) | ||
2769 | { | ||
2770 | // We have to set SP to be a root agent here so that SP.MakeRootAgent() will later not try to | ||
2771 | // start the scripts again (since this is done in RezAttachments()). | ||
2772 | // XXX: This is convoluted. | ||
2773 | sp.IsChildAgent = false; | ||
2774 | |||
2775 | if (AttachmentsModule != null) | ||
2776 | Util.FireAndForget(delegate(object o) { AttachmentsModule.RezAttachments(sp); }); | ||
2777 | } | ||
2753 | } | 2778 | } |
2754 | } | 2779 | else |
2755 | else | 2780 | { |
2756 | { | 2781 | m_log.WarnFormat( |
2757 | m_log.WarnFormat( | 2782 | "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", |
2758 | "[SCENE]: Already found {0} scene presence for {1} in {2} when asked to add new scene presence", | 2783 | sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); |
2759 | sp.IsChildAgent ? "child" : "root", sp.Name, RegionInfo.RegionName); | 2784 | } |
2760 | } | 2785 | |
2786 | // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the | ||
2787 | // client is for a root or child agent. | ||
2788 | client.SceneAgent = sp; | ||
2761 | 2789 | ||
2762 | // We must set this here so that TriggerOnNewClient and TriggerOnClientLogin can determine whether the | 2790 | // Cache the user's name |
2763 | // client is for a root or child agent. | 2791 | CacheUserName(sp, aCircuit); |
2764 | client.SceneAgent = sp; | 2792 | |
2793 | EventManager.TriggerOnNewClient(client); | ||
2794 | if (vialogin) | ||
2795 | EventManager.TriggerOnClientLogin(client); | ||
2796 | } | ||
2765 | 2797 | ||
2766 | m_LastLogin = Util.EnvironmentTickCount(); | 2798 | m_LastLogin = Util.EnvironmentTickCount(); |
2767 | 2799 | ||
2768 | // Cache the user's name | ||
2769 | CacheUserName(sp, aCircuit); | ||
2770 | |||
2771 | EventManager.TriggerOnNewClient(client); | ||
2772 | if (vialogin) | ||
2773 | EventManager.TriggerOnClientLogin(client); | ||
2774 | |||
2775 | return sp; | 2800 | return sp; |
2776 | } | 2801 | } |
2777 | 2802 | ||
@@ -3300,109 +3325,129 @@ namespace OpenSim.Region.Framework.Scenes | |||
3300 | { | 3325 | { |
3301 | // CheckHeartbeat(); | 3326 | // CheckHeartbeat(); |
3302 | bool isChildAgent = false; | 3327 | bool isChildAgent = false; |
3303 | ScenePresence avatar = GetScenePresence(agentID); | 3328 | AgentCircuitData acd; |
3304 | |||
3305 | if (avatar == null) | ||
3306 | { | ||
3307 | m_log.WarnFormat( | ||
3308 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); | ||
3309 | |||
3310 | return; | ||
3311 | } | ||
3312 | 3329 | ||
3313 | try | 3330 | lock (m_removeClientLock) |
3314 | { | 3331 | { |
3315 | isChildAgent = avatar.IsChildAgent; | 3332 | acd = m_authenticateHandler.GetAgentCircuitData(agentID); |
3316 | |||
3317 | m_log.DebugFormat( | ||
3318 | "[SCENE]: Removing {0} agent {1} {2} from {3}", | ||
3319 | (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); | ||
3320 | 3333 | ||
3321 | // Don't do this to root agents, it's not nice for the viewer | 3334 | if (acd == null) |
3322 | if (closeChildAgents && isChildAgent) | ||
3323 | { | 3335 | { |
3324 | // Tell a single agent to disconnect from the region. | 3336 | m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); |
3325 | IEventQueue eq = RequestModuleInterface<IEventQueue>(); | 3337 | return; |
3326 | if (eq != null) | ||
3327 | { | ||
3328 | eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID); | ||
3329 | } | ||
3330 | else | ||
3331 | { | ||
3332 | avatar.ControllingClient.SendShutdownConnectionNotice(); | ||
3333 | } | ||
3334 | } | 3338 | } |
3335 | 3339 | else | |
3336 | // Only applies to root agents. | ||
3337 | if (avatar.ParentID != 0) | ||
3338 | { | 3340 | { |
3339 | avatar.StandUp(); | 3341 | // We remove the acd up here to avoid later raec conditions if two RemoveClient() calls occurred |
3342 | // simultaneously. | ||
3343 | m_authenticateHandler.RemoveCircuit(acd.circuitcode); | ||
3340 | } | 3344 | } |
3345 | } | ||
3341 | 3346 | ||
3342 | m_sceneGraph.removeUserCount(!isChildAgent); | 3347 | lock (acd) |
3343 | 3348 | { | |
3344 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop | 3349 | ScenePresence avatar = GetScenePresence(agentID); |
3345 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI | 3350 | |
3346 | if (closeChildAgents && CapsModule != null) | 3351 | if (avatar == null) |
3347 | CapsModule.RemoveCaps(agentID); | ||
3348 | |||
3349 | // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever | ||
3350 | // this method is doing is HORRIBLE!!! | ||
3351 | avatar.Scene.NeedSceneCacheClear(avatar.UUID); | ||
3352 | |||
3353 | if (closeChildAgents && !isChildAgent) | ||
3354 | { | 3352 | { |
3355 | List<ulong> regions = avatar.KnownRegionHandles; | 3353 | m_log.WarnFormat( |
3356 | regions.Remove(RegionInfo.RegionHandle); | 3354 | "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); |
3357 | m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); | 3355 | |
3356 | return; | ||
3358 | } | 3357 | } |
3359 | 3358 | ||
3360 | m_eventManager.TriggerClientClosed(agentID, this); | 3359 | try |
3361 | m_eventManager.TriggerOnRemovePresence(agentID); | ||
3362 | |||
3363 | if (!isChildAgent) | ||
3364 | { | 3360 | { |
3365 | if (AttachmentsModule != null) | 3361 | isChildAgent = avatar.IsChildAgent; |
3362 | |||
3363 | m_log.DebugFormat( | ||
3364 | "[SCENE]: Removing {0} agent {1} {2} from {3}", | ||
3365 | (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); | ||
3366 | |||
3367 | // Don't do this to root agents, it's not nice for the viewer | ||
3368 | if (closeChildAgents && isChildAgent) | ||
3366 | { | 3369 | { |
3367 | AttachmentsModule.DeRezAttachments(avatar); | 3370 | // Tell a single agent to disconnect from the region. |
3371 | IEventQueue eq = RequestModuleInterface<IEventQueue>(); | ||
3372 | if (eq != null) | ||
3373 | { | ||
3374 | eq.DisableSimulator(RegionInfo.RegionHandle, avatar.UUID); | ||
3375 | } | ||
3376 | else | ||
3377 | { | ||
3378 | avatar.ControllingClient.SendShutdownConnectionNotice(); | ||
3379 | } | ||
3368 | } | 3380 | } |
3369 | 3381 | ||
3370 | ForEachClient( | 3382 | // Only applies to root agents. |
3371 | delegate(IClientAPI client) | 3383 | if (avatar.ParentID != 0) |
3384 | { | ||
3385 | avatar.StandUp(); | ||
3386 | } | ||
3387 | |||
3388 | m_sceneGraph.removeUserCount(!isChildAgent); | ||
3389 | |||
3390 | // TODO: We shouldn't use closeChildAgents here - it's being used by the NPC module to stop | ||
3391 | // unnecessary operations. This should go away once NPCs have no accompanying IClientAPI | ||
3392 | if (closeChildAgents && CapsModule != null) | ||
3393 | CapsModule.RemoveCaps(agentID); | ||
3394 | |||
3395 | // REFACTORING PROBLEM -- well not really a problem, but just to point out that whatever | ||
3396 | // this method is doing is HORRIBLE!!! | ||
3397 | avatar.Scene.NeedSceneCacheClear(avatar.UUID); | ||
3398 | |||
3399 | if (closeChildAgents && !isChildAgent) | ||
3400 | { | ||
3401 | List<ulong> regions = avatar.KnownRegionHandles; | ||
3402 | regions.Remove(RegionInfo.RegionHandle); | ||
3403 | m_sceneGridService.SendCloseChildAgentConnections(agentID, regions); | ||
3404 | } | ||
3405 | |||
3406 | m_eventManager.TriggerClientClosed(agentID, this); | ||
3407 | m_eventManager.TriggerOnRemovePresence(agentID); | ||
3408 | |||
3409 | if (!isChildAgent) | ||
3410 | { | ||
3411 | if (AttachmentsModule != null) | ||
3372 | { | 3412 | { |
3373 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway | 3413 | AttachmentsModule.DeRezAttachments(avatar); |
3374 | try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } | 3414 | } |
3375 | catch (NullReferenceException) { } | ||
3376 | }); | ||
3377 | } | ||
3378 | |||
3379 | // It's possible for child agents to have transactions if changes are being made cross-border. | ||
3380 | if (AgentTransactionsModule != null) | ||
3381 | AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); | ||
3382 | 3415 | ||
3383 | m_authenticateHandler.RemoveCircuit(avatar.ControllingClient.CircuitCode); | 3416 | ForEachClient( |
3384 | } | 3417 | delegate(IClientAPI client) |
3385 | catch (Exception e) | 3418 | { |
3386 | { | 3419 | //We can safely ignore null reference exceptions. It means the avatar is dead and cleaned up anyway |
3387 | m_log.Error( | 3420 | try { client.SendKillObject(avatar.RegionHandle, new List<uint> { avatar.LocalId }); } |
3388 | string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e); | 3421 | catch (NullReferenceException) { } |
3389 | } | 3422 | }); |
3390 | finally | 3423 | } |
3391 | { | ||
3392 | try | ||
3393 | { | ||
3394 | // Always clean these structures up so that any failure above doesn't cause them to remain in the | ||
3395 | // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering | ||
3396 | // the same cleanup exception continually. | ||
3397 | m_sceneGraph.RemoveScenePresence(agentID); | ||
3398 | m_clientManager.Remove(agentID); | ||
3399 | 3424 | ||
3400 | avatar.Close(); | 3425 | // It's possible for child agents to have transactions if changes are being made cross-border. |
3426 | if (AgentTransactionsModule != null) | ||
3427 | AgentTransactionsModule.RemoveAgentAssetTransactions(agentID); | ||
3401 | } | 3428 | } |
3402 | catch (Exception e) | 3429 | catch (Exception e) |
3403 | { | 3430 | { |
3404 | m_log.Error( | 3431 | m_log.Error( |
3405 | string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e); | 3432 | string.Format("[SCENE]: Exception removing {0} from {1}. Cleaning up. Exception ", avatar.Name, Name), e); |
3433 | } | ||
3434 | finally | ||
3435 | { | ||
3436 | try | ||
3437 | { | ||
3438 | // Always clean these structures up so that any failure above doesn't cause them to remain in the | ||
3439 | // scene with possibly bad effects (e.g. continually timing out on unacked packets and triggering | ||
3440 | // the same cleanup exception continually. | ||
3441 | m_sceneGraph.RemoveScenePresence(agentID); | ||
3442 | m_clientManager.Remove(agentID); | ||
3443 | |||
3444 | avatar.Close(); | ||
3445 | } | ||
3446 | catch (Exception e) | ||
3447 | { | ||
3448 | m_log.Error( | ||
3449 | string.Format("[SCENE]: Exception in final clean up of {0} in {1}. Exception ", avatar.Name, Name), e); | ||
3450 | } | ||
3406 | } | 3451 | } |
3407 | } | 3452 | } |
3408 | 3453 | ||
@@ -3572,87 +3617,97 @@ namespace OpenSim.Region.Framework.Scenes | |||
3572 | agent.firstname, agent.lastname, agent.Viewer); | 3617 | agent.firstname, agent.lastname, agent.Viewer); |
3573 | reason = "Access denied, your viewer is banned by the region owner"; | 3618 | reason = "Access denied, your viewer is banned by the region owner"; |
3574 | return false; | 3619 | return false; |
3575 | } | ||
3576 | |||
3577 | ScenePresence sp = GetScenePresence(agent.AgentID); | ||
3578 | |||
3579 | if (sp != null && !sp.IsChildAgent) | ||
3580 | { | ||
3581 | // We have a zombie from a crashed session. | ||
3582 | // Or the same user is trying to be root twice here, won't work. | ||
3583 | // Kill it. | ||
3584 | m_log.WarnFormat( | ||
3585 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3586 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3587 | |||
3588 | sp.ControllingClient.Close(true); | ||
3589 | sp = null; | ||
3590 | } | 3620 | } |
3591 | 3621 | ||
3592 | ILandObject land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); | 3622 | ILandObject land; |
3593 | 3623 | ||
3594 | //On login test land permisions | 3624 | lock (agent) |
3595 | if (vialogin) | ||
3596 | { | 3625 | { |
3597 | if (land != null && !TestLandRestrictions(agent, land, out reason)) | 3626 | ScenePresence sp = GetScenePresence(agent.AgentID); |
3627 | |||
3628 | if (sp != null && !sp.IsChildAgent) | ||
3598 | { | 3629 | { |
3599 | return false; | 3630 | // We have a zombie from a crashed session. |
3631 | // Or the same user is trying to be root twice here, won't work. | ||
3632 | // Kill it. | ||
3633 | m_log.WarnFormat( | ||
3634 | "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.", | ||
3635 | sp.Name, sp.UUID, RegionInfo.RegionName); | ||
3636 | |||
3637 | sp.ControllingClient.Close(true); | ||
3638 | sp = null; | ||
3600 | } | 3639 | } |
3601 | } | 3640 | |
3602 | 3641 | land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); | |
3603 | if (sp == null) // We don't have an [child] agent here already | 3642 | |
3604 | { | 3643 | //On login test land permisions |
3605 | if (requirePresenceLookup) | 3644 | if (vialogin) |
3606 | { | 3645 | { |
3607 | try | 3646 | if (land != null && !TestLandRestrictions(agent, land, out reason)) |
3608 | { | ||
3609 | if (!VerifyUserPresence(agent, out reason)) | ||
3610 | return false; | ||
3611 | } catch (Exception e) | ||
3612 | { | 3647 | { |
3613 | m_log.ErrorFormat( | ||
3614 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); | ||
3615 | return false; | 3648 | return false; |
3616 | } | 3649 | } |
3617 | } | 3650 | } |
3618 | 3651 | ||
3619 | try | 3652 | if (sp == null) // We don't have an [child] agent here already |
3620 | { | ||
3621 | if (!AuthorizeUser(agent, out reason)) | ||
3622 | return false; | ||
3623 | } catch (Exception e) | ||
3624 | { | ||
3625 | m_log.ErrorFormat( | ||
3626 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); | ||
3627 | return false; | ||
3628 | } | ||
3629 | |||
3630 | m_log.InfoFormat( | ||
3631 | "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", | ||
3632 | RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, | ||
3633 | agent.AgentID, agent.circuitcode); | ||
3634 | |||
3635 | if (CapsModule != null) | ||
3636 | { | 3653 | { |
3637 | CapsModule.SetAgentCapsSeeds(agent); | 3654 | if (requirePresenceLookup) |
3638 | CapsModule.CreateCaps(agent.AgentID); | 3655 | { |
3639 | } | 3656 | try |
3640 | } else | 3657 | { |
3641 | { | 3658 | if (!VerifyUserPresence(agent, out reason)) |
3642 | // Let the SP know how we got here. This has a lot of interesting | 3659 | return false; |
3643 | // uses down the line. | 3660 | } |
3644 | sp.TeleportFlags = (TPFlags)teleportFlags; | 3661 | catch (Exception e) |
3662 | { | ||
3663 | m_log.ErrorFormat( | ||
3664 | "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); | ||
3645 | 3665 | ||
3646 | if (sp.IsChildAgent) | 3666 | return false; |
3647 | { | 3667 | } |
3648 | m_log.DebugFormat( | 3668 | } |
3649 | "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", | 3669 | |
3650 | agent.AgentID, RegionInfo.RegionName); | 3670 | try |
3671 | { | ||
3672 | if (!AuthorizeUser(agent, out reason)) | ||
3673 | return false; | ||
3674 | } | ||
3675 | catch (Exception e) | ||
3676 | { | ||
3677 | m_log.ErrorFormat( | ||
3678 | "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); | ||
3651 | 3679 | ||
3652 | sp.AdjustKnownSeeds(); | 3680 | return false; |
3653 | 3681 | } | |
3682 | |||
3683 | m_log.InfoFormat( | ||
3684 | "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", | ||
3685 | RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, | ||
3686 | agent.AgentID, agent.circuitcode); | ||
3687 | |||
3654 | if (CapsModule != null) | 3688 | if (CapsModule != null) |
3689 | { | ||
3655 | CapsModule.SetAgentCapsSeeds(agent); | 3690 | CapsModule.SetAgentCapsSeeds(agent); |
3691 | CapsModule.CreateCaps(agent.AgentID); | ||
3692 | } | ||
3693 | } | ||
3694 | else | ||
3695 | { | ||
3696 | // Let the SP know how we got here. This has a lot of interesting | ||
3697 | // uses down the line. | ||
3698 | sp.TeleportFlags = (TPFlags)teleportFlags; | ||
3699 | |||
3700 | if (sp.IsChildAgent) | ||
3701 | { | ||
3702 | m_log.DebugFormat( | ||
3703 | "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", | ||
3704 | agent.AgentID, RegionInfo.RegionName); | ||
3705 | |||
3706 | sp.AdjustKnownSeeds(); | ||
3707 | |||
3708 | if (CapsModule != null) | ||
3709 | CapsModule.SetAgentCapsSeeds(agent); | ||
3710 | } | ||
3656 | } | 3711 | } |
3657 | } | 3712 | } |
3658 | 3713 | ||