From 25661b611d241534e5e8d7ce1731de8506481a7d Mon Sep 17 00:00:00 2001 From: MW Date: Sat, 21 Feb 2009 13:44:03 +0000 Subject: Refactored the GridServer into a GridDBService and a set of "modules". Currently they aren't plugin modules as the support for dynamically loading them isn't complete. --- OpenSim/Grid/GridServer/GridXmlRpcModule.cs | 844 ++++++++++++++++++++++++++++ 1 file changed, 844 insertions(+) create mode 100644 OpenSim/Grid/GridServer/GridXmlRpcModule.cs (limited to 'OpenSim/Grid/GridServer/GridXmlRpcModule.cs') diff --git a/OpenSim/Grid/GridServer/GridXmlRpcModule.cs b/OpenSim/Grid/GridServer/GridXmlRpcModule.cs new file mode 100644 index 0000000..0eb7d1f --- /dev/null +++ b/OpenSim/Grid/GridServer/GridXmlRpcModule.cs @@ -0,0 +1,844 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Reflection; +using System.Xml; +using log4net; +using Nwc.XmlRpc; +using OpenMetaverse; +using OpenSim.Data; +using OpenSim.Framework; +using OpenSim.Framework.Communications; +using OpenSim.Framework.Servers; + +namespace OpenSim.Grid.GridServer +{ + public class GridXmlRpcModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private GridDBService m_gridDBService; + private IGridCore m_gridCore; + + protected GridConfig m_config; + + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + private string m_opensimVersion; + + protected BaseHttpServer m_httpServer; + + /// + /// Constructor + /// + /// + /// Used to notify old regions as to which OpenSim version to upgrade to + /// + public GridXmlRpcModule(string opensimVersion, GridDBService gridDBService, IGridCore gridCore, GridConfig config) + { + m_opensimVersion = opensimVersion; + m_gridDBService = gridDBService; + m_gridCore = gridCore; + m_config = config; + m_httpServer = m_gridCore.GetHttpServer(); + } + + public void Initialise() + { + m_httpServer.AddXmlRPCHandler("simulator_login", XmlRpcSimulatorLoginMethod); + m_httpServer.AddXmlRPCHandler("simulator_data_request", XmlRpcSimulatorDataRequestMethod); + m_httpServer.AddXmlRPCHandler("simulator_after_region_moved", XmlRpcDeleteRegionMethod); + m_httpServer.AddXmlRPCHandler("map_block", XmlRpcMapBlockMethod); + m_httpServer.AddXmlRPCHandler("search_for_region_by_name", XmlRpcSearchForRegionMethod); + } + + /// + /// Returns a XML String containing a list of the neighbouring regions + /// + /// The regionhandle for the center sim + /// An XML string containing neighbour entities + public string GetXMLNeighbours(ulong reqhandle) + { + string response = String.Empty; + RegionProfileData central_region = m_gridDBService.GetRegion(reqhandle); + RegionProfileData neighbour; + for (int x = -1; x < 2; x++) + { + for (int y = -1; y < 2; y++) + { + if ( + m_gridDBService.GetRegion( + Util.UIntsToLong((uint)((central_region.regionLocX + x) * Constants.RegionSize), + (uint)(central_region.regionLocY + y) * Constants.RegionSize)) != null) + { + neighbour = + m_gridDBService.GetRegion( + Util.UIntsToLong((uint)((central_region.regionLocX + x) * Constants.RegionSize), + (uint)(central_region.regionLocY + y) * Constants.RegionSize)); + + response += ""; + response += "" + neighbour.serverIP + ""; + response += "" + neighbour.serverPort.ToString() + ""; + response += "" + neighbour.regionLocX.ToString() + ""; + response += "" + neighbour.regionLocY.ToString() + ""; + response += "" + neighbour.regionHandle.ToString() + ""; + response += ""; + } + } + } + return response; + } + + /// + /// Checks that it's valid to replace the existing region data with new data + /// + /// Currently, this means ensure that the keys passed in by the new region + /// match those in the original region. (XXX Is this correct? Shouldn't we simply check + /// against the keys in the current configuration?) + /// + /// + /// + protected virtual void ValidateOverwriteKeys(RegionProfileData sim, RegionProfileData existingSim) + { + if (!(existingSim.regionRecvKey == sim.regionRecvKey && existingSim.regionSendKey == sim.regionSendKey)) + { + throw new LoginException( + String.Format( + "Authentication failed when trying to login existing region {0} at location {1} {2} currently occupied by {3}" + + " with the region's send key {4} (expected {5}) and the region's receive key {6} (expected {7})", + sim.regionName, sim.regionLocX, sim.regionLocY, existingSim.regionName, + sim.regionSendKey, existingSim.regionSendKey, sim.regionRecvKey, existingSim.regionRecvKey), + "The keys required to login your region did not match the grid server keys. Please check your grid send and receive keys."); + } + } + + /// + /// Checks that the new region data is valid. + /// + /// Currently, this means checking that the keys passed in by the new region + /// match those in the grid server's configuration. + /// + /// + /// + /// Thrown if region login failed + protected virtual void ValidateNewRegionKeys(RegionProfileData sim) + { + if (!(sim.regionRecvKey == m_config.SimSendKey && sim.regionSendKey == m_config.SimRecvKey)) + { + throw new LoginException( + String.Format( + "Authentication failed when trying to login new region {0} at location {1} {2}" + + " with the region's send key {3} (expected {4}) and the region's receive key {5} (expected {6})", + sim.regionName, sim.regionLocX, sim.regionLocY, + sim.regionSendKey, m_config.SimRecvKey, sim.regionRecvKey, m_config.SimSendKey), + "The keys required to login your region did not match your existing region keys. Please check your grid send and receive keys."); + } + } + + /// + /// Check that a region's http uri is externally contactable. + /// + /// + /// Thrown if the region is not contactable + protected virtual void ValidateRegionContactable(RegionProfileData sim) + { + string regionStatusUrl = String.Format("{0}{1}", sim.httpServerURI, "simstatus/"); + string regionStatusResponse; + + RestClient rc = new RestClient(regionStatusUrl); + rc.RequestMethod = "GET"; + + m_log.DebugFormat("[LOGIN]: Contacting {0} for status of region {1}", regionStatusUrl, sim.regionName); + + try + { + Stream rs = rc.Request(); + StreamReader sr = new StreamReader(rs); + regionStatusResponse = sr.ReadToEnd(); + sr.Close(); + } + catch (Exception e) + { + throw new LoginException( + String.Format("Region status request to {0} failed", regionStatusUrl), + String.Format( + "The grid service could not contact the http url {0} at your region. Please make sure this url is reachable by the grid service", + regionStatusUrl), + e); + } + + if (!regionStatusResponse.Equals("OK")) + { + throw new LoginException( + String.Format( + "Region {0} at {1} returned status response {2} rather than {3}", + sim.regionName, regionStatusUrl, regionStatusResponse, "OK"), + String.Format( + "When the grid service asked for the status of your region, it received the response {0} rather than {1}. Please check your status", + regionStatusResponse, "OK")); + } + } + + /// + /// Construct an XMLRPC error response + /// + /// + /// + public static XmlRpcResponse ErrorResponse(string error) + { + XmlRpcResponse errorResponse = new XmlRpcResponse(); + Hashtable errorResponseData = new Hashtable(); + errorResponse.Value = errorResponseData; + errorResponseData["error"] = error; + return errorResponse; + } + + /// + /// Performed when a region connects to the grid server initially. + /// + /// The XML RPC Request + /// Startup parameters + public XmlRpcResponse XmlRpcSimulatorLoginMethod(XmlRpcRequest request) + { + RegionProfileData sim; + RegionProfileData existingSim; + + Hashtable requestData = (Hashtable)request.Params[0]; + UUID uuid; + + if (!requestData.ContainsKey("UUID") || !UUID.TryParse((string)requestData["UUID"], out uuid)) + { + m_log.Debug("[LOGIN PRELUDE]: Region connected without a UUID, sending back error response."); + return ErrorResponse("No UUID passed to grid server - unable to connect you"); + } + + try + { + sim = RegionFromRequest(requestData); + } + catch (FormatException e) + { + m_log.Debug("[LOGIN PRELUDE]: Invalid login parameters, sending back error response."); + return ErrorResponse("Wrong format in login parameters. Please verify parameters." + e.ToString()); + } + + m_log.InfoFormat("[LOGIN BEGIN]: Received login request from simulator: {0}", sim.regionName); + + if (!m_config.AllowRegionRegistration) + { + m_log.DebugFormat( + "[LOGIN END]: Disabled region registration blocked login request from simulator: {0}", + sim.regionName); + + return ErrorResponse("This grid is currently not accepting region registrations."); + } + + int majorInterfaceVersion = 0; + if (requestData.ContainsKey("major_interface_version")) + int.TryParse((string)requestData["major_interface_version"], out majorInterfaceVersion); + + if (majorInterfaceVersion != VersionInfo.MajorInterfaceVersion) + { + return ErrorResponse( + String.Format( + "Your region service implements OGS1 interface version {0}" + + " but this grid requires that the region implement OGS1 interface version {1} to connect." + + " Try changing to OpenSimulator {2}", + majorInterfaceVersion, VersionInfo.MajorInterfaceVersion, m_opensimVersion)); + } + + existingSim = m_gridDBService.GetRegion(sim.regionHandle); + + if (existingSim == null || existingSim.UUID == sim.UUID || sim.UUID != sim.originUUID) + { + try + { + if (existingSim == null) + { + ValidateNewRegionKeys(sim); + } + else + { + ValidateOverwriteKeys(sim, existingSim); + } + + ValidateRegionContactable(sim); + } + catch (LoginException e) + { + string logMsg = e.Message; + if (e.InnerException != null) + logMsg += ", " + e.InnerException.Message; + + m_log.WarnFormat("[LOGIN END]: {0}", logMsg); + + return e.XmlRpcErrorResponse; + } + + m_gridDBService.LoginRegion(sim, existingSim); + + XmlRpcResponse response = CreateLoginResponse(sim); + + return response; + } + else + { + m_log.Warn("[LOGIN END]: Failed to login region " + sim.regionName + " at location " + sim.regionLocX + " " + sim.regionLocY + " currently occupied by " + existingSim.regionName); + return ErrorResponse("Another region already exists at that location. Please try another."); + } + } + + /// + /// Construct a successful response to a simulator's login attempt. + /// + /// + /// + private XmlRpcResponse CreateLoginResponse(RegionProfileData sim) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + ArrayList SimNeighboursData = GetSimNeighboursData(sim); + + responseData["UUID"] = sim.UUID.ToString(); + responseData["region_locx"] = sim.regionLocX.ToString(); + responseData["region_locy"] = sim.regionLocY.ToString(); + responseData["regionname"] = sim.regionName; + responseData["estate_id"] = "1"; + responseData["neighbours"] = SimNeighboursData; + + responseData["sim_ip"] = sim.serverIP; + responseData["sim_port"] = sim.serverPort.ToString(); + responseData["asset_url"] = sim.regionAssetURI; + responseData["asset_sendkey"] = sim.regionAssetSendKey; + responseData["asset_recvkey"] = sim.regionAssetRecvKey; + responseData["user_url"] = sim.regionUserURI; + responseData["user_sendkey"] = sim.regionUserSendKey; + responseData["user_recvkey"] = sim.regionUserRecvKey; + responseData["authkey"] = sim.regionSecret; + + // New! If set, use as URL to local sim storage (ie http://remotehost/region.Yap) + responseData["data_uri"] = sim.regionDataURI; + + responseData["allow_forceful_banlines"] = m_config.AllowForcefulBanlines; + + // Instead of sending a multitude of message servers to the registering sim + // we should probably be sending a single one and parhaps it's backup + // that has responsibility over routing it's messages. + + // The Sim won't be contacting us again about any of the message server stuff during it's time up. + + responseData["messageserver_count"] = 0; + + IGridMessagingModule messagingModule; + if (m_gridCore.TryGet(out messagingModule)) + { + List messageServers = messagingModule.MessageServers; + responseData["messageserver_count"] = messageServers.Count; + + for (int i = 0; i < messageServers.Count; i++) + { + responseData["messageserver_uri" + i] = messageServers[i].URI; + responseData["messageserver_sendkey" + i] = messageServers[i].sendkey; + responseData["messageserver_recvkey" + i] = messageServers[i].recvkey; + } + } + return response; + } + + private ArrayList GetSimNeighboursData(RegionProfileData sim) + { + ArrayList SimNeighboursData = new ArrayList(); + + RegionProfileData neighbour; + Hashtable NeighbourBlock; + + //First use the fast method. (not implemented in SQLLite) + List neighbours = m_gridDBService.GetRegions(sim.regionLocX - 1, sim.regionLocY - 1, sim.regionLocX + 1, sim.regionLocY + 1); + + if (neighbours.Count > 0) + { + foreach (RegionProfileData aSim in neighbours) + { + NeighbourBlock = new Hashtable(); + NeighbourBlock["sim_ip"] = aSim.serverIP; + NeighbourBlock["sim_port"] = aSim.serverPort.ToString(); + NeighbourBlock["region_locx"] = aSim.regionLocX.ToString(); + NeighbourBlock["region_locy"] = aSim.regionLocY.ToString(); + NeighbourBlock["UUID"] = aSim.ToString(); + NeighbourBlock["regionHandle"] = aSim.regionHandle.ToString(); + + if (aSim.UUID != sim.UUID) + { + SimNeighboursData.Add(NeighbourBlock); + } + } + } + else + { + for (int x = -1; x < 2; x++) + { + for (int y = -1; y < 2; y++) + { + if ( + m_gridDBService.GetRegion( + Utils.UIntsToLong((uint)((sim.regionLocX + x) * Constants.RegionSize), + (uint)(sim.regionLocY + y) * Constants.RegionSize)) != null) + { + neighbour = + m_gridDBService.GetRegion( + Utils.UIntsToLong((uint)((sim.regionLocX + x) * Constants.RegionSize), + (uint)(sim.regionLocY + y) * Constants.RegionSize)); + + NeighbourBlock = new Hashtable(); + NeighbourBlock["sim_ip"] = neighbour.serverIP; + NeighbourBlock["sim_port"] = neighbour.serverPort.ToString(); + NeighbourBlock["region_locx"] = neighbour.regionLocX.ToString(); + NeighbourBlock["region_locy"] = neighbour.regionLocY.ToString(); + NeighbourBlock["UUID"] = neighbour.UUID.ToString(); + NeighbourBlock["regionHandle"] = neighbour.regionHandle.ToString(); + + if (neighbour.UUID != sim.UUID) SimNeighboursData.Add(NeighbourBlock); + } + } + } + } + return SimNeighboursData; + } + + /// + /// Loads the grid's own RegionProfileData object with data from the XMLRPC simulator_login request from a region + /// + /// + /// + private RegionProfileData RegionFromRequest(Hashtable requestData) + { + RegionProfileData sim; + sim = new RegionProfileData(); + + sim.UUID = new UUID((string)requestData["UUID"]); + sim.originUUID = new UUID((string)requestData["originUUID"]); + + sim.regionRecvKey = String.Empty; + sim.regionSendKey = String.Empty; + + if (requestData.ContainsKey("region_secret")) + { + string regionsecret = (string)requestData["region_secret"]; + if (regionsecret.Length > 0) + sim.regionSecret = regionsecret; + else + sim.regionSecret = m_config.SimRecvKey; + + } + else + { + sim.regionSecret = m_config.SimRecvKey; + } + + sim.regionDataURI = String.Empty; + sim.regionAssetURI = m_config.DefaultAssetServer; + sim.regionAssetRecvKey = m_config.AssetRecvKey; + sim.regionAssetSendKey = m_config.AssetSendKey; + sim.regionUserURI = m_config.DefaultUserServer; + sim.regionUserSendKey = m_config.UserSendKey; + sim.regionUserRecvKey = m_config.UserRecvKey; + + sim.serverIP = (string)requestData["sim_ip"]; + sim.serverPort = Convert.ToUInt32((string)requestData["sim_port"]); + sim.httpPort = Convert.ToUInt32((string)requestData["http_port"]); + sim.remotingPort = Convert.ToUInt32((string)requestData["remoting_port"]); + sim.regionLocX = Convert.ToUInt32((string)requestData["region_locx"]); + sim.regionLocY = Convert.ToUInt32((string)requestData["region_locy"]); + sim.regionLocZ = 0; + + UUID textureID; + if (UUID.TryParse((string)requestData["map-image-id"], out textureID)) + { + sim.regionMapTextureID = textureID; + } + + // part of an initial brutish effort to provide accurate information (as per the xml region spec) + // wrt the ownership of a given region + // the (very bad) assumption is that this value is being read and handled inconsistently or + // not at all. Current strategy is to put the code in place to support the validity of this information + // and to roll forward debugging any issues from that point + // + // this particular section of the mod attempts to receive a value from the region's xml file by way of + // OSG1GridServices for the region's owner + sim.owner_uuid = (UUID)(string)requestData["master_avatar_uuid"]; + + try + { + sim.regionRecvKey = (string)requestData["recvkey"]; + sim.regionSendKey = (string)requestData["authkey"]; + } + catch (KeyNotFoundException) { } + + sim.regionHandle = Utils.UIntsToLong((sim.regionLocX * Constants.RegionSize), (sim.regionLocY * Constants.RegionSize)); + sim.serverURI = (string)requestData["server_uri"]; + + sim.httpServerURI = "http://" + sim.serverIP + ":" + sim.httpPort + "/"; + + sim.regionName = (string)requestData["sim_name"]; + return sim; + } + + /// + /// Returns an XML RPC response to a simulator profile request + /// Performed after moving a region. + /// + /// + /// + /// The XMLRPC Request + /// Processing parameters + public XmlRpcResponse XmlRpcDeleteRegionMethod(XmlRpcRequest request) + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + + //RegionProfileData TheSim = null; + string uuid; + Hashtable requestData = (Hashtable)request.Params[0]; + + if (requestData.ContainsKey("UUID")) + { + //TheSim = GetRegion(new UUID((string) requestData["UUID"])); + uuid = requestData["UUID"].ToString(); + m_log.InfoFormat("[LOGOUT]: Logging out region: {0}", uuid); +// logToDB((new LLUUID((string)requestData["UUID"])).ToString(),"XmlRpcDeleteRegionMethod","", 5,"Attempting delete with UUID."); + } + else + { + responseData["error"] = "No UUID or region_handle passed to grid server - unable to delete"; + return response; + } + + DataResponse insertResponse = m_gridDBService.DeleteRegion(uuid); + + string insertResp = ""; + switch (insertResponse) + { + case DataResponse.RESPONSE_OK: + //MainLog.Instance.Verbose("grid", "Deleting region successful: " + uuid); + insertResp = "Deleting region successful: " + uuid; + break; + case DataResponse.RESPONSE_ERROR: + //MainLog.Instance.Warn("storage", "Deleting region failed (Error): " + uuid); + insertResp = "Deleting region failed (Error): " + uuid; + break; + case DataResponse.RESPONSE_INVALIDCREDENTIALS: + //MainLog.Instance.Warn("storage", "Deleting region failed (Invalid Credentials): " + uuid); + insertResp = "Deleting region (Invalid Credentials): " + uuid; + break; + case DataResponse.RESPONSE_AUTHREQUIRED: + //MainLog.Instance.Warn("storage", "Deleting region failed (Authentication Required): " + uuid); + insertResp = "Deleting region (Authentication Required): " + uuid; + break; + } + + responseData["status"] = insertResp; + + return response; + } + + /// + /// Returns an XML RPC response to a simulator profile request + /// + /// + /// + public XmlRpcResponse XmlRpcSimulatorDataRequestMethod(XmlRpcRequest request) + { + Hashtable requestData = (Hashtable)request.Params[0]; + Hashtable responseData = new Hashtable(); + RegionProfileData simData = null; + if (requestData.ContainsKey("region_UUID")) + { + UUID regionID = new UUID((string)requestData["region_UUID"]); + simData = m_gridDBService.GetRegion(regionID); + if (simData == null) + { + m_log.WarnFormat("[DATA] didn't find region for regionID {0} from {1}", + regionID, request.Params.Count > 1 ? request.Params[1] : "unknwon source"); + } + } + else if (requestData.ContainsKey("region_handle")) + { + //CFK: The if/else below this makes this message redundant. + //CFK: Console.WriteLine("requesting data for region " + (string) requestData["region_handle"]); + ulong regionHandle = Convert.ToUInt64((string)requestData["region_handle"]); + simData = m_gridDBService.GetRegion(regionHandle); + if (simData == null) + { + m_log.WarnFormat("[DATA] didn't find region for regionHandle {0} from {1}", + regionHandle, request.Params.Count > 1 ? request.Params[1] : "unknwon source"); + } + } + else if (requestData.ContainsKey("region_name_search")) + { + string regionName = (string)requestData["region_name_search"]; + simData = m_gridDBService.GetRegion(regionName); + if (simData == null) + { + m_log.WarnFormat("[DATA] didn't find region for regionName {0} from {1}", + regionName, request.Params.Count > 1 ? request.Params[1] : "unknwon source"); + } + } + else m_log.Warn("[DATA] regionlookup without regionID, regionHandle or regionHame"); + + if (simData == null) + { + //Sim does not exist + responseData["error"] = "Sim does not exist"; + } + else + { + m_log.Info("[DATA]: found " + (string)simData.regionName + " regionHandle = " + + (string)requestData["region_handle"]); + responseData["sim_ip"] = simData.serverIP; + responseData["sim_port"] = simData.serverPort.ToString(); + responseData["server_uri"] = simData.serverURI; + responseData["http_port"] = simData.httpPort.ToString(); + responseData["remoting_port"] = simData.remotingPort.ToString(); + responseData["region_locx"] = simData.regionLocX.ToString(); + responseData["region_locy"] = simData.regionLocY.ToString(); + responseData["region_UUID"] = simData.UUID.Guid.ToString(); + responseData["region_name"] = simData.regionName; + responseData["regionHandle"] = simData.regionHandle.ToString(); + } + + XmlRpcResponse response = new XmlRpcResponse(); + response.Value = responseData; + return response; + } + + public XmlRpcResponse XmlRpcMapBlockMethod(XmlRpcRequest request) + { + int xmin = 980, ymin = 980, xmax = 1020, ymax = 1020; + + Hashtable requestData = (Hashtable)request.Params[0]; + if (requestData.ContainsKey("xmin")) + { + xmin = (Int32)requestData["xmin"]; + } + if (requestData.ContainsKey("ymin")) + { + ymin = (Int32)requestData["ymin"]; + } + if (requestData.ContainsKey("xmax")) + { + xmax = (Int32)requestData["xmax"]; + } + if (requestData.ContainsKey("ymax")) + { + ymax = (Int32)requestData["ymax"]; + } + //CFK: The second log is more meaningful and either standard or fast generally occurs. + //CFK: m_log.Info("[MAP]: World map request for range (" + xmin + "," + ymin + ")..(" + xmax + "," + ymax + ")"); + + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + response.Value = responseData; + IList simProfileList = new ArrayList(); + + bool fastMode = (m_config.DatabaseProvider == "OpenSim.Data.MySQL.dll" || m_config.DatabaseProvider == "OpenSim.Data.MSSQL.dll"); + + if (fastMode) + { + List neighbours = m_gridDBService.GetRegions((uint)xmin, (uint)ymin, (uint)xmax, (uint)ymax); + + foreach (RegionProfileData aSim in neighbours) + { + Hashtable simProfileBlock = new Hashtable(); + simProfileBlock["x"] = aSim.regionLocX.ToString(); + simProfileBlock["y"] = aSim.regionLocY.ToString(); + //m_log.DebugFormat("[MAP]: Sending neighbour info for {0},{1}", aSim.regionLocX, aSim.regionLocY); + simProfileBlock["name"] = aSim.regionName; + simProfileBlock["access"] = 21; + simProfileBlock["region-flags"] = 512; + simProfileBlock["water-height"] = 0; + simProfileBlock["agents"] = 1; + simProfileBlock["map-image-id"] = aSim.regionMapTextureID.ToString(); + + // For Sugilite compatibility + simProfileBlock["regionhandle"] = aSim.regionHandle.ToString(); + simProfileBlock["sim_ip"] = aSim.serverIP; + simProfileBlock["sim_port"] = aSim.serverPort.ToString(); + simProfileBlock["sim_uri"] = aSim.serverURI.ToString(); + simProfileBlock["uuid"] = aSim.UUID.ToString(); + simProfileBlock["remoting_port"] = aSim.remotingPort.ToString(); + simProfileBlock["http_port"] = aSim.httpPort.ToString(); + + simProfileList.Add(simProfileBlock); + } + m_log.Info("[MAP]: Fast map " + simProfileList.Count.ToString() + + " regions @ (" + xmin + "," + ymin + ")..(" + xmax + "," + ymax + ")"); + } + else + { + RegionProfileData simProfile; + for (int x = xmin; x < xmax + 1; x++) + { + for (int y = ymin; y < ymax + 1; y++) + { + ulong regHandle = Utils.UIntsToLong((uint)(x * Constants.RegionSize), (uint)(y * Constants.RegionSize)); + simProfile = m_gridDBService.GetRegion(regHandle); + if (simProfile != null) + { + Hashtable simProfileBlock = new Hashtable(); + simProfileBlock["x"] = x; + simProfileBlock["y"] = y; + simProfileBlock["name"] = simProfile.regionName; + simProfileBlock["access"] = 0; + simProfileBlock["region-flags"] = 0; + simProfileBlock["water-height"] = 20; + simProfileBlock["agents"] = 1; + simProfileBlock["map-image-id"] = simProfile.regionMapTextureID.ToString(); + + // For Sugilite compatibility + simProfileBlock["regionhandle"] = simProfile.regionHandle.ToString(); + simProfileBlock["sim_ip"] = simProfile.serverIP.ToString(); + simProfileBlock["sim_port"] = simProfile.serverPort.ToString(); + simProfileBlock["sim_uri"] = simProfile.serverURI.ToString(); + simProfileBlock["uuid"] = simProfile.UUID.ToString(); + simProfileBlock["remoting_port"] = simProfile.remotingPort.ToString(); + simProfileBlock["http_port"] = simProfile.httpPort; + + simProfileList.Add(simProfileBlock); + } + } + } + m_log.Info("[MAP]: Std map " + simProfileList.Count.ToString() + + " regions @ (" + xmin + "," + ymin + ")..(" + xmax + "," + ymax + ")"); + } + + responseData["sim-profiles"] = simProfileList; + + return response; + } + + /// + /// Returns up to maxNumber profiles of regions that have a name starting with name + /// + /// + /// + public XmlRpcResponse XmlRpcSearchForRegionMethod(XmlRpcRequest request) + { + Hashtable requestData = (Hashtable)request.Params[0]; + + if (!requestData.ContainsKey("name") || !requestData.Contains("maxNumber")) + { + m_log.Warn("[DATA] Invalid region-search request; missing name or maxNumber"); + return new XmlRpcResponse(500, "Missing name or maxNumber in region search request"); + } + + Hashtable responseData = new Hashtable(); + + string name = (string)requestData["name"]; + int maxNumber = Convert.ToInt32((string)requestData["maxNumber"]); + if (maxNumber == 0 || name.Length < 3) + { + // either we didn't want any, or we were too unspecific + responseData["numFound"] = 0; + } + else + { + List sims = m_gridDBService.GetRegions(name, maxNumber); + + responseData["numFound"] = sims.Count; + for (int i = 0; i < sims.Count; ++i) + { + RegionProfileData sim = sims[i]; + string prefix = "region" + i + "."; + responseData[prefix + "region_name"] = sim.regionName; + responseData[prefix + "region_UUID"] = sim.UUID.ToString(); + responseData[prefix + "region_locx"] = sim.regionLocX.ToString(); + responseData[prefix + "region_locy"] = sim.regionLocY.ToString(); + responseData[prefix + "sim_ip"] = sim.serverIP.ToString(); + responseData[prefix + "sim_port"] = sim.serverPort.ToString(); + responseData[prefix + "remoting_port"] = sim.remotingPort.ToString(); + responseData[prefix + "http_port"] = sim.httpPort.ToString(); + responseData[prefix + "map_UUID"] = sim.regionMapTextureID.ToString(); + } + } + + XmlRpcResponse response = new XmlRpcResponse(); + response.Value = responseData; + return response; + } + + /// + /// Construct an XMLRPC registration disabled response + /// + /// + /// + public static XmlRpcResponse XmlRPCRegionRegistrationDisabledResponse(string error) + { + XmlRpcResponse errorResponse = new XmlRpcResponse(); + Hashtable errorResponseData = new Hashtable(); + errorResponse.Value = errorResponseData; + errorResponseData["restricted"] = error; + return errorResponse; + } + } + + /// + /// Exception generated when a simulator fails to login to the grid + /// + public class LoginException : Exception + { + /// + /// Return an XmlRpcResponse version of the exception message suitable for sending to a client + /// + /// + /// + public XmlRpcResponse XmlRpcErrorResponse + { + get { return m_xmlRpcErrorResponse; } + } + private XmlRpcResponse m_xmlRpcErrorResponse; + + public LoginException(string message, string xmlRpcMessage) : base(message) + { + // FIXME: Might be neater to refactor and put the method inside here + m_xmlRpcErrorResponse = GridXmlRpcModule.ErrorResponse(xmlRpcMessage); + } + + public LoginException(string message, string xmlRpcMessage, Exception e) : base(message, e) + { + // FIXME: Might be neater to refactor and put the method inside here + m_xmlRpcErrorResponse = GridXmlRpcModule.ErrorResponse(xmlRpcMessage); + } + } +} -- cgit v1.1