From d8ebf2fc9d7d2e50735d50e75f7153f487efe958 Mon Sep 17 00:00:00 2001
From: diva
Date: Thu, 1 Jan 2009 19:42:24 +0000
Subject: Major changes in interregion communications. This breaks
 compatibility with older versions, and may result is all sorts of weirdnesses
 when interacting with sims in older versions. Changes: - Introducing
 synchronous Teleports. Now the receiving region calls back the sending region
 after the client has been made a root agent there, that is, after client
 sends CompleteMovement to the destination. - SendCloseAgent moved from OGS1
 Remoting to RESTComms.

---
 OpenSim/Framework/ChildAgentDataUpdate.cs          |   7 +
 OpenSim/Region/Application/OpenSim.cs              |   2 +-
 .../Environment/Interfaces/IInterregionComms.cs    |   2 +
 .../Communications/Local/LocalInterregionComms.cs  |  52 +++++--
 .../Communications/REST/RESTInterregionComms.cs    | 173 ++++++++++++++++++---
 .../Hypergrid/HGSceneCommunicationService.cs       |  34 ++--
 OpenSim/Region/Environment/Scenes/Scene.cs         |  21 ++-
 .../Scenes/SceneCommunicationService.cs            | 106 +++++++++----
 OpenSim/Region/Environment/Scenes/ScenePresence.cs |  16 +-
 9 files changed, 338 insertions(+), 75 deletions(-)

diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs
index 257f435..f3ac943 100644
--- a/OpenSim/Framework/ChildAgentDataUpdate.cs
+++ b/OpenSim/Framework/ChildAgentDataUpdate.cs
@@ -144,6 +144,7 @@ namespace OpenSim.Framework
 
         byte[] VisualParams;
 
+        public string CallbackURI;
 
         public OSDMap PackUpdateMessage()
         {
@@ -191,6 +192,9 @@ namespace OpenSim.Framework
 
             // Last few fields are still missing
 
+            if ((CallbackURI != null) && (!CallbackURI.Equals("")))
+                args["callback_uri"] = OSD.FromString(CallbackURI);
+
             return args;
         }
 
@@ -284,6 +288,9 @@ namespace OpenSim.Framework
 
             if (args["active_group_id"] != null)
                 ActiveGroupID = args["active_group_id"].AsUUID();
+
+            if (args["callback_uri"] != null)
+                CallbackURI = args["callback_uri"].AsString();
         }
 
         public AgentData()
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index c3b3a01..b3ca651 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -177,7 +177,7 @@ namespace OpenSim
                              presence.UUID,
                              regionInfo.RegionName));
 
-                    presence.Scene.CloseConnection(presence.UUID);
+                    presence.Scene.IncomingCloseAgent(presence.UUID);
                 }
             }
             m_console.Notice("");
diff --git a/OpenSim/Region/Environment/Interfaces/IInterregionComms.cs b/OpenSim/Region/Environment/Interfaces/IInterregionComms.cs
index b70e885..e197622 100644
--- a/OpenSim/Region/Environment/Interfaces/IInterregionComms.cs
+++ b/OpenSim/Region/Environment/Interfaces/IInterregionComms.cs
@@ -36,6 +36,8 @@ namespace OpenSim.Region.Environment.Interfaces
     public interface IInterregionCommsOut 
     {
         bool SendChildAgentUpdate(ulong regionHandle, AgentData data);
+        bool SendReleaseAgent(ulong regionHandle, UUID id, string uri);
+        bool SendCloseAgent(ulong regionHandle, UUID id);
     }
 
     // This may not be needed, but having it here for now.
