/// <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);
        }
Example #2
0
        /// <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;
        }
Example #4
0
        /// <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);
        }
Example #5
0
        /// <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);
                }
            }
        }
Example #9
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);
        }