/* * 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; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Timers; using log4net; using Nini.Config; using OpenMetaverse; using OpenSim.Framework; using OpenSim.Framework.Console; using OpenSim.Framework.Statistics; using OpenSim.Region.Framework.Interfaces; using OpenSim.Region.Framework.Scenes; namespace OpenSim { /// /// Interactive OpenSim region server /// public class OpenSim : OpenSimBase { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); protected string m_startupCommandsFile; protected string m_shutdownCommandsFile; protected bool m_gui = false; protected string m_consoleType = "local"; protected uint m_consolePort = 0; private string m_timedScript = "disabled"; private Timer m_scriptTimer; public OpenSim(IConfigSource configSource) : base(configSource) { } protected override void ReadExtraConfigSettings() { base.ReadExtraConfigSettings(); IConfig startupConfig = m_config.Source.Configs["Startup"]; IConfig networkConfig = m_config.Source.Configs["Network"]; int stpMaxThreads = 15; if (startupConfig != null) { m_startupCommandsFile = startupConfig.GetString("startup_console_commands_file", "startup_commands.txt"); m_shutdownCommandsFile = startupConfig.GetString("shutdown_console_commands_file", "shutdown_commands.txt"); if (startupConfig.GetString("console", String.Empty) == String.Empty) m_gui = startupConfig.GetBoolean("gui", false); else m_consoleType= startupConfig.GetString("console", String.Empty); if (networkConfig != null) m_consolePort = (uint)networkConfig.GetInt("console_port", 0); m_timedScript = startupConfig.GetString("timer_Script", "disabled"); if (m_logFileAppender != null) { if (m_logFileAppender is log4net.Appender.FileAppender) { log4net.Appender.FileAppender appender = (log4net.Appender.FileAppender)m_logFileAppender; string fileName = startupConfig.GetString("LogFile", String.Empty); if (fileName != String.Empty) { appender.File = fileName; appender.ActivateOptions(); } m_log.InfoFormat("[LOGGING]: Logging started to file {0}", appender.File); } } string asyncCallMethodStr = startupConfig.GetString("async_call_method", String.Empty); FireAndForgetMethod asyncCallMethod; if (!String.IsNullOrEmpty(asyncCallMethodStr) && Utils.EnumTryParse(asyncCallMethodStr, out asyncCallMethod)) Util.FireAndForgetMethod = asyncCallMethod; stpMaxThreads = startupConfig.GetInt("MaxPoolThreads", 15); } if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) Util.InitThreadPool(stpMaxThreads); m_log.Info("[OPENSIM MAIN]: Using async_call_method " + Util.FireAndForgetMethod); } /// /// Performs initialisation of the scene, such as loading configuration from disk. /// protected override void StartupSpecific() { m_log.Info("===================================================================="); m_log.Info("========================= STARTING OPENSIM ========================="); m_log.Info("===================================================================="); m_log.InfoFormat("[OPENSIM MAIN]: Running "); //m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString()); // http://msdn.microsoft.com/en-us/library/bb384202.aspx //GCSettings.LatencyMode = GCLatencyMode.Batch; //m_log.InfoFormat("[OPENSIM MAIN]: GC Latency Mode: {0}", GCSettings.LatencyMode.ToString()); if (m_gui) // Driven by external GUI m_console = new CommandConsole("Region"); else { switch (m_consoleType) { case "basic": m_console = new CommandConsole("Region"); break; case "rest": m_console = new RemoteConsole("Region"); ((RemoteConsole)m_console).ReadConfig(m_config.Source); break; default: m_console = new LocalConsole("Region"); break; } } MainConsole.Instance = m_console; RegisterConsoleCommands(); base.StartupSpecific(); MainServer.Instance.AddStreamHandler(new OpenSim.SimStatusHandler()); MainServer.Instance.AddStreamHandler(new OpenSim.XSimStatusHandler(this)); if (userStatsURI != String.Empty) MainServer.Instance.AddStreamHandler(new OpenSim.UXSimStatusHandler(this)); if (m_console is RemoteConsole) { if (m_consolePort == 0) { ((RemoteConsole)m_console).SetServer(m_httpServer); } else { ((RemoteConsole)m_console).SetServer(MainServer.GetHttpServer(m_consolePort)); } } //Run Startup Commands if (String.IsNullOrEmpty(m_startupCommandsFile)) { m_log.Info("[STARTUP]: No startup command script specified. Moving on..."); } else { RunCommandScript(m_startupCommandsFile); } // Start timer script (run a script every xx seconds) if (m_timedScript != "disabled") { m_scriptTimer = new Timer(); m_scriptTimer.Enabled = true; m_scriptTimer.Interval = 1200*1000; m_scriptTimer.Elapsed += RunAutoTimerScript; } // Hook up to the watchdog timer Watchdog.OnWatchdogTimeout += WatchdogTimeoutHandler; PrintFileToConsole("startuplogo.txt"); // For now, start at the 'root' level by default if (m_sceneManager.Scenes.Count == 1) // If there is only one region, select it ChangeSelectedRegion("region", new string[] {"change", "region", m_sceneManager.Scenes[0].RegionInfo.RegionName}); else ChangeSelectedRegion("region", new string[] {"change", "region", "root"}); } /// /// Register standard set of region console commands /// private void RegisterConsoleCommands() { m_console.Commands.AddCommand("region", false, "clear assets", "clear assets", "Clear the asset cache", HandleClearAssets); m_console.Commands.AddCommand("region", false, "force update", "force update", "Force the update of all objects on clients", HandleForceUpdate); m_console.Commands.AddCommand("region", false, "debug packet", "debug packet ", "Turn on packet debugging", "If level > 255 then all incoming and outgoing packets are logged.\n" + "If level <= 255 then incoming AgentUpdate and outgoing SimStats and SimulatorViewerTimeMessage packets are not logged.\n" + "If level <= 200 then incoming RequestImage and outgoing ImagePacket, ImageData, LayerData and CoarseLocationUpdate packets are not logged.\n" + "If level <= 100 then incoming ViewerEffect and AgentAnimation and outgoing ViewerEffect and AvatarAnimation packets are not logged.\n" + "If level <= 0 then no packets are logged.", Debug); m_console.Commands.AddCommand("region", false, "debug scene", "debug scene ", "Turn on scene debugging", Debug); m_console.Commands.AddCommand("region", false, "change region", "change region ", "Change current console region", ChangeSelectedRegion); m_console.Commands.AddCommand("region", false, "save xml", "save xml", "Save a region's data in XML format", SaveXml); m_console.Commands.AddCommand("region", false, "save xml2", "save xml2", "Save a region's data in XML2 format", SaveXml2); m_console.Commands.AddCommand("region", false, "load xml", "load xml [-newIDs [ ]]", "Load a region's data from XML format", LoadXml); m_console.Commands.AddCommand("region", false, "load xml2", "load xml2", "Load a region's data from XML2 format", LoadXml2); m_console.Commands.AddCommand("region", false, "save prims xml2", "save prims xml2 [ ]", "Save named prim to XML2", SavePrimsXml2); m_console.Commands.AddCommand("region", false, "load oar", "load oar [--merge] [--skip-assets] []", "Load a region's data from an OAR archive.", "--merge will merge the OAR with the existing scene." + Environment.NewLine + "--skip-assets will load the OAR but ignore the assets it contains." + Environment.NewLine + "The path can be either a filesystem location or a URI." + " If this is not given then the command looks for an OAR named region.oar in the current directory.", LoadOar); m_console.Commands.AddCommand("region", false, "save oar", "save oar [--version=] []", "Save a region's data to an OAR archive.", "The OAR path must be a filesystem path." + " If this is not given then the oar is saved to region.oar in the current directory." + Environment.NewLine + "--version=0 produces old version 0.3 OARs that are compatible with OpenSim 0.7.0.2 and earlier. Current OAR version is 1.0. This version of OpenSim can load any OAR later than version 0.3", SaveOar); m_console.Commands.AddCommand("region", false, "edit scale", "edit scale ", "Change the scale of a named prim", HandleEditScale); m_console.Commands.AddCommand("region", false, "kick user", "kick user [message]", "Kick a user off the simulator", KickUserCommand); m_console.Commands.AddCommand("region", false, "show assets", "show assets", "Show asset data", HandleShow); m_console.Commands.AddCommand("region", false, "show users", "show users [full]", "Show user data", HandleShow); m_console.Commands.AddCommand("region", false, "show connections", "show connections", "Show connection data", HandleShow); m_console.Commands.AddCommand("region", false, "show users full", "show users full", String.Empty, HandleShow); m_console.Commands.AddCommand("region", false, "show modules", "show modules", "Show module data", HandleShow); m_console.Commands.AddCommand("region", false, "show regions", "show regions", "Show region data", HandleShow); m_console.Commands.AddCommand("region", false, "show queues", "show queues", "Show queue data", HandleShow); m_console.Commands.AddCommand("region", false, "show ratings", "show ratings", "Show rating data", HandleShow); m_console.Commands.AddCommand("region", false, "backup", "backup", "Persist objects to the database now", RunCommand); m_console.Commands.AddCommand("region", false, "create region", "create region [\"region name\"] ", "Create a new region.", "The settings for \"region name\" are read from . Paths specified with are relative to your Regions directory, unless an absolute path is given." + " If \"region name\" does not exist in , it will be added." + Environment.NewLine + "Without \"region name\", the first region found in will be created." + Environment.NewLine + "If does not exist, it will be created.", HandleCreateRegion); m_console.Commands.AddCommand("region", false, "restart", "restart", "Restart all sims in this instance", RunCommand); m_console.Commands.AddCommand("region", false, "config set", "config set
", "Set a config option", HandleConfig); m_console.Commands.AddCommand("region", false, "config get", "config get
", "Read a config option", HandleConfig); m_console.Commands.AddCommand("region", false, "config save", "config save", "Save current configuration", HandleConfig); m_console.Commands.AddCommand("region", false, "command-script", "command-script