diff --git a/OpenSim/Region/Environment/Modules/Communications/Local/LocalInterregionComms.cs b/OpenSim/Region/Environment/Modules/Communications/Local/LocalInterregionComms.cs
index 781bf1c..9f547a2 100644
--- a/OpenSim/Region/Environment/Modules/Communications/Local/LocalInterregionComms.cs
+++ b/OpenSim/Region/Environment/Modules/Communications/Local/LocalInterregionComms.cs
@@ -120,23 +120,57 @@ namespace OpenSim.Region.Environment.Modules.Communications.Local
 
         public bool SendChildAgentUpdate(ulong regionHandle, AgentData cAgentData)
         {
-            lock (m_sceneList)
+            foreach (Scene s in m_sceneList)
             {
-                foreach (Scene s in m_sceneList)
+                if (s.RegionInfo.RegionHandle == regionHandle)
                 {
-                    if (s.RegionInfo.RegionHandle == regionHandle)
-                    {
-                        //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
-                        return s.IncomingChildAgentDataUpdate(cAgentData);
-                        //if (OnChildAgentUpdate != null)
-                        //    return OnChildAgentUpdate(cAgentData);
-                    }
+                    //m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
+                    s.IncomingChildAgentDataUpdate(cAgentData);
+                    return true;
                 }
             }
             //m_log.Debug("[LOCAL COMMS]: region not found for ChildAgentUpdate");
             return false;
         }
 
+        public bool SendReleaseAgent(ulong regionHandle, UUID id, string uri)
+        {
+            //uint x, y;
+            //Utils.LongToUInts(regionHandle, out x, out y);
+            //x = x / Constants.RegionSize;
+            //y = y / Constants.RegionSize;
+            //Console.WriteLine("\n >>> Local SendReleaseAgent " + x + "-" + y);
+            foreach (Scene s in m_sceneList)
+            {
+                if (s.RegionInfo.RegionHandle == regionHandle)
+                {
+                    //m_log.Debug("[LOCAL COMMS]: Found region to SendReleaseAgent");
+                    return s.IncomingReleaseAgent(id);
+                }
+            }
+            //m_log.Debug("[LOCAL COMMS]: region not found in SendReleaseAgent");
+            return false;
+        }
+
+        public bool SendCloseAgent(ulong regionHandle, UUID id)
+        {
+            //uint x, y;
+            //Utils.LongToUInts(regionHandle, out x, out y);
+            //x = x / Constants.RegionSize;
+            //y = y / Constants.RegionSize;
+            //Console.WriteLine("\n >>> Local SendCloseAgent " + x + "-" + y);
+            foreach (Scene s in m_sceneList)
+            {
+                if (s.RegionInfo.RegionHandle == regionHandle)
+                {
+                    //m_log.Debug("[LOCAL COMMS]: Found region to SendCloseAgent");
+                    return s.IncomingCloseAgent(id);
+                }
+            }
+            //m_log.Debug("[LOCAL COMMS]: region not found in SendCloseAgent");
+            return false;
+        }
+
         #endregion /* IInterregionComms */
     }
 }
diff --git a/OpenSim/Region/Environment/Modules/Communications/REST/RESTInterregionComms.cs b/OpenSim/Region/Environment/Modules/Communications/REST/RESTInterregionComms.cs
index b7c9269..f48e474 100644
--- a/OpenSim/Region/Environment/Modules/Communications/REST/RESTInterregionComms.cs
+++ b/OpenSim/Region/Environment/Modules/Communications/REST/RESTInterregionComms.cs
@@ -146,6 +146,40 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
 
         }
 
