/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Framework.Monitoring;
//using OpenSim.Region.CoreModules.ServiceConnectorsOut.UserAccounts;
using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.PhysicsModules.SharedBase;
using OpenSim.Server.Base;
using OpenSim.Services.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Services.UserAccountService;
namespace OpenSim
{
///
/// Common OpenSimulator simulator code
///
public class OpenSimBase : RegionApplicationBase
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// These are the names of the plugin-points extended by this
// class during system startup.
//
private const string PLUGIN_ASSET_CACHE = "/OpenSim/AssetCache";
private const string PLUGIN_ASSET_SERVER_CLIENT = "/OpenSim/AssetClient";
// OpenSim.ini Section name for ESTATES Settings
public const string ESTATE_SECTION_NAME = "Estates";
///
/// Allow all plugin loading to be disabled for tests/debug.
///
///
/// true by default
///
public bool EnableInitialPluginLoad { get; set; }
///
/// Control whether we attempt to load an estate data service.
///
/// For tests/debugging
public bool LoadEstateDataService { get; set; }
protected string proxyUrl;
protected int proxyOffset = 0;
public string userStatsURI = String.Empty;
public string managedStatsURI = String.Empty;
public string managedStatsPassword = String.Empty;
protected bool m_autoCreateClientStack = true;
///
/// The file used to load and save prim backup xml if no filename has been specified
///
protected const string DEFAULT_PRIM_BACKUP_FILENAME = "prim-backup.xml";
public ConfigSettings ConfigurationSettings
{
get { return m_configSettings; }
set { m_configSettings = value; }
}
protected ConfigSettings m_configSettings;
protected ConfigurationLoader m_configLoader;
public ConsoleCommand CreateAccount = null;
public List m_plugins = new List();
private List m_permsModules;
private bool m_securePermissionsLoading = true;
///
/// The config information passed into the OpenSimulator region server.
///
public OpenSimConfigSource ConfigSource { get; private set; }
protected EnvConfigSource m_EnvConfigSource = new EnvConfigSource();
public EnvConfigSource envConfigSource
{
get { return m_EnvConfigSource; }
}
public uint HttpServerPort
{
get { return m_httpServerPort; }
}
protected IRegistryCore m_applicationRegistry = new RegistryCore();
public IRegistryCore ApplicationRegistry
{
get { return m_applicationRegistry; }
}
///
/// Constructor.
///
///
public OpenSimBase(IConfigSource configSource) : base()
{
EnableInitialPluginLoad = true;
LoadEstateDataService = true;
LoadConfigSettings(configSource);
}
protected virtual void LoadConfigSettings(IConfigSource configSource)
{
m_configLoader = new ConfigurationLoader();
ConfigSource = m_configLoader.LoadConfigSettings(configSource, envConfigSource, out m_configSettings, out m_networkServersInfo);
Config = ConfigSource.Source;
ReadExtraConfigSettings();
}
protected virtual void ReadExtraConfigSettings()
{
IConfig networkConfig = Config.Configs["Network"];
if (networkConfig != null)
{
proxyUrl = networkConfig.GetString("proxy_url", "");
proxyOffset = Int32.Parse(networkConfig.GetString("proxy_offset", "0"));
}
IConfig startupConfig = Config.Configs["Startup"];
if (startupConfig != null)
{
Util.LogOverloads = startupConfig.GetBoolean("LogOverloads", true);
}
}
protected virtual void LoadPlugins()
{
IConfig startupConfig = Config.Configs["Startup"];
string registryLocation = (startupConfig != null) ? startupConfig.GetString("RegistryLocation", String.Empty) : String.Empty;
// The location can also be specified in the environment. If there
// is no location in the configuration, we must call the constructor
// without a location parameter to allow that to happen.
if (registryLocation.Length == 0)
{
using (PluginLoader loader = new PluginLoader(new ApplicationPluginInitialiser(this)))
{
loader.Load("/OpenSim/Startup");
m_plugins = loader.Plugins;
}
}
else
{
using (PluginLoader loader = new PluginLoader(new ApplicationPluginInitialiser(this), registryLocation))
{
loader.Load("/OpenSim/Startup");
m_plugins = loader.Plugins;
}
}
}
protected override List GetHelpTopics()
{
List topics = base.GetHelpTopics();
Scene s = SceneManager.CurrentOrFirstScene;
if (s != null && s.GetCommanders() != null)
topics.AddRange(s.GetCommanders().Keys);
return topics;
}
///
/// Performs startup specific to the region server, including initialization of the scene
/// such as loading configuration from disk.
///
protected override void StartupSpecific()
{
IConfig startupConfig = Config.Configs["Startup"];
if (startupConfig != null)
{
// refuse to run MegaRegions
if(startupConfig.GetBoolean("CombineContiguousRegions", false))
{
m_log.Fatal("CombineContiguousRegions (MegaRegions) option is no longer suported. Use a older version to save region contents as OAR, then import into a fresh install of this new version");
throw new Exception("CombineContiguousRegions not suported");
}
string pidFile = startupConfig.GetString("PIDFile", String.Empty);
if (pidFile != String.Empty)
CreatePIDFile(pidFile);
userStatsURI = startupConfig.GetString("Stats_URI", String.Empty);
m_securePermissionsLoading = startupConfig.GetBoolean("SecurePermissionsLoading", true);
string permissionModules = Util.GetConfigVarFromSections(Config, "permissionmodules",
new string[] { "Startup", "Permissions" }, "DefaultPermissionsModule");
m_permsModules = new List(permissionModules.Split(',').Select(m => m.Trim()));
managedStatsURI = startupConfig.GetString("ManagedStatsRemoteFetchURI", String.Empty);
managedStatsPassword = startupConfig.GetString("ManagedStatsRemoteFetchPassword", String.Empty);
}
// Load the simulation data service
IConfig simDataConfig = Config.Configs["SimulationDataStore"];
if (simDataConfig == null)
throw new Exception("Configuration file is missing the [SimulationDataStore] section. Have you copied OpenSim.ini.example to OpenSim.ini to reference config-include/ files?");
string module = simDataConfig.GetString("LocalServiceModule", String.Empty);
if (String.IsNullOrEmpty(module))
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [SimulationDataStore] section.");
m_simulationDataService = ServerUtils.LoadPlugin(module, new object[] { Config });
if (m_simulationDataService == null)
throw new Exception(
string.Format(
"Could not load an ISimulationDataService implementation from {0}, as configured in the LocalServiceModule parameter of the [SimulationDataStore] config section.",
module));
// Load the estate data service
module = Util.GetConfigVarFromSections(Config, "LocalServiceModule", new string[]{"EstateDataStore", "EstateService"}, String.Empty);
if (String.IsNullOrEmpty(module))
throw new Exception("Configuration file is missing the LocalServiceModule parameter in the [EstateDataStore] or [EstateService] section");
if (LoadEstateDataService)
{
m_estateDataService = ServerUtils.LoadPlugin(module, new object[] { Config });
if (m_estateDataService == null)
throw new Exception(
string.Format(
"Could not load an IEstateDataService implementation from {0}, as configured in the LocalServiceModule parameter of the [EstateDataStore] config section.",
module));
}
base.StartupSpecific();
if (EnableInitialPluginLoad)
LoadPlugins();
// We still want to post initalize any plugins even if loading has been disabled since a test may have
// inserted them manually.
foreach (IApplicationPlugin plugin in m_plugins)
plugin.PostInitialise();
if (m_console != null)
AddPluginCommands(m_console);
}
protected virtual void AddPluginCommands(ICommandConsole console)
{
List topics = GetHelpTopics();
foreach (string topic in topics)
{
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
// away at some point.
console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
"help " + capitalizedTopic,
"Get help on plugin command '" + topic + "'",
HandleCommanderHelp);
ICommander commander = null;
Scene s = SceneManager.CurrentOrFirstScene;
if (s != null && s.GetCommanders() != null)
{
if (s.GetCommanders().ContainsKey(topic))
commander = s.GetCommanders()[topic];
}
if (commander == null)
continue;
foreach (string command in commander.Commands.Keys)
{
console.Commands.AddCommand(capitalizedTopic, false,
topic + " " + command,
topic + " " + commander.Commands[command].ShortHelp(),
String.Empty, HandleCommanderCommand);
}
}
}
private void HandleCommanderCommand(string module, string[] cmd)
{
SceneManager.SendCommandToPluginModules(cmd);
}
private void HandleCommanderHelp(string module, string[] cmd)
{
// Only safe for the interactive console, since it won't
// let us come here unless both scene and commander exist
//
ICommander moduleCommander = SceneManager.CurrentOrFirstScene.GetCommander(cmd[1].ToLower());
if (moduleCommander != null)
m_console.Output(moduleCommander.Help);
}
protected override void Initialize()
{
// Called from base.StartUp()
IConfig startupConfig = Config.Configs["Startup"];
if (startupConfig == null || startupConfig.GetBoolean("JobEngineEnabled", true))
WorkManager.JobEngine.Start();
// Sure is not the right place for this but do the job...
// Must always be called before (all) / the HTTP servers starting for the Certs creation or renewals.
if(startupConfig.GetBoolean("EnableSelfsignedCertSupport", false))
{
if(!File.Exists("SSL\\ssl\\"+ startupConfig.GetString("CertFileName") +".p12") || startupConfig.GetBoolean("CertRenewOnStartup"))
{
Util.CreateOrUpdateSelfsignedCert(
string.IsNullOrEmpty(startupConfig.GetString("CertFileName")) ? "OpenSim" : startupConfig.GetString("CertFileName"),
string.IsNullOrEmpty(startupConfig.GetString("CertHostName")) ? "localhost" : startupConfig.GetString("CertHostName"),
string.IsNullOrEmpty(startupConfig.GetString("CertHostIp")) ? "127.0.0.1" : startupConfig.GetString("CertHostIp"),
string.IsNullOrEmpty(startupConfig.GetString("CertPassword")) ? string.Empty : startupConfig.GetString("CertPassword")
);
}
}
if(startupConfig.GetBoolean("EnableCertConverter", false))
{
Util.ConvertPemToPKCS12(
string.IsNullOrEmpty(startupConfig.GetString("outputCertName")) ? "letsencrypt" : startupConfig.GetString("outputCertName"),
string.IsNullOrEmpty(startupConfig.GetString("PemCertPublicKey")) ? string.Empty : startupConfig.GetString("PemCertPublicKey"),
string.IsNullOrEmpty(startupConfig.GetString("PemCertPrivateKey")) ? string.Empty : startupConfig.GetString("PemCertPrivateKey"),
string.IsNullOrEmpty(startupConfig.GetString("outputCertPassword")) ? string.Empty : startupConfig.GetString("outputCertPassword")
);
}
if(m_networkServersInfo.HttpUsesSSL)
{
m_httpServerSSL = true;
m_httpServerPort = m_networkServersInfo.httpSSLPort;
}
else
{
m_httpServerSSL = false;
m_httpServerPort = m_networkServersInfo.HttpListenerPort;
}
SceneManager.OnRestartSim += HandleRestartRegion;
// Only enable the watchdogs when all regions are ready. Otherwise we get false positives when cpu is
// heavily used during initial startup.
//
// FIXME: It's also possible that region ready status should be flipped during an OAR load since this
// also makes heavy use of the CPU.
SceneManager.OnRegionsReadyStatusChange
+= sm => { MemoryWatchdog.Enabled = sm.AllRegionsReady; Watchdog.Enabled = sm.AllRegionsReady; };
}
///
/// Execute the region creation process. This includes setting up scene infrastructure.
///
///
///
///
public void CreateRegion(RegionInfo regionInfo, bool portadd_flag, out IScene scene)
{
CreateRegion(regionInfo, portadd_flag, false, out scene);
}
///
/// Execute the region creation process. This includes setting up scene infrastructure.
///
///
///
public void CreateRegion(RegionInfo regionInfo, out IScene scene)
{
CreateRegion(regionInfo, false, true, out scene);
}
///
/// Execute the region creation process. This includes setting up scene infrastructure.
///
///
///
///
///
public void CreateRegion(RegionInfo regionInfo, bool portadd_flag, bool do_post_init, out IScene mscene)
{
IRegionModulesController controller;
if (!ApplicationRegistry.TryGet(out controller))
{
m_log.Fatal("REGIONMODULES]: The new RegionModulesController is missing...");
Environment.Exit(0);
}
int port = regionInfo.InternalEndPoint.Port;
// set initial RegionID to originRegionID in RegionInfo. (it needs for loding prims)
// Commented this out because otherwise regions can't register with
// the grid as there is already another region with the same UUID
// at those coordinates. This is required for the load balancer to work.
// --Mike, 2009.02.25
//regionInfo.originRegionID = regionInfo.RegionID;
// set initial ServerURI
regionInfo.HttpPort = m_httpServerPort;
if(m_httpServerSSL)
{
if(!m_httpServer.CheckSSLCertHost(regionInfo.ExternalHostName))
throw new Exception("main http cert CN doesn't match region External IP");
regionInfo.ServerURI = "https://" + regionInfo.ExternalHostName +
":" + regionInfo.HttpPort.ToString() + "/";
}
else
regionInfo.ServerURI = "http://" + regionInfo.ExternalHostName +
":" + regionInfo.HttpPort.ToString() + "/";
regionInfo.osSecret = m_osSecret;
if ((proxyUrl.Length > 0) && (portadd_flag))
{
// set proxy url to RegionInfo
regionInfo.proxyUrl = proxyUrl;
regionInfo.ProxyOffset = proxyOffset;
Util.XmlRpcCommand(proxyUrl, "AddPort", port, port + proxyOffset, regionInfo.ExternalHostName);
}
Scene scene = SetupScene(regionInfo, proxyOffset, Config);
m_log.Info("[REGIONMODULES]: Loading Region's modules");
if (controller != null)
controller.AddRegionToModules(scene);
if (m_securePermissionsLoading)
{
foreach (string s in m_permsModules)
{
if (!scene.RegionModules.ContainsKey(s))
{
m_log.Fatal("[MODULES]: Required module " + s + " not found.");
Environment.Exit(0);
}
}
m_log.InfoFormat("[SCENE]: Secure permissions loading enabled, modules loaded: {0}", String.Join(" ", m_permsModules.ToArray()));
}
scene.SetModuleInterfaces();
// First Step of bootreport sequence
if (scene.SnmpService != null)
{
scene.SnmpService.ColdStart(1,scene);
scene.SnmpService.LinkDown(scene);
}
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("Loading prims", scene);
}
while (regionInfo.EstateSettings.EstateOwner.IsZero() && MainConsole.Instance != null)
SetUpEstateOwner(scene);
scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
// Prims have to be loaded after module configuration since some modules may be invoked during the load
scene.LoadPrimsFromStorage(regionInfo.originRegionID);
// TODO : Try setting resource for region xstats here on scene
MainServer.Instance.AddSimpleStreamHandler(new RegionStatsSimpleHandler(regionInfo));
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("Grid Registration in progress", scene);
}
try
{
scene.RegisterRegionWithGrid();
}
catch (Exception e)
{
m_log.ErrorFormat(
"[STARTUP]: Registration of region with grid failed, aborting startup due to {0} {1}",
e.Message, e.StackTrace);
if (scene.SnmpService != null)
{
scene.SnmpService.Critical("Grid registration failed. Startup aborted.", scene);
}
// Carrying on now causes a lot of confusion down the
// line - we need to get the user's attention
Environment.Exit(1);
}
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("Grid Registration done", scene);
}
// We need to do this after we've initialized the scripting engines.
scene.CreateScriptInstances();
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("ScriptEngine started", scene);
}
SceneManager.Add(scene);
//if (m_autoCreateClientStack)
//{
// foreach (IClientNetworkServer clientserver in clientServers)
// {
// m_clientServers.Add(clientserver);
// clientserver.Start();
// }
//}
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("Initializing region modules", scene);
}
scene.EventManager.OnShutdown += delegate() { ShutdownRegion(scene); };
mscene = scene;
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("The region is operational", scene);
scene.SnmpService.LinkUp(scene);
}
//return clientServers;
}
///
/// Try to set up the estate owner for the given scene.
///
///
/// The involves asking the user for information about the user on the console. If the user does not already
/// exist then it is created.
///
///
private void SetUpEstateOwner(Scene scene)
{
RegionInfo regionInfo = scene.RegionInfo;
string estateOwnerFirstName = null;
string estateOwnerLastName = null;
string estateOwnerEMail = null;
string estateOwnerPassword = null;
string rawEstateOwnerUuid = null;
if (Config.Configs[ESTATE_SECTION_NAME] != null)
{
string defaultEstateOwnerName
= Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerName", "").Trim();
string[] ownerNames = defaultEstateOwnerName.Split(' ');
if (ownerNames.Length >= 2)
{
estateOwnerFirstName = ownerNames[0];
estateOwnerLastName = ownerNames[1];
}
// Info to be used only on Standalone Mode
rawEstateOwnerUuid = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerUUID", null);
estateOwnerEMail = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerEMail", null);
estateOwnerPassword = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateOwnerPassword", null);
}
MainConsole.Instance.Output("Estate {0} has no owner set.", regionInfo.EstateSettings.EstateName);
List excluded = new List(new char[1]{' '});
if (estateOwnerFirstName == null || estateOwnerLastName == null)
{
estateOwnerFirstName = MainConsole.Instance.Prompt("Estate owner first name", "Test", excluded);
estateOwnerLastName = MainConsole.Instance.Prompt("Estate owner last name", "User", excluded);
}
UserAccount account
= scene.UserAccountService.GetUserAccount(regionInfo.ScopeID, estateOwnerFirstName, estateOwnerLastName);
if (account == null)
{
// XXX: The LocalUserAccountServicesConnector is currently registering its inner service rather than
// itself!
// if (scene.UserAccountService is LocalUserAccountServicesConnector)
// {
// IUserAccountService innerUas
// = ((LocalUserAccountServicesConnector)scene.UserAccountService).UserAccountService;
//
// m_log.DebugFormat("B {0}", innerUas.GetType());
//
// if (innerUas is UserAccountService)
// {
if (scene.UserAccountService is UserAccountService)
{
if (estateOwnerPassword == null)
estateOwnerPassword = MainConsole.Instance.Prompt("Password", null, null, false);
if (estateOwnerEMail == null)
estateOwnerEMail = MainConsole.Instance.Prompt("Email");
if (rawEstateOwnerUuid == null)
rawEstateOwnerUuid = MainConsole.Instance.Prompt("User ID", UUID.Random().ToString());
UUID estateOwnerUuid = UUID.Zero;
if (!UUID.TryParse(rawEstateOwnerUuid, out estateOwnerUuid))
{
m_log.ErrorFormat("[OPENSIM]: ID {0} is not a valid UUID", rawEstateOwnerUuid);
return;
}
// If we've been given a zero uuid then this signals that we should use a random user id
if (estateOwnerUuid.IsZero())
estateOwnerUuid = UUID.Random();
account
= ((UserAccountService)scene.UserAccountService).CreateUser(
regionInfo.ScopeID,
estateOwnerUuid,
estateOwnerFirstName,
estateOwnerLastName,
estateOwnerPassword,
estateOwnerEMail);
}
}
if (account == null)
{
m_log.ErrorFormat(
"[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.");
}
else
{
regionInfo.EstateSettings.EstateOwner = account.PrincipalID;
m_estateDataService.StoreEstateSettings(regionInfo.EstateSettings);
}
}
private void ShutdownRegion(Scene scene)
{
m_log.DebugFormat("[SHUTDOWN]: Shutting down region {0}", scene.RegionInfo.RegionName);
if (scene.SnmpService != null)
{
scene.SnmpService.BootInfo("The region is shutting down", scene);
scene.SnmpService.LinkDown(scene);
}
IRegionModulesController controller;
if (ApplicationRegistry.TryGet(out controller))
{
controller.RemoveRegionFromModules(scene);
}
}
public void RemoveRegion(Scene scene, bool cleanup)
{
// only need to check this if we are not at the
// root level
if ((SceneManager.CurrentScene != null) &&
(SceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
{
SceneManager.TrySetCurrentScene("..");
}
scene.DeleteAllSceneObjects();
SceneManager.CloseScene(scene);
//ShutdownClientServer(scene.RegionInfo);
if (!cleanup)
return;
if (!String.IsNullOrEmpty(scene.RegionInfo.RegionFile))
{
if (scene.RegionInfo.RegionFile.ToLower().EndsWith(".xml"))
{
File.Delete(scene.RegionInfo.RegionFile);
m_log.InfoFormat("[OPENSIM]: deleting region file \"{0}\"", scene.RegionInfo.RegionFile);
}
if (scene.RegionInfo.RegionFile.ToLower().EndsWith(".ini"))
{
try
{
IniConfigSource source = new IniConfigSource(scene.RegionInfo.RegionFile);
if (source.Configs[scene.RegionInfo.RegionName] != null)
{
source.Configs.Remove(scene.RegionInfo.RegionName);
if (source.Configs.Count == 0)
{
File.Delete(scene.RegionInfo.RegionFile);
}
else
{
source.Save(scene.RegionInfo.RegionFile);
}
}
}
catch (Exception)
{
}
}
}
}
public void RemoveRegion(string name, bool cleanUp)
{
Scene target;
if (SceneManager.TryGetScene(name, out target))
RemoveRegion(target, cleanUp);
}
///
/// Remove a region from the simulator without deleting it permanently.
///
///
///
public void CloseRegion(Scene scene)
{
// only need to check this if we are not at the
// root level
if ((SceneManager.CurrentScene != null) &&
(SceneManager.CurrentScene.RegionInfo.RegionID == scene.RegionInfo.RegionID))
{
SceneManager.TrySetCurrentScene("..");
}
SceneManager.CloseScene(scene);
//ShutdownClientServer(scene.RegionInfo);
}
///
/// Remove a region from the simulator without deleting it permanently.
///
///
///
public void CloseRegion(string name)
{
Scene target;
if (SceneManager.TryGetScene(name, out target))
CloseRegion(target);
}
///
/// Create a scene and its initial base structures.
///
///
///
///
protected Scene SetupScene(RegionInfo regionInfo)
{
return SetupScene(regionInfo, 0, null);
}
///
/// Create a scene and its initial base structures.
///
///
///
///
///
///
protected Scene SetupScene(RegionInfo regionInfo, int proxyOffset, IConfigSource configSource)
{
//List clientNetworkServers = null;
AgentCircuitManager circuitManager = new AgentCircuitManager();
Scene scene = CreateScene(regionInfo, m_simulationDataService, m_estateDataService, circuitManager);
scene.LoadWorldMap();
return scene;
}
protected override Scene CreateScene(RegionInfo regionInfo, ISimulationDataService simDataService,
IEstateDataService estateDataService, AgentCircuitManager circuitManager)
{
return new Scene(
regionInfo, circuitManager,
simDataService, estateDataService,
Config, m_version);
}
protected virtual void HandleRestartRegion(RegionInfo whichRegion)
{
m_log.InfoFormat(
"[OPENSIM]: Got restart signal from SceneManager for region {0} ({1},{2})",
whichRegion.RegionName, whichRegion.RegionLocX, whichRegion.RegionLocY);
//ShutdownClientServer(whichRegion);
IScene scene;
CreateRegion(whichRegion, true, out scene);
scene.Start();
}
# region Setup methods
///
/// Handler to supply the current status of this sim
///
///
/// Currently this is always OK if the simulator is still listening for connections on its HTTP service
///
public class SimStatusHandler : SimpleStreamHandler
{
public SimStatusHandler() : base("/simstatus", "SimStatus") {}
protected override void ProcessRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
httpResponse.KeepAlive = false;
httpResponse.RawBuffer = Util.UTF8.GetBytes("OK");
httpResponse.StatusCode = (int)HttpStatusCode.OK;
}
}
///
/// Handler to supply the current extended status of this sim
/// Sends the statistical data in a json serialization
///
public class XSimStatusHandler : SimpleStreamHandler
{
OpenSimBase m_opensim;
public XSimStatusHandler(OpenSimBase sim)
: base("/" + Util.SHA1Hash(sim.osSecret), "XSimStatus")
{
m_opensim = sim;
}
protected override void ProcessRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
httpResponse.KeepAlive = false;
try
{
httpResponse.RawBuffer = Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest));
httpResponse.StatusCode = (int)HttpStatusCode.OK;
}
catch
{
httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError;
}
}
}
///
/// Handler to supply the current extended status of this sim to a user configured URI
/// Sends the statistical data in a json serialization
/// If the request contains a key, "callback" the response will be wrappend in the
/// associated value for jsonp used with ajax/javascript
///
protected class UXSimStatusHandler : SimpleStreamHandler
{
OpenSimBase m_opensim;
public UXSimStatusHandler(OpenSimBase sim)
: base("/" + sim.userStatsURI, "UXSimStatus")
{
m_opensim = sim;
}
protected override void ProcessRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
httpResponse.KeepAlive = false;
try
{
httpResponse.RawBuffer = Util.UTF8.GetBytes(m_opensim.StatReport(httpRequest));
httpResponse.StatusCode = (int)HttpStatusCode.OK;
}
catch
{
httpResponse.StatusCode = (int)HttpStatusCode.InternalServerError;
}
}
}
///
/// handler to supply serving http://domainname:port/robots.txt
///
public class SimRobotsHandler : SimpleStreamHandler
{
private readonly byte[] binmsg;
public SimRobotsHandler() : base("/robots.txt", "SimRobots")
{
binmsg = Util.UTF8.GetBytes("# go away\nUser-agent: *\nDisallow: /\n");
}
protected override void ProcessRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
httpResponse.KeepAlive = false;
httpResponse.RawBuffer = binmsg;
httpResponse.StatusCode = (int)HttpStatusCode.OK;
}
}
#endregion
///
/// Performs any last-minute sanity checking and shuts down the region server
///
protected override void ShutdownSpecific()
{
if (proxyUrl.Length > 0)
{
Util.XmlRpcCommand(proxyUrl, "Stop");
}
m_log.Info("[SHUTDOWN]: Closing all threads");
m_log.Info("[SHUTDOWN]: Killing listener thread");
m_log.Info("[SHUTDOWN]: Killing clients");
m_log.Info("[SHUTDOWN]: Closing console and terminating");
try
{
SceneManager.Close();
foreach (IApplicationPlugin plugin in m_plugins)
plugin.Dispose();
}
catch (Exception e)
{
m_log.Error("[SHUTDOWN]: Ignoring failure during shutdown - ", e);
}
base.ShutdownSpecific();
}
///
/// Get the start time and up time of Region server
///
/// The first out parameter describing when the Region server started
/// The second out parameter describing how long the Region server has run
public void GetRunTime(out string starttime, out string uptime)
{
starttime = m_startuptime.ToString();
uptime = (DateTime.Now - m_startuptime).ToString();
}
///
/// Get the number of the avatars in the Region server
///
/// The first out parameter describing the number of all the avatars in the Region server
public void GetAvatarNumber(out int usernum)
{
usernum = SceneManager.GetCurrentSceneAvatars().Count;
}
///
/// Get the number of regions
///
/// The first out parameter describing the number of regions
public void GetRegionNumber(out int regionnum)
{
regionnum = SceneManager.Scenes.Count;
}
///
/// Create an estate with an initial region.
///
///
/// This method doesn't allow an estate to be created with the same name as existing estates.
///
///
/// A list of estate names that already exist.
/// Estate name to create if already known
/// true if the estate was created, false otherwise
public bool CreateEstate(RegionInfo regInfo, Dictionary estatesByName, string estateName)
{
// Create a new estate
regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, true);
string newName;
if (!string.IsNullOrEmpty(estateName))
newName = estateName;
else
newName = MainConsole.Instance.Prompt("New estate name", regInfo.EstateSettings.EstateName);
if (estatesByName.ContainsKey(newName))
{
MainConsole.Instance.Output("An estate named {0} already exists. Please try again.", newName);
return false;
}
regInfo.EstateSettings.EstateName = newName;
// FIXME: Later on, the scene constructor will reload the estate settings no matter what.
// Therefore, we need to do an initial save here otherwise the new estate name will be reset
// back to the default. The reloading of estate settings by scene could be eliminated if it
// knows that the passed in settings in RegionInfo are already valid. Also, it might be
// possible to eliminate some additional later saves made by callers of this method.
EstateDataService.StoreEstateSettings(regInfo.EstateSettings);
return true;
}
///
/// Load the estate information for the provided RegionInfo object.
///
///
public bool PopulateRegionEstateInfo(RegionInfo regInfo)
{
if (EstateDataService != null)
regInfo.EstateSettings = EstateDataService.LoadEstateSettings(regInfo.RegionID, false);
if (regInfo.EstateSettings.EstateID != 0)
return false; // estate info in the database did not change
m_log.WarnFormat("[ESTATE] Region {0} is not part of an estate.", regInfo.RegionName);
List estates = EstateDataService.LoadEstateSettingsAll();
Dictionary estatesByName = new Dictionary();
foreach (EstateSettings estate in estates)
estatesByName[estate.EstateName] = estate;
//##
// Target Estate Specified in Region.ini
string targetEstateIDstr = regInfo.GetSetting("TargetEstate");
if (!string.IsNullOrWhiteSpace(targetEstateIDstr))
{
bool targetEstateJoined = false;
if (Int32.TryParse(targetEstateIDstr, out int targetEstateID) && targetEstateID > 99)
{
// Attempt to join the target estate given in Config by ID
foreach (EstateSettings estate in estates)
{
if (estate.EstateID == targetEstateID)
{
if (EstateDataService.LinkRegion(regInfo.RegionID, targetEstateID))
targetEstateJoined = true;
break;
}
}
}
else
{
// Attempt to join the target estate given in Config by name
if (estatesByName.TryGetValue(targetEstateIDstr, out EstateSettings targetEstate))
{
if (EstateDataService.LinkRegion(regInfo.RegionID, (int)targetEstate.EstateID))
targetEstateJoined = true;
}
}
if (targetEstateJoined)
return true; // need to update the database
else
m_log.ErrorFormat(
"[OPENSIM BASE]: Joining target estate specified in region config {0} failed", targetEstateIDstr);
}
//##
// Default Estate
if (Config.Configs[ESTATE_SECTION_NAME] != null)
{
string defaultEstateName = Config.Configs[ESTATE_SECTION_NAME].GetString("DefaultEstateName", null);
if (defaultEstateName != null)
{
bool defaultEstateJoined = false;
if (estatesByName.TryGetValue(defaultEstateName, out EstateSettings defaultEstate))
{
if (EstateDataService.LinkRegion(regInfo.RegionID, (int)defaultEstate.EstateID))
defaultEstateJoined = true;
}
else
{
if (CreateEstate(regInfo, estatesByName, defaultEstateName))
defaultEstateJoined = true;
}
if (defaultEstateJoined)
return true; // need to update the database
else
m_log.ErrorFormat(
"[OPENSIM BASE]: Joining default estate {0} failed", defaultEstateName);
}
}
// If we have no default estate or creation of the default estate failed then ask the user.
while (true)
{
if (estates.Count == 0)
{
m_log.Info("[ESTATE]: No existing estates found. You must create a new one.");
if (CreateEstate(regInfo, estatesByName, null))
break;
else
continue;
}
else
{
string response = MainConsole.Instance.Prompt(
string.Format(
"Do you wish to join region {0} to an existing estate (yes/no)?", regInfo.RegionName),
"yes",
new List() { "yes", "no" });
if (response == "no")
{
if (CreateEstate(regInfo, estatesByName, null))
break;
else
continue;
}
else
{
string[] estateNames = estatesByName.Keys.ToArray();
response
= MainConsole.Instance.Prompt(
string.Format(
"Name of estate to join. Existing estate names are ({0})",
string.Join(", ", estateNames)),
estateNames[0]);
List estateIDs = EstateDataService.GetEstates(response);
if (estateIDs.Count < 1)
{
MainConsole.Instance.Output("The name you have entered matches no known estate. Please try again.");
continue;
}
int estateID = estateIDs[0];
regInfo.EstateSettings = EstateDataService.LoadEstateSettings(estateID);
if (EstateDataService.LinkRegion(regInfo.RegionID, estateID))
break;
MainConsole.Instance.Output("Joining the estate failed. Please try again.");
}
}
}
return true; // need to update the database
}
}
public class OpenSimConfigSource
{
public IConfigSource Source;
}
}