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