+        public bool SendReleaseAgent(ulong regionHandle, UUID id, string uri)
+        {
+            // Try local first
+            if (m_localBackend.SendReleaseAgent(regionHandle, id, uri))
+                return true;
+
+            // else do the remote thing
+            return DoReleaseAgentCall(regionHandle, id, uri);
+        }
+
+        public bool SendCloseAgent(ulong regionHandle, UUID id)
+        {
+            // Try local first
+            if (m_localBackend.SendCloseAgent(regionHandle, id))
+                return true;
+
+            // else do the remote thing
+            RegionInfo regInfo = m_commsManager.GridService.RequestNeighbourInfo(regionHandle);
+            if (regInfo != null)
+            {
+                return DoCloseAgentCall(regInfo, id);
+            }
+            //else
+            //    m_log.Warn("[REST COMMS]: Region not found " + regionHandle);
+            return false;
+        }
+
+        #endregion /* IInterregionComms */
+
+        #region DoWork functions for the above public interface
+        //-------------------------------------------------------------------
+        // Internal  functions for the above public interface
+        //-------------------------------------------------------------------
+
         protected bool DoChildAgentUpdateCall(RegionInfo region, AgentData cAgentData)
         {
             // Eventually, we want to use a caps url instead of the agentID
@@ -168,7 +202,7 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
                 m_log.Debug("[REST COMMS]: PackUpdateMessage failed with exception: " + e.Message);
             }
             // Add the regionhandle of the destination region
-            ulong regionHandle = GetRegionHandle(region);
+            ulong regionHandle = GetRegionHandle(region.RegionHandle);
             args["destination_handle"] = OSD.FromString(regionHandle.ToString());
 
             string strBuffer = "";
@@ -231,9 +265,77 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
 
         }
 
-        #endregion /* IInterregionComms */
+        protected bool DoReleaseAgentCall(ulong regionHandle, UUID id, string uri)
+        {
+            //Console.WriteLine("   >>> DoReleaseAgentCall <<< " + uri);
+
+            WebRequest request = WebRequest.Create(uri);
+            request.Method = "DELETE";
+            request.Timeout = 10000;
+
+            try
+            {
+                WebResponse webResponse = request.GetResponse();
+                if (webResponse == null)
+                {
+                    m_log.Info("[REST COMMS]: Null reply on agent get ");
+                }
+
+                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
+                //reply = sr.ReadToEnd().Trim();
+                sr.ReadToEnd().Trim();
+                sr.Close();
+                //m_log.InfoFormat("[REST COMMS]: ChilAgentUpdate reply was {0} ", reply);
+
+            }
+            catch (WebException ex)
+            {
+                m_log.InfoFormat("[REST COMMS]: exception on reply of agent get {0}", ex.Message);
+                // ignore, really
+            }
+
+            return true;
+
+        }
+
+        protected bool DoCloseAgentCall(RegionInfo region, UUID id)
+        {
+            string uri = "http://" + region.ExternalEndPoint.Address + ":" + region.HttpPort + "/agent/" + id + "/" + region.RegionHandle.ToString() +"/";
+
+            //Console.WriteLine("   >>> DoCloseAgentCall <<< " + uri);
 
-        #region Called from remote instances on this instance
+            WebRequest request = WebRequest.Create(uri);
+            request.Method = "DELETE";
+            request.Timeout = 10000;
+
+            try
+            {
+                WebResponse webResponse = request.GetResponse();
+                if (webResponse == null)
+                {
+                    m_log.Info("[REST COMMS]: Null reply on agent get ");
+                }
+
+                StreamReader sr = new StreamReader(webResponse.GetResponseStream());
+                //reply = sr.ReadToEnd().Trim();
+                sr.ReadToEnd().Trim();
+                sr.Close();
+                //m_log.InfoFormat("[REST COMMS]: ChilAgentUpdate reply was {0} ", reply);
+
+            }
+            catch (WebException ex)
+            {
+                m_log.InfoFormat("[REST COMMS]: exception on reply of agent get {0}", ex.Message);
+                // ignore, really
+            }
+
+            return true;
+
+        }
+
+        #endregion /* DoWork */
+
+        #region Incoming calls from remote instances
 
         public Hashtable AgentHandler(Hashtable request)
         {
@@ -250,7 +352,8 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
 
             UUID agentID;
             string action;
-            if (!GetParams((string)request["uri"], out agentID, out action))
+            ulong regionHandle;
+            if (!GetParams((string)request["uri"], out agentID, out regionHandle, out action))
             {
                 m_log.InfoFormat("[REST COMMS]: Invalid parameters for agent message {0}", request["uri"]);
                 responsedata["int_response_code"] = 404;
@@ -274,11 +377,9 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
 
                 return responsedata;
             }
-            else if (method.Equals("GET"))
+            else if (method.Equals("DELETE"))
             {
-                m_log.InfoFormat("[REST COMMS]: method {0} not implemented yet in agent message", method);
-                responsedata["int_response_code"] = 404;
-                responsedata["str_response_string"] = "false";
+                DoDelete(request, responsedata, agentID, action, regionHandle);
 
                 return responsedata;
             }
@@ -293,7 +394,7 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
 
         }
 
