aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs59
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs124
2 files changed, 149 insertions, 34 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
index 01b1668..34f0924 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferModule.cs
@@ -148,6 +148,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
148 148
149 protected virtual void OnNewClient(IClientAPI client) 149 protected virtual void OnNewClient(IClientAPI client)
150 { 150 {
151 client.OnTeleportCancel += OnClientCancelTeleport;
151 client.OnTeleportHomeRequest += TeleportHome; 152 client.OnTeleportHomeRequest += TeleportHome;
152 client.OnTeleportLandmarkRequest += RequestTeleportLandmark; 153 client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
153 } 154 }
@@ -168,6 +169,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
168 169
169 #region Agent Teleports 170 #region Agent Teleports
170 171
172 private void OnClientCancelTeleport(IClientAPI client)
173 {
174 m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
175
176 m_log.DebugFormat(
177 "[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
178 }
179
171 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) 180 public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
172 { 181 {
173 if (sp.Scene.Permissions.IsGridGod(sp.UUID)) 182 if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@@ -567,6 +576,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
567 return; 576 return;
568 } 577 }
569 578
579 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
580 {
581 m_log.DebugFormat(
582 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
583 sp.Name, finalDestination.RegionName, sp.Scene.Name);
584
585 return;
586 }
587
570 // Past this point we have to attempt clean up if the teleport fails, so update transfer state. 588 // Past this point we have to attempt clean up if the teleport fails, so update transfer state.
571 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring); 589 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
572 590
@@ -631,7 +649,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
631 return; 649 return;
632 } 650 }
633 651
634 sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest"); 652 if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
653 {
654 m_log.DebugFormat(
655 "[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
656 sp.Name, finalDestination.RegionName, sp.Scene.Name);
657
658 CleanupAbortedInterRegionTeleport(sp, finalDestination);
659
660 return;
661 }
635 662
636 m_log.DebugFormat( 663 m_log.DebugFormat(
637 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}", 664 "[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
@@ -714,14 +741,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
714// } 741// }
715 } 742 }
716 743
717 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout) 744 /// <summary>
745 /// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
746 /// </summary>
747 /// <remarks>
748 /// All operations here must be idempotent so that we can call this method at any point in the teleport process
749 /// up until we send the TeleportFinish event quene event to the viewer.
750 /// <remarks>
751 /// <param name='sp'> </param>
752 /// <param name='finalDestination'></param>
753 protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
718 { 754 {
719 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp); 755 m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
720 756
721 // Client never contacted destination. Let's restore everything back
722 sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
723
724 // Fail. Reset it back
725 sp.IsChildAgent = false; 757 sp.IsChildAgent = false;
726 ReInstantiateScripts(sp); 758 ReInstantiateScripts(sp);
727 759
@@ -729,7 +761,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
729 761
730 // Finally, kill the agent we just created at the destination. 762 // Finally, kill the agent we just created at the destination.
731 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID); 763 Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
764 }
765
766 /// <summary>
767 /// Signal that the inter-region teleport failed and perform cleanup.
768 /// </summary>
769 /// <param name='sp'></param>
770 /// <param name='finalDestination'></param>
771 /// <param name='logout'></param>
772 protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
773 {
774 CleanupAbortedInterRegionTeleport(sp, finalDestination);
732 775
776 sp.ControllingClient.SendTeleportFailed(
777 string.Format("Problems connecting to destination {0}", finalDestination.RegionName));
733 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout); 778 sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
734 } 779 }
735 780
@@ -2097,7 +2142,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
2097 2142
2098 public bool IsInTransit(UUID id) 2143 public bool IsInTransit(UUID id)
2099 { 2144 {
2100 return m_entityTransferStateMachine.IsInTransit(id); 2145 return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
2101 } 2146 }
2102 2147
2103 protected void ReInstantiateScripts(ScenePresence sp) 2148 protected void ReInstantiateScripts(ScenePresence sp)
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
index d0cab49..24d81d9 100644
--- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
+++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
@@ -51,8 +51,9 @@ 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 || CleaningUp || [Exit] } 54 /// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] }
55 /// Transferring => { ReceivedAtDestination || CleaningUp } 55 /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp }
56 /// Cancelling => CleaningUp
56 /// ReceivedAtDestination => CleaningUp 57 /// ReceivedAtDestination => CleaningUp
57 /// CleaningUp => [Exit] 58 /// CleaningUp => [Exit]
58 /// 59 ///
@@ -64,7 +65,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
64 Preparing, // The agent is being prepared for transfer 65 Preparing, // The agent is being prepared for transfer
65 Transferring, // The agent is in the process of being transferred to a destination 66 Transferring, // The agent is in the process of being transferred to a destination
66 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received 67 ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
67 CleaningUp // The agent is being changed to child/removed after a transfer 68 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.
68 } 70 }
69 71
70 /// <summary> 72 /// <summary>
@@ -115,42 +117,110 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
115 /// <param name='newState'></param> 117 /// <param name='newState'></param>
116 /// <returns></returns> 118 /// <returns></returns>
117 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> 119 /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
118 internal void UpdateInTransit(UUID id, AgentTransferState newState) 120 internal bool UpdateInTransit(UUID id, AgentTransferState newState)
119 { 121 {
122 bool transitionOkay = false;
123
124 // We don't want to throw an exception on cancel since this can come it at any time.
125 bool failIfNotOkay = true;
126
127 // Should be a failure message if failure is not okay.
128 string failureMessage = null;
129
130 AgentTransferState? oldState = null;
131
120 lock (m_agentsInTransit) 132 lock (m_agentsInTransit)
121 { 133 {
122 // Illegal to try and update an agent that's not actually in transit. 134 // Illegal to try and update an agent that's not actually in transit.
123 if (!m_agentsInTransit.ContainsKey(id)) 135 if (!m_agentsInTransit.ContainsKey(id))
124 throw new Exception( 136 {
125 string.Format( 137 if (newState != AgentTransferState.Cancelling)
126 "Agent with ID {0} is not registered as in transit in {1}", 138 failureMessage = string.Format(
127 id, m_mod.Scene.RegionInfo.RegionName)); 139 "Agent with ID {0} is not registered as in transit in {1}",
128 140 id, m_mod.Scene.RegionInfo.RegionName);
129 AgentTransferState oldState = m_agentsInTransit[id]; 141 else
142 failIfNotOkay = false;
143 }
144 else
145 {
146 oldState = m_agentsInTransit[id];
130 147
131 bool transitionOkay = false; 148 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
149 {
150 transitionOkay = true;
151 }
152 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
153 {
154 transitionOkay = true;
155 }
156 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
157 {
158 transitionOkay = true;
159 }
160 else
161 {
162 if (newState == AgentTransferState.Cancelling
163 && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
164 {
165 transitionOkay = true;
166 }
167 else
168 {
169 failIfNotOkay = false;
170 }
171 }
132 172
133 if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) 173 if (!transitionOkay)
134 transitionOkay = true; 174 failureMessage
135 else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) 175 = string.Format(
136 transitionOkay = true; 176 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
137 else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) 177 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
138 transitionOkay = true; 178 }
139 179
140 if (transitionOkay) 180 if (transitionOkay)
181 {
141 m_agentsInTransit[id] = newState; 182 m_agentsInTransit[id] = newState;
142 else 183
143 throw new Exception( 184// m_log.DebugFormat(
144 string.Format( 185// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
145 "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", 186// id, oldState, newState, m_mod.Scene.Name);
146 id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); 187 }
188 else if (failIfNotOkay)
189 {
190 throw new Exception(failureMessage);
191 }
192// else
193// {
194// if (oldState != null)
195// m_log.DebugFormat(
196// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
197// id, oldState, newState, m_mod.Scene.Name);
198// else
199// m_log.DebugFormat(
200// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
201// id, newState, m_mod.Scene.Name);
202// }
147 } 203 }
204
205 return transitionOkay;
148 } 206 }
149 207
150 internal bool IsInTransit(UUID id) 208 /// <summary>
209 /// Gets the current agent transfer state.
210 /// </summary>
211 /// <returns>Null if the agent is not in transit</returns>
212 /// <param name='id'>
213 /// Identifier.
214 /// </param>
215 internal AgentTransferState? GetAgentTransferState(UUID id)
151 { 216 {
152 lock (m_agentsInTransit) 217 lock (m_agentsInTransit)
153 return m_agentsInTransit.ContainsKey(id); 218 {
219 if (!m_agentsInTransit.ContainsKey(id))
220 return null;
221 else
222 return m_agentsInTransit[id];
223 }
154 } 224 }
155 225
156 /// <summary> 226 /// <summary>
@@ -203,14 +273,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
203 273
204 lock (m_agentsInTransit) 274 lock (m_agentsInTransit)
205 { 275 {
206 if (!IsInTransit(id)) 276 AgentTransferState? currentState = GetAgentTransferState(id);
277
278 if (currentState == null)
207 throw new Exception( 279 throw new Exception(
208 string.Format( 280 string.Format(
209 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", 281 "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
210 id, m_mod.Scene.RegionInfo.RegionName)); 282 id, m_mod.Scene.RegionInfo.RegionName));
211 283
212 AgentTransferState currentState = m_agentsInTransit[id];
213
214 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) 284 if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
215 throw new Exception( 285 throw new Exception(
216 string.Format( 286 string.Format(