Esempio n. 1
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);
        }