-        protected virtual void DoPut(Hashtable request, Hashtable responsedata)
+        protected OSDMap GetOSDMap(Hashtable request)
         {
             OSDMap args = null;
             try
@@ -302,20 +403,32 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
                 // We should pay attention to the content-type, but let's assume we know it's Json
                 buffer = OSDParser.DeserializeJson((string)request["body"]);
                 if (buffer.Type == OSDType.Map)
+                {
                     args = (OSDMap)buffer;
+                    return args;
+                }
                 else
                 {
                     // uh?
                     m_log.Debug("[REST COMMS]: Got OSD of type " + buffer.Type.ToString());
+                    return null;
                 }
             }
             catch (Exception ex)
             {
                 m_log.InfoFormat("[REST COMMS]: exception on parse of ChildAgentUpdate message {0}", ex.Message);
+                return null;
+            }
+        }
+
+        protected virtual void DoPut(Hashtable request, Hashtable responsedata)
+        {
+            OSDMap args = GetOSDMap(request);
+            if (args == null)
+            {
                 responsedata["int_response_code"] = 400;
                 responsedata["str_response_string"] = "false";
-
-                return ;
+                return;
             }
 
             // retrieve the regionhandle
@@ -343,19 +456,34 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
             responsedata["str_response_string"] = result.ToString();
         }
 
+        protected virtual void DoDelete(Hashtable request, Hashtable responsedata, UUID id, string action, ulong regionHandle)
+        {
+            //Console.WriteLine(" >>> DoDelete action:" + action + "; regionHandle:" + regionHandle);
+            bool result = true;
+            if (action.Equals("release"))
+            {
+                result = m_localBackend.SendReleaseAgent(regionHandle, id, "");
+            }
+            else
+                result = m_localBackend.SendCloseAgent(regionHandle, id);
+
+            responsedata["int_response_code"] = 200;
+            responsedata["str_response_string"] = "OpenSim agent " + id.ToString();
+        }
         #endregion 
 
         #region Misc
         /// <summary>
         /// Extract the param from an uri.
         /// </summary>
-        /// <param name="uri">Something like this: /agent/uuid/ or /agent/uuid/release</param>
+        /// <param name="uri">Something like this: /agent/uuid/ or /agent/uuid/handle/release</param>
         /// <param name="uri">uuid on uuid field</param>
         /// <param name="action">optional action</param>
-        protected bool GetParams(string uri, out UUID uuid, out string action)
+        protected bool GetParams(string uri, out UUID uuid, out ulong regionHandle, out string action)
         {
             uuid = UUID.Zero;
             action = "";
+            regionHandle = 0;
 
             uri = uri.Trim(new char[] { '/' });
             string[] parts = uri.Split('/');
@@ -369,20 +497,29 @@ namespace OpenSim.Region.Environment.Modules.Communications.REST
                     return false;
 
                 if (parts.Length >= 3)
-                    action = parts[2];
-
+                    UInt64.TryParse(parts[2], out regionHandle);
+                if (parts.Length >= 4)
+                    action = parts[3];
+                
                 return true;
             }
         }
 
