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