aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Framework/Scenes
diff options
context:
space:
mode:
authorJustin Clark-Casey (justincc)2013-08-08 23:29:30 +0100
committerJustin Clark-Casey (justincc)2013-08-08 23:29:30 +0100
commitb1c26a56b3d615f3709363e3a2f91b5423f5891f (patch)
treeea87893e6a13813dcf383d064fe33d3b3740c7ce /OpenSim/Region/Framework/Scenes
parentminor: Remove console lines at bottom of FakeParcelIDTests() regression test ... (diff)
downloadopensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.zip
opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.tar.gz
opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.tar.bz2
opensim-SC_OLD-b1c26a56b3d615f3709363e3a2f91b5423f5891f.tar.xz
Fix an issue where under teleport v2 protocol, teleporting from regions in an line from A->B->C would not close region A when reaching C
The root cause was that v2 was only closing neighbour agents if the root connection also needed a close. However, fixing this requires the neighbour regions also detect when they should not close due to re-teleports re-establishing the child connection. This involves restructuring the code to introduce a scene presence state machine that can serialize the different add and remove client calls that are now possible with the late close of the This commit appears to fix these issues and improve teleport, but still has holes on at least quick reteleporting (and possibly occasionally on ordinary teleports). Also, has not been completely tested yet in scenarios where regions are running on different simulators
Diffstat (limited to 'OpenSim/Region/Framework/Scenes')
-rw-r--r--OpenSim/Region/Framework/Scenes/Scene.cs308
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs36
2 files changed, 228 insertions, 116 deletions
diff --git a/OpenSim/Region/Framework/Scenes/Scene.cs b/OpenSim/Region/Framework/Scenes/Scene.cs
index 56cd57e..5f10869 100644
--- a/OpenSim/Region/Framework/Scenes/Scene.cs
+++ b/OpenSim/Region/Framework/Scenes/Scene.cs
@@ -151,7 +151,7 @@ namespace OpenSim.Region.Framework.Scenes
151 public SynchronizeSceneHandler SynchronizeScene; 151 public SynchronizeSceneHandler SynchronizeScene;
152 152
153 /// <summary> 153 /// <summary>
154 /// Used to prevent simultaneous calls to RemoveClient() for the same agent from interfering with each other. 154 /// Used to prevent simultaneous calls to code that adds and removes agents.
155 /// </summary> 155 /// </summary>
156 private object m_removeClientLock = new object(); 156 private object m_removeClientLock = new object();
157 157
@@ -1312,7 +1312,7 @@ namespace OpenSim.Region.Framework.Scenes
1312 Thread.Sleep(500); 1312 Thread.Sleep(500);
1313 1313
1314 // Stop all client threads. 1314 // Stop all client threads.
1315 ForEachScenePresence(delegate(ScenePresence avatar) { avatar.ControllingClient.Close(); }); 1315 ForEachScenePresence(delegate(ScenePresence avatar) { IncomingCloseAgent(avatar.UUID, false); });
1316 1316
1317 m_log.Debug("[SCENE]: Persisting changed objects"); 1317 m_log.Debug("[SCENE]: Persisting changed objects");
1318 EventManager.TriggerSceneShuttingDown(this); 1318 EventManager.TriggerSceneShuttingDown(this);
@@ -2972,7 +2972,7 @@ namespace OpenSim.Region.Framework.Scenes
2972 { 2972 {
2973 PresenceService.LogoutAgent(sp.ControllingClient.SessionId); 2973 PresenceService.LogoutAgent(sp.ControllingClient.SessionId);
2974 2974
2975 sp.ControllingClient.Close(); 2975 IncomingCloseAgent(sp.UUID, false);
2976 } 2976 }
2977 else 2977 else
2978 { 2978 {
@@ -3384,47 +3384,48 @@ namespace OpenSim.Region.Framework.Scenes
3384 3384
3385 public override void RemoveClient(UUID agentID, bool closeChildAgents) 3385 public override void RemoveClient(UUID agentID, bool closeChildAgents)
3386 { 3386 {
3387// CheckHeartbeat(); 3387 AgentCircuitData acd = m_authenticateHandler.GetAgentCircuitData(agentID);
3388 bool isChildAgent = false;
3389 AgentCircuitData acd;
3390 3388
3391 lock (m_removeClientLock) 3389 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3390 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3391 // However, will keep for now just in case.
3392 if (acd == null)
3392 { 3393 {
3393 acd = m_authenticateHandler.GetAgentCircuitData(agentID); 3394 m_log.ErrorFormat(
3395 "[SCENE]: No agent circuit found for {0} in {1}, aborting Scene.RemoveClient", agentID, Name);
3394 3396
3395 if (acd == null) 3397 return;
3396 { 3398 }
3397 m_log.ErrorFormat("[SCENE]: No agent circuit found for {0}, aborting Scene.RemoveClient", agentID); 3399 else
3398 return; 3400 {
3399 } 3401 m_authenticateHandler.RemoveCircuit(agentID);
3400 else
3401 {
3402 // We remove the acd up here to avoid later race conditions if two RemoveClient() calls occurred
3403 // simultaneously.
3404 // We also need to remove by agent ID since NPCs will have no circuit code.
3405 m_authenticateHandler.RemoveCircuit(agentID);
3406 }
3407 } 3402 }
3408 3403
3404 // TODO: Can we now remove this lock?
3409 lock (acd) 3405 lock (acd)
3410 { 3406 {
3407 bool isChildAgent = false;
3408
3411 ScenePresence avatar = GetScenePresence(agentID); 3409 ScenePresence avatar = GetScenePresence(agentID);
3412 3410
3411 // Shouldn't be necessary since RemoveClient() is currently only called by IClientAPI.Close() which
3412 // in turn is only called by Scene.IncomingCloseAgent() which checks whether the presence exists or not
3413 // However, will keep for now just in case.
3413 if (avatar == null) 3414 if (avatar == null)
3414 { 3415 {
3415 m_log.WarnFormat( 3416 m_log.ErrorFormat(
3416 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID); 3417 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in the scene.", agentID);
3417 3418
3418 return; 3419 return;
3419 } 3420 }
3420 3421
3421 try 3422 try
3422 { 3423 {
3423 isChildAgent = avatar.IsChildAgent; 3424 isChildAgent = avatar.IsChildAgent;
3424 3425
3425 m_log.DebugFormat( 3426 m_log.DebugFormat(
3426 "[SCENE]: Removing {0} agent {1} {2} from {3}", 3427 "[SCENE]: Removing {0} agent {1} {2} from {3}",
3427 (isChildAgent ? "child" : "root"), avatar.Name, agentID, RegionInfo.RegionName); 3428 isChildAgent ? "child" : "root", avatar.Name, agentID, Name);
3428 3429
3429 // Don't do this to root agents, it's not nice for the viewer 3430 // Don't do this to root agents, it's not nice for the viewer
3430 if (closeChildAgents && isChildAgent) 3431 if (closeChildAgents && isChildAgent)
@@ -3587,13 +3588,13 @@ namespace OpenSim.Region.Framework.Scenes
3587 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of 3588 /// is activated later when the viewer sends the initial UseCircuitCodePacket UDP packet (in the case of
3588 /// the LLUDP stack). 3589 /// the LLUDP stack).
3589 /// </remarks> 3590 /// </remarks>
3590 /// <param name="agent">CircuitData of the agent who is connecting</param> 3591 /// <param name="acd">CircuitData of the agent who is connecting</param>
3591 /// <param name="reason">Outputs the reason for the false response on this string</param> 3592 /// <param name="reason">Outputs the reason for the false response on this string</param>
3592 /// <param name="requirePresenceLookup">True for normal presence. False for NPC 3593 /// <param name="requirePresenceLookup">True for normal presence. False for NPC
3593 /// or other applications where a full grid/Hypergrid presence may not be required.</param> 3594 /// or other applications where a full grid/Hypergrid presence may not be required.</param>
3594 /// <returns>True if the region accepts this agent. False if it does not. False will 3595 /// <returns>True if the region accepts this agent. False if it does not. False will
3595 /// also return a reason.</returns> 3596 /// also return a reason.</returns>
3596 public bool NewUserConnection(AgentCircuitData agent, uint teleportFlags, out string reason, bool requirePresenceLookup) 3597 public bool NewUserConnection(AgentCircuitData acd, uint teleportFlags, out string reason, bool requirePresenceLookup)
3597 { 3598 {
3598 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 || 3599 bool vialogin = ((teleportFlags & (uint)TPFlags.ViaLogin) != 0 ||
3599 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0); 3600 (teleportFlags & (uint)TPFlags.ViaHGLogin) != 0);
@@ -3613,15 +3614,15 @@ namespace OpenSim.Region.Framework.Scenes
3613 m_log.DebugFormat( 3614 m_log.DebugFormat(
3614 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})", 3615 "[SCENE]: Region {0} told of incoming {1} agent {2} {3} {4} (circuit code {5}, IP {6}, viewer {7}, teleportflags ({8}), position {9})",
3615 RegionInfo.RegionName, 3616 RegionInfo.RegionName,
3616 (agent.child ? "child" : "root"), 3617 (acd.child ? "child" : "root"),
3617 agent.firstname, 3618 acd.firstname,
3618 agent.lastname, 3619 acd.lastname,
3619 agent.AgentID, 3620 acd.AgentID,
3620 agent.circuitcode, 3621 acd.circuitcode,
3621 agent.IPAddress, 3622 acd.IPAddress,
3622 agent.Viewer, 3623 acd.Viewer,
3623 ((TPFlags)teleportFlags).ToString(), 3624 ((TPFlags)teleportFlags).ToString(),
3624 agent.startpos 3625 acd.startpos
3625 ); 3626 );
3626 3627
3627 if (!LoginsEnabled) 3628 if (!LoginsEnabled)
@@ -3639,7 +3640,7 @@ namespace OpenSim.Region.Framework.Scenes
3639 { 3640 {
3640 foreach (string viewer in m_AllowedViewers) 3641 foreach (string viewer in m_AllowedViewers)
3641 { 3642 {
3642 if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3643 if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
3643 { 3644 {
3644 ViewerDenied = false; 3645 ViewerDenied = false;
3645 break; 3646 break;
@@ -3656,7 +3657,7 @@ namespace OpenSim.Region.Framework.Scenes
3656 { 3657 {
3657 foreach (string viewer in m_BannedViewers) 3658 foreach (string viewer in m_BannedViewers)
3658 { 3659 {
3659 if (viewer == agent.Viewer.Substring(0, viewer.Length).Trim().ToLower()) 3660 if (viewer == acd.Viewer.Substring(0, viewer.Length).Trim().ToLower())
3660 { 3661 {
3661 ViewerDenied = true; 3662 ViewerDenied = true;
3662 break; 3663 break;
@@ -3668,61 +3669,104 @@ namespace OpenSim.Region.Framework.Scenes
3668 { 3669 {
3669 m_log.DebugFormat( 3670 m_log.DebugFormat(
3670 "[SCENE]: Access denied for {0} {1} using {2}", 3671 "[SCENE]: Access denied for {0} {1} using {2}",
3671 agent.firstname, agent.lastname, agent.Viewer); 3672 acd.firstname, acd.lastname, acd.Viewer);
3672 reason = "Access denied, your viewer is banned by the region owner"; 3673 reason = "Access denied, your viewer is banned by the region owner";
3673 return false; 3674 return false;
3674 } 3675 }
3675 3676
3676 ILandObject land; 3677 ILandObject land;
3678 ScenePresence sp;
3677 3679
3678 lock (agent) 3680 lock (m_removeClientLock)
3679 { 3681 {
3680 ScenePresence sp = GetScenePresence(agent.AgentID); 3682 sp = GetScenePresence(acd.AgentID);
3681 3683
3682 if (sp != null) 3684 // We need to ensure that we are not already removing the scene presence before we ask it not to be
3685 // closed.
3686 if (sp != null && sp.IsChildAgent && sp.LifecycleState == ScenePresenceState.Running)
3683 { 3687 {
3684 if (!sp.IsChildAgent) 3688 m_log.DebugFormat(
3685 { 3689 "[SCENE]: Reusing existing child scene presence for {0} in {1}", sp.Name, Name);
3686 // We have a root agent. Is it in transit?
3687 if (!EntityTransferModule.IsInTransit(sp.UUID))
3688 {
3689 // We have a zombie from a crashed session.
3690 // Or the same user is trying to be root twice here, won't work.
3691 // Kill it.
3692 m_log.WarnFormat(
3693 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3694 sp.Name, sp.UUID, RegionInfo.RegionName);
3695 3690
3696 if (sp.ControllingClient != null) 3691 // In the case where, for example, an A B C D region layout, an avatar may
3697 sp.ControllingClient.Close(true); 3692 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. When C
3693 // renews the lease on the child agent at B, we must make sure that the close from A does not succeed.
3694 if (!acd.ChildrenCapSeeds.ContainsKey(RegionInfo.RegionHandle))
3695 {
3696 m_log.DebugFormat(
3697 "[SCENE]: Setting DoNotCloseAfterTeleport for child scene presence {0} in {1} because source will attempt close.",
3698 sp.Name, Name);
3698 3699
3699 sp = null; 3700 sp.DoNotCloseAfterTeleport = true;
3700 }
3701 //else
3702 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3703 } 3701 }
3704 else 3702 }
3703 }
3704
3705 // Need to poll here in case we are currently deleting an sp. Letting threads run over each other will
3706 // allow unpredictable things to happen.
3707 if (sp != null)
3708 {
3709 const int polls = 10;
3710 const int pollInterval = 1000;
3711 int pollsLeft = polls;
3712
3713 while (sp.LifecycleState == ScenePresenceState.Removing && pollsLeft-- > 0)
3714 Thread.Sleep(pollInterval);
3715
3716 if (sp.LifecycleState == ScenePresenceState.Removing)
3717 {
3718 m_log.WarnFormat(
3719 "[SCENE]: Agent {0} in {1} was still being removed after {2}s. Aborting NewUserConnection.",
3720 sp.Name, Name, polls * pollInterval / 1000);
3721
3722 return false;
3723 }
3724 else if (polls != pollsLeft)
3725 {
3726 m_log.DebugFormat(
3727 "[SCENE]: NewUserConnection for agent {0} in {1} had to wait {2}s for in-progress removal to complete on an old presence.",
3728 sp.Name, Name, polls * pollInterval / 1000);
3729 }
3730 }
3731
3732 // TODO: can we remove this lock?
3733 lock (acd)
3734 {
3735 if (sp != null && !sp.IsChildAgent)
3736 {
3737 // We have a root agent. Is it in transit?
3738 if (!EntityTransferModule.IsInTransit(sp.UUID))
3705 { 3739 {
3706 // We have a child agent here 3740 // We have a zombie from a crashed session.
3707 sp.DoNotCloseAfterTeleport = true; 3741 // Or the same user is trying to be root twice here, won't work.
3708 //m_log.WarnFormat("[SCENE]: Existing child scene presence for {0} {1} in {2}", sp.Name, sp.UUID, RegionInfo.RegionName); 3742 // Kill it.
3743 m_log.WarnFormat(
3744 "[SCENE]: Existing root scene presence detected for {0} {1} in {2} when connecting. Removing existing presence.",
3745 sp.Name, sp.UUID, RegionInfo.RegionName);
3746
3747 if (sp.ControllingClient != null)
3748 IncomingCloseAgent(sp.UUID, true);
3749
3750 sp = null;
3709 } 3751 }
3752 //else
3753 // m_log.WarnFormat("[SCENE]: Existing root scene presence for {0} {1} in {2}, but agent is in trasit", sp.Name, sp.UUID, RegionInfo.RegionName);
3710 } 3754 }
3711 3755
3712 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags. 3756 // Optimistic: add or update the circuit data with the new agent circuit data and teleport flags.
3713 // We need the circuit data here for some of the subsequent checks. (groups, for example) 3757 // We need the circuit data here for some of the subsequent checks. (groups, for example)
3714 // If the checks fail, we remove the circuit. 3758 // If the checks fail, we remove the circuit.
3715 agent.teleportFlags = teleportFlags; 3759 acd.teleportFlags = teleportFlags;
3716 m_authenticateHandler.AddNewCircuit(agent.circuitcode, agent); 3760 m_authenticateHandler.AddNewCircuit(acd.circuitcode, acd);
3717 3761
3718 land = LandChannel.GetLandObject(agent.startpos.X, agent.startpos.Y); 3762 land = LandChannel.GetLandObject(acd.startpos.X, acd.startpos.Y);
3719 3763
3720 // On login test land permisions 3764 // On login test land permisions
3721 if (vialogin) 3765 if (vialogin)
3722 { 3766 {
3723 if (land != null && !TestLandRestrictions(agent.AgentID, out reason, ref agent.startpos.X, ref agent.startpos.Y)) 3767 if (land != null && !TestLandRestrictions(acd.AgentID, out reason, ref acd.startpos.X, ref acd.startpos.Y))
3724 { 3768 {
3725 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3769 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3726 return false; 3770 return false;
3727 } 3771 }
3728 } 3772 }
@@ -3733,9 +3777,9 @@ namespace OpenSim.Region.Framework.Scenes
3733 { 3777 {
3734 try 3778 try
3735 { 3779 {
3736 if (!VerifyUserPresence(agent, out reason)) 3780 if (!VerifyUserPresence(acd, out reason))
3737 { 3781 {
3738 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3782 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3739 return false; 3783 return false;
3740 } 3784 }
3741 } 3785 }
@@ -3744,16 +3788,16 @@ namespace OpenSim.Region.Framework.Scenes
3744 m_log.ErrorFormat( 3788 m_log.ErrorFormat(
3745 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace); 3789 "[SCENE]: Exception verifying presence {0}{1}", e.Message, e.StackTrace);
3746 3790
3747 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3791 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3748 return false; 3792 return false;
3749 } 3793 }
3750 } 3794 }
3751 3795
3752 try 3796 try
3753 { 3797 {
3754 if (!AuthorizeUser(agent, SeeIntoRegion, out reason)) 3798 if (!AuthorizeUser(acd, SeeIntoRegion, out reason))
3755 { 3799 {
3756 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3800 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3757 return false; 3801 return false;
3758 } 3802 }
3759 } 3803 }
@@ -3762,19 +3806,19 @@ namespace OpenSim.Region.Framework.Scenes
3762 m_log.ErrorFormat( 3806 m_log.ErrorFormat(
3763 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace); 3807 "[SCENE]: Exception authorizing user {0}{1}", e.Message, e.StackTrace);
3764 3808
3765 m_authenticateHandler.RemoveCircuit(agent.circuitcode); 3809 m_authenticateHandler.RemoveCircuit(acd.circuitcode);
3766 return false; 3810 return false;
3767 } 3811 }
3768 3812
3769 m_log.InfoFormat( 3813 m_log.InfoFormat(
3770 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})", 3814 "[SCENE]: Region {0} authenticated and authorized incoming {1} agent {2} {3} {4} (circuit code {5})",
3771 RegionInfo.RegionName, (agent.child ? "child" : "root"), agent.firstname, agent.lastname, 3815 Name, (acd.child ? "child" : "root"), acd.firstname, acd.lastname,
3772 agent.AgentID, agent.circuitcode); 3816 acd.AgentID, acd.circuitcode);
3773 3817
3774 if (CapsModule != null) 3818 if (CapsModule != null)
3775 { 3819 {
3776 CapsModule.SetAgentCapsSeeds(agent); 3820 CapsModule.SetAgentCapsSeeds(acd);
3777 CapsModule.CreateCaps(agent.AgentID); 3821 CapsModule.CreateCaps(acd.AgentID);
3778 } 3822 }
3779 } 3823 }
3780 else 3824 else
@@ -3787,14 +3831,14 @@ namespace OpenSim.Region.Framework.Scenes
3787 { 3831 {
3788 m_log.DebugFormat( 3832 m_log.DebugFormat(
3789 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}", 3833 "[SCENE]: Adjusting known seeds for existing agent {0} in {1}",
3790 agent.AgentID, RegionInfo.RegionName); 3834 acd.AgentID, RegionInfo.RegionName);
3791 3835
3792 sp.AdjustKnownSeeds(); 3836 sp.AdjustKnownSeeds();
3793 3837
3794 if (CapsModule != null) 3838 if (CapsModule != null)
3795 { 3839 {
3796 CapsModule.SetAgentCapsSeeds(agent); 3840 CapsModule.SetAgentCapsSeeds(acd);
3797 CapsModule.CreateCaps(agent.AgentID); 3841 CapsModule.CreateCaps(acd.AgentID);
3798 } 3842 }
3799 } 3843 }
3800 } 3844 }
@@ -3802,23 +3846,23 @@ namespace OpenSim.Region.Framework.Scenes
3802 // Try caching an incoming user name much earlier on to see if this helps with an issue 3846 // Try caching an incoming user name much earlier on to see if this helps with an issue
3803 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName 3847 // where HG users are occasionally seen by others as "Unknown User" because their UUIDName
3804 // request for the HG avatar appears to trigger before the user name is cached. 3848 // request for the HG avatar appears to trigger before the user name is cached.
3805 CacheUserName(null, agent); 3849 CacheUserName(null, acd);
3806 } 3850 }
3807 3851
3808 if (vialogin) 3852 if (vialogin)
3809 { 3853 {
3810// CleanDroppedAttachments(); 3854// CleanDroppedAttachments();
3811 3855
3812 if (TestBorderCross(agent.startpos, Cardinals.E)) 3856 if (TestBorderCross(acd.startpos, Cardinals.E))
3813 { 3857 {
3814 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.E); 3858 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.E);
3815 agent.startpos.X = crossedBorder.BorderLine.Z - 1; 3859 acd.startpos.X = crossedBorder.BorderLine.Z - 1;
3816 } 3860 }
3817 3861
3818 if (TestBorderCross(agent.startpos, Cardinals.N)) 3862 if (TestBorderCross(acd.startpos, Cardinals.N))
3819 { 3863 {
3820 Border crossedBorder = GetCrossedBorder(agent.startpos, Cardinals.N); 3864 Border crossedBorder = GetCrossedBorder(acd.startpos, Cardinals.N);
3821 agent.startpos.Y = crossedBorder.BorderLine.Z - 1; 3865 acd.startpos.Y = crossedBorder.BorderLine.Z - 1;
3822 } 3866 }
3823 3867
3824 //Mitigate http://opensimulator.org/mantis/view.php?id=3522 3868 //Mitigate http://opensimulator.org/mantis/view.php?id=3522
@@ -3828,39 +3872,39 @@ namespace OpenSim.Region.Framework.Scenes
3828 { 3872 {
3829 lock (EastBorders) 3873 lock (EastBorders)
3830 { 3874 {
3831 if (agent.startpos.X > EastBorders[0].BorderLine.Z) 3875 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
3832 { 3876 {
3833 m_log.Warn("FIX AGENT POSITION"); 3877 m_log.Warn("FIX AGENT POSITION");
3834 agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; 3878 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
3835 if (agent.startpos.Z > 720) 3879 if (acd.startpos.Z > 720)
3836 agent.startpos.Z = 720; 3880 acd.startpos.Z = 720;
3837 } 3881 }
3838 } 3882 }
3839 lock (NorthBorders) 3883 lock (NorthBorders)
3840 { 3884 {
3841 if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) 3885 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
3842 { 3886 {
3843 m_log.Warn("FIX Agent POSITION"); 3887 m_log.Warn("FIX Agent POSITION");
3844 agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; 3888 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
3845 if (agent.startpos.Z > 720) 3889 if (acd.startpos.Z > 720)
3846 agent.startpos.Z = 720; 3890 acd.startpos.Z = 720;
3847 } 3891 }
3848 } 3892 }
3849 } else 3893 } else
3850 { 3894 {
3851 if (agent.startpos.X > EastBorders[0].BorderLine.Z) 3895 if (acd.startpos.X > EastBorders[0].BorderLine.Z)
3852 { 3896 {
3853 m_log.Warn("FIX AGENT POSITION"); 3897 m_log.Warn("FIX AGENT POSITION");
3854 agent.startpos.X = EastBorders[0].BorderLine.Z * 0.5f; 3898 acd.startpos.X = EastBorders[0].BorderLine.Z * 0.5f;
3855 if (agent.startpos.Z > 720) 3899 if (acd.startpos.Z > 720)
3856 agent.startpos.Z = 720; 3900 acd.startpos.Z = 720;
3857 } 3901 }
3858 if (agent.startpos.Y > NorthBorders[0].BorderLine.Z) 3902 if (acd.startpos.Y > NorthBorders[0].BorderLine.Z)
3859 { 3903 {
3860 m_log.Warn("FIX Agent POSITION"); 3904 m_log.Warn("FIX Agent POSITION");
3861 agent.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f; 3905 acd.startpos.Y = NorthBorders[0].BorderLine.Z * 0.5f;
3862 if (agent.startpos.Z > 720) 3906 if (acd.startpos.Z > 720)
3863 agent.startpos.Z = 720; 3907 acd.startpos.Z = 720;
3864 } 3908 }
3865 } 3909 }
3866 3910
@@ -3876,12 +3920,12 @@ namespace OpenSim.Region.Framework.Scenes
3876 { 3920 {
3877 // We have multiple SpawnPoints, Route the agent to a random or sequential one 3921 // We have multiple SpawnPoints, Route the agent to a random or sequential one
3878 if (SpawnPointRouting == "random") 3922 if (SpawnPointRouting == "random")
3879 agent.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation( 3923 acd.startpos = spawnpoints[Util.RandomClass.Next(spawnpoints.Count) - 1].GetLocation(
3880 telehub.AbsolutePosition, 3924 telehub.AbsolutePosition,
3881 telehub.GroupRotation 3925 telehub.GroupRotation
3882 ); 3926 );
3883 else 3927 else
3884 agent.startpos = spawnpoints[SpawnPoint()].GetLocation( 3928 acd.startpos = spawnpoints[SpawnPoint()].GetLocation(
3885 telehub.AbsolutePosition, 3929 telehub.AbsolutePosition,
3886 telehub.GroupRotation 3930 telehub.GroupRotation
3887 ); 3931 );
@@ -3889,7 +3933,7 @@ namespace OpenSim.Region.Framework.Scenes
3889 else 3933 else
3890 { 3934 {
3891 // We have a single SpawnPoint and will route the agent to it 3935 // We have a single SpawnPoint and will route the agent to it
3892 agent.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation); 3936 acd.startpos = spawnpoints[0].GetLocation(telehub.AbsolutePosition, telehub.GroupRotation);
3893 } 3937 }
3894 3938
3895 return true; 3939 return true;
@@ -3900,7 +3944,7 @@ namespace OpenSim.Region.Framework.Scenes
3900 { 3944 {
3901 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero) 3945 if (land.LandData.LandingType == (byte)1 && land.LandData.UserLocation != Vector3.Zero)
3902 { 3946 {
3903 agent.startpos = land.LandData.UserLocation; 3947 acd.startpos = land.LandData.UserLocation;
3904 } 3948 }
3905 } 3949 }
3906 } 3950 }
@@ -4359,11 +4403,51 @@ namespace OpenSim.Region.Framework.Scenes
4359 /// </param> 4403 /// </param>
4360 public bool IncomingCloseAgent(UUID agentID, bool force) 4404 public bool IncomingCloseAgent(UUID agentID, bool force)
4361 { 4405 {
4362 //m_log.DebugFormat("[SCENE]: Processing incoming close agent for {0}", agentID); 4406 ScenePresence sp;
4363 ScenePresence presence = m_sceneGraph.GetScenePresence(agentID); 4407
4364 if (presence != null) 4408 lock (m_removeClientLock)
4409 {
4410 sp = GetScenePresence(agentID);
4411
4412 if (sp == null)
4413 {
4414 m_log.DebugFormat(
4415 "[SCENE]: Called RemoveClient() with agent ID {0} but no such presence is in {1}",
4416 agentID, Name);
4417
4418 return false;
4419 }
4420
4421 if (sp.LifecycleState != ScenePresenceState.Running)
4422 {
4423 m_log.DebugFormat(
4424 "[SCENE]: Called RemoveClient() for {0} in {1} but presence is already in state {2}",
4425 sp.Name, Name, sp.LifecycleState);
4426
4427 return false;
4428 }
4429
4430 // We need to avoid a race condition where in, for example, an A B C D region layout, an avatar may
4431 // teleport from A -> D, but then -> C before A has asked B to close its old child agent. We do not
4432 // want to obey this close since C may have renewed the child agent lease on B.
4433 if (sp.DoNotCloseAfterTeleport)
4434 {
4435 m_log.DebugFormat(
4436 "[SCENE]: Not closing {0} agent {1} in {2} since another simulator has re-established the child connection",
4437 sp.IsChildAgent ? "child" : "root", sp.Name, Name);
4438
4439 // Need to reset the flag so that a subsequent close after another teleport can succeed.
4440 sp.DoNotCloseAfterTeleport = false;
4441
4442 return false;
4443 }
4444
4445 sp.LifecycleState = ScenePresenceState.Removing;
4446 }
4447
4448 if (sp != null)
4365 { 4449 {
4366 presence.ControllingClient.Close(force); 4450 sp.ControllingClient.Close(force);
4367 return true; 4451 return true;
4368 } 4452 }
4369 4453
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index 7fd1302..bdcdf03 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -74,6 +74,8 @@ namespace OpenSim.Region.Framework.Scenes
74 74
75 public class ScenePresence : EntityBase, IScenePresence 75 public class ScenePresence : EntityBase, IScenePresence
76 { 76 {
77 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
78
77// ~ScenePresence() 79// ~ScenePresence()
78// { 80// {
79// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name); 81// m_log.DebugFormat("[SCENE PRESENCE]: Destructor called on {0}", Name);
@@ -85,10 +87,27 @@ namespace OpenSim.Region.Framework.Scenes
85 m_scene.EventManager.TriggerScenePresenceUpdated(this); 87 m_scene.EventManager.TriggerScenePresenceUpdated(this);
86 } 88 }
87 89
88 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
89
90 public PresenceType PresenceType { get; private set; } 90 public PresenceType PresenceType { get; private set; }
91 91
92 private ScenePresenceStateMachine m_stateMachine;
93
94 /// <summary>
95 /// The current state of this presence. Governs only the existence lifecycle. See ScenePresenceStateMachine
96 /// for more details.
97 /// </summary>
98 public ScenePresenceState LifecycleState
99 {
100 get
101 {
102 return m_stateMachine.GetState();
103 }
104
105 set
106 {
107 m_stateMachine.SetState(value);
108 }
109 }
110
92// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes(); 111// private static readonly byte[] DEFAULT_TEXTURE = AvatarAppearance.GetDefaultTexture().GetBytes();
93 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags)); 112 private static readonly Array DIR_CONTROL_FLAGS = Enum.GetValues(typeof(Dir_ControlFlags));
94 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f); 113 private static readonly Vector3 HEAD_ADJUSTMENT = new Vector3(0f, 0f, 0.3f);
@@ -766,7 +785,7 @@ namespace OpenSim.Region.Framework.Scenes
766 785
767 public ScenePresence( 786 public ScenePresence(
768 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type) 787 IClientAPI client, Scene world, AvatarAppearance appearance, PresenceType type)
769 { 788 {
770 AttachmentsSyncLock = new Object(); 789 AttachmentsSyncLock = new Object();
771 AllowMovement = true; 790 AllowMovement = true;
772 IsChildAgent = true; 791 IsChildAgent = true;
@@ -811,6 +830,8 @@ namespace OpenSim.Region.Framework.Scenes
811 SetDirectionVectors(); 830 SetDirectionVectors();
812 831
813 Appearance = appearance; 832 Appearance = appearance;
833
834 m_stateMachine = new ScenePresenceStateMachine(this);
814 } 835 }
815 836
816 public void RegisterToEvents() 837 public void RegisterToEvents()
@@ -879,7 +900,7 @@ namespace OpenSim.Region.Framework.Scenes
879 /// </summary> 900 /// </summary>
880 public void MakeRootAgent(Vector3 pos, bool isFlying) 901 public void MakeRootAgent(Vector3 pos, bool isFlying)
881 { 902 {
882 m_log.DebugFormat( 903 m_log.InfoFormat(
883 "[SCENE]: Upgrading child to root agent for {0} in {1}", 904 "[SCENE]: Upgrading child to root agent for {0} in {1}",
884 Name, m_scene.RegionInfo.RegionName); 905 Name, m_scene.RegionInfo.RegionName);
885 906
@@ -887,6 +908,11 @@ namespace OpenSim.Region.Framework.Scenes
887 908
888 IsChildAgent = false; 909 IsChildAgent = false;
889 910
911 // Must reset this here so that a teleport to a region next to an existing region does not keep the flag
912 // set and prevent the close of the connection on a subsequent re-teleport.
913 // Should not be needed if we are not trying to tell this region to close
914// DoNotCloseAfterTeleport = false;
915
890 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>(); 916 IGroupsModule gm = m_scene.RequestModuleInterface<IGroupsModule>();
891 if (gm != null) 917 if (gm != null)
892 Grouptitle = gm.GetGroupTitle(m_uuid); 918 Grouptitle = gm.GetGroupTitle(m_uuid);
@@ -3738,6 +3764,8 @@ namespace OpenSim.Region.Framework.Scenes
3738 // m_reprioritizationTimer.Dispose(); 3764 // m_reprioritizationTimer.Dispose();
3739 3765
3740 RemoveFromPhysicalScene(); 3766 RemoveFromPhysicalScene();
3767
3768 LifecycleState = ScenePresenceState.Removed;
3741 } 3769 }
3742 3770
3743 public void AddAttachment(SceneObjectGroup gobj) 3771 public void AddAttachment(SceneObjectGroup gobj)