-        protected virtual ulong GetRegionHandle(RegionInfo region)
+        protected virtual ulong GetRegionHandle(ulong handle)
         {
             if (m_aScene.SceneGridService is HGSceneCommunicationService)
-                return ((HGSceneCommunicationService)(m_aScene.SceneGridService)).m_hg.FindRegionHandle(region.RegionHandle);
+                return ((HGSceneCommunicationService)(m_aScene.SceneGridService)).m_hg.FindRegionHandle(handle);
 
-            return region.RegionHandle;
+            return handle;
         }
 
+        protected virtual bool IsHyperlink(ulong handle)
+        {
+            if (m_aScene.SceneGridService is HGSceneCommunicationService)
+                return ((HGSceneCommunicationService)(m_aScene.SceneGridService)).m_hg.IsHyperlinkRegion(handle);
+
+            return false;
+        }
         #endregion /* Misc */
 
     }
diff --git a/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs
index bcd378f..abf4065 100644
--- a/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs
+++ b/OpenSim/Region/Environment/Scenes/Hypergrid/HGSceneCommunicationService.cs
@@ -256,15 +256,16 @@ namespace OpenSim.Region.Environment.Scenes.Hypergrid
                         //    return;
                         //}
 
+                        SetInTransit(avatar.UUID);
                         // Let's send a full update of the agent. This is a synchronous call.
                         AgentData agent = new AgentData();
                         avatar.CopyTo(agent);
                         agent.Position = new Vector3(-1, -1, -1); // this means ignore position info; UGH!!!!
+                        agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort +
+                            "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/";
 
                         m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent);
 
-                        avatar.MakeChildAgent();
-
                         m_log.DebugFormat(
                             "[CAPS]: Sending new CAPS seed url {0} to client {1}", agentCircuit.CapsPath, avatar.UUID);
 
@@ -288,17 +289,32 @@ namespace OpenSim.Region.Environment.Scenes.Hypergrid
                         /// Hypergrid mod stop
                         /// 
 
+
+                        // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
+                        // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
+                        // that the client contacted the destination before we send the attachments and close things here.
+                        if (!WaitForCallback(avatar.UUID))
+                        {
+                            // Client never contacted destination. Let's restore everything back
+                            avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
+
+                            ResetFromTransit(avatar.UUID);
+                            // Yikes! We should just have a ref to scene here.
+                            avatar.Scene.InformClientOfNeighbours(avatar);
+
+                            // Finally, kill the agent we just created at the destination.
+                            m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID);
+
+                            return;
+                        }
+
+                        // Can't go back from here
                         if (KiPrimitive != null)
                         {
                             KiPrimitive(avatar.LocalId);
                         }
 
-                        // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
-                        // trigers a whole shebang of things there, including MakeRoot. So let's wait plenty before 
-                        // we send the attachments and close things here.
-                        // It would be nice if the client would tell us when that whole thing is done, so we wouldn't have
-                        // to use this Thread.Sleep voodoo
-                        Thread.Sleep(4000);
+                        avatar.MakeChildAgent();
 
                         // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
                         avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true);
@@ -310,7 +326,7 @@ namespace OpenSim.Region.Environment.Scenes.Hypergrid
                         /// 
                         if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink)
                         {
-                            Thread.Sleep(8000);
+                            Thread.Sleep(5000);
                             avatar.Close();
                             CloseConnection(avatar.UUID);
                         }
diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs
index 56b5df6..13b9169 100644
--- a/OpenSim/Region/Environment/Scenes/Scene.cs
+++ b/OpenSim/Region/Environment/Scenes/Scene.cs
@@ -2692,7 +2692,7 @@ namespace OpenSim.Region.Environment.Scenes
         {
             m_sceneGridService.OnExpectUser += NewUserConnection;
             m_sceneGridService.OnAvatarCrossingIntoRegion += AgentCrossing;
-            m_sceneGridService.OnCloseAgentConnection += CloseConnection;
+            m_sceneGridService.OnCloseAgentConnection += IncomingCloseAgent;
             m_sceneGridService.OnRegionUp += OtherRegionUp;
             //m_sceneGridService.OnChildAgentUpdate += IncomingChildAgentDataUpdate;
             m_sceneGridService.OnExpectPrim += IncomingInterRegionPrimGroup;
@@ -2724,7 +2724,7 @@ namespace OpenSim.Region.Environment.Scenes
             m_sceneGridService.OnRegionUp -= OtherRegionUp;
             m_sceneGridService.OnExpectUser -= NewUserConnection;
             m_sceneGridService.OnAvatarCrossingIntoRegion -= AgentCrossing;
-            m_sceneGridService.OnCloseAgentConnection -= CloseConnection;
+            m_sceneGridService.OnCloseAgentConnection -= IncomingCloseAgent;
             m_sceneGridService.OnGetLandData -= GetLandData;
 
             if (m_interregionCommsIn != null)
@@ -2979,12 +2979,22 @@ namespace OpenSim.Region.Environment.Scenes
             return false;
         }
 
+        public virtual bool IncomingReleaseAgent(UUID id)
+        {
+            return m_sceneGridService.ReleaseAgent(id);
+        }
+
+        public void SendReleaseAgent(ulong regionHandle, UUID id, string uri)
+        {
+            m_interregionCommsOut.SendReleaseAgent(regionHandle, id, uri);
+        }
+
         /// <summary>
         /// Tell a single agent to disconnect from the region.
         /// </summary>
         /// <param name="regionHandle"></param>
         /// <param name="agentID"></param>
-        public bool CloseConnection(UUID agentID)
+        public bool IncomingCloseAgent(UUID agentID)
         {
             ScenePresence presence = m_sceneGraph.GetScenePresence(agentID);
             if (presence != null)
@@ -3013,9 +3023,10 @@ namespace OpenSim.Region.Environment.Scenes
                         presence.ControllingClient.SendShutdownConnectionNotice();
                 }
                 presence.ControllingClient.Close(true);
-
+                return true;
             }
-            return true;
+            // Agent not here
+            return false;
         }
 
         /// <summary>
diff --git a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
index 2bf81d8..da3a9d3 100644
--- a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
+++ b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs
@@ -55,6 +55,8 @@ namespace OpenSim.Region.Environment.Scenes
 
         protected RegionCommsListener regionCommsHost;
 
+        protected List<UUID> m_agentsInTransit;
+
         public event AgentCrossing OnAvatarCrossingIntoRegion;
         public event ExpectUserDelegate OnExpectUser;
         public event ExpectPrimDelegate OnExpectPrim;
@@ -82,6 +84,7 @@ namespace OpenSim.Region.Environment.Scenes
         public SceneCommunicationService(CommunicationsManager commsMan)
         {
             m_commsProvider = commsMan;
+            m_agentsInTransit = new List<UUID>();
         }
 
         /// <summary>
