diff options
author | Justin Clark-Casey (justincc) | 2013-03-22 01:00:13 +0000 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2013-03-22 01:00:13 +0000 |
commit | 7471bc77757ce0b294d04f0eb552dbc5ea749793 (patch) | |
tree | 11500087275dfe980377a3f06985e296ad35fb1b | |
parent | Implement chat across region borders since we can tell if avatars in neighbou... (diff) | |
download | opensim-SC_OLD-7471bc77757ce0b294d04f0eb552dbc5ea749793.zip opensim-SC_OLD-7471bc77757ce0b294d04f0eb552dbc5ea749793.tar.gz opensim-SC_OLD-7471bc77757ce0b294d04f0eb552dbc5ea749793.tar.bz2 opensim-SC_OLD-7471bc77757ce0b294d04f0eb552dbc5ea749793.tar.xz |
At strategic points in the teleport process, if the client has simultaneously logged out then do not continue.
This aims to reduce any side effects if the process tries to complete after the client has logged back in (e.g. it was delayed due to a slow destination region response).
This introduces a new Aborting entity transfer state which signals that the teleport should be stopped but no compensating actions performed.
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | 59 | ||||
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | 20 |
2 files changed, 69 insertions, 10 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs index 82358d8..5713e88 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs | |||
@@ -167,6 +167,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
167 | 167 | ||
168 | if (!DisableInterRegionTeleportCancellation) | 168 | if (!DisableInterRegionTeleportCancellation) |
169 | client.OnTeleportCancel += OnClientCancelTeleport; | 169 | client.OnTeleportCancel += OnClientCancelTeleport; |
170 | |||
171 | client.OnConnectionClosed += OnConnectionClosed; | ||
170 | } | 172 | } |
171 | 173 | ||
172 | public virtual void Close() {} | 174 | public virtual void Close() {} |
@@ -185,6 +187,18 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
185 | 187 | ||
186 | #region Agent Teleports | 188 | #region Agent Teleports |
187 | 189 | ||
190 | private void OnConnectionClosed(IClientAPI client) | ||
191 | { | ||
192 | if (client.IsLoggingOut) | ||
193 | { | ||
194 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Aborting); | ||
195 | |||
196 | m_log.DebugFormat( | ||
197 | "[ENTITY TRANSFER MODULE]: Aborted teleport request from {0} in {1} due to simultaneous logout", | ||
198 | client.Name, Scene.Name); | ||
199 | } | ||
200 | } | ||
201 | |||
188 | private void OnClientCancelTeleport(IClientAPI client) | 202 | private void OnClientCancelTeleport(IClientAPI client) |
189 | { | 203 | { |
190 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling); | 204 | m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling); |
@@ -590,6 +604,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
590 | return; | 604 | return; |
591 | } | 605 | } |
592 | 606 | ||
607 | Thread.Sleep(30000); | ||
608 | |||
593 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) | 609 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling) |
594 | { | 610 | { |
595 | m_log.DebugFormat( | 611 | m_log.DebugFormat( |
@@ -598,6 +614,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
598 | 614 | ||
599 | return; | 615 | return; |
600 | } | 616 | } |
617 | else if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
618 | { | ||
619 | m_log.DebugFormat( | ||
620 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after CreateAgent due to previous client close.", | ||
621 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
622 | |||
623 | return; | ||
624 | } | ||
601 | 625 | ||
602 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. | 626 | // Past this point we have to attempt clean up if the teleport fails, so update transfer state. |
603 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); | 627 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); |
@@ -657,12 +681,32 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
657 | 681 | ||
658 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); | 682 | //sp.ControllingClient.SendTeleportProgress(teleportFlags, "Updating agent..."); |
659 | 683 | ||
684 | // We will check for an abort before UpdateAgent since UpdateAgent will require an active viewer to | ||
685 | // establish th econnection to the destination which makes it return true. | ||
686 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
687 | { | ||
688 | m_log.DebugFormat( | ||
689 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} before UpdateAgent", | ||
690 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
691 | |||
692 | return; | ||
693 | } | ||
694 | |||
660 | // A common teleport failure occurs when we can send CreateAgent to the | 695 | // A common teleport failure occurs when we can send CreateAgent to the |
661 | // destination region but the viewer cannot establish the connection (e.g. due to network issues between | 696 | // destination region but the viewer cannot establish the connection (e.g. due to network issues between |
662 | // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then | 697 | // the viewer and the destination). In this case, UpdateAgent timesout after 10 seconds, although then |
663 | // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). | 698 | // there's a further 10 second wait whilst we attempt to tell the destination to delete the agent in Fail(). |
664 | if (!UpdateAgent(reg, finalDestination, agent, sp)) | 699 | if (!UpdateAgent(reg, finalDestination, agent, sp)) |
665 | { | 700 | { |
701 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
702 | { | ||
703 | m_log.DebugFormat( | ||
704 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after UpdateAgent due to previous client close.", | ||
705 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
706 | |||
707 | return; | ||
708 | } | ||
709 | |||
666 | m_log.WarnFormat( | 710 | m_log.WarnFormat( |
667 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", | 711 | "[ENTITY TRANSFER MODULE]: UpdateAgent failed on teleport of {0} to {1} from {2}. Keeping avatar in source region.", |
668 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 712 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); |
@@ -677,7 +721,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
677 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", | 721 | "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request", |
678 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | 722 | sp.Name, finalDestination.RegionName, sp.Scene.Name); |
679 | 723 | ||
680 | CleanupAbortedInterRegionTeleport(sp, finalDestination); | 724 | CleanupFailedInterRegionTeleport(sp, finalDestination); |
681 | 725 | ||
682 | return; | 726 | return; |
683 | } | 727 | } |
@@ -706,6 +750,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
706 | // that the client contacted the destination before we close things here. | 750 | // that the client contacted the destination before we close things here. |
707 | if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) | 751 | if (!m_entityTransferStateMachine.WaitForAgentArrivedAtDestination(sp.UUID)) |
708 | { | 752 | { |
753 | if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Aborting) | ||
754 | { | ||
755 | m_log.DebugFormat( | ||
756 | "[ENTITY TRANSFER MODULE]: Aborted teleport of {0} to {1} from {2} after WaitForAgentArrivedAtDestination due to previous client close.", | ||
757 | sp.Name, finalDestination.RegionName, sp.Scene.Name); | ||
758 | |||
759 | return; | ||
760 | } | ||
761 | |||
709 | m_log.WarnFormat( | 762 | m_log.WarnFormat( |
710 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", | 763 | "[ENTITY TRANSFER MODULE]: Teleport of {0} to {1} from {2} failed due to no callback from destination region. Returning avatar to source region.", |
711 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); | 764 | sp.Name, finalDestination.RegionName, sp.Scene.RegionInfo.RegionName); |
@@ -772,7 +825,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
772 | /// <remarks> | 825 | /// <remarks> |
773 | /// <param name='sp'> </param> | 826 | /// <param name='sp'> </param> |
774 | /// <param name='finalDestination'></param> | 827 | /// <param name='finalDestination'></param> |
775 | protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) | 828 | protected virtual void CleanupFailedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination) |
776 | { | 829 | { |
777 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); | 830 | m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); |
778 | 831 | ||
@@ -794,7 +847,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
794 | /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param> | 847 | /// <param name='reason'>Human readable reason for teleport failure. Will be sent to client.</param> |
795 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason) | 848 | protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout, string reason) |
796 | { | 849 | { |
797 | CleanupAbortedInterRegionTeleport(sp, finalDestination); | 850 | CleanupFailedInterRegionTeleport(sp, finalDestination); |
798 | 851 | ||
799 | sp.ControllingClient.SendTeleportFailed( | 852 | sp.ControllingClient.SendTeleportFailed( |
800 | string.Format( | 853 | string.Format( |
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index 7314727..fc02916 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | |||
@@ -51,11 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
51 | /// This is a state machine. | 51 | /// This is a state machine. |
52 | /// | 52 | /// |
53 | /// [Entry] => Preparing | 53 | /// [Entry] => Preparing |
54 | /// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] } | 54 | /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] } |
55 | /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp } | 55 | /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting } |
56 | /// Cancelling => CleaningUp | 56 | /// Cancelling => CleaningUp || Aborting |
57 | /// ReceivedAtDestination => CleaningUp | 57 | /// ReceivedAtDestination => CleaningUp || Aborting |
58 | /// CleaningUp => [Exit] | 58 | /// CleaningUp => [Exit] |
59 | /// Aborting => [Exit] | ||
59 | /// | 60 | /// |
60 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp | 61 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp |
61 | /// However, any state can transition to CleaningUp if the teleport has failed. | 62 | /// However, any state can transition to CleaningUp if the teleport has failed. |
@@ -66,7 +67,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
66 | Transferring, // The agent is in the process of being transferred to a destination | 67 | Transferring, // The agent is in the process of being transferred to a destination |
67 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received | 68 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received |
68 | CleaningUp, // The agent is being changed to child/removed after a transfer | 69 | CleaningUp, // The agent is being changed to child/removed after a transfer |
69 | Cancelling // The user has cancelled the teleport but we have yet to act upon this. | 70 | Cancelling, // The user has cancelled the teleport but we have yet to act upon this. |
71 | Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed | ||
70 | } | 72 | } |
71 | 73 | ||
72 | /// <summary> | 74 | /// <summary> |
@@ -134,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
134 | // Illegal to try and update an agent that's not actually in transit. | 136 | // Illegal to try and update an agent that's not actually in transit. |
135 | if (!m_agentsInTransit.ContainsKey(id)) | 137 | if (!m_agentsInTransit.ContainsKey(id)) |
136 | { | 138 | { |
137 | if (newState != AgentTransferState.Cancelling) | 139 | if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting) |
138 | failureMessage = string.Format( | 140 | failureMessage = string.Format( |
139 | "Agent with ID {0} is not registered as in transit in {1}", | 141 | "Agent with ID {0} is not registered as in transit in {1}", |
140 | id, m_mod.Scene.RegionInfo.RegionName); | 142 | id, m_mod.Scene.RegionInfo.RegionName); |
@@ -145,7 +147,11 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
145 | { | 147 | { |
146 | oldState = m_agentsInTransit[id]; | 148 | oldState = m_agentsInTransit[id]; |
147 | 149 | ||
148 | if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | 150 | if (newState == AgentTransferState.Aborting) |
151 | { | ||
152 | transitionOkay = true; | ||
153 | } | ||
154 | else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | ||
149 | { | 155 | { |
150 | transitionOkay = true; | 156 | transitionOkay = true; |
151 | } | 157 | } |