/// <summary> /// Attempts to establish a presence on the given region /// </summary> /// <param name="region">The region we want to establish a child presence on</param> /// <param name="forceReestablish">Whether to force a reestablishment even if we already think we have a remote presence</param> /// <param name="isFarPresence">Is this presence intentionally far away? Eg. The beginning of a remote teleport</param> /// <returns></returns> private async Task <Tuple <EstablishPresenceResult, string> > EstablishPresenceOnRegion(SimpleRegionInfo region, bool forceReestablish, bool isFarPresence) { Task <Tuple <EstablishPresenceResult, string> > establishTask = null; bool presenceExisted = false; //check if we already have or are waiting on an establish TryGetRemotePresenceLocked(region.RegionHandle, (AvatarRemotePresence presence) => { if (presence != null && !forceReestablish) { //we have a presence //if it is established just return if (presence.State == RemotePresenceState.Established) { presenceExisted = true; } else { //if not, we can await the existing callback establishTask = presence.EstablishTask; } } else { //we have no presence and we're not waiting for a callback //begin an async establish and await a callback presence = new AvatarRemotePresence { PresenceInfo = new RemotePresenceInfo { RegionInfo = region, CapsPath = CapsUtil.GetRandomCapsObjectPath() }, IsFarPresence = isFarPresence, State = RemotePresenceState.Establishing }; if (_remotePresences.ContainsKey(region.RegionHandle)) { _remotePresences.Remove(region.RegionHandle); } _remotePresences.Add(region.RegionHandle, presence); establishTask = DoEstablishPresenceOnRegion(region, presence); presence.EstablishTask = establishTask; } }); //nothing to do, we're already established if (presenceExisted) { return(Tuple.Create(EstablishPresenceResult.Success, String.Empty)); } return(await establishTask); }
/// <summary> /// Not really informing the region. Just filling out the response fields related to the region. /// </summary> /// <param name="sim"></param> /// <param name="user"></param> /// <param name="response"></param> /// <returns>true if the region was successfully contacted, false otherwise</returns> protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response, IPEndPoint remoteClient) { IPEndPoint endPoint = regionInfo.ExternalEndPoint; response.SimAddress = endPoint.Address.ToString(); response.SimPort = (uint)endPoint.Port; response.RegionX = regionInfo.RegionLocX; response.RegionY = regionInfo.RegionLocY; response.SimHttpPort = regionInfo.HttpPort; string capsPath = CapsUtil.GetRandomCapsObjectPath(); string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath); // Don't use the following! It Fails for logging into any region not on the same port as the http server! // Kept here so it doesn't happen again! // response.SeedCapability = regionInfo.ServerURI + capsSeedPath; string seedcap = "http://"; if (m_serversInfo.HttpUsesSSL) { // For NAT string host = NetworkUtil.GetHostFor(remoteClient.Address, m_serversInfo.HttpSSLCN); seedcap = "https://" + host + ":" + m_serversInfo.httpSSLPort + capsSeedPath; } else { // For NAT string host = NetworkUtil.GetHostFor(remoteClient.Address, regionInfo.ExternalHostName); seedcap = "http://" + host + ":" + m_serversInfo.HttpListenerPort + capsSeedPath; } response.SeedCapability = seedcap; // Notify the target of an incoming user m_log.InfoFormat( "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection", regionInfo.RegionName, response.RegionX, response.RegionY, regionInfo.ServerURI); // Update agent with target sim user.CurrentAgent.Region = regionInfo.RegionID; user.CurrentAgent.Handle = regionInfo.RegionHandle; return(true); }
private AgentCircuitData MakeAgent(GridRegion region, UserAccount account, AvatarAppearance avatar, UUID session, UUID secureSession, uint circuit, Vector3 position, string ipaddress, string viewer, string channel, string mac, string id0) { AgentCircuitData aCircuit = new AgentCircuitData(); aCircuit.AgentID = account.PrincipalID; if (avatar != null) { aCircuit.Appearance = new AvatarAppearance(avatar); } else { aCircuit.Appearance = new AvatarAppearance(account.PrincipalID); } //aCircuit.BaseFolder = irrelevant aCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); aCircuit.child = false; // the first login agent is root aCircuit.ChildrenCapSeeds = new Dictionary <ulong, string>(); aCircuit.circuitcode = circuit; aCircuit.firstname = account.FirstName; //aCircuit.InventoryFolder = irrelevant aCircuit.lastname = account.LastName; aCircuit.SecureSessionID = secureSession; aCircuit.SessionID = session; aCircuit.startpos = position; aCircuit.IPAddress = ipaddress; aCircuit.Viewer = viewer; aCircuit.Channel = channel; aCircuit.Mac = mac; aCircuit.Id0 = id0; SetServiceURLs(aCircuit, account); return(aCircuit); //m_UserAgentService.LoginAgentToGrid(aCircuit, GatekeeperServiceConnector, region, out reason); //if (simConnector.CreateAgent(region, aCircuit, 0, out reason)) // return aCircuit; //return null; }
/// <summary> /// Prepare a login to the given region. This involves both telling the region to expect a connection /// and appropriately customising the response to the user. /// </summary> /// <param name="regionInfo"></param> /// <param name="user"></param> /// <param name="response"></param> /// <returns>true if the region was successfully contacted, false otherwise</returns> private bool PrepareLoginToRegion(RegionProfileData regionInfo, UserProfileData user, LoginResponse response, string clientVersion) { string regionName = regionInfo.regionName; bool success = false; try { lock (_LastRegionFailure) { if (_LastRegionFailure.ContainsKey(regionName)) { // region failed previously RegionLoginFailure failure = _LastRegionFailure[regionName]; if (failure.IsExpired()) { // failure has expired, retry this region again _LastRegionFailure.Remove(regionName); // m_log.WarnFormat("[LOGIN]: Region '{0}' was previously down, retrying.", regionName); } else { if (failure.IsFailed()) { // m_log.WarnFormat("[LOGIN]: Region '{0}' was recently down, skipping.", regionName); return(false); // within 5 minutes, don't repeat attempt } // m_log.WarnFormat("[LOGIN]: Region '{0}' was recently down but under threshold, retrying.", regionName); } } } response.SimAddress = regionInfo.OutsideIpOrResolvedHostname; response.SimPort = regionInfo.serverPort; response.RegionX = regionInfo.regionLocX; response.RegionY = regionInfo.regionLocY; string capsPath = CapsUtil.GetRandomCapsObjectPath(); response.SeedCapability = CapsUtil.GetFullCapsSeedURL(regionInfo.httpServerURI, capsPath); // Notify the target of an incoming user m_log.InfoFormat( "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection", regionInfo.regionName, response.RegionX, response.RegionY, response.SeedCapability); // Update agent with target sim user.CurrentAgent.Region = regionInfo.UUID; user.CurrentAgent.Handle = regionInfo.regionHandle; // Prepare notification Hashtable loginParams = new Hashtable(); loginParams["session_id"] = user.CurrentAgent.SessionID.ToString(); loginParams["secure_session_id"] = user.CurrentAgent.SecureSessionID.ToString(); loginParams["firstname"] = user.FirstName; loginParams["lastname"] = user.SurName; loginParams["agent_id"] = user.ID.ToString(); loginParams["circuit_code"] = (Int32)Convert.ToUInt32(response.CircuitCode); loginParams["startpos_x"] = user.CurrentAgent.Position.X.ToString(); loginParams["startpos_y"] = user.CurrentAgent.Position.Y.ToString(); loginParams["startpos_z"] = user.CurrentAgent.Position.Z.ToString(); loginParams["regionhandle"] = user.CurrentAgent.Handle.ToString(); loginParams["caps_path"] = capsPath; loginParams["client_version"] = clientVersion; // Get appearance AvatarAppearance appearance = m_userManager.GetUserAppearance(user.ID); if (appearance != null) { loginParams["appearance"] = appearance.ToHashTable(); m_log.DebugFormat("[LOGIN]: Found appearance version {0} for {1} {2}", appearance.Serial, user.FirstName, user.SurName); } else { m_log.DebugFormat("[LOGIN]: Appearance not for {0} {1}. Creating default.", user.FirstName, user.SurName); appearance = new AvatarAppearance(user.ID); } // Tell the client the COF version so it can use cached appearance if it matches. response.CofVersion = appearance.Serial.ToString(); loginParams["cof_version"] = response.CofVersion; ArrayList SendParams = new ArrayList(); SendParams.Add(loginParams); SendParams.Add(m_config.GridSendKey); // Send const string METHOD_NAME = "expect_user"; XmlRpcRequest GridReq = new XmlRpcRequest(METHOD_NAME, SendParams); XmlRpcResponse GridResp = GridReq.Send(Util.XmlRpcRequestURI(regionInfo.httpServerURI, METHOD_NAME), 6000); if (!GridResp.IsFault) { bool responseSuccess = true; if (GridResp.Value != null) { Hashtable resp = (Hashtable)GridResp.Value; if (resp.ContainsKey("success")) { if ((string)resp["success"] == "FALSE") { responseSuccess = false; } } if (!responseSuccess) { if (resp.ContainsKey("reason")) { response.ErrorMessage = resp["reason"].ToString(); } } } if (responseSuccess) { handlerUserLoggedInAtLocation = OnUserLoggedInAtLocation; if (handlerUserLoggedInAtLocation != null) { handlerUserLoggedInAtLocation(user.ID, user.CurrentAgent.SessionID, user.CurrentAgent.Region, user.CurrentAgent.Handle, user.CurrentAgent.Position.X, user.CurrentAgent.Position.Y, user.CurrentAgent.Position.Z, user.FirstName, user.SurName); } success = true; } else { m_log.ErrorFormat("[LOGIN]: Region responded that it is not available to receive clients"); } } else { m_log.ErrorFormat("[LOGIN]: XmlRpc request to region failed with message {0}, code {1} ", GridResp.FaultString, GridResp.FaultCode); } } catch (Exception e) { m_log.ErrorFormat("[LOGIN]: Region not available for login, {0}", e); } lock (_LastRegionFailure) { if (_LastRegionFailure.ContainsKey(regionName)) { RegionLoginFailure failure = _LastRegionFailure[regionName]; if (success) { // Success, so if we've been storing this as a failed region, remove that from the failed list. m_log.WarnFormat("[LOGIN]: Region '{0}' recently down, is available again.", regionName); _LastRegionFailure.Remove(regionName); } else { // Region not available, update cache with incremented count. failure.AddFailure(); // m_log.WarnFormat("[LOGIN]: Region '{0}' is still down ({1}).", regionName, failure.Count); } } else { if (!success) { // Region not available, cache that temporarily. m_log.WarnFormat("[LOGIN]: Region '{0}' is down, marking.", regionName); _LastRegionFailure[regionName] = new RegionLoginFailure(); } } } return(success); }
/// <summary> /// Async component for informing client of which neighbors exist /// </summary> /// <remarks> /// This needs to run asynchronously, as a network timeout may block the thread for a long while /// </remarks> /// <param name="remoteClient"></param> /// <param name="a"></param> /// <param name="regionHandle"></param> /// <param name="endPoint"></param> private bool InformClientOfNeighbor(UUID AgentID, ulong requestingRegion, AgentCircuitData circuitData, GridRegion neighbor, uint TeleportFlags, AgentData agentData, out string reason) { if (neighbor == null) { reason = "Could not find neighbor to inform"; return(false); } m_log.Info("[AgentProcessing]: Starting to inform client about neighbor " + neighbor.RegionName); //Notes on this method // 1) the SimulationService.CreateAgent MUST have a fixed CapsUrl for the region, so we have to create (if needed) // a new Caps handler for it. // 2) Then we can call the methods (EnableSimulator and EstatablishAgentComm) to tell the client the new Urls // 3) This allows us to make the Caps on the grid server without telling any other regions about what the // Urls are. ISimulationService SimulationService = m_registry.RequestModuleInterface <ISimulationService>(); if (SimulationService != null) { ICapsService capsService = m_registry.RequestModuleInterface <ICapsService>(); IClientCapsService clientCaps = capsService.GetClientCapsService(AgentID); IRegionClientCapsService oldRegionService = clientCaps.GetCapsService(neighbor.RegionHandle); //If its disabled, it should be removed, so kill it! if (oldRegionService != null && oldRegionService.Disabled) { clientCaps.RemoveCAPS(neighbor.RegionHandle); oldRegionService = null; } bool newAgent = oldRegionService == null; IRegionClientCapsService otherRegionService = clientCaps.GetOrCreateCapsService(neighbor.RegionHandle, CapsUtil.GetCapsSeedPath(CapsUtil.GetRandomCapsObjectPath()), circuitData); if (!newAgent) { //Note: if the agent is already there, send an agent update then bool result = true; if (agentData != null) { result = SimulationService.UpdateAgent(neighbor, agentData); if (result) { oldRegionService.Disabled = false; } } reason = ""; return(result); } ICommunicationService commsService = m_registry.RequestModuleInterface <ICommunicationService>(); if (commsService != null) { circuitData.OtherInformation["UserUrls"] = commsService.GetUrlsForUser(neighbor, circuitData.AgentID); } #region OpenSim teleport compatibility! if (!m_useCallbacks) { circuitData.CapsPath = CapsUtil.GetRandomCapsObjectPath(); circuitData.startpos.X += (neighbor.RegionLocX - clientCaps.GetRootCapsService().RegionX); circuitData.startpos.Y += (neighbor.RegionLocY - clientCaps.GetRootCapsService().RegionY); } #endregion bool regionAccepted = SimulationService.CreateAgent(neighbor, circuitData, TeleportFlags, agentData, out reason); if (regionAccepted) { string otherRegionsCapsURL; //If the region accepted us, we should get a CAPS url back as the reason, if not, its not updated or not an Aurora region, so don't touch it. if (reason != "") { OSDMap responseMap = (OSDMap)OSDParser.DeserializeJson(reason); OSDMap SimSeedCaps = (OSDMap)responseMap["CapsUrls"]; otherRegionService.AddCAPS(SimSeedCaps); otherRegionsCapsURL = otherRegionService.CapsUrl; } else { //We are assuming an OpenSim region now! #region OpenSim teleport compatibility! otherRegionsCapsURL = "http://" + otherRegionService.Region.ExternalEndPoint.ToString() + CapsUtil.GetCapsSeedPath(circuitData.CapsPath); otherRegionService.CapsUrl = otherRegionsCapsURL; #endregion } IEventQueueService EQService = m_registry.RequestModuleInterface <IEventQueueService>(); EQService.EnableSimulator(neighbor.RegionHandle, neighbor.ExternalEndPoint.Address.GetAddressBytes(), neighbor.ExternalEndPoint.Port, AgentID, neighbor.RegionSizeX, neighbor.RegionSizeY, requestingRegion); // EnableSimulator makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(300); EQService.EstablishAgentCommunication(AgentID, neighbor.RegionHandle, neighbor.ExternalEndPoint.Address.GetAddressBytes(), neighbor.ExternalEndPoint.Port, otherRegionsCapsURL, neighbor.RegionSizeX, neighbor.RegionSizeY, requestingRegion); if (!m_useCallbacks) { Thread.Sleep(3000); //Give it a bit of time } m_log.Info("[AgentProcessing]: Completed inform client about neighbor " + neighbor.RegionName); } else { m_log.Error("[AgentProcessing]: Failed to inform client about neighbor " + neighbor.RegionName + ", reason: " + reason); return(false); } return(true); } reason = "SimulationService does not exist"; m_log.Error("[AgentProcessing]: Failed to inform client about neighbor " + neighbor.RegionName + ", reason: " + reason + "!"); return(false); }
/// <summary> /// Prepare a login to the given region. This involves both telling the region to expect a connection /// and appropriately customising the response to the user. /// </summary> /// <param name="sim"></param> /// <param name="user"></param> /// <param name="response"></param> /// <returns>true if the region was successfully contacted, false otherwise</returns> protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response, string clientVersion) { IPEndPoint endPoint = regionInfo.ExternalEndPoint; response.SimAddress = endPoint.Address.ToString(); response.SimPort = (uint)endPoint.Port; response.RegionX = regionInfo.RegionLocX; response.RegionY = regionInfo.RegionLocY; string capsPath = CapsUtil.GetRandomCapsObjectPath(); string capsSeedPath = CapsUtil.GetCapsSeedPath(capsPath); // Don't use the following! It Fails for logging into any region not on the same port as the http server! // Kept here so it doesn't happen again! // response.SeedCapability = regionInfo.ServerURI + capsSeedPath; string seedcap = "http://" + regionInfo.ExternalHostName + ":" + m_serversInfo.HttpListenerPort + capsSeedPath; response.SeedCapability = seedcap; // Notify the target of an incoming user m_log.InfoFormat( "[LOGIN]: Telling {0} @ {1},{2} to prepare for client connection", regionInfo.RegionName, response.RegionX, response.RegionY); // Update agent with target sim user.CurrentAgent.Region = regionInfo.RegionID; user.CurrentAgent.Handle = regionInfo.RegionHandle; AgentCircuitData agent = new AgentCircuitData(); agent.AgentID = user.ID; agent.FirstName = user.FirstName; agent.LastName = user.SurName; agent.SessionID = user.CurrentAgent.SessionID; agent.SecureSessionID = user.CurrentAgent.SecureSessionID; agent.CircuitCode = Convert.ToUInt32(response.CircuitCode); agent.BaseFolder = UUID.Zero; agent.InventoryFolder = UUID.Zero; agent.startpos = user.CurrentAgent.Position; agent.CapsPath = capsPath; agent.Appearance = m_userManager.GetUserAppearance(user.ID); agent.ClientVersion = clientVersion; if (agent.Appearance == null) { m_log.WarnFormat("[INTER]: Appearance not found for {0} {1}. Creating default.", agent.FirstName, agent.LastName); agent.Appearance = new AvatarAppearance(agent.AgentID); } // Tell the client what the Cof Version is. If it matches the client can use cached appearance response.CofVersion = agent.Appearance.Serial.ToString(); if (m_regionsConnector.RegionLoginsEnabled) { string reason; bool success = m_regionsConnector.NewUserConnection(regionInfo.RegionHandle, agent, true, out reason); if (!success) { response.ErrorReason = "key"; response.ErrorMessage = reason; } return(success); // return m_regionsConnector.NewUserConnection(regionInfo.RegionHandle, agent, out reason); } return(false); }
/// <summary> /// Prepare a login to the given region. This involves both telling the region to expect a connection /// and appropriately customising the response to the user. /// </summary> /// <param name="regionInfo"></param> /// <param name="user"></param> /// <param name="response"></param> /// <returns>true if the region was successfully contacted, false otherwise</returns> private bool PrepareLoginToRegion(RegionProfileData regionInfo, UserProfileData user, LoginResponse response, IPEndPoint remoteClient) { try { response.SimAddress = Util.GetHostFromURL(regionInfo.serverURI).ToString(); response.SimPort = uint.Parse(regionInfo.serverURI.Split(new char[] { '/', ':' })[4]); response.RegionX = regionInfo.regionLocX; response.RegionY = regionInfo.regionLocY; string capsPath = CapsUtil.GetRandomCapsObjectPath(); // Adam's working code commented for now -- Diva 5/25/2009 //// For NAT ////string host = NetworkUtil.GetHostFor(remoteClient.Address, regionInfo.ServerIP); //string host = response.SimAddress; //// TODO: This doesnt support SSL. -Adam //string serverURI = "http://" + host + ":" + regionInfo.ServerPort; //response.SeedCapability = serverURI + CapsUtil.GetCapsSeedPath(capsPath); // Take off trailing / so that the caps path isn't //CAPS/someUUID if (regionInfo.httpServerURI.EndsWith("/")) { regionInfo.httpServerURI = regionInfo.httpServerURI.Substring(0, regionInfo.httpServerURI.Length - 1); } response.SeedCapability = regionInfo.httpServerURI + CapsUtil.GetCapsSeedPath(capsPath); // Notify the target of an incoming user m_log.InfoFormat( "[LOGIN]: Telling {0} @ {1},{2} ({3}) to prepare for client connection", regionInfo.regionName, response.RegionX, response.RegionY, regionInfo.httpServerURI); // Update agent with target sim user.CurrentAgent.Region = regionInfo.UUID; user.CurrentAgent.Handle = regionInfo.regionHandle; // Prepare notification Hashtable loginParams = new Hashtable(); loginParams["session_id"] = user.CurrentAgent.SessionID.ToString(); loginParams["secure_session_id"] = user.CurrentAgent.SecureSessionID.ToString(); loginParams["firstname"] = user.FirstName; loginParams["lastname"] = user.SurName; loginParams["agent_id"] = user.ID.ToString(); loginParams["circuit_code"] = (Int32)Convert.ToUInt32(response.CircuitCode); loginParams["startpos_x"] = user.CurrentAgent.Position.X.ToString(); loginParams["startpos_y"] = user.CurrentAgent.Position.Y.ToString(); loginParams["startpos_z"] = user.CurrentAgent.Position.Z.ToString(); loginParams["regionhandle"] = user.CurrentAgent.Handle.ToString(); loginParams["caps_path"] = capsPath; // Get appearance AvatarAppearance appearance = m_userManager.GetUserAppearance(user.ID); if (appearance != null) { loginParams["appearance"] = appearance.ToHashTable(); m_log.DebugFormat("[LOGIN]: Found appearance for {0} {1}", user.FirstName, user.SurName); } else { m_log.DebugFormat("[LOGIN]: Appearance not for {0} {1}. Creating default.", user.FirstName, user.SurName); appearance = new AvatarAppearance(user.ID); } ArrayList SendParams = new ArrayList(); SendParams.Add(loginParams); // Send XmlRpcRequest GridReq = new XmlRpcRequest("expect_user", SendParams); XmlRpcResponse GridResp = GridReq.Send(regionInfo.httpServerURI, 6000); if (!GridResp.IsFault) { bool responseSuccess = true; if (GridResp.Value != null) { Hashtable resp = (Hashtable)GridResp.Value; if (resp.ContainsKey("success")) { if ((string)resp["success"] == "FALSE") { responseSuccess = false; } } } if (responseSuccess) { handlerUserLoggedInAtLocation = OnUserLoggedInAtLocation; if (handlerUserLoggedInAtLocation != null) { handlerUserLoggedInAtLocation(user.ID, user.CurrentAgent.SessionID, user.CurrentAgent.Region, user.CurrentAgent.Handle, user.CurrentAgent.Position.X, user.CurrentAgent.Position.Y, user.CurrentAgent.Position.Z, user.FirstName, user.SurName); } } else { m_log.ErrorFormat("[LOGIN]: Region responded that it is not available to receive clients"); return(false); } } else { m_log.ErrorFormat("[LOGIN]: XmlRpc request to region failed with message {0}, code {1} ", GridResp.FaultString, GridResp.FaultCode); return(false); } } catch (Exception e) { m_log.ErrorFormat("[LOGIN]: Region not available for login, {0}", e); return(false); } return(true); }
/// <summary> /// Try to teleport an agent to a new region. /// </summary> /// <param name="remoteClient"></param> /// <param name="RegionHandle"></param> /// <param name="position"></param> /// <param name="lookAt"></param> /// <param name="flags"></param> public override void RequestTeleportToLocation(ScenePresence avatar, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags) { if (!avatar.Scene.Permissions.CanTeleport(avatar.UUID)) { return; } bool destRegionUp = true; IEventQueue eq = avatar.Scene.RequestModuleInterface <IEventQueue>(); // Reset animations; the viewer does that in teleports. avatar.ResetAnimations(); if (regionHandle == m_regionInfo.RegionHandle) { // Teleport within the same region if (position.X < 0 || position.X > Constants.RegionSize || position.Y < 0 || position.Y > Constants.RegionSize || position.Z < 0) { Vector3 emergencyPos = new Vector3(128, 128, 128); m_log.WarnFormat( "[HGSceneCommService]: RequestTeleportToLocation() was given an illegal position of {0} for avatar {1}, {2}. Substituting {3}", position, avatar.Name, avatar.UUID, emergencyPos); position = emergencyPos; } // TODO: Get proper AVG Height float localAVHeight = 1.56f; float posZLimit = (float)avatar.Scene.Heightmap[(int)position.X, (int)position.Y]; float newPosZ = posZLimit + localAVHeight; if (posZLimit >= (position.Z - (localAVHeight / 2)) && !(Single.IsInfinity(newPosZ) || Single.IsNaN(newPosZ))) { position.Z = newPosZ; } // Only send this if the event queue is null if (eq == null) { avatar.ControllingClient.SendTeleportLocationStart(); } avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); avatar.Teleport(position); } else { RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle); if (reg != null) { uint newRegionX = (uint)(reg.RegionHandle >> 40); uint newRegionY = (((uint)(reg.RegionHandle)) >> 8); uint oldRegionX = (uint)(m_regionInfo.RegionHandle >> 40); uint oldRegionY = (((uint)(m_regionInfo.RegionHandle)) >> 8); /// /// Hypergrid mod start /// /// bool isHyperLink = m_hg.IsHyperlinkRegion(reg.RegionHandle); bool isHomeUser = true; ulong realHandle = regionHandle; CachedUserInfo uinfo = m_commsProvider.UserProfileCacheService.GetUserDetails(avatar.UUID); if (uinfo != null) { isHomeUser = HGNetworkServersInfo.Singleton.IsLocalUser(uinfo.UserProfile); realHandle = m_hg.FindRegionHandle(regionHandle); m_log.Debug("XXX ---- home user? " + isHomeUser + " --- hyperlink? " + isHyperLink + " --- real handle: " + realHandle.ToString()); } /// /// Hypergrid mod stop /// /// if (eq == null) { avatar.ControllingClient.SendTeleportLocationStart(); } // Let's do DNS resolution only once in this process, please! // This may be a costly operation. The reg.ExternalEndPoint field is not a passive field, // it's actually doing a lot of work. IPEndPoint endPoint = reg.ExternalEndPoint; if (endPoint.Address == null) { // Couldn't resolve the name. Can't TP, because the viewer wants IP addresses. destRegionUp = false; } if (destRegionUp) { // Fixing a bug where teleporting while sitting results in the avatar ending up removed from // both regions if (avatar.ParentID != (uint)0) { avatar.StandUp(); } if (!avatar.ValidateAttachments()) { avatar.ControllingClient.SendTeleportFailed("Inconsistent attachment state"); return; } // the avatar.Close below will clear the child region list. We need this below for (possibly) // closing the child agents, so save it here (we need a copy as it is Clear()-ed). //List<ulong> childRegions = new List<ulong>(avatar.GetKnownRegionList()); // Compared to ScenePresence.CrossToNewRegion(), there's no obvious code to handle a teleport // failure at this point (unlike a border crossing failure). So perhaps this can never fail // once we reach here... //avatar.Scene.RemoveCapsHandler(avatar.UUID); string capsPath = String.Empty; AgentCircuitData agentCircuit = avatar.ControllingClient.RequestClientInfo(); agentCircuit.BaseFolder = UUID.Zero; agentCircuit.InventoryFolder = UUID.Zero; agentCircuit.startpos = position; agentCircuit.child = true; if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY)) { // brand new agent, let's create a new caps seed agentCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); } string reason = String.Empty; //if (!m_commsProvider.InterRegion.InformRegionOfChildAgent(reg.RegionHandle, agentCircuit)) if (!m_interregionCommsOut.SendCreateChildAgent(reg.RegionHandle, agentCircuit, out reason)) { avatar.ControllingClient.SendTeleportFailed(String.Format("Destination is not accepting teleports: {0}", reason)); return; } // Let's close some agents if (isHyperLink) // close them all except this one { List <ulong> regions = new List <ulong>(avatar.KnownChildRegionHandles); regions.Remove(avatar.Scene.RegionInfo.RegionHandle); SendCloseChildAgentConnections(avatar.UUID, regions); } else // close just a few { avatar.CloseChildAgents(newRegionX, newRegionY); } if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink) { capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + CapsUtil.GetCapsSeedPath(agentCircuit.CapsPath); if (eq != null) { eq.EnableSimulator(realHandle, endPoint, avatar.UUID); // ES makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(2000); eq.EstablishAgentCommunication(avatar.UUID, endPoint, capsPath); } else { avatar.ControllingClient.InformClientOfNeighbour(realHandle, endPoint); // TODO: make Event Queue disablable! } } else { // child agent already there agentCircuit.CapsPath = avatar.Scene.CapsModule.GetChildSeed(avatar.UUID, reg.RegionHandle); capsPath = "http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + agentCircuit.CapsPath + "0000/"; } //m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, // position, false); //if (!m_commsProvider.InterRegion.ExpectAvatarCrossing(reg.RegionHandle, avatar.ControllingClient.AgentId, // position, false)) //{ // avatar.ControllingClient.SendTeleportFailed("Problem with destination."); // // We should close that agent we just created over at destination... // List<ulong> lst = new List<ulong>(); // lst.Add(realHandle); // SendCloseChildAgentAsync(avatar.UUID, lst); // 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 = position; 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); m_log.DebugFormat( "[CAPS]: Sending new CAPS seed url {0} to client {1}", agentCircuit.CapsPath, avatar.UUID); /// /// Hypergrid mod: realHandle instead of reg.RegionHandle /// /// if (eq != null) { eq.TeleportFinishEvent(realHandle, 13, endPoint, 4, teleportFlags, capsPath, avatar.UUID); } else { avatar.ControllingClient.SendRegionTeleport(realHandle, 13, endPoint, 4, teleportFlags, capsPath); } /// /// 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); } avatar.MakeChildAgent(); // CrossAttachmentsIntoNewRegion is a synchronous call. We shouldn't need to wait after it avatar.CrossAttachmentsIntoNewRegion(reg.RegionHandle, true); // Finally, let's close this previously-known-as-root agent, when the jump is outside the view zone /// /// Hypergrid mod: extra check for isHyperLink /// if (Util.IsOutsideView(oldRegionX, newRegionX, oldRegionY, newRegionY) || isHyperLink) { Thread.Sleep(5000); avatar.Close(); CloseConnection(avatar.UUID); } // if (teleport success) // seems to be always success here // the user may change their profile information in other region, // so the userinfo in UserProfileCache is not reliable any more, delete it if (avatar.Scene.NeedSceneCacheClear(avatar.UUID) || isHyperLink) { m_commsProvider.UserProfileCacheService.RemoveUser(avatar.UUID); m_log.DebugFormat( "[HGSceneCommService]: User {0} is going to another region, profile cache removed", avatar.UUID); } } else { avatar.ControllingClient.SendTeleportFailed("Remote Region appears to be down"); } } else { // TP to a place that doesn't exist (anymore) // Inform the viewer about that avatar.ControllingClient.SendTeleportFailed("The region you tried to teleport to doesn't exist anymore"); // and set the map-tile to '(Offline)' uint regX, regY; Utils.LongToUInts(regionHandle, out regX, out regY); MapBlockData block = new MapBlockData(); block.X = (ushort)(regX / Constants.RegionSize); block.Y = (ushort)(regY / Constants.RegionSize); block.Access = 254; // == not there List <MapBlockData> blocks = new List <MapBlockData>(); blocks.Add(block); avatar.ControllingClient.SendMapBlock(blocks, 0); } } }
public override bool InformClientOfNeighbor(UUID AgentID, ulong requestingRegion, AgentCircuitData circuitData, ref GridRegion neighbor, uint TeleportFlags, AgentData agentData, out string reason, out bool useCallbacks) { useCallbacks = true; if (neighbor == null) { reason = "Could not find neighbor to inform"; return(false); } MainConsole.Instance.Info("[AgentProcessing]: Starting to inform client about neighbor " + neighbor.RegionName); //Notes on this method // 1) the SimulationService.CreateAgent MUST have a fixed CapsUrl for the region, so we have to create (if needed) // a new Caps handler for it. // 2) Then we can call the methods (EnableSimulator and EstatablishAgentComm) to tell the client the new Urls // 3) This allows us to make the Caps on the grid server without telling any other regions about what the // Urls are. ISimulationService SimulationService = m_registry.RequestModuleInterface <ISimulationService> (); if (SimulationService != null) { ICapsService capsService = m_registry.RequestModuleInterface <ICapsService> (); IClientCapsService clientCaps = capsService.GetClientCapsService(AgentID); GridRegion originalDest = neighbor; if ((neighbor.Flags & (int)Aurora.Framework.RegionFlags.Hyperlink) == (int)Aurora.Framework.RegionFlags.Hyperlink) { neighbor = GetFinalDestination(neighbor); if (neighbor == null || neighbor.RegionHandle == 0) { reason = "Could not find neighbor to inform"; return(false); } //Remove any offenders clientCaps.RemoveCAPS(originalDest.RegionHandle); clientCaps.RemoveCAPS(neighbor.RegionHandle); } IRegionClientCapsService oldRegionService = clientCaps.GetCapsService(neighbor.RegionHandle); //If its disabled, it should be removed, so kill it! if (oldRegionService != null && oldRegionService.Disabled) { clientCaps.RemoveCAPS(neighbor.RegionHandle); oldRegionService = null; } bool newAgent = oldRegionService == null; IRegionClientCapsService otherRegionService = clientCaps.GetOrCreateCapsService(neighbor.RegionHandle, CapsUtil.GetCapsSeedPath(CapsUtil.GetRandomCapsObjectPath()), circuitData, 0); if (!newAgent) { //Note: if the agent is already there, send an agent update then bool result = true; if (agentData != null) { agentData.IsCrossing = false; result = SimulationService.UpdateAgent(neighbor, agentData); } if (result) { oldRegionService.Disabled = false; } reason = ""; return(result); } ICommunicationService commsService = m_registry.RequestModuleInterface <ICommunicationService> (); if (commsService != null) { commsService.GetUrlsForUser(neighbor, circuitData.AgentID); //Make sure that we make userURLs if we need to } circuitData.CapsPath = CapsUtil.GetCapsPathFromCapsSeed(otherRegionService.CapsUrl); if (clientCaps.AccountInfo != null) { circuitData.firstname = clientCaps.AccountInfo.FirstName; circuitData.lastname = clientCaps.AccountInfo.LastName; } bool regionAccepted = false; int requestedUDPPort = 0; if ((originalDest.Flags & (int)Aurora.Framework.RegionFlags.Hyperlink) == (int)Aurora.Framework.RegionFlags.Hyperlink) { if (circuitData.ServiceURLs == null || circuitData.ServiceURLs.Count == 0) { if (clientCaps.AccountInfo != null) { circuitData.ServiceURLs = new Dictionary <string, object> (); circuitData.ServiceURLs[GetHandlers.Helpers_HomeURI] = GetHandlers.GATEKEEPER_URL; circuitData.ServiceURLs[GetHandlers.Helpers_GatekeeperURI] = GetHandlers.GATEKEEPER_URL; circuitData.ServiceURLs[GetHandlers.Helpers_InventoryServerURI] = GetHandlers.GATEKEEPER_URL; circuitData.ServiceURLs[GetHandlers.Helpers_AssetServerURI] = GetHandlers.GATEKEEPER_URL; circuitData.ServiceURLs[GetHandlers.Helpers_ProfileServerURI] = GetHandlers.GATEKEEPER_URL; circuitData.ServiceURLs[GetHandlers.Helpers_FriendsServerURI] = GetHandlers.GATEKEEPER_URL; circuitData.ServiceURLs[GetHandlers.Helpers_IMServerURI] = GetHandlers.IM_URL; clientCaps.AccountInfo.ServiceURLs = circuitData.ServiceURLs; //Store the new urls m_registry.RequestModuleInterface <IUserAccountService> ().StoreUserAccount(clientCaps.AccountInfo); } } string userAgentDriver = circuitData.ServiceURLs[GetHandlers.Helpers_HomeURI].ToString(); IUserAgentService connector = new UserAgentServiceConnector(userAgentDriver); regionAccepted = connector.LoginAgentToGrid(circuitData, originalDest, neighbor, new IPEndPoint(IPAddress.Parse(circuitData.IPAddress), circuitData.RegionUDPPort), out reason); } else { if (circuitData.child) { circuitData.reallyischild = true; } regionAccepted = SimulationService.CreateAgent(neighbor, circuitData, TeleportFlags, agentData, out requestedUDPPort, out reason); } if (regionAccepted) { IPAddress ipAddress = neighbor.ExternalEndPoint.Address; string otherRegionsCapsURL; //If the region accepted us, we should get a CAPS url back as the reason, if not, its not updated or not an Aurora region, so don't touch it. if (reason != "" && reason != "authorized") { OSDMap responseMap = (OSDMap)OSDParser.DeserializeJson(reason); OSDMap SimSeedCaps = (OSDMap)responseMap["CapsUrls"]; if (responseMap.ContainsKey("OurIPForClient")) { string ip = responseMap["OurIPForClient"].AsString(); ipAddress = IPAddress.Parse(ip); } otherRegionService.AddCAPS(SimSeedCaps); otherRegionsCapsURL = otherRegionService.CapsUrl; } else { //We are assuming an OpenSim region now! #region OpenSim teleport compatibility! useCallbacks = false; otherRegionsCapsURL = neighbor.ServerURI + CapsUtil.GetCapsSeedPath(circuitData.CapsPath); otherRegionService.CapsUrl = otherRegionsCapsURL; #endregion } if (requestedUDPPort == 0) { requestedUDPPort = neighbor.ExternalEndPoint.Port; } if (ipAddress == null) { ipAddress = neighbor.ExternalEndPoint.Address; } circuitData.RegionUDPPort = requestedUDPPort; otherRegionService = clientCaps.GetCapsService(neighbor.RegionHandle); otherRegionService.LoopbackRegionIP = ipAddress; otherRegionService.CircuitData.RegionUDPPort = requestedUDPPort; IEventQueueService EQService = m_registry.RequestModuleInterface <IEventQueueService> (); EQService.EnableSimulator(neighbor.RegionHandle, ipAddress.GetAddressBytes(), requestedUDPPort, AgentID, neighbor.RegionSizeX, neighbor.RegionSizeY, requestingRegion); // EnableSimulator makes the client send a UseCircuitCode message to the destination, // which triggers a bunch of things there. // So let's wait Thread.Sleep(300); EQService.EstablishAgentCommunication(AgentID, neighbor.RegionHandle, ipAddress.GetAddressBytes(), requestedUDPPort, otherRegionsCapsURL, neighbor.RegionSizeX, neighbor.RegionSizeY, requestingRegion); if (!useCallbacks) { Thread.Sleep(3000); //Give it a bit of time, only for OpenSim... } MainConsole.Instance.Info("[AgentProcessing]: Completed inform client about neighbor " + neighbor.RegionName); } else { clientCaps.RemoveCAPS(neighbor.RegionHandle); MainConsole.Instance.Error("[AgentProcessing]: Failed to inform client about neighbor " + neighbor.RegionName + ", reason: " + reason); return(false); } return(true); } reason = "SimulationService does not exist"; MainConsole.Instance.Error("[AgentProcessing]: Failed to inform client about neighbor " + neighbor.RegionName + ", reason: " + reason + "!"); return(false); }