@@ -546,8 +549,7 @@ namespace OpenSim.Region.Environment.Scenes
         /// </summary>
         private void SendChildAgentDataUpdateAsync(AgentData cAgentData, ulong regionHandle)
         {
-            m_log.Info("[INTERGRID]: Informing neighbors about my agent in " + m_regionInfo.RegionName);
-            //bool regionAccepted = m_commsProvider.InterRegion.ChildAgentUpdate(regionHandle, cAgentData);
+            //m_log.Info("[INTERGRID]: Informing neighbors about my agent in " + m_regionInfo.RegionName);
             try
             {
                 //m_commsProvider.InterRegion.ChildAgentUpdate(regionHandle, cAgentData);
@@ -608,29 +610,10 @@ namespace OpenSim.Region.Environment.Scenes
         {
 
             m_log.Debug("[INTERGRID]: Sending close agent to " + regionHandle);
-            //bool regionAccepted = m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
             // let's do our best, but there's not much we can do if the neighbour doesn't accept.
-            m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
-
-                //if (regionAccepted)
-                //{
-                //    m_log.Info("[INTERGRID]: Completed sending agent Close agent Request to neighbor");
-
-                //}
-                //else
-                //{
-                //    m_log.Info("[INTERGRID]: Failed sending agent Close agent Request to neighbor");
 
-                //}
-
-            //// We remove the list of known regions from the agent's known region list through an event
-            //// to scene, because, if an agent logged of, it's likely that there will be no scene presence
-            //// by the time we get to this part of the method.
-            //handlerRemoveKnownRegionFromAvatar = OnRemoveKnownRegionFromAvatar;
-            //if (handlerRemoveKnownRegionFromAvatar != null)
-            //{
-            //    handlerRemoveKnownRegionFromAvatar(agentID, regionlst);
-            //}
+            //m_commsProvider.InterRegion.TellRegionToCloseChildConnection(regionHandle, agentID);
+            m_interregionCommsOut.SendCloseAgent(regionHandle, agentID);
         }
 
         private void SendCloseChildAgentCompleted(IAsyncResult iar)
@@ -860,15 +843,16 @@ namespace OpenSim.Region.Environment.Scenes
                         //    return;
                         //}
 
+                        SetInTransit(avatar.UUID);
                         // Let's send a full update of the agent. This is a synchronous call.
                         AgentData agent = new AgentData();
                         avatar.CopyTo(agent);
                         agent.Position = new Vector3(-1, -1, -1); // this means ignore position info; UGH!!!!
+                        agent.CallbackURI = "http://" + m_regionInfo.ExternalHostName + ":" + m_regionInfo.HttpPort + 
+                            "/agent/" + avatar.UUID.ToString() + "/" + avatar.Scene.RegionInfo.RegionHandle.ToString() + "/release/";
 
                         m_interregionCommsOut.SendChildAgentUpdate(reg.RegionHandle, agent);
 
-                        avatar.MakeChildAgent();
-
                         m_log.DebugFormat(
                             "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID);
 
@@ -885,17 +869,32 @@ namespace OpenSim.Region.Environment.Scenes
                                                                         teleportFlags, capsPath);
                         }
 
+
+                        // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
+                        // trigers a whole shebang of things there, including MakeRoot. So let's wait for confirmation
+                        // that the client contacted the destination before we send the attachments and close things here.
+                        if (!WaitForCallback(avatar.UUID))
+                        {
+                            // Client never contacted destination. Let's restore everything back
+                            avatar.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
+
+                            ResetFromTransit(avatar.UUID);
+                            // Yikes! We should just have a ref to scene here.
+                            avatar.Scene.InformClientOfNeighbours(avatar);
+
+                            // Finally, kill the agent we just created at the destination.
+                            m_interregionCommsOut.SendCloseAgent(reg.RegionHandle, avatar.UUID);
+
+                            return;
+                        }
+
+                        // Can't go back from here
                         if (KiPrimitive != null)
                         {
                             KiPrimitive(avatar.LocalId);
                         }
 
-                        // TeleportFinish makes the client send CompleteMovementIntoRegion (at the destination), which
-                        // trigers a whole shebang of things there, including MakeRoot. So let's wait plenty before 
-                        // we send the attachments and close things here.
-                        // We need to change this part of the protocol. The receiving region should tell this region
-                        // when it's ok to continue.
-                        Thread.Sleep(4000);
+                        avatar.MakeChildAgent();
 
                         // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it
                         avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true);
@@ -904,7 +903,7 @@ namespace OpenSim.Region.Environment.Scenes
 
                         if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY))
                         {
-                            Thread.Sleep(8000);
+                            Thread.Sleep(5000);
                             avatar.Close();
                             CloseConnection(avatar.UUID);
                         }
@@ -947,6 +946,49 @@ namespace OpenSim.Region.Environment.Scenes
             }
         }
 
