From 1a7efc2c64ac70b4ea77a370964c7a3df2c283e2 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 23 Aug 2014 17:33:14 +0200 Subject: [PATCH 1/3] Change the map tile system to be multi-grid hosting compatible Conflicts: OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs --- .../MapImage/MapImageServiceModule.cs | 2 +- .../Handlers/Map/MapAddServerConnector.cs | 5 +- .../Handlers/Map/MapGetServerConnector.cs | 12 +- .../Handlers/Map/MapRemoveServerConnector.cs | 252 ++++++++++++++++++ .../MapImage/MapImageServicesConnector.cs | 8 +- .../Services/Interfaces/IMapImageService.cs | 6 +- .../MapImageService/MapImageService.cs | 39 +-- 7 files changed, 297 insertions(+), 27 deletions(-) create mode 100644 OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs index b61062f2ce..40bedc1913 100644 --- a/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs +++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/MapImage/MapImageServiceModule.cs @@ -227,7 +227,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.MapImage } string reason = string.Empty; - if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, out reason)) + if (!m_MapService.AddMapTile((int)scene.RegionInfo.RegionLocX, (int)scene.RegionInfo.RegionLocY, jpgData, scene.RegionInfo.ScopeID, out reason)) { m_log.DebugFormat("[MAP IMAGE SERVICE MODULE]: Unable to upload tile image for {0} at {1}-{2}: {3}", scene.RegionInfo.RegionName, scene.RegionInfo.RegionLocX, scene.RegionInfo.RegionLocY, reason); diff --git a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs index 4a619698bc..c2c575c583 100644 --- a/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapAddServerConnector.cs @@ -117,8 +117,11 @@ namespace OpenSim.Server.Handlers.MapImage return FailureResult("Bad request."); } int x = 0, y = 0; + UUID scopeID = new UUID("07f8d88e-cd5e-4239-a0ed-843f75d09992"); Int32.TryParse(request["X"].ToString(), out x); Int32.TryParse(request["Y"].ToString(), out y); + if (request.ContainsKey("SCOPE")) + UUID.TryParse(request["SCOPE"].ToString(), out scopeID); m_log.DebugFormat("[MAP ADD SERVER CONNECTOR]: Received map data for region at {0}-{1}", x, y); @@ -151,7 +154,7 @@ namespace OpenSim.Server.Handlers.MapImage byte[] data = Convert.FromBase64String(request["DATA"].ToString()); string reason = string.Empty; - bool result = m_MapService.AddMapTile(x, y, data, out reason); + bool result = m_MapService.AddMapTile(x, y, data, scopeID, out reason); if (result) return SuccessResult(); diff --git a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs index 4502b7d9f7..5454c6fbc4 100644 --- a/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs +++ b/OpenSim/Server/Handlers/Map/MapGetServerConnector.cs @@ -38,6 +38,7 @@ using OpenSim.Server.Base; using OpenSim.Services.Interfaces; using OpenSim.Framework.Servers.HttpServer; using OpenSim.Server.Handlers.Base; +using OpenMetaverse; namespace OpenSim.Server.Handlers.MapImage { @@ -93,7 +94,16 @@ namespace OpenSim.Server.Handlers.MapImage byte[] result = new byte[0]; string format = string.Empty; - result = m_MapService.GetMapTile(path.Trim('/'), out format); + + UUID scopeID = new UUID("07f8d88e-cd5e-4239-a0ed-843f75d09992"); + + string[] bits = path.Trim('/').Split(new char[] {'/'}); + if (bits.Length > 1) + { + scopeID = new UUID(bits[0]); + path = bits[1]; + } + result = m_MapService.GetMapTile(path.Trim('/'), scopeID, out format); if (result.Length > 0) { httpResponse.StatusCode = (int)HttpStatusCode.OK; diff --git a/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs b/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs new file mode 100644 index 0000000000..8a31579c7f --- /dev/null +++ b/OpenSim/Server/Handlers/Map/MapRemoveServerConnector.cs @@ -0,0 +1,252 @@ +/* + * 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 OpenSimulator 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.Generic; +using System.IO; +using System.Reflection; +using System.Xml; + +using Nini.Config; +using log4net; +using OpenMetaverse; + +using OpenSim.Framework; +using OpenSim.Server.Base; +using OpenSim.Services.Interfaces; +using OpenSim.Framework.Servers.HttpServer; +using OpenSim.Server.Handlers.Base; + +using GridRegion = OpenSim.Services.Interfaces.GridRegion; + +namespace OpenSim.Server.Handlers.MapImage +{ + public class MapRemoveServiceConnector : ServiceConnector + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private IMapImageService m_MapService; + private IGridService m_GridService; + private string m_ConfigName = "MapImageService"; + + public MapRemoveServiceConnector(IConfigSource config, IHttpServer server, string configName) : + base(config, server, configName) + { + IConfig serverConfig = config.Configs[m_ConfigName]; + if (serverConfig == null) + throw new Exception(String.Format("No section {0} in config file", m_ConfigName)); + + string mapService = serverConfig.GetString("LocalServiceModule", + String.Empty); + + if (mapService == String.Empty) + throw new Exception("No LocalServiceModule in config file"); + + Object[] args = new Object[] { config }; + m_MapService = ServerUtils.LoadPlugin(mapService, args); + + string gridService = serverConfig.GetString("GridService", String.Empty); + if (gridService != string.Empty) + m_GridService = ServerUtils.LoadPlugin(gridService, args); + + if (m_GridService != null) + m_log.InfoFormat("[MAP IMAGE HANDLER]: GridService check is ON"); + else + m_log.InfoFormat("[MAP IMAGE HANDLER]: GridService check is OFF"); + + bool proxy = serverConfig.GetBoolean("HasProxy", false); + server.AddStreamHandler(new MapServerRemoveHandler(m_MapService, m_GridService, proxy)); + + } + } + + class MapServerRemoveHandler : BaseStreamHandler + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private IMapImageService m_MapService; + private IGridService m_GridService; + bool m_Proxy; + + public MapServerRemoveHandler(IMapImageService service, IGridService grid, bool proxy) : + base("POST", "/removemap") + { + m_MapService = service; + m_GridService = grid; + m_Proxy = proxy; + } + + public override byte[] Handle(string path, Stream requestData, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) + { +// m_log.DebugFormat("[MAP SERVICE IMAGE HANDLER]: Received {0}", path); + StreamReader sr = new StreamReader(requestData); + string body = sr.ReadToEnd(); + sr.Close(); + body = body.Trim(); + + try + { + Dictionary request = ServerUtils.ParseQueryString(body); + + if (!request.ContainsKey("X") || !request.ContainsKey("Y")) + { + httpResponse.StatusCode = (int)OSHttpStatusCode.ClientErrorBadRequest; + return FailureResult("Bad request."); + } + int x = 0, y = 0; + Int32.TryParse(request["X"].ToString(), out x); + Int32.TryParse(request["Y"].ToString(), out y); + UUID scopeID = new UUID("07f8d88e-cd5e-4239-a0ed-843f75d09992"); + if (request.ContainsKey("SCOPE")) + UUID.TryParse(request["SCOPE"].ToString(), out scopeID); + + m_log.DebugFormat("[MAP REMOVE SERVER CONNECTOR]: Received position data for region at {0}-{1}", x, y); + + if (m_GridService != null) + { + System.Net.IPAddress ipAddr = GetCallerIP(httpRequest); + GridRegion r = m_GridService.GetRegionByPosition(UUID.Zero, x * (int)Constants.RegionSize, y * (int)Constants.RegionSize); + if (r != null) + { + if (r.ExternalEndPoint.Address.ToString() != ipAddr.ToString()) + { + m_log.WarnFormat("[MAP IMAGE HANDLER]: IP address {0} may be trying to impersonate region in IP {1}", ipAddr, r.ExternalEndPoint.Address); + return FailureResult("IP address of caller does not match IP address of registered region"); + } + + } + else + { + m_log.WarnFormat("[MAP IMAGE HANDLER]: IP address {0} may be rogue. Region not found at coordinates {1}-{2}", + ipAddr, x, y); + return FailureResult("Region not found at given coordinates"); + } + } + + string reason = string.Empty; + bool result = m_MapService.RemoveMapTile(x, y, scopeID, out reason); + + if (result) + return SuccessResult(); + else + return FailureResult(reason); + + } + catch (Exception e) + { + m_log.ErrorFormat("[MAP SERVICE IMAGE HANDLER]: Exception {0} {1}", e.Message, e.StackTrace); + } + + return FailureResult("Unexpected server error"); + } + + private byte[] SuccessResult() + { + XmlDocument doc = new XmlDocument(); + + XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + + doc.AppendChild(xmlnode); + + XmlElement rootElement = doc.CreateElement("", "ServerResponse", + ""); + + doc.AppendChild(rootElement); + + XmlElement result = doc.CreateElement("", "Result", ""); + result.AppendChild(doc.CreateTextNode("Success")); + + rootElement.AppendChild(result); + + return DocToBytes(doc); + } + + private byte[] FailureResult(string msg) + { + XmlDocument doc = new XmlDocument(); + + XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration, + "", ""); + + doc.AppendChild(xmlnode); + + XmlElement rootElement = doc.CreateElement("", "ServerResponse", + ""); + + doc.AppendChild(rootElement); + + XmlElement result = doc.CreateElement("", "Result", ""); + result.AppendChild(doc.CreateTextNode("Failure")); + + rootElement.AppendChild(result); + + XmlElement message = doc.CreateElement("", "Message", ""); + message.AppendChild(doc.CreateTextNode(msg)); + + rootElement.AppendChild(message); + + return DocToBytes(doc); + } + + private byte[] DocToBytes(XmlDocument doc) + { + MemoryStream ms = new MemoryStream(); + XmlTextWriter xw = new XmlTextWriter(ms, null); + xw.Formatting = Formatting.Indented; + doc.WriteTo(xw); + xw.Flush(); + + return ms.ToArray(); + } + + private System.Net.IPAddress GetCallerIP(IOSHttpRequest request) + { + if (!m_Proxy) + return request.RemoteIPEndPoint.Address; + + // We're behind a proxy + string xff = "X-Forwarded-For"; + string xffValue = request.Headers[xff.ToLower()]; + if (xffValue == null || (xffValue != null && xffValue == string.Empty)) + xffValue = request.Headers[xff]; + + if (xffValue == null || (xffValue != null && xffValue == string.Empty)) + { + m_log.WarnFormat("[MAP IMAGE HANDLER]: No XFF header"); + return request.RemoteIPEndPoint.Address; + } + + System.Net.IPEndPoint ep = Util.GetClientIPFromXFF(xffValue); + if (ep != null) + return ep.Address; + + // Oops + return request.RemoteIPEndPoint.Address; + } + + } +} diff --git a/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs b/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs index 267dd71d16..6095598a58 100644 --- a/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs +++ b/OpenSim/Services/Connectors/MapImage/MapImageServicesConnector.cs @@ -86,13 +86,14 @@ namespace OpenSim.Services.Connectors m_ServerURI = serviceURI.TrimEnd('/'); } - public bool RemoveMapTile(int x, int y, out string reason) + public bool RemoveMapTile(int x, int y, UUID scopeID, out string reason) { reason = string.Empty; int tickstart = Util.EnvironmentTickCount(); Dictionary sendData = new Dictionary(); sendData["X"] = x.ToString(); sendData["Y"] = y.ToString(); + sendData["SCOPE"] = scopeID.ToString(); string reqString = ServerUtils.BuildQueryString(sendData); string uri = m_ServerURI + "/removemap"; @@ -146,13 +147,14 @@ namespace OpenSim.Services.Connectors return false; } - public bool AddMapTile(int x, int y, byte[] jpgData, out string reason) + public bool AddMapTile(int x, int y, byte[] jpgData, UUID scopeID, out string reason) { reason = string.Empty; int tickstart = Util.EnvironmentTickCount(); Dictionary sendData = new Dictionary(); sendData["X"] = x.ToString(); sendData["Y"] = y.ToString(); + sendData["SCOPE"] = scopeID.ToString(); sendData["TYPE"] = "image/jpeg"; sendData["DATA"] = Convert.ToBase64String(jpgData); @@ -209,7 +211,7 @@ namespace OpenSim.Services.Connectors } - public byte[] GetMapTile(string fileName, out string format) + public byte[] GetMapTile(string fileName, UUID scopeID, out string format) { format = string.Empty; new Exception("GetMapTile method not Implemented"); diff --git a/OpenSim/Services/Interfaces/IMapImageService.cs b/OpenSim/Services/Interfaces/IMapImageService.cs index 78daa5f0e4..b8d45dd922 100644 --- a/OpenSim/Services/Interfaces/IMapImageService.cs +++ b/OpenSim/Services/Interfaces/IMapImageService.cs @@ -34,8 +34,8 @@ namespace OpenSim.Services.Interfaces public interface IMapImageService { //List GetMapBlocks(UUID scopeID, int minX, int minY, int maxX, int maxY); - bool AddMapTile(int x, int y, byte[] imageData, out string reason); - bool RemoveMapTile(int x, int y, out string reason); - byte[] GetMapTile(string fileName, out string format); + bool AddMapTile(int x, int y, byte[] imageData, UUID scopeID, out string reason); + bool RemoveMapTile(int x, int y, UUID scopeID, out string reason); + byte[] GetMapTile(string fileName, UUID scopeID, out string format); } } diff --git a/OpenSim/Services/MapImageService/MapImageService.cs b/OpenSim/Services/MapImageService/MapImageService.cs index e2f256ff07..9de5085845 100644 --- a/OpenSim/Services/MapImageService/MapImageService.cs +++ b/OpenSim/Services/MapImageService/MapImageService.cs @@ -94,10 +94,10 @@ namespace OpenSim.Services.MapImageService #region IMapImageService - public bool AddMapTile(int x, int y, byte[] imageData, out string reason) + public bool AddMapTile(int x, int y, byte[] imageData, UUID scopeID, out string reason) { reason = string.Empty; - string fileName = GetFileName(1, x, y); + string fileName = GetFileName(1, x, y, scopeID); lock (m_Sync) { @@ -114,13 +114,13 @@ namespace OpenSim.Services.MapImageService } } - return UpdateMultiResolutionFiles(x, y, out reason); + return UpdateMultiResolutionFiles(x, y, scopeID, out reason); } - public bool RemoveMapTile(int x, int y, out string reason) + public bool RemoveMapTile(int x, int y, UUID scopeID, out string reason) { reason = String.Empty; - string fileName = GetFileName(1, x, y); + string fileName = GetFileName(1, x, y, scopeID); lock (m_Sync) { @@ -136,10 +136,10 @@ namespace OpenSim.Services.MapImageService } } - return UpdateMultiResolutionFiles(x, y, out reason); + return UpdateMultiResolutionFiles(x, y, scopeID, out reason); } - private bool UpdateMultiResolutionFiles(int x, int y, out string reason) + private bool UpdateMultiResolutionFiles(int x, int y, UUID scopeID, out string reason) { reason = String.Empty; lock (m_Sync) @@ -153,7 +153,7 @@ namespace OpenSim.Services.MapImageService int x1 = x - (x % width); int y1 = y - (y % width); - if (!CreateTile(zoomLevel, x1, y1)) + if (!CreateTile(zoomLevel, x1, y1, scopeID)) { m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0},{1} at zoom level {1}", x, y, zoomLevel); reason = string.Format("Map tile at zoom level {0} failed", zoomLevel); @@ -165,12 +165,13 @@ namespace OpenSim.Services.MapImageService return true; } - public byte[] GetMapTile(string fileName, out string format) + public byte[] GetMapTile(string fileName, UUID scopeID, out string format) { // m_log.DebugFormat("[MAP IMAGE SERVICE]: Getting map tile {0}", fileName); format = ".jpg"; - string fullName = Path.Combine(m_TilesStoragePath, fileName); + string fullName = Path.Combine(m_TilesStoragePath, scopeID.ToString()); + fullName = Path.Combine(fullName, fileName); if (File.Exists(fullName)) { format = Path.GetExtension(fileName).ToLower(); @@ -191,10 +192,12 @@ namespace OpenSim.Services.MapImageService #endregion - private string GetFileName(uint zoomLevel, int x, int y) + private string GetFileName(uint zoomLevel, int x, int y, UUID scopeID) { string extension = "jpg"; - return Path.Combine(m_TilesStoragePath, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension)); + string path = Path.Combine(m_TilesStoragePath, scopeID.ToString()); + Directory.CreateDirectory(path); + return Path.Combine(path, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension)); } private Bitmap GetInputTileImage(string fileName) @@ -235,7 +238,7 @@ namespace OpenSim.Services.MapImageService return null; } - private bool CreateTile(uint zoomLevel, int x, int y) + private bool CreateTile(uint zoomLevel, int x, int y, UUID scopeID) { // m_log.DebugFormat("[MAP IMAGE SERVICE]: Create tile for {0} {1}, zoom {2}", x, y, zoomLevel); int prevWidth = (int)Math.Pow(2, (double)zoomLevel - 2); @@ -250,13 +253,13 @@ namespace OpenSim.Services.MapImageService int yOut = y - (y % thisWidth); // Try to open the four input tiles from the previous zoom level - Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn)); - Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn)); - Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth)); - Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth)); + Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn, scopeID)); + Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn, scopeID)); + Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth, scopeID)); + Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth, scopeID)); // Open the output tile (current zoom level) - string outputFile = GetFileName(zoomLevel, xOut, yOut); + string outputFile = GetFileName(zoomLevel, xOut, yOut, scopeID); Bitmap output = GetOutputTileImage(outputFile); if (output == null) return false; From d34599b1a5de2bec045cfc8509a7857cd9cba13e Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 23 Aug 2014 18:16:11 +0200 Subject: [PATCH 2/3] If GridUserService is asked for a nonexistent user, bail gracefully --- OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs index 687cf8ddb1..cad93a1330 100644 --- a/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs +++ b/OpenSim/Server/Handlers/GridUser/GridUserServerPostHandler.cs @@ -184,6 +184,9 @@ namespace OpenSim.Server.Handlers.GridUser GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(user); + if (guinfo == null) + return FailureResult(); + Dictionary result = new Dictionary(); result["result"] = guinfo.ToKeyValuePairs(); From 39e052982baebb60801984965d8865886f20931d Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 23 Aug 2014 19:10:15 +0200 Subject: [PATCH 3/3] Fix a null ref that will cause an exception if a grid region doesnt' specify a URI. --- OpenSim/Services/Interfaces/IGridService.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs index 3f4c958ce3..a3d237ffb8 100644 --- a/OpenSim/Services/Interfaces/IGridService.cs +++ b/OpenSim/Services/Interfaces/IGridService.cs @@ -141,6 +141,12 @@ namespace OpenSim.Services.Interfaces } } set { + if ( value == null) + { + m_serverURI = String.Empty; + return; + } + if ( value.EndsWith("/") ) { m_serverURI = value; } else {