clockwerk-opensim – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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  
28 using System;
29 using System.Collections.Generic;
30 using System.IO;
31 using System.Linq;
32 using System.Net;
33 using System.Reflection;
34 using System.Text;
35 using log4net;
36 using Nini.Config;
37 using OpenMetaverse;
38 using OpenSim.Framework;
39 using OpenSim.Framework.Communications;
40 using OpenSim.Framework.Console;
41 using OpenSim.Framework.Servers;
42 using OpenSim.Framework.Servers.HttpServer;
43 using OpenSim.Framework.Monitoring;
44 using OpenSim.Region.ClientStack;
45 using OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts;
46 using OpenSim.Region.Framework;
47 using OpenSim.Region.Framework.Interfaces;
48 using OpenSim.Region.Framework.Scenes;
49 using OpenSim.Region.Physics.Manager;
50 using OpenSim.Server.Base;
51 using OpenSim.Services.Base;
52 using OpenSim.Services.Interfaces;
53 using OpenSim.Services.UserAccountService;
54  
55 namespace OpenSim
56 {
57 /// <summary>
58 /// Common OpenSimulator simulator code
59 /// </summary>
60 public class OpenSimBase : RegionApplicationBase
61 {
62 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
63  
64 // These are the names of the plugin-points extended by this
65 // class during system startup.
66 //
67  
68 private const string PLUGIN_ASSET_CACHE = "/OpenSim/AssetCache";
69 private const string PLUGIN_ASSET_SERVER_CLIENT = "/OpenSim/AssetClient";
70  
71 // OpenSim.ini Section name for ESTATES Settings
72 public const string ESTATE_SECTION_NAME = "Estates";
73  
74 /// <summary>
75 /// Allow all plugin loading to be disabled for tests/debug.
76 /// </summary>
77 /// <remarks>
78 /// true by default
79 /// </remarks>
80 public bool EnableInitialPluginLoad { get; set; }
81  
82 /// <summary>
83 /// Control whether we attempt to load an estate data service.
84 /// </summary>
85 /// <remarks>For tests/debugging</remarks>
86 public bool LoadEstateDataService { get; set; }
87  
88 protected string proxyUrl;
89 protected int proxyOffset = 0;
90  
91 public string userStatsURI = String.Empty;
92 public string managedStatsURI = String.Empty;
93  
94 protected bool m_autoCreateClientStack = true;
95  
96 /// <value>
97 /// The file used to load and save prim backup xml if no filename has been specified
98 /// </value>
99 protected const string DEFAULT_PRIM_BACKUP_FILENAME = "prim-backup.xml";
100  
101 public ConfigSettings ConfigurationSettings
102 {
103 get { return m_configSettings; }
104 set { m_configSettings = value; }
105 }
106  
107 protected ConfigSettings m_configSettings;
108  
109 protected ConfigurationLoader m_configLoader;
110  
111 public ConsoleCommand CreateAccount = null;
112  
113 public List<IApplicationPlugin> m_plugins = new List<IApplicationPlugin>();
114  
115 /// <value>
116 /// The config information passed into the OpenSimulator region server.
117 /// </value>
118 public OpenSimConfigSource ConfigSource { get; private set; }
119  
120 public List<IClientNetworkServer> ClientServers
121 {
122 get { return m_clientServers; }
123 }
124  
125 protected EnvConfigSource m_EnvConfigSource = new EnvConfigSource();
126  
127 public EnvConfigSource envConfigSource
128 {
129 get { return m_EnvConfigSource; }
130 }
131  
132 protected List<IClientNetworkServer> m_clientServers = new List<IClientNetworkServer>();
133  
134 public uint HttpServerPort
135 {
136 get { return m_httpServerPort; }
137 }
138  
139 protected IRegistryCore m_applicationRegistry = new RegistryCore();
140  
141 public IRegistryCore ApplicationRegistry
142 {
143 get { return m_applicationRegistry; }
144 }
145  
146 /// <summary>
147 /// Constructor.
148 /// </summary>
149 /// <param name="configSource"></param>
150 public OpenSimBase(IConfigSource configSource) : base()
151 {
152 EnableInitialPluginLoad = true;
153 LoadEstateDataService = true;
154 LoadConfigSettings(configSource);
155 }
156  
157 protected virtual void LoadConfigSettings(IConfigSource configSource)
158 {
159 m_configLoader = new ConfigurationLoader();
160 ConfigSource = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
161 Config = ConfigSource.Source;
162 ReadExtraConfigSettings();
163 }
164  
165 protected virtual void ReadExtraConfigSettings()
166 {
167 IConfig networkConfig = Config.Configs["Network"];
168 if (networkConfig != null)
169 {
170 proxyUrl = networkConfig.GetString("proxy_url", "");
171 proxyOffset = Int32.Parse(networkConfig.GetString("proxy_offset", "0"));
172 }
173  
174 IConfig startupConfig = Config.Configs["Startup"];
175 if (startupConfig != null)
176 {
177 Util.LogOverloads = startupConfig.GetBoolean("LogOverloads", true);
178 }
179 }
180  
181 protected virtual void LoadPlugins()
182 {
183 IConfig startupConfig = Config.Configs["Startup"];
184 string registryLocation = (startupConfig != null) ? startupConfig.GetString("RegistryLocation", String.Empty) : String.Empty;
185  
186 // The location can also be specified in the environment. If there
187 // is no location in the configuration, we must call the constructor
188 // without a location parameter to allow that to happen.
189 if (registryLocation == String.Empty)
190 {
191 using (PluginLoader<IApplicationPlugin> loader = new PluginLoader<IApplicationPlugin>(new ApplicationPluginInitialiser(this)))
192 {
193 loader.Load("/OpenSim/Startup");
194 m_plugins = loader.Plugins;
195 }
196 }
197 else
198 {
199 using (PluginLoader<IApplicationPlugin> loader = new PluginLoader<IApplicationPlugin>(new ApplicationPluginInitialiser(this), registryLocation))
200 {
201 loader.Load("/OpenSim/Startup");
202 m_plugins = loader.Plugins;
203 }
204 }
205 }
206  
207 protected override List<string> GetHelpTopics()
208 {
209 List<string> topics = base.GetHelpTopics();
210 Scene s = SceneManager.CurrentOrFirstScene;
211 if (s != null && s.GetCommanders() != null)
212 topics.AddRange(s.GetCommanders().Keys);
213  
214 return topics;
215 }
216  
217 /// <summary>
218 /// Performs startup specific to the region server, including initialization of the scene
219 /// such as loading configuration from disk.
220 /// </summary>
221 protected override void StartupSpecific()
222 {
223 IConfig startupConfig = Config.Configs["Startup"];
224 if (startupConfig != null)
225 {
226 string pidFile = startupConfig.GetString("PIDFile", String.Empty);
227 if (pidFile != String.Empty)
228 CreatePIDFile(pidFile);
229  
230 userStatsURI = startupConfig.GetString("Stats_URI", String.Empty);
231 managedStatsURI = startupConfig.GetString("ManagedStatsRemoteFetchURI", String.Empty);
232 }
233  
234 // Load the simulation data service
235 IConfig simDataConfig = Config.Configs["SimulationDataStore"];
236 if (simDataConfig == null)
237 throw new Exception("Configuration file is missing the [SimulationDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
238  
239 string module = simDataConfig.GetString("LocalServiceModule", String.Empty);
240 if (String.IsNullOrEmpty(module))
241 throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [SimulationDataStore] section.");
242  
243 m_simulationDataService = ServerUtils.LoadPlugin<ISimulationDataService>(module, new object[] { Config });
244 if (m_simulationDataService == null)
245 throw new Exception(
246 string.Format(
247 "Could not load an ISimulationDataService implementation from {0}, as configured in the LocalServiceModule parameter of the [SimulationDataStore] config section.",
248 module));
249  
250 // Load the estate data service
251 module = Util.GetConfigVarFromSections<string>(Config, "LocalServiceModule", new string[]{"EstateDataStore", "EstateService"}, String.Empty);
252 if (String.IsNullOrEmpty(module))
253 throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [EstateDataStore] or [EstateService] section");
254  
255 if (LoadEstateDataService)
256 {
257 m_estateDataService = ServerUtils.LoadPlugin<IEstateDataService>(module, new object[] { Config });
258 if (m_estateDataService == null)
259 throw new Exception(
260 string.Format(
261 "Could not load an IEstateDataService implementation from {0}, as configured in the LocalServiceModule parameter of the [EstateDataStore] config section.",
262 module));
263 }
264  
265 base.StartupSpecific();
266  
267 if (EnableInitialPluginLoad)
268 LoadPlugins();
269  
270 // We still want to post initalize any plugins even if loading has been disabled since a test may have
271 // inserted them manually.
272 foreach (IApplicationPlugin plugin in m_plugins)
273 plugin.PostInitialise();
274  
275 if (m_console != null)
276 AddPluginCommands(m_console);
277 }
278  
279 protected virtual void AddPluginCommands(ICommandConsole console)
280 {
281 List<string> topics = GetHelpTopics();
282  
283 foreach (string topic in topics)
284 {
285 string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
286  
287 // This is a hack to allow the user to enter the help command in upper or lowercase. This will go
288 // away at some point.
289 console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
290 "help " + capitalizedTopic,
291 "Get help on plugin command '" + topic + "'",
292 HandleCommanderHelp);
293 console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
294 "help " + capitalizedTopic,
295 "Get help on plugin command '" + topic + "'",
296 HandleCommanderHelp);
297  
298 ICommander commander = null;
299  
300 Scene s = SceneManager.CurrentOrFirstScene;
301  
302 if (s != null && s.GetCommanders() != null)
303 {
304 if (s.GetCommanders().ContainsKey(topic))
305 commander = s.GetCommanders()[topic];
306 }
307  
308 if (commander == null)
309 continue;
310  
311 foreach (string command in commander.Commands.Keys)
312 {
313 console.Commands.AddCommand(capitalizedTopic, false,
314 topic + " " + command,
315 topic + " " + commander.Commands[command].ShortHelp(),
316 String.Empty, HandleCommanderCommand);
317 }
318 }
319 }
320  
321 private void HandleCommanderCommand(string module, string[] cmd)
322 {
323 SceneManager.SendCommandToPluginModules(cmd);
324 }
325  
326 private void HandleCommanderHelp(string module, string[] cmd)
327 {
328 // Only safe for the interactive console, since it won't
329 // let us come here unless both scene and commander exist
330 //
331 ICommander moduleCommander = SceneManager.CurrentOrFirstScene.GetCommander(cmd[1].ToLower());
332 if (moduleCommander != null)
333 m_console.Output(moduleCommander.Help);
334 }
335  
336 protected override void Initialize()
337 {
338 // Called from base.StartUp()
339  
340 m_httpServerPort = m_networkServersInfo.HttpListenerPort;
341 SceneManager.OnRestartSim += HandleRestartRegion;
342  
343 // Only enable the watchdogs when all regions are ready. Otherwise we get false positives when cpu is
344 // heavily used during initial startup.
345 //
346 // FIXME: It's also possible that region ready status should be flipped during an OAR load since this
347 // also makes heavy use of the CPU.
348 SceneManager.OnRegionsReadyStatusChange
349 += sm => { MemoryWatchdog.Enabled = sm.AllRegionsReady; Watchdog.Enabled = sm.AllRegionsReady; };
350 }
351  
352 /// <summary>
353 /// Execute the region creation process. This includes setting up scene infrastructure.
354 /// </summary>
355 /// <param name="regionInfo"></param>
356 /// <param name="portadd_flag"></param>
357 /// <returns></returns>
358 public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, bool portadd_flag, out IScene scene)
359 {
360 return CreateRegion(regionInfo, portadd_flag, false, out scene);
361 }
362  
363 /// <summary>
364 /// Execute the region creation process. This includes setting up scene infrastructure.
365 /// </summary>
366 /// <param name="regionInfo"></param>
367 /// <returns></returns>
368 public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, out IScene scene)
369 {
370 return CreateRegion(regionInfo, false, true, out scene);
371 }
372  
373 /// <summary>
374 /// Execute the region creation process. This includes setting up scene infrastructure.
375 /// </summary>
376 /// <param name="regionInfo"></param>
377 /// <param name="portadd_flag"></param>
378 /// <param name="do_post_init"></param>
379 /// <returns></returns>
380 public List<IClientNetworkServer> CreateRegion(RegionInfo regionInfo, bool portadd_flag, bool do_post_init, out IScene mscene)
381 {
382 int port = regionInfo.InternalEndPoint.Port;
383  
384 // set initial RegionID to originRegionID in RegionInfo. (it needs for loding prims)
385 // Commented this out because otherwise regions can't register with
386 // the grid as there is already another region with the same UUID
387 // at those coordinates. This is required for the load balancer to work.
388 // --Mike, 2009.02.25
389 //regionInfo.originRegionID = regionInfo.RegionID;
390  
391 // set initial ServerURI
392 regionInfo.HttpPort = m_httpServerPort;
393 regionInfo.ServerURI = "http://" + regionInfo.ExternalHostName + ":" + regionInfo.HttpPort.ToString() + "/";
394  
395 regionInfo.osSecret = m_osSecret;
396  
397 if ((proxyUrl.Length > 0) && (portadd_flag))
398 {
399 // set proxy url to RegionInfo
400 regionInfo.proxyUrl = proxyUrl;
401 regionInfo.ProxyOffset = proxyOffset;
402 Util.XmlRpcCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName);
403 }
404  
405 List<IClientNetworkServer> clientServers;
406 Scene scene = SetupScene(regionInfo, proxyOffset, Config, out clientServers);
407  
408 m_log.Info("[MODULES]: Loading Region's modules (old style)");
409  
410 // Use this in the future, the line above will be deprecated soon
411 m_log.Info("[REGIONMODULES]: Loading Region's modules (new style)");
412 IRegionModulesController controller;
413 if (ApplicationRegistry.TryGet(out controller))
414 {
415 controller.AddRegionToModules(scene);
416 }
417 else m_log.Error("[REGIONMODULES]: The new RegionModulesController is missing...");
418  
419 scene.SetModuleInterfaces();
420  
421 while (regionInfo.EstateSettings.EstateOwner == UUID.Zero && MainConsole.Instance != null)
422 SetUpEstateOwner(scene);
423  
424 // Prims have to be loaded after module configuration since some modules may be invoked during the load
425 scene.LoadPrimsFromStorage(regionInfo.originRegionID);
426  
427 // TODO : Try setting resource for region xstats here on scene
428 MainServer.Instance.AddStreamHandler(new RegionStatsHandler(regionInfo));
429  
430 scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
431 scene.EventManager.TriggerParcelPrimCountUpdate();
432  
433 try
434 {
435 scene.RegisterRegionWithGrid();
436 }
437 catch (Exception e)
438 {
439 m_log.ErrorFormat(
440 "[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}",
441 e.Message, e.StackTrace);
442  
443 // Carrying on now causes a lot of confusion down the
444 // line - we need to get the user's attention
445 Environment.Exit(1);
446 }
447  
448 // We need to do this after we've initialized the
449 // scripting engines.
450 scene.CreateScriptInstances();
451  
452 SceneManager.Add(scene);
453  
454 if (m_autoCreateClientStack)
455 {
456 foreach (IClientNetworkServer clientserver in clientServers)
457 {
458 m_clientServers.Add(clientserver);
459 clientserver.Start();
460 }
461 }
462  
463 scene.EventManager.OnShutdown += delegate() { ShutdownRegion(scene); };
464  
465 mscene = scene;
466  
467 return clientServers;
468 }
469  
470 /// <summary>
471 /// Try to set up the estate owner for the given scene.
472 /// </summary>
473 /// <remarks>
474 /// The involves asking the user for information about the user on the console. If the user does not already
475 /// exist then it is created.
476 /// </remarks>
477 /// <param name="scene"></param>
478 private void SetUpEstateOwner(Scene scene)
479 {
480 RegionInfo regionInfo = scene.RegionInfo;
481  
482 string estateOwnerFirstName = null;
483 string estateOwnerLastName = null;
484 string estateOwnerEMail = null;
485 string estateOwnerPassword = null;
486 string rawEstateOwnerUuid = null;
487  
488 if (Config.Configs[ESTATE_SECTION_NAME] != null)
489 {
490 string defaultEstateOwnerName
491 = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
492 string[] ownerNames = defaultEstateOwnerName.Split(' ');
493  
494 if (ownerNames.Length >= 2)
495 {
496 estateOwnerFirstName = ownerNames[0];
497 estateOwnerLastName = ownerNames[1];
498 }
499  
500 // Info to be used only on Standalone Mode
501 rawEstateOwnerUuid = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
502 estateOwnerEMail = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
503 estateOwnerPassword = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
504 }
505  
506 MainConsole.Instance.OutputFormat("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
507 List<char> excluded = new List<char>(new char[1]{' '});
508  
509  
510 if (estateOwnerFirstName == null || estateOwnerLastName == null)
511 {
512 estateOwnerFirstName = MainConsole.Instance.CmdPrompt("Estate owner first name", "Test", excluded);
513 estateOwnerLastName = MainConsole.Instance.CmdPrompt("Estate owner last name", "User", excluded);
514 }
515  
516 UserAccount account
517 = scene.UserAccountService.GetUserAccount(regionInfo.ScopeID, estateOwnerFirstName, estateOwnerLastName);
518  
519 if (account == null)
520 {
521  
522 // XXX: The LocalUserAccountServicesConnector is currently registering its inner service rather than
523 // itself!
524 // if (scene.UserAccountService is LocalUserAccountServicesConnector)
525 // {
526 // IUserAccountService innerUas
527 // = ((LocalUserAccountServicesConnector)scene.UserAccountService).UserAccountService;
528 //
529 // m_log.DebugFormat("B {0}", innerUas.GetType());
530 //
531 // if (innerUas is UserAccountService)
532 // {
533  
534 if (scene.UserAccountService is UserAccountService)
535 {
536 if (estateOwnerPassword == null)
537 estateOwnerPassword = MainConsole.Instance.PasswdPrompt("Password");
538  
539 if (estateOwnerEMail == null)
540 estateOwnerEMail = MainConsole.Instance.CmdPrompt("Email");
541  
542 if (rawEstateOwnerUuid == null)
543 rawEstateOwnerUuid = MainConsole.Instance.CmdPrompt("User ID", UUID.Random().ToString());
544  
545 UUID estateOwnerUuid = UUID.Zero;
546 if (!UUID.TryParse(rawEstateOwnerUuid, out estateOwnerUuid))
547 {
548 m_log.ErrorFormat("[OPENSIM]: ID {0} is not a valid UUID", rawEstateOwnerUuid);
549 return;
550 }
551  
552 // If we've been given a zero uuid then this signals that we should use a random user id
553 if (estateOwnerUuid == UUID.Zero)
554 estateOwnerUuid = UUID.Random();
555  
556 account
557 = ((UserAccountService)scene.UserAccountService).CreateUser(
558 regionInfo.ScopeID,
559 estateOwnerUuid,
560 estateOwnerFirstName,
561 estateOwnerLastName,
562 estateOwnerPassword,
563 estateOwnerEMail);
564 }
565 }
566  
567 if (account == null)
568 {
569 m_log.ErrorFormat(
570 "[OPENSIM]: Unable to store account. If this simulator is connected to a grid, you must create the estate owner account first at the grid level.");
571 }
572 else
573 {
574 regionInfo.EstateSettings.EstateOwner = account.PrincipalID;
575 m_estateDataService.StoreEstateSettings(regionInfo.EstateSettings);
576 }
577 }
578  
579 private void ShutdownRegion(Scene scene)
580 {
581 m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName);
582 IRegionModulesController controller;
583 if (ApplicationRegistry.TryGet<IRegionModulesController>(out controller))
584 {
585 controller.RemoveRegionFromModules(scene);
586 }
587 }
588  
589 public void RemoveRegion(Scene scene, bool cleanup)
590 {
591 // only need to check this if we are not at the
592 // root level
593 if ((SceneManager.CurrentScene != null) &&
594 (SceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
595 {
596 SceneManager.TrySetCurrentScene("..");
597 }
598  
599 scene.DeleteAllSceneObjects();
600 SceneManager.CloseScene(scene);
601 ShutdownClientServer(scene.RegionInfo);
602  
603 if (!cleanup)
604 return;
605  
606 if (!String.IsNullOrEmpty(scene.RegionInfo.RegionFile))
607 {
608 if (scene.RegionInfo.RegionFile.ToLower().EndsWith(".xml"))
609 {
610 File.Delete(scene.RegionInfo.RegionFile);
611 m_log.InfoFormat("[OPENSIM]: deleting region file \"{0}\"", scene.RegionInfo.RegionFile);
612 }
613 if (scene.RegionInfo.RegionFile.ToLower().EndsWith(".ini"))
614 {
615 try
616 {
617 IniConfigSource source = new IniConfigSource(scene.RegionInfo.RegionFile);
618 if (source.Configs[scene.RegionInfo.RegionName] != null)
619 {
620 source.Configs.Remove(scene.RegionInfo.RegionName);
621  
622 if (source.Configs.Count == 0)
623 {
624 File.Delete(scene.RegionInfo.RegionFile);
625 }
626 else
627 {
628 source.Save(scene.RegionInfo.RegionFile);
629 }
630 }
631 }
632 catch (Exception)
633 {
634 }
635 }
636 }
637 }
638  
639 public void RemoveRegion(string name, bool cleanUp)
640 {
641 Scene target;
642 if (SceneManager.TryGetScene(name, out target))
643 RemoveRegion(target, cleanUp);
644 }
645  
646 /// <summary>
647 /// Remove a region from the simulator without deleting it permanently.
648 /// </summary>
649 /// <param name="scene"></param>
650 /// <returns></returns>
651 public void CloseRegion(Scene scene)
652 {
653 // only need to check this if we are not at the
654 // root level
655 if ((SceneManager.CurrentScene != null) &&
656 (SceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
657 {
658 SceneManager.TrySetCurrentScene("..");
659 }
660  
661 SceneManager.CloseScene(scene);
662 ShutdownClientServer(scene.RegionInfo);
663 }
664  
665 /// <summary>
666 /// Remove a region from the simulator without deleting it permanently.
667 /// </summary>
668 /// <param name="name"></param>
669 /// <returns></returns>
670 public void CloseRegion(string name)
671 {
672 Scene target;
673 if (SceneManager.TryGetScene(name, out target))
674 CloseRegion(target);
675 }
676  
677 /// <summary>
678 /// Create a scene and its initial base structures.
679 /// </summary>
680 /// <param name="regionInfo"></param>
681 /// <param name="clientServer"> </param>
682 /// <returns></returns>
683 protected Scene SetupScene(RegionInfo regionInfo, out List<IClientNetworkServer> clientServer)
684 {
685 return SetupScene(regionInfo, 0, null, out clientServer);
686 }
687  
688 /// <summary>
689 /// Create a scene and its initial base structures.
690 /// </summary>
691 /// <param name="regionInfo"></param>
692 /// <param name="proxyOffset"></param>
693 /// <param name="configSource"></param>
694 /// <param name="clientServer"> </param>
695 /// <returns></returns>
696 protected Scene SetupScene(
697 RegionInfo regionInfo, int proxyOffset, IConfigSource configSource, out List<IClientNetworkServer> clientServer)
698 {
699 List<IClientNetworkServer> clientNetworkServers = null;
700  
701 AgentCircuitManager circuitManager = new AgentCircuitManager();
702 IPAddress listenIP = regionInfo.InternalEndPoint.Address;
703 //if (!IPAddress.TryParse(regionInfo.InternalEndPoint, out listenIP))
704 // listenIP = IPAddress.Parse("0.0.0.0");
705  
706 uint port = (uint) regionInfo.InternalEndPoint.Port;
707  
708 if (m_autoCreateClientStack)
709 {
710 clientNetworkServers = m_clientStackManager.CreateServers(
711 listenIP, ref port, proxyOffset, regionInfo.m_allow_alternate_ports, configSource,
712 circuitManager);
713 }
714 else
715 {
716 clientServer = null;
717 }
718  
719 regionInfo.InternalEndPoint.Port = (int) port;
720  
721 Scene scene = CreateScene(regionInfo, m_simulationDataService, m_estateDataService, circuitManager);
722  
723 if (m_autoCreateClientStack)
724 {
725 foreach (IClientNetworkServer clientnetserver in clientNetworkServers)
726 {
727 clientnetserver.AddScene(scene);
728 }
729 }
730 clientServer = clientNetworkServers;
731 scene.LoadWorldMap();
732  
733 scene.PhysicsScene.RequestAssetMethod = scene.PhysicsRequestAsset;
734 scene.PhysicsScene.SetTerrain(scene.Heightmap.GetFloatsSerialised());
735 scene.PhysicsScene.SetWaterLevel((float) regionInfo.RegionSettings.WaterHeight);
736  
737 return scene;
738 }
739  
740 protected override ClientStackManager CreateClientStackManager()
741 {
742 return new ClientStackManager(m_configSettings.ClientstackDll);
743 }
744  
745 protected override Scene CreateScene(RegionInfo regionInfo, ISimulationDataService simDataService,
746 IEstateDataService estateDataService, AgentCircuitManager circuitManager)
747 {
748 Vector3 regionExtent = new Vector3(regionInfo.RegionSizeX, regionInfo.RegionSizeY, regionInfo.RegionSizeZ);
749 PhysicsScene physicsScene = GetPhysicsScene(regionInfo.RegionName, regionExtent);
750  
751 SceneCommunicationService sceneGridService = new SceneCommunicationService();
752  
753 return new Scene(
754 regionInfo, circuitManager, physicsScene, sceneGridService,
755 simDataService, estateDataService,
756 Config, m_version);
757 }
758  
759 protected void ShutdownClientServer(RegionInfo whichRegion)
760 {
761 // Close and remove the clientserver for a region
762 bool foundClientServer = false;
763 int clientServerElement = 0;
764 Location location = new Location(whichRegion.RegionHandle);
765  
766 for (int i = 0; i < m_clientServers.Count; i++)
767 {
768 if (m_clientServers[i].HandlesRegion(location))
769 {
770 clientServerElement = i;
771 foundClientServer = true;
772 break;
773 }
774 }
775  
776 if (foundClientServer)
777 {
778 m_clientServers[clientServerElement].Stop();
779 m_clientServers.RemoveAt(clientServerElement);
780 }
781 }
782  
783 protected virtual void HandleRestartRegion(RegionInfo whichRegion)
784 {
785 m_log.InfoFormat(
786 "[OPENSIM]: Got restart signal from SceneManager for region {0} ({1},{2})",
787 whichRegion.RegionName, whichRegion.RegionLocX, whichRegion.RegionLocY);
788  
789 ShutdownClientServer(whichRegion);
790 IScene scene;
791 CreateRegion(whichRegion, true, out scene);
792 scene.Start();
793 }
794  
795 # region Setup methods
796  
797 protected override PhysicsScene GetPhysicsScene(string osSceneIdentifier, Vector3 regionExtent)
798 {
799 return GetPhysicsScene(
800 m_configSettings.PhysicsEngine, m_configSettings.MeshEngineName, Config, osSceneIdentifier, regionExtent);
801 }
802  
803 /// <summary>
804 /// Handler to supply the current status of this sim
805 /// </summary>
806 /// <remarks>
807 /// Currently this is always OK if the simulator is still listening for connections on its HTTP service
808 /// </remarks>
809 public class SimStatusHandler : BaseStreamHandler
810 {
811 public SimStatusHandler() : base("GET", "/simstatus", "SimStatus", "Simulator Status") {}
812  
813 protected override byte[] ProcessRequest(string path, Stream request,
814 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
815 {
816 return Util.UTF8.GetBytes("OK");
817 }
818  
819 public override string ContentType
820 {
821 get { return "text/plain"; }
822 }
823 }
824  
825 /// <summary>
826 /// Handler to supply the current extended status of this sim
827 /// Sends the statistical data in a json serialization
828 /// </summary>
829 public class XSimStatusHandler : BaseStreamHandler
830 {
831 OpenSimBase m_opensim;
832  
833 public XSimStatusHandler(OpenSimBase sim)
834 : base("GET", "/" + Util.SHA1Hash(sim.osSecret), "XSimStatus", "Simulator XStatus")
835 {
836 m_opensim = sim;
837 }
838  
839 protected override byte[] ProcessRequest(string path, Stream request,
840 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
841 {
842 return Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest));
843 }
844  
845 public override string ContentType
846 {
847 get { return "text/plain"; }
848 }
849 }
850  
851 /// <summary>
852 /// Handler to supply the current extended status of this sim to a user configured URI
853 /// Sends the statistical data in a json serialization
854 /// If the request contains a key, "callback" the response will be wrappend in the
855 /// associated value for jsonp used with ajax/javascript
856 /// </summary>
857 protected class UXSimStatusHandler : BaseStreamHandler
858 {
859 OpenSimBase m_opensim;
860  
861 public UXSimStatusHandler(OpenSimBase sim)
862 : base("GET", "/" + sim.userStatsURI, "UXSimStatus", "Simulator UXStatus")
863 {
864 m_opensim = sim;
865 }
866  
867 protected override byte[] ProcessRequest(string path, Stream request,
868 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
869 {
870 return Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest));
871 }
872  
873 public override string ContentType
874 {
875 get { return "text/plain"; }
876 }
877 }
878  
879 #endregion
880  
881 /// <summary>
882 /// Performs any last-minute sanity checking and shuts down the region server
883 /// </summary>
884 protected override void ShutdownSpecific()
885 {
886 if (proxyUrl.Length > 0)
887 {
888 Util.XmlRpcCommand(proxyUrl, "Stop");
889 }
890  
891 m_log.Info("[SHUTDOWN]: Closing all threads");
892 m_log.Info("[SHUTDOWN]: Killing listener thread");
893 m_log.Info("[SHUTDOWN]: Killing clients");
894 m_log.Info("[SHUTDOWN]: Closing console and terminating");
895  
896 try
897 {
898 SceneManager.Close();
899  
900 foreach (IApplicationPlugin plugin in m_plugins)
901 plugin.Dispose();
902 }
903 catch (Exception e)
904 {
905 m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e);
906 }
907  
908 base.ShutdownSpecific();
909 }
910  
911 /// <summary>
912 /// Get the start time and up time of Region server
913 /// </summary>
914 /// <param name="starttime">The first out parameter describing when the Region server started</param>
915 /// <param name="uptime">The second out parameter describing how long the Region server has run</param>
916 public void GetRunTime(out string starttime, out string uptime)
917 {
918 starttime = m_startuptime.ToString();
919 uptime = (DateTime.Now - m_startuptime).ToString();
920 }
921  
922 /// <summary>
923 /// Get the number of the avatars in the Region server
924 /// </summary>
925 /// <param name="usernum">The first out parameter describing the number of all the avatars in the Region server</param>
926 public void GetAvatarNumber(out int usernum)
927 {
928 usernum = SceneManager.GetCurrentSceneAvatars().Count;
929 }
930  
931 /// <summary>
932 /// Get the number of regions
933 /// </summary>
934 /// <param name="regionnum">The first out parameter describing the number of regions</param>
935 public void GetRegionNumber(out int regionnum)
936 {
937 regionnum = SceneManager.Scenes.Count;
938 }
939  
940 /// <summary>
941 /// Create an estate with an initial region.
942 /// </summary>
943 /// <remarks>
944 /// This method doesn't allow an estate to be created with the same name as existing estates.
945 /// </remarks>
946 /// <param name="regInfo"></param>
947 /// <param name="estatesByName">A list of estate names that already exist.</param>
948 /// <param name="estateName">Estate name to create if already known</param>
949 /// <returns>true if the estate was created, false otherwise</returns>
950 public bool CreateEstate(RegionInfo regInfo, Dictionary<string, EstateSettings> estatesByName, string estateName)
951 {
952 // Create a new estate
953 regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, true);
954  
955 string newName;
956 if (!string.IsNullOrEmpty(estateName))
957 newName = estateName;
958 else
959 newName = MainConsole.Instance.CmdPrompt("New estate name", regInfo.EstateSettings.EstateName);
960  
961 if (estatesByName.ContainsKey(newName))
962 {
963 MainConsole.Instance.OutputFormat("An estate named {0} already exists. Please try again.", newName);
964 return false;
965 }
966  
967 regInfo.EstateSettings.EstateName = newName;
968  
969 // FIXME: Later on, the scene constructor will reload the estate settings no matter what.
970 // Therefore, we need to do an initial save here otherwise the new estate name will be reset
971 // back to the default. The reloading of estate settings by scene could be eliminated if it
972 // knows that the passed in settings in RegionInfo are already valid. Also, it might be
973 // possible to eliminate some additional later saves made by callers of this method.
974 EstateDataService.StoreEstateSettings(regInfo.EstateSettings);
975  
976 return true;
977 }
978  
979 /// <summary>
980 /// Load the estate information for the provided RegionInfo object.
981 /// </summary>
982 /// <param name="regInfo"></param>
983 public bool PopulateRegionEstateInfo(RegionInfo regInfo)
984 {
985 if (EstateDataService != null)
986 regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, false);
987  
988 if (regInfo.EstateSettings.EstateID != 0)
989 return false; // estate info in the database did not change
990  
991 m_log.WarnFormat("[ESTATE] Region {0} is not part of an estate.", regInfo.RegionName);
992  
993 List<EstateSettings> estates = EstateDataService.LoadEstateSettingsAll();
994 Dictionary<string, EstateSettings> estatesByName = new Dictionary<string, EstateSettings>();
995  
996 foreach (EstateSettings estate in estates)
997 estatesByName[estate.EstateName] = estate;
998  
999 string defaultEstateName = null;
1000  
1001 if (Config.Configs[ESTATE_SECTION_NAME] != null)
1002 {
1003 defaultEstateName = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
1004  
1005 if (defaultEstateName != null)
1006 {
1007 EstateSettings defaultEstate;
1008 bool defaultEstateJoined = false;
1009  
1010 if (estatesByName.ContainsKey(defaultEstateName))
1011 {
1012 defaultEstate = estatesByName[defaultEstateName];
1013  
1014 if (EstateDataService.LinkRegion(regInfo.RegionID, (int)defaultEstate.EstateID))
1015 defaultEstateJoined = true;
1016 }
1017 else
1018 {
1019 if (CreateEstate(regInfo, estatesByName, defaultEstateName))
1020 defaultEstateJoined = true;
1021 }
1022  
1023 if (defaultEstateJoined)
1024 return true; // need to update the database
1025 else
1026 m_log.ErrorFormat(
1027 "[OPENSIM BASE]: Joining default estate {0} failed", defaultEstateName);
1028 }
1029 }
1030  
1031 // If we have no default estate or creation of the default estate failed then ask the user.
1032 while (true)
1033 {
1034 if (estates.Count == 0)
1035 {
1036 m_log.Info("[ESTATE]: No existing estates found. You must create a new one.");
1037  
1038 if (CreateEstate(regInfo, estatesByName, null))
1039 break;
1040 else
1041 continue;
1042 }
1043 else
1044 {
1045 string response
1046 = MainConsole.Instance.CmdPrompt(
1047 string.Format(
1048 "Do you wish to join region {0} to an existing estate (yes/no)?", regInfo.RegionName),
1049 "yes",
1050 new List<string>() { "yes", "no" });
1051  
1052 if (response == "no")
1053 {
1054 if (CreateEstate(regInfo, estatesByName, null))
1055 break;
1056 else
1057 continue;
1058 }
1059 else
1060 {
1061 string[] estateNames = estatesByName.Keys.ToArray();
1062 response
1063 = MainConsole.Instance.CmdPrompt(
1064 string.Format(
1065 "Name of estate to join. Existing estate names are ({0})",
1066 string.Join(", ", estateNames)),
1067 estateNames[0]);
1068  
1069 List<int> estateIDs = EstateDataService.GetEstates(response);
1070 if (estateIDs.Count < 1)
1071 {
1072 MainConsole.Instance.Output("The name you have entered matches no known estate. Please try again.");
1073 continue;
1074 }
1075  
1076 int estateID = estateIDs[0];
1077  
1078 regInfo.EstateSettings = EstateDataService.LoadEstateSettings(estateID);
1079  
1080 if (EstateDataService.LinkRegion(regInfo.RegionID, estateID))
1081 break;
1082  
1083 MainConsole.Instance.Output("Joining the estate failed. Please try again.");
1084 }
1085 }
1086 }
1087  
1088 return true; // need to update the database
1089 }
1090 }
1091  
1092 public class OpenSimConfigSource
1093 {
1094 public IConfigSource Source;
1095 }
1096 }