+        protected bool WaitForCallback(UUID id)
+        {
+            int count = 20;
+            while (m_agentsInTransit.Contains(id) && count-- > 0)
+            {
+                //Console.WriteLine("  >>> Waiting... " + count);
+                Thread.Sleep(1000);
+            }
+
+            if (count > 0)
+                return true;
+            else
+                return false;
+        }
+
+        public bool ReleaseAgent(UUID id)
+        {
+            //Console.WriteLine(" >>> ReleaseAgent called <<< ");
+            return ResetFromTransit(id);
+        }
+
+        protected void SetInTransit(UUID id)
+        {
+            lock (m_agentsInTransit)
+            {
+                if (!m_agentsInTransit.Contains(id))
+                    m_agentsInTransit.Add(id);
+            }
+        }
+
+        protected bool ResetFromTransit(UUID id)
+        {
+            lock (m_agentsInTransit)
+            {
+                if (m_agentsInTransit.Contains(id))
+                {
+                    m_agentsInTransit.Remove(id);
+                    return true;
+                }
+            }
+            return false;
+        }
+
         private List<ulong> NeighbourHandles(List<SimpleRegionInfo> neighbours)
         {
             List<ulong> handles = new List<ulong>();
diff --git a/OpenSim/Region/Environment/Scenes/ScenePresence.cs b/OpenSim/Region/Environment/Scenes/ScenePresence.cs
index 23dc9be..166e051 100644
--- a/OpenSim/Region/Environment/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Environment/Scenes/ScenePresence.cs
@@ -217,6 +217,10 @@ namespace OpenSim.Region.Environment.Scenes
 
         private Dictionary<UUID, ScenePartUpdate> m_updateTimes = new Dictionary<UUID, ScenePartUpdate>();
 
+        // For teleports and crossings callbacks
+        string m_callbackURI;
+        ulong m_rootRegionHandle;
+
         #region Properties
 
         /// <summary>
@@ -1000,6 +1004,7 @@ namespace OpenSim.Region.Environment.Scenes
         /// </summary>
         public void CompleteMovement()
         {
+            //Console.WriteLine("\n CompleteMovement \n");
             Vector3 look = Velocity;
             if ((look.X == 0) && (look.Y == 0) && (look.Z == 0))
             {
@@ -1013,6 +1018,12 @@ namespace OpenSim.Region.Environment.Scenes
                 m_isChildAgent = false;
 
                 MakeRootAgent(AbsolutePosition, false);
+
+                if ((m_callbackURI != null) && !m_callbackURI.Equals(""))
+                {
+                    Scene.SendReleaseAgent(m_rootRegionHandle, UUID, m_callbackURI);
+                    m_callbackURI = null;
+                }
             }
         }
 
@@ -2582,7 +2593,7 @@ namespace OpenSim.Region.Environment.Scenes
             if (!IsChildAgent)
                 return;
 
-            //Console.WriteLine("   >>> ChildAgentDataUpdate <<<");
+            //Console.WriteLine("   >>> ChildAgentDataUpdate <<< " + rRegionX + "-" + rRegionY);
             int shiftx = ((int)rRegionX - (int)tRegionX) * (int)Constants.RegionSize;
             int shifty = ((int)rRegionY - (int)tRegionY) * (int)Constants.RegionSize;
 
@@ -2615,6 +2626,9 @@ namespace OpenSim.Region.Environment.Scenes
             if (m_scene.m_seeIntoRegionFromNeighbor)
                 m_pendingObjects = null;
 
+            m_callbackURI = cAgentData.CallbackURI;
+            m_rootRegionHandle = Util.UIntsToLong(rRegionX * Constants.RegionSize, rRegionY * Constants.RegionSize);
+
             //cAgentData.AVHeight;
             //cAgentData.regionHandle;
             //m_velocity = cAgentData.Velocity;
-- 
cgit v1.1