aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs')
-rw-r--r--OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs560
1 files changed, 560 insertions, 0 deletions
diff --git a/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs
new file mode 100644
index 0000000..0c2a835
--- /dev/null
+++ b/OpenSim/Region/CoreModules/ServiceConnectorsOut/Grid/HGGridConnector.cs
@@ -0,0 +1,560 @@
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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using System.Net;
31using System.Reflection;
32using System.Xml;
33
34using OpenSim.Framework;
35using OpenSim.Region.Framework.Interfaces;
36using OpenSim.Region.Framework.Scenes;
37using OpenSim.Region.Framework.Scenes.Hypergrid;
38using OpenSim.Services.Interfaces;
39using GridRegion = OpenSim.Services.Interfaces.GridRegion;
40using OpenSim.Server.Base;
41using OpenSim.Services.Connectors.Grid;
42using OpenSim.Framework.Console;
43
44using OpenMetaverse;
45using log4net;
46using Nini.Config;
47
48namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Grid
49{
50 public class HGGridConnector : ISharedRegionModule, IGridService
51 {
52 private static readonly ILog m_log =
53 LogManager.GetLogger(
54 MethodBase.GetCurrentMethod().DeclaringType);
55
56 private bool m_Enabled = false;
57 private bool m_Initialized = false;
58
59 private IGridService m_GridServiceConnector;
60 private HypergridServiceConnector m_HypergridServiceConnector;
61
62 // Hyperlink regions are hyperlinks on the map
63 protected Dictionary<UUID, GridRegion> m_HyperlinkRegions = new Dictionary<UUID, GridRegion>();
64
65 // Known regions are home regions of visiting foreign users.
66 // They are not on the map as static hyperlinks. They are dynamic hyperlinks, they go away when
67 // the visitor goes away. They are mapped to X=0 on the map.
68 // This is key-ed on agent ID
69 protected Dictionary<UUID, GridRegion> m_knownRegions = new Dictionary<UUID, GridRegion>();
70
71 protected Dictionary<UUID, ulong> m_HyperlinkHandles = new Dictionary<UUID, ulong>();
72
73 #region ISharedRegionModule
74
75 public Type ReplaceableInterface
76 {
77 get { return null; }
78 }
79
80 public string Name
81 {
82 get { return "HGGridServicesConnector"; }
83 }
84
85 public void Initialise(IConfigSource source)
86 {
87 IConfig moduleConfig = source.Configs["Modules"];
88 if (moduleConfig != null)
89 {
90 string name = moduleConfig.GetString("GridServices", "");
91 if (name == Name)
92 {
93 IConfig gridConfig = source.Configs["GridService"];
94 if (gridConfig == null)
95 {
96 m_log.Error("[HGGRID CONNECTOR]: GridService missing from OpenSim.ini");
97 return;
98 }
99
100
101 InitialiseConnectorModule(source);
102
103 m_Enabled = true;
104 m_log.Info("[HGGRID CONNECTOR]: HG grid enabled");
105 }
106 }
107 }
108
109 private void InitialiseConnectorModule(IConfigSource source)
110 {
111 IConfig gridConfig = source.Configs["GridService"];
112 if (gridConfig == null)
113 {
114 m_log.Error("[HGGRID CONNECTOR]: GridService missing from OpenSim.ini");
115 throw new Exception("Grid connector init error");
116 }
117
118 string module = gridConfig.GetString("GridServiceConnectorModule", String.Empty);
119 if (module == String.Empty)
120 {
121 m_log.Error("[HGGRID CONNECTOR]: No GridServiceConnectorModule named in section GridService");
122 //return;
123 throw new Exception("Unable to proceed. Please make sure your ini files in config-include are updated according to .example's");
124 }
125
126 Object[] args = new Object[] { source };
127 m_GridServiceConnector = ServerUtils.LoadPlugin<IGridService>(module, args);
128
129 }
130
131 public void PostInitialise()
132 {
133 }
134
135 public void Close()
136 {
137 }
138
139 public void AddRegion(Scene scene)
140 {
141 if (!m_Enabled)
142 return;
143
144 scene.RegisterModuleInterface<IGridService>(this);
145
146 }
147
148 public void RemoveRegion(Scene scene)
149 {
150 }
151
152 public void RegionLoaded(Scene scene)
153 {
154 if (!m_Enabled)
155 return;
156
157 if (!m_Initialized)
158 {
159 m_HypergridServiceConnector = new HypergridServiceConnector(scene.AssetService);
160 HGCommands hgCommands = new HGCommands(this, scene);
161 MainConsole.Instance.Commands.AddCommand("HGGridServicesConnector", false, "linkk-region",
162 "link-region <Xloc> <Yloc> <HostName>:<HttpPort>[:<RemoteRegionName>] <cr>",
163 "Link a hypergrid region", hgCommands.RunCommand);
164 MainConsole.Instance.Commands.AddCommand("HGGridServicesConnector", false, "unlinkk-region",
165 "unlink-region <local name> or <HostName>:<HttpPort> <cr>",
166 "Unlink a hypergrid region", hgCommands.RunCommand);
167 MainConsole.Instance.Commands.AddCommand("HGGridServicesConnector", false, "linkk-mapping", "link-mapping [<x> <y>] <cr>",
168 "Set local coordinate to map HG regions to", hgCommands.RunCommand);
169 m_Initialized = true;
170 }
171
172
173 //scene.AddCommand("HGGridServicesConnector", "linkk-region",
174 // "link-region <Xloc> <Yloc> <HostName>:<HttpPort>[:<RemoteRegionName>] <cr>",
175 // "Link a hypergrid region", hgCommands.RunCommand);
176 //scene.AddCommand("HGGridServicesConnector", "unlinkk-region",
177 // "unlink-region <local name> or <HostName>:<HttpPort> <cr>",
178 // "Unlink a hypergrid region", hgCommands.RunCommand);
179 //scene.AddCommand("HGGridServicesConnector", "linkk-mapping", "link-mapping [<x> <y>] <cr>",
180 // "Set local coordinate to map HG regions to", hgCommands.RunCommand);
181
182 }
183
184 #endregion
185
186 #region IGridService
187
188 public bool RegisterRegion(UUID scopeID, GridRegion regionInfo)
189 {
190 // Region doesn't exist here. Trying to link remote region
191 if (regionInfo.RegionID.Equals(UUID.Zero))
192 {
193 m_log.Info("[HGrid]: Linking remote region " + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort);
194 ulong regionHandle = 0;
195 regionInfo.RegionID = m_HypergridServiceConnector.LinkRegion(regionInfo, out regionHandle);
196 if (!regionInfo.RegionID.Equals(UUID.Zero))
197 {
198 AddHyperlinkRegion(regionInfo, regionHandle);
199 m_log.Info("[HGrid]: Successfully linked to region_uuid " + regionInfo.RegionID);
200
201 // Try get the map image
202 m_HypergridServiceConnector.GetMapImage(regionInfo);
203 return true;
204 }
205 else
206 {
207 m_log.Info("[HGrid]: No such region " + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort + "(" + regionInfo.InternalEndPoint.Port + ")");
208 return false;
209 }
210 // Note that these remote regions aren't registered in localBackend, so return null, no local listeners
211 }
212 else // normal grid
213 return m_GridServiceConnector.RegisterRegion(scopeID, regionInfo);
214 }
215
216 public bool DeregisterRegion(UUID regionID)
217 {
218 // Try the hyperlink collection
219 if (m_HyperlinkRegions.ContainsKey(regionID))
220 {
221 RemoveHyperlinkRegion(regionID);
222 return true;
223 }
224 // Try the foreign users home collection
225
226 foreach (GridRegion r in m_knownRegions.Values)
227 if (r.RegionID == regionID)
228 {
229 RemoveHyperlinkHomeRegion(regionID);
230 return true;
231 }
232
233 // Finally, try the normal route
234 return m_GridServiceConnector.DeregisterRegion(regionID);
235 }
236
237 public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID)
238 {
239 // No serving neighbours on hyperliked regions.
240 // Just the regular regions.
241 return m_GridServiceConnector.GetNeighbours(scopeID, regionID);
242 }
243
244 public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID)
245 {
246 // Try the hyperlink collection
247 if (m_HyperlinkRegions.ContainsKey(regionID))
248 return m_HyperlinkRegions[regionID];
249
250 // Try the foreign users home collection
251 foreach (GridRegion r in m_knownRegions.Values)
252 if (r.RegionID == regionID)
253 return m_knownRegions[regionID];
254
255 // Finally, try the normal route
256 return m_GridServiceConnector.GetRegionByUUID(scopeID, regionID);
257 }
258
259 public GridRegion GetRegionByPosition(UUID scopeID, int x, int y)
260 {
261 int snapX = (int) (x / Constants.RegionSize) * (int)Constants.RegionSize;
262 int snapY = (int) (y / Constants.RegionSize) * (int)Constants.RegionSize;
263 // Try the hyperlink collection
264 foreach (GridRegion r in m_HyperlinkRegions.Values)
265 {
266 if ((r.RegionLocX == snapX) && (r.RegionLocY == snapY))
267 return r;
268 }
269
270 // Try the foreign users home collection
271 foreach (GridRegion r in m_knownRegions.Values)
272 {
273 if ((r.RegionLocX == snapX) && (r.RegionLocY == snapY))
274 return r;
275 }
276
277 // Finally, try the normal route
278 return m_GridServiceConnector.GetRegionByPosition(scopeID, x, y);
279 }
280
281 public GridRegion GetRegionByName(UUID scopeID, string regionName)
282 {
283 // Try normal grid first
284 GridRegion region = m_GridServiceConnector.GetRegionByName(scopeID, regionName);
285 if (region != null)
286 return region;
287
288 // Try the hyperlink collection
289 foreach (GridRegion r in m_HyperlinkRegions.Values)
290 {
291 if (r.RegionName == regionName)
292 return r;
293 }
294
295 // Try the foreign users home collection
296 foreach (GridRegion r in m_knownRegions.Values)
297 {
298 if (r.RegionName == regionName)
299 return r;
300 }
301 return null;
302 }
303
304 public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber)
305 {
306 List<GridRegion> rinfos = new List<GridRegion>();
307
308 // Commenting until regionname exists
309 //foreach (SimpleRegionInfo r in m_HyperlinkRegions.Values)
310 // if ((r.RegionName != null) && r.RegionName.StartsWith(name))
311 // rinfos.Add(r);
312
313 rinfos.AddRange(m_GridServiceConnector.GetRegionsByName(scopeID, name, maxNumber));
314 return rinfos;
315 }
316
317 public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax)
318 {
319 int snapXmin = (int)(xmin / Constants.RegionSize) * (int)Constants.RegionSize;
320 int snapXmax = (int)(xmax / Constants.RegionSize) * (int)Constants.RegionSize;
321 int snapYmin = (int)(ymin / Constants.RegionSize) * (int)Constants.RegionSize;
322 int snapYmax = (int)(ymax / Constants.RegionSize) * (int)Constants.RegionSize;
323
324 List<GridRegion> rinfos = new List<GridRegion>();
325 foreach (GridRegion r in m_HyperlinkRegions.Values)
326 if ((r.RegionLocX > snapXmin) && (r.RegionLocX < snapYmax) &&
327 (r.RegionLocY > snapYmin) && (r.RegionLocY < snapYmax))
328 rinfos.Add(r);
329
330 rinfos.AddRange(m_GridServiceConnector.GetRegionRange(scopeID, xmin, xmax, ymin, ymax));
331
332 return rinfos;
333 }
334
335 #endregion
336
337 #region Auxiliary
338
339 private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle)
340 {
341 m_HyperlinkRegions.Add(regionInfo.RegionID, regionInfo);
342 m_HyperlinkHandles.Add(regionInfo.RegionID, regionHandle);
343 }
344
345 private void RemoveHyperlinkRegion(UUID regionID)
346 {
347 m_HyperlinkRegions.Remove(regionID);
348 m_HyperlinkHandles.Remove(regionID);
349 }
350
351 private void AddHyperlinkHomeRegion(UUID userID, GridRegion regionInfo, ulong regionHandle)
352 {
353 m_knownRegions.Add(userID, regionInfo);
354 m_HyperlinkHandles.Add(regionInfo.RegionID, regionHandle);
355 }
356
357 private void RemoveHyperlinkHomeRegion(UUID regionID)
358 {
359 foreach (KeyValuePair<UUID, GridRegion> kvp in m_knownRegions)
360 {
361 if (kvp.Value.RegionID == regionID)
362 {
363 m_knownRegions.Remove(kvp.Key);
364 }
365 }
366 m_HyperlinkHandles.Remove(regionID);
367 }
368 #endregion
369
370 #region Hyperlinks
371
372 private static Random random = new Random();
373
374 public GridRegion TryLinkRegionToCoords(Scene m_scene, IClientAPI client, string mapName, int xloc, int yloc)
375 {
376 string host = "127.0.0.1";
377 string portstr;
378 string regionName = "";
379 uint port = 9000;
380 string[] parts = mapName.Split(new char[] { ':' });
381 if (parts.Length >= 1)
382 {
383 host = parts[0];
384 }
385 if (parts.Length >= 2)
386 {
387 portstr = parts[1];
388 if (!UInt32.TryParse(portstr, out port))
389 regionName = parts[1];
390 }
391 // always take the last one
392 if (parts.Length >= 3)
393 {
394 regionName = parts[2];
395 }
396
397 // Sanity check. Don't ever link to this sim.
398 IPAddress ipaddr = null;
399 try
400 {
401 ipaddr = Util.GetHostFromDNS(host);
402 }
403 catch { }
404
405 if ((ipaddr != null) &&
406 !((m_scene.RegionInfo.ExternalEndPoint.Address.Equals(ipaddr)) && (m_scene.RegionInfo.HttpPort == port)))
407 {
408 GridRegion regInfo;
409 bool success = TryCreateLink(m_scene, client, xloc, yloc, regionName, port, host, out regInfo);
410 if (success)
411 {
412 regInfo.RegionName = mapName;
413 return regInfo;
414 }
415 }
416
417 return null;
418 }
419
420 // From the map search and secondlife://blah
421 public GridRegion TryLinkRegion(Scene m_scene, IClientAPI client, string mapName)
422 {
423 int xloc = random.Next(0, Int16.MaxValue);
424 return TryLinkRegionToCoords(m_scene, client, mapName, xloc, 0);
425 }
426
427 public bool TryCreateLink(Scene m_scene, IClientAPI client, int xloc, int yloc,
428 string externalRegionName, uint externalPort, string externalHostName, out GridRegion regInfo)
429 {
430 m_log.DebugFormat("[HGrid]: Link to {0}:{1}, in {2}-{3}", externalHostName, externalPort, xloc, yloc);
431
432 regInfo = new GridRegion();
433 regInfo.RegionName = externalRegionName;
434 regInfo.HttpPort = externalPort;
435 regInfo.ExternalHostName = externalHostName;
436 regInfo.RegionLocX = xloc;
437 regInfo.RegionLocY = yloc;
438
439 try
440 {
441 regInfo.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), (int)0);
442 }
443 catch (Exception e)
444 {
445 m_log.Warn("[HGrid]: Wrong format for link-region: " + e.Message);
446 return false;
447 }
448
449 // Finally, link it
450 try
451 {
452 RegisterRegion(UUID.Zero, regInfo);
453 }
454 catch (Exception e)
455 {
456 m_log.Warn("[HGrid]: Unable to link region: " + e.Message);
457 return false;
458 }
459
460 int x, y;
461 if (!Check4096(m_scene, regInfo, out x, out y))
462 {
463 DeregisterRegion(regInfo.RegionID);
464 if (client != null)
465 client.SendAlertMessage("Region is too far (" + x + ", " + y + ")");
466 m_log.Info("[HGrid]: Unable to link, region is too far (" + x + ", " + y + ")");
467 return false;
468 }
469
470 if (!CheckCoords(m_scene.RegionInfo.RegionLocX, m_scene.RegionInfo.RegionLocY, x, y))
471 {
472 DeregisterRegion(regInfo.RegionID);
473 if (client != null)
474 client.SendAlertMessage("Region has incompatible coordinates (" + x + ", " + y + ")");
475 m_log.Info("[HGrid]: Unable to link, region has incompatible coordinates (" + x + ", " + y + ")");
476 return false;
477 }
478
479 m_log.Debug("[HGrid]: link region succeeded");
480 return true;
481 }
482
483 public bool TryUnlinkRegion(Scene m_scene, string mapName)
484 {
485 GridRegion regInfo = null;
486 if (mapName.Contains(":"))
487 {
488 string host = "127.0.0.1";
489 //string portstr;
490 //string regionName = "";
491 uint port = 9000;
492 string[] parts = mapName.Split(new char[] { ':' });
493 if (parts.Length >= 1)
494 {
495 host = parts[0];
496 }
497 // if (parts.Length >= 2)
498 // {
499 // portstr = parts[1];
500 // if (!UInt32.TryParse(portstr, out port))
501 // regionName = parts[1];
502 // }
503 // always take the last one
504 // if (parts.Length >= 3)
505 // {
506 // regionName = parts[2];
507 // }
508 foreach (GridRegion r in m_HyperlinkRegions.Values)
509 if (host.Equals(r.ExternalHostName) && (port == r.HttpPort))
510 regInfo = r;
511 }
512 else
513 {
514 foreach (GridRegion r in m_HyperlinkRegions.Values)
515 if (r.RegionName.Equals(mapName))
516 regInfo = r;
517 }
518 if (regInfo != null)
519 {
520 return DeregisterRegion(regInfo.RegionID);
521 }
522 else
523 {
524 m_log.InfoFormat("[HGrid]: Region {0} not found", mapName);
525 return false;
526 }
527 }
528
529 /// <summary>
530 /// Cope with this viewer limitation.
531 /// </summary>
532 /// <param name="regInfo"></param>
533 /// <returns></returns>
534 public bool Check4096(Scene m_scene, GridRegion regInfo, out int x, out int y)
535 {
536 ulong realHandle = m_HyperlinkHandles[regInfo.RegionID];
537 uint ux = 0, uy = 0;
538 Utils.LongToUInts(realHandle, out ux, out uy);
539 x = (int)(ux / Constants.RegionSize);
540 y = (int)(uy / Constants.RegionSize);
541
542 if ((Math.Abs((int)(m_scene.RegionInfo.RegionLocX / Constants.RegionSize) - x) >= 4096) ||
543 (Math.Abs((int)(m_scene.RegionInfo.RegionLocY / Constants.RegionSize) - y) >= 4096))
544 {
545 return false;
546 }
547 return true;
548 }
549
550 public bool CheckCoords(uint thisx, uint thisy, int x, int y)
551 {
552 if ((thisx == x) && (thisy == y))
553 return false;
554 return true;
555 }
556
557 #endregion
558
559 }
560}