diff options
Diffstat (limited to 'OpenSim/Grid/GridServer/GridXmlRpcModule.cs')
-rw-r--r-- | OpenSim/Grid/GridServer/GridXmlRpcModule.cs | 844 |
1 files changed, 844 insertions, 0 deletions
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 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Xml; | ||
34 | using log4net; | ||
35 | using Nwc.XmlRpc; | ||
36 | using OpenMetaverse; | ||
37 | using OpenSim.Data; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Communications; | ||
40 | using OpenSim.Framework.Servers; | ||
41 | |||
42 | namespace OpenSim.Grid.GridServer | ||
43 | { | ||
44 | public class GridXmlRpcModule | ||
45 | { | ||
46 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | private GridDBService m_gridDBService; | ||
49 | private IGridCore m_gridCore; | ||
50 | |||
51 | protected GridConfig m_config; | ||
52 | |||
53 | /// <value> | ||
54 | /// Used to notify old regions as to which OpenSim version to upgrade to | ||
55 | /// </value> | ||
56 | private string m_opensimVersion; | ||
57 | |||
58 | protected BaseHttpServer m_httpServer; | ||
59 | |||
60 | /// <summary> | ||
61 | /// Constructor | ||
62 | /// </summary> | ||
63 | /// <param name="opensimVersion"> | ||
64 | /// Used to notify old regions as to which OpenSim version to upgrade to | ||
65 | /// </param> | ||
66 | public GridXmlRpcModule(string opensimVersion, GridDBService gridDBService, IGridCore gridCore, GridConfig config) | ||
67 | { | ||
68 | m_opensimVersion = opensimVersion; | ||
69 | m_gridDBService = gridDBService; | ||
70 | m_gridCore = gridCore; | ||
71 | m_config = config; | ||
72 | m_httpServer = m_gridCore.GetHttpServer(); | ||
73 | } | ||
74 | |||
75 | public void Initialise() | ||
76 | { | ||
77 | m_httpServer.AddXmlRPCHandler("simulator_login", XmlRpcSimulatorLoginMethod); | ||
78 | m_httpServer.AddXmlRPCHandler("simulator_data_request", XmlRpcSimulatorDataRequestMethod); | ||
79 | m_httpServer.AddXmlRPCHandler("simulator_after_region_moved", XmlRpcDeleteRegionMethod); | ||
80 | m_httpServer.AddXmlRPCHandler("map_block", XmlRpcMapBlockMethod); | ||
81 | m_httpServer.AddXmlRPCHandler("search_for_region_by_name", XmlRpcSearchForRegionMethod); | ||
82 | } | ||
83 | |||
84 | /// <summary> | ||
85 | /// Returns a XML String containing a list of the neighbouring regions | ||
86 | /// </summary> | ||
87 | /// <param name="reqhandle">The regionhandle for the center sim</param> | ||
88 | /// <returns>An XML string containing neighbour entities</returns> | ||
89 | public string GetXMLNeighbours(ulong reqhandle) | ||
90 | { | ||
91 | string response = String.Empty; | ||
92 | RegionProfileData central_region = m_gridDBService.GetRegion(reqhandle); | ||
93 | RegionProfileData neighbour; | ||
94 | for (int x = -1; x < 2; x++) | ||
95 | { | ||
96 | for (int y = -1; y < 2; y++) | ||
97 | { | ||
98 | if ( | ||
99 | m_gridDBService.GetRegion( | ||
100 | Util.UIntsToLong((uint)((central_region.regionLocX + x) * Constants.RegionSize), | ||
101 | (uint)(central_region.regionLocY + y) * Constants.RegionSize)) != null) | ||
102 | { | ||
103 | neighbour = | ||
104 | m_gridDBService.GetRegion( | ||
105 | Util.UIntsToLong((uint)((central_region.regionLocX + x) * Constants.RegionSize), | ||
106 | (uint)(central_region.regionLocY + y) * Constants.RegionSize)); | ||
107 | |||
108 | response += "<neighbour>"; | ||
109 | response += "<sim_ip>" + neighbour.serverIP + "</sim_ip>"; | ||
110 | response += "<sim_port>" + neighbour.serverPort.ToString() + "</sim_port>"; | ||
111 | response += "<locx>" + neighbour.regionLocX.ToString() + "</locx>"; | ||
112 | response += "<locy>" + neighbour.regionLocY.ToString() + "</locy>"; | ||
113 | response += "<regionhandle>" + neighbour.regionHandle.ToString() + "</regionhandle>"; | ||
114 | response += "</neighbour>"; | ||
115 | } | ||
116 | } | ||
117 | } | ||
118 | return response; | ||
119 | } | ||
120 | |||
121 | /// <summary> | ||
122 | /// Checks that it's valid to replace the existing region data with new data | ||
123 | /// | ||
124 | /// Currently, this means ensure that the keys passed in by the new region | ||
125 | /// match those in the original region. (XXX Is this correct? Shouldn't we simply check | ||
126 | /// against the keys in the current configuration?) | ||
127 | /// </summary> | ||
128 | /// <param name="sim"></param> | ||
129 | /// <returns></returns> | ||
130 | protected virtual void ValidateOverwriteKeys(RegionProfileData sim, RegionProfileData existingSim) | ||
131 | { | ||
132 | if (!(existingSim.regionRecvKey == sim.regionRecvKey && existingSim.regionSendKey == sim.regionSendKey)) | ||
133 | { | ||
134 | throw new LoginException( | ||
135 | String.Format( | ||
136 | "Authentication failed when trying to login existing region {0} at location {1} {2} currently occupied by {3}" | ||
137 | + " with the region's send key {4} (expected {5}) and the region's receive key {6} (expected {7})", | ||
138 | sim.regionName, sim.regionLocX, sim.regionLocY, existingSim.regionName, | ||
139 | sim.regionSendKey, existingSim.regionSendKey, sim.regionRecvKey, existingSim.regionRecvKey), | ||
140 | "The keys required to login your region did not match the grid server keys. Please check your grid send and receive keys."); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | /// <summary> | ||
145 | /// Checks that the new region data is valid. | ||
146 | /// | ||
147 | /// Currently, this means checking that the keys passed in by the new region | ||
148 | /// match those in the grid server's configuration. | ||
149 | /// </summary> | ||
150 | /// | ||
151 | /// <param name="sim"></param> | ||
152 | /// <exception cref="LoginException">Thrown if region login failed</exception> | ||
153 | protected virtual void ValidateNewRegionKeys(RegionProfileData sim) | ||
154 | { | ||
155 | if (!(sim.regionRecvKey == m_config.SimSendKey && sim.regionSendKey == m_config.SimRecvKey)) | ||
156 | { | ||
157 | throw new LoginException( | ||
158 | String.Format( | ||
159 | "Authentication failed when trying to login new region {0} at location {1} {2}" | ||
160 | + " with the region's send key {3} (expected {4}) and the region's receive key {5} (expected {6})", | ||
161 | sim.regionName, sim.regionLocX, sim.regionLocY, | ||
162 | sim.regionSendKey, m_config.SimRecvKey, sim.regionRecvKey, m_config.SimSendKey), | ||
163 | "The keys required to login your region did not match your existing region keys. Please check your grid send and receive keys."); | ||
164 | } | ||
165 | } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Check that a region's http uri is externally contactable. | ||
169 | /// </summary> | ||
170 | /// <param name="sim"></param> | ||
171 | /// <exception cref="LoginException">Thrown if the region is not contactable</exception> | ||
172 | protected virtual void ValidateRegionContactable(RegionProfileData sim) | ||
173 | { | ||
174 | string regionStatusUrl = String.Format("{0}{1}", sim.httpServerURI, "simstatus/"); | ||
175 | string regionStatusResponse; | ||
176 | |||
177 | RestClient rc = new RestClient(regionStatusUrl); | ||
178 | rc.RequestMethod = "GET"; | ||
179 | |||
180 | m_log.DebugFormat("[LOGIN]: Contacting {0} for status of region {1}", regionStatusUrl, sim.regionName); | ||
181 | |||
182 | try | ||
183 | { | ||
184 | Stream rs = rc.Request(); | ||
185 | StreamReader sr = new StreamReader(rs); | ||
186 | regionStatusResponse = sr.ReadToEnd(); | ||
187 | sr.Close(); | ||
188 | } | ||
189 | catch (Exception e) | ||
190 | { | ||
191 | throw new LoginException( | ||
192 | String.Format("Region status request to {0} failed", regionStatusUrl), | ||
193 | String.Format( | ||
194 | "The grid service could not contact the http url {0} at your region. Please make sure this url is reachable by the grid service", | ||
195 | regionStatusUrl), | ||
196 | e); | ||
197 | } | ||
198 | |||
199 | if (!regionStatusResponse.Equals("OK")) | ||
200 | { | ||
201 | throw new LoginException( | ||
202 | String.Format( | ||
203 | "Region {0} at {1} returned status response {2} rather than {3}", | ||
204 | sim.regionName, regionStatusUrl, regionStatusResponse, "OK"), | ||
205 | String.Format( | ||
206 | "When the grid service asked for the status of your region, it received the response {0} rather than {1}. Please check your status", | ||
207 | regionStatusResponse, "OK")); | ||
208 | } | ||
209 | } | ||
210 | |||
211 | /// <summary> | ||
212 | /// Construct an XMLRPC error response | ||
213 | /// </summary> | ||
214 | /// <param name="error"></param> | ||
215 | /// <returns></returns> | ||
216 | public static XmlRpcResponse ErrorResponse(string error) | ||
217 | { | ||
218 | XmlRpcResponse errorResponse = new XmlRpcResponse(); | ||
219 | Hashtable errorResponseData = new Hashtable(); | ||
220 | errorResponse.Value = errorResponseData; | ||
221 | errorResponseData["error"] = error; | ||
222 | return errorResponse; | ||
223 | } | ||
224 | |||
225 | /// <summary> | ||
226 | /// Performed when a region connects to the grid server initially. | ||
227 | /// </summary> | ||
228 | /// <param name="request">The XML RPC Request</param> | ||
229 | /// <returns>Startup parameters</returns> | ||
230 | public XmlRpcResponse XmlRpcSimulatorLoginMethod(XmlRpcRequest request) | ||
231 | { | ||
232 | RegionProfileData sim; | ||
233 | RegionProfileData existingSim; | ||
234 | |||
235 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
236 | UUID uuid; | ||
237 | |||
238 | if (!requestData.ContainsKey("UUID") || !UUID.TryParse((string)requestData["UUID"], out uuid)) | ||
239 | { | ||
240 | m_log.Debug("[LOGIN PRELUDE]: Region connected without a UUID, sending back error response."); | ||
241 | return ErrorResponse("No UUID passed to grid server - unable to connect you"); | ||
242 | } | ||
243 | |||
244 | try | ||
245 | { | ||
246 | sim = RegionFromRequest(requestData); | ||
247 | } | ||
248 | catch (FormatException e) | ||
249 | { | ||
250 | m_log.Debug("[LOGIN PRELUDE]: Invalid login parameters, sending back error response."); | ||
251 | return ErrorResponse("Wrong format in login parameters. Please verify parameters." + e.ToString()); | ||
252 | } | ||
253 | |||
254 | m_log.InfoFormat("[LOGIN BEGIN]: Received login request from simulator: {0}", sim.regionName); | ||
255 | |||
256 | if (!m_config.AllowRegionRegistration) | ||
257 | { | ||
258 | m_log.DebugFormat( | ||
259 | "[LOGIN END]: Disabled region registration blocked login request from simulator: {0}", | ||
260 | sim.regionName); | ||
261 | |||
262 | return ErrorResponse("This grid is currently not accepting region registrations."); | ||
263 | } | ||
264 | |||
265 | int majorInterfaceVersion = 0; | ||
266 | if (requestData.ContainsKey("major_interface_version")) | ||
267 | int.TryParse((string)requestData["major_interface_version"], out majorInterfaceVersion); | ||
268 | |||
269 | if (majorInterfaceVersion != VersionInfo.MajorInterfaceVersion) | ||
270 | { | ||
271 | return ErrorResponse( | ||
272 | String.Format( | ||
273 | "Your region service implements OGS1 interface version {0}" | ||
274 | + " but this grid requires that the region implement OGS1 interface version {1} to connect." | ||
275 | + " Try changing to OpenSimulator {2}", | ||
276 | majorInterfaceVersion, VersionInfo.MajorInterfaceVersion, m_opensimVersion)); | ||
277 | } | ||
278 | |||
279 | existingSim = m_gridDBService.GetRegion(sim.regionHandle); | ||
280 | |||
281 | if (existingSim == null || existingSim.UUID == sim.UUID || sim.UUID != sim.originUUID) | ||
282 | { | ||
283 | try | ||
284 | { | ||
285 | if (existingSim == null) | ||
286 | { | ||
287 | ValidateNewRegionKeys(sim); | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | ValidateOverwriteKeys(sim, existingSim); | ||
292 | } | ||
293 | |||
294 | ValidateRegionContactable(sim); | ||
295 | } | ||
296 | catch (LoginException e) | ||
297 | { | ||
298 | string logMsg = e.Message; | ||
299 | if (e.InnerException != null) | ||
300 | logMsg += ", " + e.InnerException.Message; | ||
301 | |||
302 | m_log.WarnFormat("[LOGIN END]: {0}", logMsg); | ||
303 | |||
304 | return e.XmlRpcErrorResponse; | ||
305 | } | ||
306 | |||
307 | m_gridDBService.LoginRegion(sim, existingSim); | ||
308 | |||
309 | XmlRpcResponse response = CreateLoginResponse(sim); | ||
310 | |||
311 | return response; | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | m_log.Warn("[LOGIN END]: Failed to login region " + sim.regionName + " at location " + sim.regionLocX + " " + sim.regionLocY + " currently occupied by " + existingSim.regionName); | ||
316 | return ErrorResponse("Another region already exists at that location. Please try another."); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | /// <summary> | ||
321 | /// Construct a successful response to a simulator's login attempt. | ||
322 | /// </summary> | ||
323 | /// <param name="sim"></param> | ||
324 | /// <returns></returns> | ||
325 | private XmlRpcResponse CreateLoginResponse(RegionProfileData sim) | ||
326 | { | ||
327 | XmlRpcResponse response = new XmlRpcResponse(); | ||
328 | Hashtable responseData = new Hashtable(); | ||
329 | response.Value = responseData; | ||
330 | |||
331 | ArrayList SimNeighboursData = GetSimNeighboursData(sim); | ||
332 | |||
333 | responseData["UUID"] = sim.UUID.ToString(); | ||
334 | responseData["region_locx"] = sim.regionLocX.ToString(); | ||
335 | responseData["region_locy"] = sim.regionLocY.ToString(); | ||
336 | responseData["regionname"] = sim.regionName; | ||
337 | responseData["estate_id"] = "1"; | ||
338 | responseData["neighbours"] = SimNeighboursData; | ||
339 | |||
340 | responseData["sim_ip"] = sim.serverIP; | ||
341 | responseData["sim_port"] = sim.serverPort.ToString(); | ||
342 | responseData["asset_url"] = sim.regionAssetURI; | ||
343 | responseData["asset_sendkey"] = sim.regionAssetSendKey; | ||
344 | responseData["asset_recvkey"] = sim.regionAssetRecvKey; | ||
345 | responseData["user_url"] = sim.regionUserURI; | ||
346 | responseData["user_sendkey"] = sim.regionUserSendKey; | ||
347 | responseData["user_recvkey"] = sim.regionUserRecvKey; | ||
348 | responseData["authkey"] = sim.regionSecret; | ||
349 | |||
350 | // New! If set, use as URL to local sim storage (ie http://remotehost/region.Yap) | ||
351 | responseData["data_uri"] = sim.regionDataURI; | ||
352 | |||
353 | responseData["allow_forceful_banlines"] = m_config.AllowForcefulBanlines; | ||
354 | |||
355 | // Instead of sending a multitude of message servers to the registering sim | ||
356 | // we should probably be sending a single one and parhaps it's backup | ||
357 | // that has responsibility over routing it's messages. | ||
358 | |||
359 | // The Sim won't be contacting us again about any of the message server stuff during it's time up. | ||
360 | |||
361 | responseData["messageserver_count"] = 0; | ||
362 | |||
363 | IGridMessagingModule messagingModule; | ||
364 | if (m_gridCore.TryGet<IGridMessagingModule>(out messagingModule)) | ||
365 | { | ||
366 | List<MessageServerInfo> messageServers = messagingModule.MessageServers; | ||
367 | responseData["messageserver_count"] = messageServers.Count; | ||
368 | |||
369 | for (int i = 0; i < messageServers.Count; i++) | ||
370 | { | ||
371 | responseData["messageserver_uri" + i] = messageServers[i].URI; | ||
372 | responseData["messageserver_sendkey" + i] = messageServers[i].sendkey; | ||
373 | responseData["messageserver_recvkey" + i] = messageServers[i].recvkey; | ||
374 | } | ||
375 | } | ||
376 | return response; | ||
377 | } | ||
378 | |||
379 | private ArrayList GetSimNeighboursData(RegionProfileData sim) | ||
380 | { | ||
381 | ArrayList SimNeighboursData = new ArrayList(); | ||
382 | |||
383 | RegionProfileData neighbour; | ||
384 | Hashtable NeighbourBlock; | ||
385 | |||
386 | //First use the fast method. (not implemented in SQLLite) | ||
387 | List<RegionProfileData> neighbours = m_gridDBService.GetRegions(sim.regionLocX - 1, sim.regionLocY - 1, sim.regionLocX + 1, sim.regionLocY + 1); | ||
388 | |||
389 | if (neighbours.Count > 0) | ||
390 | { | ||
391 | foreach (RegionProfileData aSim in neighbours) | ||
392 | { | ||
393 | NeighbourBlock = new Hashtable(); | ||
394 | NeighbourBlock["sim_ip"] = aSim.serverIP; | ||
395 | NeighbourBlock["sim_port"] = aSim.serverPort.ToString(); | ||
396 | NeighbourBlock["region_locx"] = aSim.regionLocX.ToString(); | ||
397 | NeighbourBlock["region_locy"] = aSim.regionLocY.ToString(); | ||
398 | NeighbourBlock["UUID"] = aSim.ToString(); | ||
399 | NeighbourBlock["regionHandle"] = aSim.regionHandle.ToString(); | ||
400 | |||
401 | if (aSim.UUID != sim.UUID) | ||
402 | { | ||
403 | SimNeighboursData.Add(NeighbourBlock); | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | else | ||
408 | { | ||
409 | for (int x = -1; x < 2; x++) | ||
410 | { | ||
411 | for (int y = -1; y < 2; y++) | ||
412 | { | ||
413 | if ( | ||
414 | m_gridDBService.GetRegion( | ||
415 | Utils.UIntsToLong((uint)((sim.regionLocX + x) * Constants.RegionSize), | ||
416 | (uint)(sim.regionLocY + y) * Constants.RegionSize)) != null) | ||
417 | { | ||
418 | neighbour = | ||
419 | m_gridDBService.GetRegion( | ||
420 | Utils.UIntsToLong((uint)((sim.regionLocX + x) * Constants.RegionSize), | ||
421 | (uint)(sim.regionLocY + y) * Constants.RegionSize)); | ||
422 | |||
423 | NeighbourBlock = new Hashtable(); | ||
424 | NeighbourBlock["sim_ip"] = neighbour.serverIP; | ||
425 | NeighbourBlock["sim_port"] = neighbour.serverPort.ToString(); | ||
426 | NeighbourBlock["region_locx"] = neighbour.regionLocX.ToString(); | ||
427 | NeighbourBlock["region_locy"] = neighbour.regionLocY.ToString(); | ||
428 | NeighbourBlock["UUID"] = neighbour.UUID.ToString(); | ||
429 | NeighbourBlock["regionHandle"] = neighbour.regionHandle.ToString(); | ||
430 | |||
431 | if (neighbour.UUID != sim.UUID) SimNeighboursData.Add(NeighbourBlock); | ||
432 | } | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | return SimNeighboursData; | ||
437 | } | ||
438 | |||
439 | /// <summary> | ||
440 | /// Loads the grid's own RegionProfileData object with data from the XMLRPC simulator_login request from a region | ||
441 | /// </summary> | ||
442 | /// <param name="requestData"></param> | ||
443 | /// <returns></returns> | ||
444 | private RegionProfileData RegionFromRequest(Hashtable requestData) | ||
445 | { | ||
446 | RegionProfileData sim; | ||
447 | sim = new RegionProfileData(); | ||
448 | |||
449 | sim.UUID = new UUID((string)requestData["UUID"]); | ||
450 | sim.originUUID = new UUID((string)requestData["originUUID"]); | ||
451 | |||
452 | sim.regionRecvKey = String.Empty; | ||
453 | sim.regionSendKey = String.Empty; | ||
454 | |||
455 | if (requestData.ContainsKey("region_secret")) | ||
456 | { | ||
457 | string regionsecret = (string)requestData["region_secret"]; | ||
458 | if (regionsecret.Length > 0) | ||
459 | sim.regionSecret = regionsecret; | ||
460 | else | ||
461 | sim.regionSecret = m_config.SimRecvKey; | ||
462 | |||
463 | } | ||
464 | else | ||
465 | { | ||
466 | sim.regionSecret = m_config.SimRecvKey; | ||
467 | } | ||
468 | |||
469 | sim.regionDataURI = String.Empty; | ||
470 | sim.regionAssetURI = m_config.DefaultAssetServer; | ||
471 | sim.regionAssetRecvKey = m_config.AssetRecvKey; | ||
472 | sim.regionAssetSendKey = m_config.AssetSendKey; | ||
473 | sim.regionUserURI = m_config.DefaultUserServer; | ||
474 | sim.regionUserSendKey = m_config.UserSendKey; | ||
475 | sim.regionUserRecvKey = m_config.UserRecvKey; | ||
476 | |||
477 | sim.serverIP = (string)requestData["sim_ip"]; | ||
478 | sim.serverPort = Convert.ToUInt32((string)requestData["sim_port"]); | ||
479 | sim.httpPort = Convert.ToUInt32((string)requestData["http_port"]); | ||
480 | sim.remotingPort = Convert.ToUInt32((string)requestData["remoting_port"]); | ||
481 | sim.regionLocX = Convert.ToUInt32((string)requestData["region_locx"]); | ||
482 | sim.regionLocY = Convert.ToUInt32((string)requestData["region_locy"]); | ||
483 | sim.regionLocZ = 0; | ||
484 | |||
485 | UUID textureID; | ||
486 | if (UUID.TryParse((string)requestData["map-image-id"], out textureID)) | ||
487 | { | ||
488 | sim.regionMapTextureID = textureID; | ||
489 | } | ||
490 | |||
491 | // part of an initial brutish effort to provide accurate information (as per the xml region spec) | ||
492 | // wrt the ownership of a given region | ||
493 | // the (very bad) assumption is that this value is being read and handled inconsistently or | ||
494 | // not at all. Current strategy is to put the code in place to support the validity of this information | ||
495 | // and to roll forward debugging any issues from that point | ||
496 | // | ||
497 | // this particular section of the mod attempts to receive a value from the region's xml file by way of | ||
498 | // OSG1GridServices for the region's owner | ||
499 | sim.owner_uuid = (UUID)(string)requestData["master_avatar_uuid"]; | ||
500 | |||
501 | try | ||
502 | { | ||
503 | sim.regionRecvKey = (string)requestData["recvkey"]; | ||
504 | sim.regionSendKey = (string)requestData["authkey"]; | ||
505 | } | ||
506 | catch (KeyNotFoundException) { } | ||
507 | |||
508 | sim.regionHandle = Utils.UIntsToLong((sim.regionLocX * Constants.RegionSize), (sim.regionLocY * Constants.RegionSize)); | ||
509 | sim.serverURI = (string)requestData["server_uri"]; | ||
510 | |||
511 | sim.httpServerURI = "http://" + sim.serverIP + ":" + sim.httpPort + "/"; | ||
512 | |||
513 | sim.regionName = (string)requestData["sim_name"]; | ||
514 | return sim; | ||
515 | } | ||
516 | |||
517 | /// <summary> | ||
518 | /// Returns an XML RPC response to a simulator profile request | ||
519 | /// Performed after moving a region. | ||
520 | /// </summary> | ||
521 | /// <param name="request"></param> | ||
522 | /// <returns></returns> | ||
523 | /// <param name="request">The XMLRPC Request</param> | ||
524 | /// <returns>Processing parameters</returns> | ||
525 | public XmlRpcResponse XmlRpcDeleteRegionMethod(XmlRpcRequest request) | ||
526 | { | ||
527 | XmlRpcResponse response = new XmlRpcResponse(); | ||
528 | Hashtable responseData = new Hashtable(); | ||
529 | response.Value = responseData; | ||
530 | |||
531 | //RegionProfileData TheSim = null; | ||
532 | string uuid; | ||
533 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
534 | |||
535 | if (requestData.ContainsKey("UUID")) | ||
536 | { | ||
537 | //TheSim = GetRegion(new UUID((string) requestData["UUID"])); | ||
538 | uuid = requestData["UUID"].ToString(); | ||
539 | m_log.InfoFormat("[LOGOUT]: Logging out region: {0}", uuid); | ||
540 | // logToDB((new LLUUID((string)requestData["UUID"])).ToString(),"XmlRpcDeleteRegionMethod","", 5,"Attempting delete with UUID."); | ||
541 | } | ||
542 | else | ||
543 | { | ||
544 | responseData["error"] = "No UUID or region_handle passed to grid server - unable to delete"; | ||
545 | return response; | ||
546 | } | ||
547 | |||
548 | DataResponse insertResponse = m_gridDBService.DeleteRegion(uuid); | ||
549 | |||
550 | string insertResp = ""; | ||
551 | switch (insertResponse) | ||
552 | { | ||
553 | case DataResponse.RESPONSE_OK: | ||
554 | //MainLog.Instance.Verbose("grid", "Deleting region successful: " + uuid); | ||
555 | insertResp = "Deleting region successful: " + uuid; | ||
556 | break; | ||
557 | case DataResponse.RESPONSE_ERROR: | ||
558 | //MainLog.Instance.Warn("storage", "Deleting region failed (Error): " + uuid); | ||
559 | insertResp = "Deleting region failed (Error): " + uuid; | ||
560 | break; | ||
561 | case DataResponse.RESPONSE_INVALIDCREDENTIALS: | ||
562 | //MainLog.Instance.Warn("storage", "Deleting region failed (Invalid Credentials): " + uuid); | ||
563 | insertResp = "Deleting region (Invalid Credentials): " + uuid; | ||
564 | break; | ||
565 | case DataResponse.RESPONSE_AUTHREQUIRED: | ||
566 | //MainLog.Instance.Warn("storage", "Deleting region failed (Authentication Required): " + uuid); | ||
567 | insertResp = "Deleting region (Authentication Required): " + uuid; | ||
568 | break; | ||
569 | } | ||
570 | |||
571 | responseData["status"] = insertResp; | ||
572 | |||
573 | return response; | ||
574 | } | ||
575 | |||
576 | /// <summary> | ||
577 | /// Returns an XML RPC response to a simulator profile request | ||
578 | /// </summary> | ||
579 | /// <param name="request"></param> | ||
580 | /// <returns></returns> | ||
581 | public XmlRpcResponse XmlRpcSimulatorDataRequestMethod(XmlRpcRequest request) | ||
582 | { | ||
583 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
584 | Hashtable responseData = new Hashtable(); | ||
585 | RegionProfileData simData = null; | ||
586 | if (requestData.ContainsKey("region_UUID")) | ||
587 | { | ||
588 | UUID regionID = new UUID((string)requestData["region_UUID"]); | ||
589 | simData = m_gridDBService.GetRegion(regionID); | ||
590 | if (simData == null) | ||
591 | { | ||
592 | m_log.WarnFormat("[DATA] didn't find region for regionID {0} from {1}", | ||
593 | regionID, request.Params.Count > 1 ? request.Params[1] : "unknwon source"); | ||
594 | } | ||
595 | } | ||
596 | else if (requestData.ContainsKey("region_handle")) | ||
597 | { | ||
598 | //CFK: The if/else below this makes this message redundant. | ||
599 | //CFK: Console.WriteLine("requesting data for region " + (string) requestData["region_handle"]); | ||
600 | ulong regionHandle = Convert.ToUInt64((string)requestData["region_handle"]); | ||
601 | simData = m_gridDBService.GetRegion(regionHandle); | ||
602 | if (simData == null) | ||
603 | { | ||
604 | m_log.WarnFormat("[DATA] didn't find region for regionHandle {0} from {1}", | ||
605 | regionHandle, request.Params.Count > 1 ? request.Params[1] : "unknwon source"); | ||
606 | } | ||
607 | } | ||
608 | else if (requestData.ContainsKey("region_name_search")) | ||
609 | { | ||
610 | string regionName = (string)requestData["region_name_search"]; | ||
611 | simData = m_gridDBService.GetRegion(regionName); | ||
612 | if (simData == null) | ||
613 | { | ||
614 | m_log.WarnFormat("[DATA] didn't find region for regionName {0} from {1}", | ||
615 | regionName, request.Params.Count > 1 ? request.Params[1] : "unknwon source"); | ||
616 | } | ||
617 | } | ||
618 | else m_log.Warn("[DATA] regionlookup without regionID, regionHandle or regionHame"); | ||
619 | |||
620 | if (simData == null) | ||
621 | { | ||
622 | //Sim does not exist | ||
623 | responseData["error"] = "Sim does not exist"; | ||
624 | } | ||
625 | else | ||
626 | { | ||
627 | m_log.Info("[DATA]: found " + (string)simData.regionName + " regionHandle = " + | ||
628 | (string)requestData["region_handle"]); | ||
629 | responseData["sim_ip"] = simData.serverIP; | ||
630 | responseData["sim_port"] = simData.serverPort.ToString(); | ||
631 | responseData["server_uri"] = simData.serverURI; | ||
632 | responseData["http_port"] = simData.httpPort.ToString(); | ||
633 | responseData["remoting_port"] = simData.remotingPort.ToString(); | ||
634 | responseData["region_locx"] = simData.regionLocX.ToString(); | ||
635 | responseData["region_locy"] = simData.regionLocY.ToString(); | ||
636 | responseData["region_UUID"] = simData.UUID.Guid.ToString(); | ||
637 | responseData["region_name"] = simData.regionName; | ||
638 | responseData["regionHandle"] = simData.regionHandle.ToString(); | ||
639 | } | ||
640 | |||
641 | XmlRpcResponse response = new XmlRpcResponse(); | ||
642 | response.Value = responseData; | ||
643 | return response; | ||
644 | } | ||
645 | |||
646 | public XmlRpcResponse XmlRpcMapBlockMethod(XmlRpcRequest request) | ||
647 | { | ||
648 | int xmin = 980, ymin = 980, xmax = 1020, ymax = 1020; | ||
649 | |||
650 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
651 | if (requestData.ContainsKey("xmin")) | ||
652 | { | ||
653 | xmin = (Int32)requestData["xmin"]; | ||
654 | } | ||
655 | if (requestData.ContainsKey("ymin")) | ||
656 | { | ||
657 | ymin = (Int32)requestData["ymin"]; | ||
658 | } | ||
659 | if (requestData.ContainsKey("xmax")) | ||
660 | { | ||
661 | xmax = (Int32)requestData["xmax"]; | ||
662 | } | ||
663 | if (requestData.ContainsKey("ymax")) | ||
664 | { | ||
665 | ymax = (Int32)requestData["ymax"]; | ||
666 | } | ||
667 | //CFK: The second log is more meaningful and either standard or fast generally occurs. | ||
668 | //CFK: m_log.Info("[MAP]: World map request for range (" + xmin + "," + ymin + ")..(" + xmax + "," + ymax + ")"); | ||
669 | |||
670 | XmlRpcResponse response = new XmlRpcResponse(); | ||
671 | Hashtable responseData = new Hashtable(); | ||
672 | response.Value = responseData; | ||
673 | IList simProfileList = new ArrayList(); | ||
674 | |||
675 | bool fastMode = (m_config.DatabaseProvider == "OpenSim.Data.MySQL.dll" || m_config.DatabaseProvider == "OpenSim.Data.MSSQL.dll"); | ||
676 | |||
677 | if (fastMode) | ||
678 | { | ||
679 | List<RegionProfileData> neighbours = m_gridDBService.GetRegions((uint)xmin, (uint)ymin, (uint)xmax, (uint)ymax); | ||
680 | |||
681 | foreach (RegionProfileData aSim in neighbours) | ||
682 | { | ||
683 | Hashtable simProfileBlock = new Hashtable(); | ||
684 | simProfileBlock["x"] = aSim.regionLocX.ToString(); | ||
685 | simProfileBlock["y"] = aSim.regionLocY.ToString(); | ||
686 | //m_log.DebugFormat("[MAP]: Sending neighbour info for {0},{1}", aSim.regionLocX, aSim.regionLocY); | ||
687 | simProfileBlock["name"] = aSim.regionName; | ||
688 | simProfileBlock["access"] = 21; | ||
689 | simProfileBlock["region-flags"] = 512; | ||
690 | simProfileBlock["water-height"] = 0; | ||
691 | simProfileBlock["agents"] = 1; | ||
692 | simProfileBlock["map-image-id"] = aSim.regionMapTextureID.ToString(); | ||
693 | |||
694 | // For Sugilite compatibility | ||
695 | simProfileBlock["regionhandle"] = aSim.regionHandle.ToString(); | ||
696 | simProfileBlock["sim_ip"] = aSim.serverIP; | ||
697 | simProfileBlock["sim_port"] = aSim.serverPort.ToString(); | ||
698 | simProfileBlock["sim_uri"] = aSim.serverURI.ToString(); | ||
699 | simProfileBlock["uuid"] = aSim.UUID.ToString(); | ||
700 | simProfileBlock["remoting_port"] = aSim.remotingPort.ToString(); | ||
701 | simProfileBlock["http_port"] = aSim.httpPort.ToString(); | ||
702 | |||
703 | simProfileList.Add(simProfileBlock); | ||
704 | } | ||
705 | m_log.Info("[MAP]: Fast map " + simProfileList.Count.ToString() + | ||
706 | " regions @ (" + xmin + "," + ymin + ")..(" + xmax + "," + ymax + ")"); | ||
707 | } | ||
708 | else | ||
709 | { | ||
710 | RegionProfileData simProfile; | ||
711 | for (int x = xmin; x < xmax + 1; x++) | ||
712 | { | ||
713 | for (int y = ymin; y < ymax + 1; y++) | ||
714 | { | ||
715 | ulong regHandle = Utils.UIntsToLong((uint)(x * Constants.RegionSize), (uint)(y * Constants.RegionSize)); | ||
716 | simProfile = m_gridDBService.GetRegion(regHandle); | ||
717 | if (simProfile != null) | ||
718 | { | ||
719 | Hashtable simProfileBlock = new Hashtable(); | ||
720 | simProfileBlock["x"] = x; | ||
721 | simProfileBlock["y"] = y; | ||
722 | simProfileBlock["name"] = simProfile.regionName; | ||
723 | simProfileBlock["access"] = 0; | ||
724 | simProfileBlock["region-flags"] = 0; | ||
725 | simProfileBlock["water-height"] = 20; | ||
726 | simProfileBlock["agents"] = 1; | ||
727 | simProfileBlock["map-image-id"] = simProfile.regionMapTextureID.ToString(); | ||
728 | |||
729 | // For Sugilite compatibility | ||
730 | simProfileBlock["regionhandle"] = simProfile.regionHandle.ToString(); | ||
731 | simProfileBlock["sim_ip"] = simProfile.serverIP.ToString(); | ||
732 | simProfileBlock["sim_port"] = simProfile.serverPort.ToString(); | ||
733 | simProfileBlock["sim_uri"] = simProfile.serverURI.ToString(); | ||
734 | simProfileBlock["uuid"] = simProfile.UUID.ToString(); | ||
735 | simProfileBlock["remoting_port"] = simProfile.remotingPort.ToString(); | ||
736 | simProfileBlock["http_port"] = simProfile.httpPort; | ||
737 | |||
738 | simProfileList.Add(simProfileBlock); | ||
739 | } | ||
740 | } | ||
741 | } | ||
742 | m_log.Info("[MAP]: Std map " + simProfileList.Count.ToString() + | ||
743 | " regions @ (" + xmin + "," + ymin + ")..(" + xmax + "," + ymax + ")"); | ||
744 | } | ||
745 | |||
746 | responseData["sim-profiles"] = simProfileList; | ||
747 | |||
748 | return response; | ||
749 | } | ||
750 | |||
751 | /// <summary> | ||
752 | /// Returns up to <code>maxNumber</code> profiles of regions that have a name starting with <code>name</code> | ||
753 | /// </summary> | ||
754 | /// <param name="request"></param> | ||
755 | /// <returns></returns> | ||
756 | public XmlRpcResponse XmlRpcSearchForRegionMethod(XmlRpcRequest request) | ||
757 | { | ||
758 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
759 | |||
760 | if (!requestData.ContainsKey("name") || !requestData.Contains("maxNumber")) | ||
761 | { | ||
762 | m_log.Warn("[DATA] Invalid region-search request; missing name or maxNumber"); | ||
763 | return new XmlRpcResponse(500, "Missing name or maxNumber in region search request"); | ||
764 | } | ||
765 | |||
766 | Hashtable responseData = new Hashtable(); | ||
767 | |||
768 | string name = (string)requestData["name"]; | ||
769 | int maxNumber = Convert.ToInt32((string)requestData["maxNumber"]); | ||
770 | if (maxNumber == 0 || name.Length < 3) | ||
771 | { | ||
772 | // either we didn't want any, or we were too unspecific | ||
773 | responseData["numFound"] = 0; | ||
774 | } | ||
775 | else | ||
776 | { | ||
777 | List<RegionProfileData> sims = m_gridDBService.GetRegions(name, maxNumber); | ||
778 | |||
779 | responseData["numFound"] = sims.Count; | ||
780 | for (int i = 0; i < sims.Count; ++i) | ||
781 | { | ||
782 | RegionProfileData sim = sims[i]; | ||
783 | string prefix = "region" + i + "."; | ||
784 | responseData[prefix + "region_name"] = sim.regionName; | ||
785 | responseData[prefix + "region_UUID"] = sim.UUID.ToString(); | ||
786 | responseData[prefix + "region_locx"] = sim.regionLocX.ToString(); | ||
787 | responseData[prefix + "region_locy"] = sim.regionLocY.ToString(); | ||
788 | responseData[prefix + "sim_ip"] = sim.serverIP.ToString(); | ||
789 | responseData[prefix + "sim_port"] = sim.serverPort.ToString(); | ||
790 | responseData[prefix + "remoting_port"] = sim.remotingPort.ToString(); | ||
791 | responseData[prefix + "http_port"] = sim.httpPort.ToString(); | ||
792 | responseData[prefix + "map_UUID"] = sim.regionMapTextureID.ToString(); | ||
793 | } | ||
794 | } | ||
795 | |||
796 | XmlRpcResponse response = new XmlRpcResponse(); | ||
797 | response.Value = responseData; | ||
798 | return response; | ||
799 | } | ||
800 | |||
801 | /// <summary> | ||
802 | /// Construct an XMLRPC registration disabled response | ||
803 | /// </summary> | ||
804 | /// <param name="error"></param> | ||
805 | /// <returns></returns> | ||
806 | public static XmlRpcResponse XmlRPCRegionRegistrationDisabledResponse(string error) | ||
807 | { | ||
808 | XmlRpcResponse errorResponse = new XmlRpcResponse(); | ||
809 | Hashtable errorResponseData = new Hashtable(); | ||
810 | errorResponse.Value = errorResponseData; | ||
811 | errorResponseData["restricted"] = error; | ||
812 | return errorResponse; | ||
813 | } | ||
814 | } | ||
815 | |||
816 | /// <summary> | ||
817 | /// Exception generated when a simulator fails to login to the grid | ||
818 | /// </summary> | ||
819 | public class LoginException : Exception | ||
820 | { | ||
821 | /// <summary> | ||
822 | /// Return an XmlRpcResponse version of the exception message suitable for sending to a client | ||
823 | /// </summary> | ||
824 | /// <param name="message"></param> | ||
825 | /// <param name="xmlRpcMessage"></param> | ||
826 | public XmlRpcResponse XmlRpcErrorResponse | ||
827 | { | ||
828 | get { return m_xmlRpcErrorResponse; } | ||
829 | } | ||
830 | private XmlRpcResponse m_xmlRpcErrorResponse; | ||
831 | |||
832 | public LoginException(string message, string xmlRpcMessage) : base(message) | ||
833 | { | ||
834 | // FIXME: Might be neater to refactor and put the method inside here | ||
835 | m_xmlRpcErrorResponse = GridXmlRpcModule.ErrorResponse(xmlRpcMessage); | ||
836 | } | ||
837 | |||
838 | public LoginException(string message, string xmlRpcMessage, Exception e) : base(message, e) | ||
839 | { | ||
840 | // FIXME: Might be neater to refactor and put the method inside here | ||
841 | m_xmlRpcErrorResponse = GridXmlRpcModule.ErrorResponse(xmlRpcMessage); | ||
842 | } | ||
843 | } | ||
844 | } | ||