protected override bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response, string clientVersion) { return PrepareLoginToRegion(RegionProfileData.FromRegionInfo(regionInfo), user, response, clientVersion); }
/// <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; }
// For returning users' where the preferred region is down protected bool PrepareNextDefaultRegion(LoginResponse response, UserProfileData theUser, string clientVersion) { return PrepareNextRegion(response, theUser, _DefaultRegionsList, "safe", clientVersion); }
/// <summary> /// Customises the login response and fills in missing values. This method also tells the login region to /// expect a client connection. /// </summary> /// <param name="response">The existing response</param> /// <param name="theUser">The user profile</param> /// <param name="startLocationRequest">The requested start location</param> /// <returns>true on success, false if the region was not successfully told to expect a user connection</returns> public bool CustomiseResponse(LoginResponse response, UserProfileData theUser, string startLocationRequest, string clientVersion) { // add active gestures to login-response AddActiveGestures(response, theUser); // HomeLocation RegionInfo homeInfo = null; // use the homeRegionID if it is stored already. If not, use the regionHandle as before UUID homeRegionId = theUser.HomeRegionID; ulong homeRegionHandle = theUser.HomeRegion; if (homeRegionId != UUID.Zero) { homeInfo = GetRegionInfo(homeRegionId); } else { homeInfo = GetRegionInfo(homeRegionHandle); } if (homeInfo != null) { response.Home = string.Format( "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}", (homeInfo.RegionLocX * Constants.RegionSize), (homeInfo.RegionLocY * Constants.RegionSize), theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z, theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z); } else { m_log.InfoFormat("not found the region at {0} {1}", theUser.HomeRegionX, theUser.HomeRegionY); // Emergency mode: Home-region isn't available, so we can't request the region info. // Use the stored home regionHandle instead. // NOTE: If the home-region moves, this will be wrong until the users update their user-profile again ulong regionX = homeRegionHandle >> 32; ulong regionY = homeRegionHandle & 0xffffffff; response.Home = string.Format( "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}", regionX, regionY, theUser.HomeLocation.X, theUser.HomeLocation.Y, theUser.HomeLocation.Z, theUser.HomeLookAt.X, theUser.HomeLookAt.Y, theUser.HomeLookAt.Z); m_log.InfoFormat("[LOGIN] Home region of user {0} {1} is not available; using computed region position {2} {3}", theUser.FirstName, theUser.SurName, regionX, regionY); } // StartLocation RegionInfo regionInfo = null; if (theUser.LastLogin == 0) { // New user first login if (PrepareNextDefaultLogin(response, theUser, startLocationRequest, clientVersion)) return true; } else { // Returning user login if (startLocationRequest == "home") { regionInfo = homeInfo; theUser.CurrentAgent.Position = theUser.HomeLocation; response.LookAt = String.Format("[r{0},r{1},r{2}]", theUser.HomeLookAt.X.ToString(), theUser.HomeLookAt.Y.ToString(), theUser.HomeLookAt.Z.ToString()); } else if (startLocationRequest == "last") { UUID lastRegion = theUser.CurrentAgent.Region; regionInfo = GetRegionInfo(lastRegion); response.LookAt = String.Format("[r{0},r{1},r{2}]", theUser.CurrentAgent.LookAt.X.ToString(), theUser.CurrentAgent.LookAt.Y.ToString(), theUser.CurrentAgent.LookAt.Z.ToString()); } else { // Logging in to a specific URL... try to find the region Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+)&(?<y>\d+)&(?<z>\d+)$"); if (PrepareLoginToREURI(reURI, response, theUser, startLocationRequest, "url", "Custom Login URL", clientVersion)) return true; } // Logging in to home or last... try to find the region if ((regionInfo != null) && (PrepareLoginToRegion(regionInfo, theUser, response, clientVersion))) { return true; } // StartLocation not available, send him to a nearby region instead // regionInfo = m_gridService.RequestClosestRegion(""); //m_log.InfoFormat("[LOGIN]: StartLocation not available sending to region {0}", regionInfo.regionName); // Normal login failed, try to find a default region from the list if (PrepareNextDefaultRegion(response, theUser, clientVersion)) return true; } // No default regions available either. // Send him to global default region home location instead (e.g. 1000,1000) ulong defaultHandle = (((ulong)m_defaultHomeX * Constants.RegionSize) << 32) | ((ulong)m_defaultHomeY * Constants.RegionSize); if ((regionInfo != null) && (defaultHandle == regionInfo.RegionHandle)) { m_log.ErrorFormat("[LOGIN]: Not trying the default region since this is the same as the selected region"); return false; } m_log.Error("[LOGIN]: Sending user to default region " + defaultHandle + " instead"); regionInfo = GetRegionInfo(defaultHandle); if (regionInfo == null) { m_log.ErrorFormat("[LOGIN]: No default region available. Aborting."); return false; } theUser.CurrentAgent.Position = new Vector3(128, 128, 0); response.StartLocation = "safe"; return PrepareLoginToRegion(regionInfo, theUser, response, clientVersion); }
protected bool PrepareNextRegion(LoginResponse response, UserProfileData theUser, List<string> theList, string startLocationRequest, string clientVersion) { Regex reURI = new Regex(@"^(?<region>[^&]+)/(?<x>\d+)/(?<y>\d+)/(?<z>\d+)$"); if ((startLocationRequest != "home") && (startLocationRequest != "last")) startLocationRequest = "safe"; foreach (string location in theList) { if (PrepareLoginToREURI(reURI, response, theUser, location, "safe", "default region", clientVersion)) return true; } return false; }
// For new users' first-time logins protected bool PrepareNextDefaultLogin(LoginResponse response, UserProfileData theUser, string startLocationRequest, string clientVersion) { return PrepareNextRegion(response, theUser, _DefaultLoginsList, startLocationRequest, clientVersion); }
/// <summary> /// Called when we receive the client's initial XMLRPC login_to_simulator request message /// </summary> /// <param name="request">The XMLRPC request</param> /// <returns>The response to send</returns> public virtual XmlRpcResponse XmlRpcLoginMethod(XmlRpcRequest request, IPEndPoint remoteClient) { string loginUsername = null; try { XmlRpcResponse response = new XmlRpcResponse(); Hashtable requestData = (Hashtable)request.Params[0]; SniffLoginKey((Uri)request.Params[2], requestData); bool GoodXML = (requestData.Contains("first") && requestData.Contains("last") && (requestData.Contains("passwd") || requestData.Contains("web_login_key"))); string firstname = null; string lastname = null; LoginResponse logResponse = new LoginResponse(); if (GoodXML) { //make sure the user isn't already trying to log in firstname = (string)requestData["first"]; lastname = (string)requestData["last"]; loginUsername = firstname + " " + lastname; lock (_loginsProcessing) { if (_loginsProcessing.Contains(loginUsername)) { return logResponse.CreateAlreadyLoggedInResponse(); } else { _loginsProcessing.Add(loginUsername); } } } string startLocationRequest = "last"; UserProfileData userProfile; string clientVersion = "Unknown"; if (GoodXML) { if (requestData.Contains("start")) { startLocationRequest = (string)requestData["start"]; } m_log.InfoFormat( "[LOGIN BEGIN]: XMLRPC Received login request message from user '{0}' '{1}'", firstname, lastname); if (requestData.Contains("version")) { clientVersion = (string)requestData["version"]; } if (this.IsViewerBlacklisted(clientVersion)) { m_log.DebugFormat("[LOGIN]: Denying login, Client {0} is blacklisted", clientVersion); return logResponse.CreateViewerNotAllowedResponse(); } m_log.DebugFormat( "[LOGIN]: XMLRPC Client is {0}, start location is {1}", clientVersion, startLocationRequest); if (!TryAuthenticateXmlRpcLogin(request, firstname, lastname, out userProfile)) { return logResponse.CreateLoginFailedResponse(); } } else { m_log.Info("[LOGIN END]: XMLRPC login_to_simulator login message did not contain all the required data"); return logResponse.CreateGridErrorResponse(); } if (userProfile.GodLevel < m_minLoginLevel) { return logResponse.CreateLoginBlockedResponse(); } else { // If we already have a session... if (userProfile.CurrentAgent != null && userProfile.CurrentAgent.AgentOnline) { // Force a refresh for this due to Commit below UUID userID = userProfile.ID; m_userManager.PurgeUserFromCaches(userID); userProfile = m_userManager.GetUserProfile(userID); // on an error, return the former error we returned before recovery was supported. if (userProfile == null) return logResponse.CreateAlreadyLoggedInResponse(); //TODO: The following statements can cause trouble: // If agentOnline could not turn from true back to false normally // because of some problem, for instance, the crashment of server or client, // the user cannot log in any longer. userProfile.CurrentAgent.AgentOnline = false; userProfile.CurrentAgent.LogoutTime = Util.UnixTimeSinceEpoch(); m_userManager.CommitAgent(ref userProfile); // try to tell the region that their user is dead. LogOffUser(userProfile, " XMLRPC You were logged off because you logged in from another location"); // Don't reject the login. We've already cleaned it up, above. m_log.InfoFormat( "[LOGIN END]: XMLRPC Reset user {0} {1} that we believe is already logged in", firstname, lastname); // return logResponse.CreateAlreadyLoggedInResponse(); } // Otherwise... // Create a new agent session m_userManager.ResetAttachments(userProfile.ID); CreateAgent(userProfile, request); // We need to commit the agent right here, even though the userProfile info is not complete // at this point. There is another commit further down. // This is for the new sessionID to be stored so that the region can check it for session authentication. // CustomiseResponse->PrepareLoginToRegion CommitAgent(ref userProfile); try { UUID agentID = userProfile.ID; InventoryData inventData = null; try { inventData = GetInventorySkeleton(agentID); } catch (Exception e) { m_log.ErrorFormat( "[LOGIN END]: Error retrieving inventory skeleton of agent {0} - {1}", agentID, e); return logResponse.CreateLoginInventoryFailedResponse(); } if (inventData != null) { ArrayList AgentInventoryArray = inventData.InventoryArray; Hashtable InventoryRootHash = new Hashtable(); InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); ArrayList InventoryRoot = new ArrayList(); InventoryRoot.Add(InventoryRootHash); userProfile.RootInventoryFolderID = inventData.RootFolderID; logResponse.InventoryRoot = InventoryRoot; logResponse.InventorySkeleton = AgentInventoryArray; } // Inventory Library Section Hashtable InventoryLibRootHash = new Hashtable(); InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; ArrayList InventoryLibRoot = new ArrayList(); InventoryLibRoot.Add(InventoryLibRootHash); logResponse.InventoryLibRoot = InventoryLibRoot; logResponse.InventoryLibraryOwner = GetLibraryOwner(); logResponse.InventoryLibrary = GetInventoryLibrary(); logResponse.CircuitCode = Util.RandomClass.Next(); logResponse.Lastname = userProfile.SurName; logResponse.Firstname = userProfile.FirstName; logResponse.AgentID = agentID; logResponse.SessionID = userProfile.CurrentAgent.SessionID; logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID; logResponse.Message = GetMessage(); logResponse.MapServerURI = m_MapServerURI; logResponse.BuddList = ConvertFriendListItem(m_userManager.GetUserFriendList(agentID)); logResponse.StartLocation = startLocationRequest; // m_log.WarnFormat("[LOGIN END]: >>> Login response for {0} SSID={1}", logResponse.AgentID, logResponse.SecureSessionID); if (CustomiseResponse(logResponse, userProfile, startLocationRequest, clientVersion)) { userProfile.LastLogin = userProfile.CurrentAgent.LoginTime; CommitAgent(ref userProfile); // If we reach this point, then the login has successfully logged onto the grid if (StatsManager.UserStats != null) StatsManager.UserStats.AddSuccessfulLogin(); m_log.DebugFormat( "[LOGIN END]: XMLRPC Authentication of user {0} {1} successful. Sending response to client.", firstname, lastname); return logResponse.ToXmlRpcResponse(); } else { m_log.ErrorFormat("[LOGIN END]: XMLRPC informing user {0} {1} that login failed due to an unavailable region", firstname, lastname); return logResponse.CreateDeadRegionResponse(); } } catch (Exception e) { m_log.Error("[LOGIN END]: XMLRPC Login failed, " + e); m_log.Error(e.StackTrace); } } m_log.Info("[LOGIN END]: XMLRPC Login failed. Sending back blank XMLRPC response"); return response; } finally { if (loginUsername != null) { lock (_loginsProcessing) { _loginsProcessing.Remove(loginUsername); } } } }
protected bool PrepareLoginToREURI(Regex reURI, LoginResponse response, UserProfileData theUser, string startLocationRequest, string StartLocationType, string desc, string clientVersion) { string region; RegionInfo regionInfo = null; Match uriMatch = reURI.Match(startLocationRequest); if (uriMatch == null) { m_log.InfoFormat("[LOGIN]: Got {0} {1}, but can't process it", desc, startLocationRequest); return false; } region = uriMatch.Groups["region"].ToString(); regionInfo = RequestClosestRegion(region); if (regionInfo == null) { m_log.InfoFormat("[LOGIN]: Got {0} {1}, can't locate region {2}", desc, startLocationRequest, region); return false; } theUser.CurrentAgent.Position = new Vector3(float.Parse(uriMatch.Groups["x"].Value), float.Parse(uriMatch.Groups["y"].Value), float.Parse(uriMatch.Groups["z"].Value)); response.LookAt = "[r0,r1,r0]"; // can be: last, home, safe, url response.StartLocation = StartLocationType; return PrepareLoginToRegion(regionInfo, theUser, response, clientVersion); }
/// <summary> /// Add active gestures of the user to the login response. /// </summary> /// <param name="response"> /// A <see cref="LoginResponse"/> /// </param> /// <param name="theUser"> /// A <see cref="UserProfileData"/> /// </param> protected void AddActiveGestures(LoginResponse response, UserProfileData theUser) { IInventoryProviderSelector inventorySelect = ProviderRegistry.Instance.Get<IInventoryProviderSelector>(); IInventoryStorage inventory = inventorySelect.GetProvider(theUser.ID); List<InventoryItemBase> gestures = null; try { gestures = inventory.GetActiveGestureItems(theUser.ID); } catch (Exception e) { m_log.Debug("[LOGIN]: Unable to retrieve active gestures from inventory server. Reason: " + e.Message); } //m_log.DebugFormat("[LOGIN]: AddActiveGestures, found {0}", gestures == null ? 0 : gestures.Count); ArrayList list = new ArrayList(); if (gestures != null) { foreach (InventoryItemBase gesture in gestures) { Hashtable item = new Hashtable(); item["item_id"] = gesture.ID.ToString(); item["asset_id"] = gesture.AssetID.ToString(); list.Add(item); } } response.ActiveGestures = list; }
protected abstract bool PrepareLoginToRegion(RegionInfo regionInfo, UserProfileData user, LoginResponse response, string clientVersion);
/// <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); } 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> /// 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; }
XmlRpcResponse LoginHandler(XmlRpcRequest request, Uri requestUrl) { XmlRpcResponse response = new XmlRpcResponse(); Hashtable requestData = (Hashtable)request.Params[0]; IPEndPoint remoteClient = null; if (request.Params.Count > 1) remoteClient = request.Params[1] as IPEndPoint; UserProfileData userProfile; LoginResponse logResponse = new LoginResponse(); UUID sessionID; IsXmlRpcLogin(requestUrl, out sessionID); m_log.Info("[CABLE BEACH XMLRPC]: XML-RPC Received login request message with sessionID " + sessionID); string startLocationRequest = "last"; if (requestData.Contains("start")) startLocationRequest = (requestData["start"] as string) ?? "last"; string clientVersion = "Unknown"; if (requestData.Contains("version")) clientVersion = (requestData["version"] as string) ?? "Unknown"; if (TryAuthenticateXmlRpcLogin(sessionID, out userProfile)) { try { UUID agentID = userProfile.ID; LoginService.InventoryData skeleton = null; try { skeleton = CableBeachState.LoginService.GetInventorySkeleton(agentID); } catch (Exception e) { m_log.ErrorFormat("[CABLE BEACH XMLRPC]: Error retrieving inventory skeleton of agent {0} - {1}", agentID, e); // Let's not panic if (!CableBeachState.LoginService.AllowLoginWithoutInventory()) return logResponse.CreateLoginInventoryFailedResponse(); } #region Inventory Skeletons if (skeleton != null) { ArrayList AgentInventoryArray = skeleton.InventoryArray; Hashtable InventoryRootHash = new Hashtable(); InventoryRootHash["folder_id"] = skeleton.RootFolderID.ToString(); ArrayList InventoryRoot = new ArrayList(); InventoryRoot.Add(InventoryRootHash); logResponse.InventoryRoot = InventoryRoot; logResponse.InventorySkeleton = AgentInventoryArray; } // Inventory Library Section Hashtable InventoryLibRootHash = new Hashtable(); InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; ArrayList InventoryLibRoot = new ArrayList(); InventoryLibRoot.Add(InventoryLibRootHash); logResponse.InventoryLibRoot = InventoryLibRoot; logResponse.InventoryLibraryOwner = CableBeachState.LoginService.GetLibraryOwner(); logResponse.InventoryLibrary = CableBeachState.LoginService.GetInventoryLibrary(); logResponse.CircuitCode = Util.RandomClass.Next(); logResponse.Lastname = userProfile.SurName; logResponse.Firstname = userProfile.FirstName; logResponse.AgentID = agentID; logResponse.SessionID = userProfile.CurrentAgent.SessionID; logResponse.SecureSessionID = userProfile.CurrentAgent.SecureSessionID; logResponse.Message = CableBeachState.LoginService.GetMessage(); logResponse.BuddList = CableBeachState.LoginService.ConvertFriendListItem(CableBeachState.LoginService.UserManager.GetUserFriendList(agentID)); logResponse.StartLocation = startLocationRequest; #endregion Inventory Skeletons if (CableBeachState.LoginService.CustomiseResponse(logResponse, userProfile, startLocationRequest, remoteClient)) { userProfile.LastLogin = userProfile.CurrentAgent.LoginTime; CableBeachState.LoginService.CommitAgent(ref userProfile); // If we reach this point, then the login has successfully logged onto the grid if (StatsManager.UserStats != null) StatsManager.UserStats.AddSuccessfulLogin(); m_log.DebugFormat("[CABLE BEACH XMLRPC]: Authentication of user {0} {1} successful. Sending response to client", userProfile.FirstName, userProfile.FirstName); return logResponse.ToXmlRpcResponse(); } else { m_log.ErrorFormat("[CABLE BEACH XMLRPC]: Informing user {0} {1} that login failed due to an unavailable region", userProfile.FirstName, userProfile.FirstName); return logResponse.CreateDeadRegionResponse(); } } catch (Exception e) { m_log.Error("[CABLE BEACH XMLRPC]: Login failed, returning a blank response. Error: " + e); return response; } } else { m_log.Warn("[CABLE BEACH XMLRPC]: Authentication failed using sessionID " + sessionID + ", there are " + CableBeachState.PendingLogins.Count + " valid pending logins"); return logResponse.CreateLoginFailedResponse(); } }