Merge branch 'master' into careminster-presence-refactor

avinationmerge
Melanie 2011-05-08 20:23:06 +01:00
commit b451cc1ebb
37 changed files with 1554 additions and 418 deletions

View File

@ -50,8 +50,8 @@ namespace OpenSim.Framework.Capabilities
public class Caps public class Caps
{ {
private static readonly ILog m_log = // private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_httpListenerHostName; private string m_httpListenerHostName;
private uint m_httpListenPort; private uint m_httpListenPort;

View File

@ -0,0 +1,19 @@
:VERSION 1 # --------------------------
BEGIN TRANSACTION
CREATE TABLE "GridUser" (
"UserID" VARCHAR(255) NOT NULL,
"HomeRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"HomePosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"HomeLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"LastRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"LastPosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"LastLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"Online" CHAR(5) NOT NULL DEFAULT 'false',
"Login" CHAR(16) NOT NULL DEFAULT '0',
"Logout" CHAR(16) NOT NULL DEFAULT '0',
PRIMARY KEY ("UserID")
)
COMMIT

View File

@ -43,7 +43,7 @@ namespace OpenSim.Data.MySQL
public class MySQLAvatarData : MySQLGenericTableHandler<AvatarBaseData>, public class MySQLAvatarData : MySQLGenericTableHandler<AvatarBaseData>,
IAvatarData IAvatarData
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySQLAvatarData(string connectionString, string realm) : public MySQLAvatarData(string connectionString, string realm) :
base(connectionString, realm, "Avatar") base(connectionString, realm, "Avatar")

View File

@ -48,7 +48,7 @@ namespace OpenSim.Data.MySQL
private string m_connectionString; private string m_connectionString;
private long m_waitTimeout; private long m_waitTimeout;
private long m_waitTimeoutLeeway = 60 * TimeSpan.TicksPerSecond; private long m_waitTimeoutLeeway = 60 * TimeSpan.TicksPerSecond;
private long m_lastConnectionUse; // private long m_lastConnectionUse;
private FieldInfo[] m_Fields; private FieldInfo[] m_Fields;
private Dictionary<string, FieldInfo> m_FieldMap = private Dictionary<string, FieldInfo> m_FieldMap =
@ -127,7 +127,7 @@ namespace OpenSim.Data.MySQL
} }
} }
m_lastConnectionUse = DateTime.Now.Ticks; // m_lastConnectionUse = DateTime.Now.Ticks;
m_log.DebugFormat( m_log.DebugFormat(
"[REGION DB]: Connection wait timeout {0} seconds", "[REGION DB]: Connection wait timeout {0} seconds",

View File

@ -39,7 +39,7 @@ namespace OpenSim.Data.MySQL
{ {
public class MySQLGenericTableHandler<T> : MySqlFramework where T: class, new() public class MySQLGenericTableHandler<T> : MySqlFramework where T: class, new()
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Dictionary<string, FieldInfo> m_Fields = protected Dictionary<string, FieldInfo> m_Fields =
new Dictionary<string, FieldInfo>(); new Dictionary<string, FieldInfo>();

View File

@ -43,7 +43,7 @@ namespace OpenSim.Data.MySQL
public class MySQLPresenceData : MySQLGenericTableHandler<PresenceData>, public class MySQLPresenceData : MySQLGenericTableHandler<PresenceData>,
IPresenceData IPresenceData
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public MySQLPresenceData(string connectionString, string realm) : public MySQLPresenceData(string connectionString, string realm) :
base(connectionString, realm, "Presence") base(connectionString, realm, "Presence")

View File

@ -189,7 +189,7 @@ namespace OpenSim.Data.MySQL
{ {
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
} }
catch (Exception e) catch (Exception)
{ {
return false; return false;
} }

View File

@ -33,7 +33,7 @@ using System.Reflection;
using log4net; using log4net;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
using log4net;
#if CSharpSqlite #if CSharpSqlite
using Community.CsharpSqlite.Sqlite; using Community.CsharpSqlite.Sqlite;
#else #else
@ -49,7 +49,6 @@ namespace OpenSim.Data.SQLite
private string m_Realm; private string m_Realm;
private List<string> m_ColumnNames; private List<string> m_ColumnNames;
private int m_LastExpire; private int m_LastExpire;
private string m_connectionString;
protected static SqliteConnection m_Connection; protected static SqliteConnection m_Connection;
private static bool m_initialized = false; private static bool m_initialized = false;
@ -58,7 +57,6 @@ namespace OpenSim.Data.SQLite
: base(connectionString) : base(connectionString)
{ {
m_Realm = realm; m_Realm = realm;
m_connectionString = connectionString;
if (!m_initialized) if (!m_initialized)
{ {

View File

@ -47,7 +47,7 @@ namespace OpenSim.Data.SQLite
public class SQLiteAvatarData : SQLiteGenericTableHandler<AvatarBaseData>, public class SQLiteAvatarData : SQLiteGenericTableHandler<AvatarBaseData>,
IAvatarData IAvatarData
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public SQLiteAvatarData(string connectionString, string realm) : public SQLiteAvatarData(string connectionString, string realm) :
base(connectionString, realm, "Avatar") base(connectionString, realm, "Avatar")

View File

@ -460,7 +460,7 @@ namespace OpenSim.Framework
{ {
info["state"] = OSD.FromString(AttachmentObjectStates[i++]); info["state"] = OSD.FromString(AttachmentObjectStates[i++]);
} }
catch (IndexOutOfRangeException e) catch (IndexOutOfRangeException)
{ {
m_log.WarnFormat("[CHILD AGENT DATA]: scripts list is shorter than object list."); m_log.WarnFormat("[CHILD AGENT DATA]: scripts list is shorter than object list.");
} }

View File

@ -29,113 +29,13 @@ namespace OpenSim.Framework
{ {
public class ConfigSettings public class ConfigSettings
{ {
private string m_physicsEngine; public string PhysicsEngine { get; set; }
public string MeshEngineName { get; set; }
public string PhysicsEngine public bool See_into_region_from_neighbor { get; set; }
{ public string StorageDll { get; set; }
get { return m_physicsEngine; } public string ClientstackDll { get; set; }
set { m_physicsEngine = value; } public bool PhysicalPrim { get; set; }
} public string LibrariesXMLFile { get; set; }
private string m_meshEngineName;
public string MeshEngineName
{
get { return m_meshEngineName; }
set { m_meshEngineName = value; }
}
private bool m_see_into_region_from_neighbor;
public bool See_into_region_from_neighbor
{
get { return m_see_into_region_from_neighbor; }
set { m_see_into_region_from_neighbor = value; }
}
private string m_storageDll;
public string StorageDll
{
get { return m_storageDll; }
set { m_storageDll = value; }
}
private string m_clientstackDll;
public string ClientstackDll
{
get { return m_clientstackDll; }
set { m_clientstackDll = value; }
}
private bool m_physicalPrim;
public bool PhysicalPrim
{
get { return m_physicalPrim; }
set { m_physicalPrim = value; }
}
private bool m_standaloneAuthenticate = false;
public bool StandaloneAuthenticate
{
get { return m_standaloneAuthenticate; }
set { m_standaloneAuthenticate = value; }
}
private string m_standaloneWelcomeMessage = null;
public string StandaloneWelcomeMessage
{
get { return m_standaloneWelcomeMessage; }
set { m_standaloneWelcomeMessage = value; }
}
private string m_standaloneInventoryPlugin;
public string StandaloneInventoryPlugin
{
get { return m_standaloneInventoryPlugin; }
set { m_standaloneInventoryPlugin = value; }
}
private string m_standaloneUserPlugin;
public string StandaloneUserPlugin
{
get { return m_standaloneUserPlugin; }
set { m_standaloneUserPlugin = value; }
}
private string m_standaloneInventorySource;
public string StandaloneInventorySource
{
get { return m_standaloneInventorySource; }
set { m_standaloneInventorySource = value; }
}
private string m_standaloneUserSource;
public string StandaloneUserSource
{
get { return m_standaloneUserSource; }
set { m_standaloneUserSource = value; }
}
protected string m_librariesXMLFile;
public string LibrariesXMLFile
{
get
{
return m_librariesXMLFile;
}
set
{
m_librariesXMLFile = value;
}
}
public const uint DefaultAssetServerHttpPort = 8003; public const uint DefaultAssetServerHttpPort = 8003;
public const uint DefaultRegionHttpPort = 9000; public const uint DefaultRegionHttpPort = 9000;

View File

@ -52,6 +52,11 @@ namespace OpenSim.Framework
return GetHttpServer(port,null); return GetHttpServer(port,null);
} }
public static void AddHttpServer(BaseHttpServer server)
{
m_Servers.Add(server.Port, server);
}
public static IHttpServer GetHttpServer(uint port, IPAddress ipaddr) public static IHttpServer GetHttpServer(uint port, IPAddress ipaddr)
{ {
if (port == 0) if (port == 0)

View File

@ -49,6 +49,12 @@ namespace OpenSim.Framework
public string HttpSSLCN = ""; public string HttpSSLCN = "";
public uint httpSSLPort = 9001; public uint httpSSLPort = 9001;
// "Out of band" managemnt https
public bool ssl_listener = false;
public uint https_port = 0;
public string cert_path = String.Empty;
public string cert_pass = String.Empty;
public string MessagingURL = String.Empty; public string MessagingURL = String.Empty;
public NetworkServersInfo() public NetworkServersInfo()
@ -86,6 +92,15 @@ namespace OpenSim.Framework
secureInventoryServer = config.Configs["Network"].GetBoolean("secure_inventory_server", true); secureInventoryServer = config.Configs["Network"].GetBoolean("secure_inventory_server", true);
MessagingURL = config.Configs["Network"].GetString("messaging_server_url", string.Empty); MessagingURL = config.Configs["Network"].GetString("messaging_server_url", string.Empty);
// "Out of band management https"
ssl_listener = config.Configs["Network"].GetBoolean("https_listener",false);
if( ssl_listener)
{
cert_path = config.Configs["Network"].GetString("cert_path",String.Empty);
cert_pass = config.Configs["Network"].GetString("cert_pass",String.Empty);
https_port = (uint)config.Configs["Network"].GetInt("https_port", 0);
}
} }
} }
} }

View File

@ -38,7 +38,7 @@ namespace OpenSim.Framework
{ {
public class PriorityQueue public class PriorityQueue
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity); public delegate bool UpdatePriorityHandler(ref uint priority, ISceneEntity entity);

View File

@ -97,251 +97,6 @@ namespace OpenSim.Framework
} }
[Serializable]
public class SimpleRegionInfo
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// The port by which http communication occurs with the region (most noticeably, CAPS communication)
/// </summary>
public uint HttpPort
{
get { return m_httpPort; }
set { m_httpPort = value; }
}
protected uint m_httpPort;
/// <summary>
/// A well-formed URI for the host region server (namely "http://" + ExternalHostName)
/// </summary>
public string ServerURI
{
get {
if ( m_serverURI != string.Empty ) {
return m_serverURI;
} else {
return "http://" + m_externalHostName + ":" + m_httpPort + "/";
}
}
set {
if ( value.EndsWith("/") ) {
m_serverURI = value;
} else {
m_serverURI = value + '/';
}
}
}
protected string m_serverURI;
public string RegionName
{
get { return m_regionName; }
set { m_regionName = value; }
}
protected string m_regionName = String.Empty;
protected bool Allow_Alternate_Ports;
public bool m_allow_alternate_ports;
protected string m_externalHostName;
protected IPEndPoint m_internalEndPoint;
protected uint? m_regionLocX;
protected uint? m_regionLocY;
protected uint m_remotingPort;
public UUID RegionID = UUID.Zero;
public string RemotingAddress;
public UUID ScopeID = UUID.Zero;
public SimpleRegionInfo()
{
m_serverURI = string.Empty;
}
public SimpleRegionInfo(uint regionLocX, uint regionLocY, IPEndPoint internalEndPoint, string externalUri)
{
m_regionLocX = regionLocX;
m_regionLocY = regionLocY;
m_internalEndPoint = internalEndPoint;
m_externalHostName = externalUri;
m_serverURI = string.Empty;
}
public SimpleRegionInfo(uint regionLocX, uint regionLocY, string externalUri, uint port)
{
m_regionLocX = regionLocX;
m_regionLocY = regionLocY;
m_externalHostName = externalUri;
m_internalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), (int) port);
m_serverURI = string.Empty;
}
public SimpleRegionInfo(RegionInfo ConvertFrom)
{
m_regionName = ConvertFrom.RegionName;
m_regionLocX = ConvertFrom.RegionLocX;
m_regionLocY = ConvertFrom.RegionLocY;
m_internalEndPoint = ConvertFrom.InternalEndPoint;
m_externalHostName = ConvertFrom.ExternalHostName;
m_remotingPort = ConvertFrom.RemotingPort;
m_httpPort = ConvertFrom.HttpPort;
m_allow_alternate_ports = ConvertFrom.m_allow_alternate_ports;
RemotingAddress = ConvertFrom.RemotingAddress;
RegionID = UUID.Zero;
ServerURI = ConvertFrom.ServerURI;
}
public uint RemotingPort
{
get { return m_remotingPort; }
set { m_remotingPort = value; }
}
/// <value>
/// This accessor can throw all the exceptions that Dns.GetHostAddresses can throw.
///
/// XXX Isn't this really doing too much to be a simple getter, rather than an explict method?
/// </value>
public IPEndPoint ExternalEndPoint
{
get
{
// Old one defaults to IPv6
//return new IPEndPoint(Dns.GetHostAddresses(m_externalHostName)[0], m_internalEndPoint.Port);
IPAddress ia = null;
// If it is already an IP, don't resolve it - just return directly
if (IPAddress.TryParse(m_externalHostName, out ia))
return new IPEndPoint(ia, m_internalEndPoint.Port);
// Reset for next check
ia = null;
try
{
foreach (IPAddress Adr in Dns.GetHostAddresses(m_externalHostName))
{
if (ia == null)
ia = Adr;
if (Adr.AddressFamily == AddressFamily.InterNetwork)
{
ia = Adr;
break;
}
}
}
catch (SocketException e)
{
throw new Exception(
"Unable to resolve local hostname " + m_externalHostName + " innerException of type '" +
e + "' attached to this exception", e);
}
return new IPEndPoint(ia, m_internalEndPoint.Port);
}
set { m_externalHostName = value.ToString(); }
}
public string ExternalHostName
{
get { return m_externalHostName; }
set { m_externalHostName = value; }
}
public IPEndPoint InternalEndPoint
{
get { return m_internalEndPoint; }
set { m_internalEndPoint = value; }
}
public uint RegionLocX
{
get { return m_regionLocX.Value; }
set { m_regionLocX = value; }
}
public uint RegionLocY
{
get { return m_regionLocY.Value; }
set { m_regionLocY = value; }
}
public ulong RegionHandle
{
get { return Util.UIntsToLong((RegionLocX * (uint) Constants.RegionSize), (RegionLocY * (uint) Constants.RegionSize)); }
}
public int getInternalEndPointPort()
{
return m_internalEndPoint.Port;
}
public Dictionary<string, object> ToKeyValuePairs()
{
Dictionary<string, object> kvp = new Dictionary<string, object>();
kvp["uuid"] = RegionID.ToString();
kvp["locX"] = RegionLocX.ToString();
kvp["locY"] = RegionLocY.ToString();
kvp["external_ip_address"] = ExternalEndPoint.Address.ToString();
kvp["external_port"] = ExternalEndPoint.Port.ToString();
kvp["external_host_name"] = ExternalHostName;
kvp["http_port"] = HttpPort.ToString();
kvp["internal_ip_address"] = InternalEndPoint.Address.ToString();
kvp["internal_port"] = InternalEndPoint.Port.ToString();
kvp["alternate_ports"] = m_allow_alternate_ports.ToString();
kvp["server_uri"] = ServerURI;
return kvp;
}
public SimpleRegionInfo(Dictionary<string, object> kvp)
{
if ((kvp["external_ip_address"] != null) && (kvp["external_port"] != null))
{
int port = 0;
Int32.TryParse((string)kvp["external_port"], out port);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse((string)kvp["external_ip_address"]), port);
ExternalEndPoint = ep;
}
else
ExternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
if (kvp["external_host_name"] != null)
ExternalHostName = (string)kvp["external_host_name"];
if (kvp["http_port"] != null)
{
UInt32 port = 0;
UInt32.TryParse((string)kvp["http_port"], out port);
HttpPort = port;
}
if ((kvp["internal_ip_address"] != null) && (kvp["internal_port"] != null))
{
int port = 0;
Int32.TryParse((string)kvp["internal_port"], out port);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse((string)kvp["internal_ip_address"]), port);
InternalEndPoint = ep;
}
else
InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0);
if (kvp["alternate_ports"] != null)
{
bool alts = false;
Boolean.TryParse((string)kvp["alternate_ports"], out alts);
m_allow_alternate_ports = alts;
}
if (kvp["server_uri"] != null)
ServerURI = (string)kvp["server_uri"];
}
}
public class RegionInfo public class RegionInfo
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

View File

@ -32,6 +32,7 @@ using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Reflection; using System.Reflection;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
@ -72,6 +73,7 @@ namespace OpenSim.Framework.Servers.HttpServer
protected uint m_port; protected uint m_port;
protected uint m_sslport; protected uint m_sslport;
protected bool m_ssl; protected bool m_ssl;
private X509Certificate2 m_cert;
protected bool m_firstcaps = true; protected bool m_firstcaps = true;
protected string m_SSLCommonName = ""; protected string m_SSLCommonName = "";
@ -123,6 +125,14 @@ namespace OpenSim.Framework.Servers.HttpServer
} }
} }
public BaseHttpServer(uint port, bool ssl, string CPath, string CPass) : this (port, ssl)
{
if (m_ssl)
{
m_cert = new X509Certificate2(CPath, CPass);
}
}
/// <summary> /// <summary>
/// Add a stream handler to the http server. If the handler already exists, then nothing happens. /// Add a stream handler to the http server. If the handler already exists, then nothing happens.
/// </summary> /// </summary>
@ -1683,6 +1693,7 @@ namespace OpenSim.Framework.Servers.HttpServer
try try
{ {
//m_httpListener = new HttpListener(); //m_httpListener = new HttpListener();
NotSocketErrors = 0; NotSocketErrors = 0;
if (!m_ssl) if (!m_ssl)
{ {
@ -1702,6 +1713,9 @@ namespace OpenSim.Framework.Servers.HttpServer
{ {
//m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/"); //m_httpListener.Prefixes.Add("https://+:" + (m_sslport) + "/");
//m_httpListener.Prefixes.Add("http://+:" + m_port + "/"); //m_httpListener.Prefixes.Add("http://+:" + m_port + "/");
m_httpListener2 = CoolHTTPListener.Create(IPAddress.Any, (int)m_port, m_cert);
m_httpListener2.ExceptionThrown += httpServerException;
m_httpListener2.LogWriter = httpserverlog;
} }
m_httpListener2.RequestReceived += OnRequest; m_httpListener2.RequestReceived += OnRequest;

View File

@ -372,20 +372,6 @@ namespace OpenSim
= startupConfig.GetString("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll"); = startupConfig.GetString("clientstack_plugin", "OpenSim.Region.ClientStack.LindenUDP.dll");
} }
IConfig standaloneConfig = m_config.Source.Configs["StandAlone"];
if (standaloneConfig != null)
{
m_configSettings.StandaloneAuthenticate = standaloneConfig.GetBoolean("accounts_authenticate", true);
m_configSettings.StandaloneWelcomeMessage = standaloneConfig.GetString("welcome_message");
m_configSettings.StandaloneInventoryPlugin = standaloneConfig.GetString("inventory_plugin");
m_configSettings.StandaloneInventorySource = standaloneConfig.GetString("inventory_source");
m_configSettings.StandaloneUserPlugin = standaloneConfig.GetString("userDatabase_plugin");
m_configSettings.StandaloneUserSource = standaloneConfig.GetString("user_source");
m_configSettings.LibrariesXMLFile = standaloneConfig.GetString("LibrariesXMLFile");
}
m_networkServersInfo.loadFromConfiguration(m_config.Source); m_networkServersInfo.loadFromConfiguration(m_config.Source);
} }
} }

View File

@ -6038,7 +6038,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
AvatarWearingArgs wearingArgs = new AvatarWearingArgs(); AvatarWearingArgs wearingArgs = new AvatarWearingArgs();
for (int i = 0; i < nowWearing.WearableData.Length; i++) for (int i = 0; i < nowWearing.WearableData.Length; i++)
{ {
m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID); //m_log.DebugFormat("[XXX]: Wearable type {0} item {1}", nowWearing.WearableData[i].WearableType, nowWearing.WearableData[i].ItemID);
AvatarWearingArgs.Wearable wearable = AvatarWearingArgs.Wearable wearable =
new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID, new AvatarWearingArgs.Wearable(nowWearing.WearableData[i].ItemID,
nowWearing.WearableData[i].WearableType); nowWearing.WearableData[i].WearableType);

View File

@ -96,6 +96,22 @@ namespace OpenSim.Region.ClientStack
MainServer.Instance = m_httpServer; MainServer.Instance = m_httpServer;
// "OOB" Server
if (m_networkServersInfo.ssl_listener)
{
BaseHttpServer server = null;
server = new BaseHttpServer(
m_networkServersInfo.https_port, m_networkServersInfo.ssl_listener, m_networkServersInfo.cert_path,
m_networkServersInfo.cert_pass);
// Add the server to m_Servers
if(server != null)
{
m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port);
MainServer.AddHttpServer(server);
server.Start();
}
}
base.StartupSpecific(); base.StartupSpecific();
} }

View File

@ -162,12 +162,12 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
// one and we're done otherwise, ask for a rebake // one and we're done otherwise, ask for a rebake
if (checkonly) return false; if (checkonly) return false;
m_log.InfoFormat("[AVFACTORY] missing baked texture {0}, request rebake",face.TextureID); m_log.InfoFormat("[AVFACTORY]: missing baked texture {0}, requesting rebake",face.TextureID);
client.SendRebakeAvatarTextures(face.TextureID); client.SendRebakeAvatarTextures(face.TextureID);
} }
} }
m_log.DebugFormat("[AVFACTORY]: complete texture check for {0}", client.AgentId); m_log.DebugFormat("[AVFACTORY]: completed texture check for {0}", client.AgentId);
// If we only found default textures, then the appearance is not cached // If we only found default textures, then the appearance is not cached
return (defonly ? false : true); return (defonly ? false : true);

View File

@ -66,8 +66,8 @@ namespace OpenSim.Region.CoreModules.Framework
m_scene = scene; m_scene = scene;
m_scene.RegisterModuleInterface<ICapabilitiesModule>(this); m_scene.RegisterModuleInterface<ICapabilitiesModule>(this);
MainConsole.Instance.Commands.AddCommand("Capabilities", false, "show caps", MainConsole.Instance.Commands.AddCommand("Capabilities", false, "show caps",
"show capabilities", "show caps",
"Shows all registered capabilities", CapabilitiesCommand); "Shows all registered capabilities", CapabilitiesCommand);
} }
public void RegionLoaded(Scene scene) public void RegionLoaded(Scene scene)

View File

@ -911,6 +911,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent)) if (!m_scene.SimulationService.UpdateAgent(neighbourRegion, cAgent))
{ {
// region doesn't take it // region doesn't take it
ReInstantiateScripts(agent);
ResetFromTransit(agent.UUID); ResetFromTransit(agent.UUID);
return agent; return agent;
} }
@ -1787,14 +1788,22 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
protected void ReInstantiateScripts(ScenePresence sp) protected void ReInstantiateScripts(ScenePresence sp)
{ {
int i = 0; int i = 0;
sp.Attachments.ForEach(delegate(SceneObjectGroup sog) if (sp.InTransitScriptStates.Count > 0)
{ {
sog.SetState(sp.InTransitScriptStates[i++], sp.Scene); sp.Attachments.ForEach(delegate(SceneObjectGroup sog)
sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0); {
sog.ResumeScripts(); if (i < sp.InTransitScriptStates.Count)
}); {
sog.SetState(sp.InTransitScriptStates[i++], sp.Scene);
sog.CreateScriptInstances(0, false, sp.Scene.DefaultScriptEngine, 0);
sog.ResumeScripts();
}
else
m_log.ErrorFormat("[ENTITY TRANSFER MODULE]: InTransitScriptStates.Count={0} smaller than Attachments.Count={1}", sp.InTransitScriptStates.Count, sp.Attachments.Count);
});
sp.InTransitScriptStates.Clear(); sp.InTransitScriptStates.Clear();
}
} }
#endregion #endregion

View File

@ -79,7 +79,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
private int m_TotalUrls = 5000; private int m_TotalUrls = 5000;
private uint https_port = 0;
private IHttpServer m_HttpServer = null; private IHttpServer m_HttpServer = null;
private IHttpServer m_HttpsServer = null;
private string m_ExternalHostNameForLSL = ""; private string m_ExternalHostNameForLSL = "";
@ -101,6 +103,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
public void Initialise(IConfigSource config) public void Initialise(IConfigSource config)
{ {
m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName);
bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false);
if (ssl_enabled)
{
https_port = (uint) config.Configs["Network"].GetInt("https_port",0);
}
} }
public void PostInitialise() public void PostInitialise()
@ -114,6 +121,12 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
// There can only be one // There can only be one
// //
m_HttpServer = MainServer.Instance; m_HttpServer = MainServer.Instance;
//
// We can use the https if it is enabled
if (https_port > 0)
{
m_HttpsServer = MainServer.GetHttpServer(https_port);
}
} }
scene.RegisterModuleInterface<IUrlModule>(this); scene.RegisterModuleInterface<IUrlModule>(this);
@ -171,7 +184,40 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
{ {
UUID urlcode = UUID.Random(); UUID urlcode = UUID.Random();
engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" }); if (m_HttpsServer == null)
{
engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
return urlcode;
}
lock (m_UrlMap)
{
if (m_UrlMap.Count >= m_TotalUrls)
{
engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_DENIED", "" });
return urlcode;
}
string url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + "/lslhttps/" + urlcode.ToString() + "/";
UrlData urlData = new UrlData();
urlData.hostID = host.UUID;
urlData.itemID = itemID;
urlData.engine = engine;
urlData.url = url;
urlData.urlcode = urlcode;
urlData.requests = new Dictionary<UUID, RequestData>();
m_UrlMap[url] = urlData;
string uri = "/lslhttps/" + urlcode.ToString() + "/";
m_HttpsServer.AddPollServiceHTTPHandler(uri,HandleHttpPoll,
new PollServiceEventArgs(HttpRequestHandler,HasEvents, GetEvents, NoEvents,
urlcode));
engine.PostScriptEvent(itemID, "http_request", new Object[] { urlcode.ToString(), "URL_REQUEST_GRANTED", url });
}
return urlcode; return urlcode;
} }
@ -349,7 +395,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
} }
private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) private Hashtable GetEvents(UUID requestID, UUID sessionID, string request)
{ {
UrlData url = null; UrlData url = null;
RequestData requestData = null; RequestData requestData = null;
lock (m_RequestMap) lock (m_RequestMap)
@ -396,6 +442,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
lock (request) lock (request)
{ {
string uri = request["uri"].ToString(); string uri = request["uri"].ToString();
bool is_ssl = uri.Contains("lslhttps");
try try
{ {
@ -414,7 +461,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp
pathInfo = uri.Substring(pos3); pathInfo = uri.Substring(pos3);
UrlData url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp]; UrlData url = null;
if (!is_ssl)
url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp];
else
url = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp];
//for llGetHttpHeader support we need to store original URI here //for llGetHttpHeader support we need to store original URI here
//to make x-path-info / x-query-string / x-script-url / x-remote-ip headers //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers

View File

@ -76,19 +76,26 @@ namespace OpenSim.Region.CoreModules.World.Region
scene.RegionInfo.RegionID.ToString())); scene.RegionInfo.RegionID.ToString()));
m_Scene = scene; m_Scene = scene;
scene.RegisterModuleInterface<IRestartModule>(this); scene.RegisterModuleInterface<IRestartModule>(this);
MainConsole.Instance.Commands.AddCommand("RestartModule", MainConsole.Instance.Commands.AddCommand("RestartModule",
false, "region restart bluebox", false, "region restart bluebox",
"region restart bluebox <message> <time> ...", "region restart bluebox <message> <delta seconds>+",
"Restart the region", HandleRegionRestart); "Schedule a region restart",
"Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a transient notice. If multiple deltas are given then a notice is sent when we reach each delta.",
HandleRegionRestart);
MainConsole.Instance.Commands.AddCommand("RestartModule", MainConsole.Instance.Commands.AddCommand("RestartModule",
false, "region restart notice", false, "region restart notice",
"region restart notice <message> <time> ...", "region restart notice <message> <delta seconds>+",
"Restart the region", HandleRegionRestart); "Schedule a region restart",
"Schedule a region restart after a given number of seconds. If one delta is given then the region is restarted in delta seconds time. A time to restart is sent to users in the region as a dismissable bluebox notice. If multiple deltas are given then a notice is sent when we reach each delta.",
HandleRegionRestart);
MainConsole.Instance.Commands.AddCommand("RestartModule", MainConsole.Instance.Commands.AddCommand("RestartModule",
false, "region restart abort", false, "region restart abort",
"region restart abort [<message>]", "region restart abort [<message>]",
"Restart the region", HandleRegionRestart); "Abort a region restart", HandleRegionRestart);
} }
public void RegionLoaded(Scene scene) public void RegionLoaded(Scene scene)
@ -260,7 +267,7 @@ namespace OpenSim.Region.CoreModules.World.Region
} }
} }
MainConsole.Instance.Output("Error: restart region <mode> <name> <time> ..."); MainConsole.Instance.Output("Error: restart region <mode> <name> <delta seconds>+");
return; return;
} }

View File

@ -698,7 +698,7 @@ namespace OpenSim.Region.Framework.Scenes
newName = item.Name; newName = item.Name;
} }
if (remoteClient.AgentId == oldAgentID) if (remoteClient.AgentId == oldAgentID || (LibraryService != null && LibraryService.LibraryRootFolder != null && oldAgentID == LibraryService.LibraryRootFolder.Owner))
{ {
CreateNewInventoryItem( CreateNewInventoryItem(
remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType, remoteClient, item.CreatorId, item.CreatorData, newFolderID, newName, item.Flags, callbackID, asset, (sbyte)item.InvType,

View File

@ -802,6 +802,8 @@ namespace OpenSim.Region.Framework.Scenes
m_regInfo = regInfo; m_regInfo = regInfo;
m_eventManager = new EventManager(); m_eventManager = new EventManager();
m_permissions = new ScenePermissions(this);
m_lastUpdate = Util.EnvironmentTickCount(); m_lastUpdate = Util.EnvironmentTickCount();
} }

View File

@ -2847,8 +2847,12 @@ namespace OpenSim.Region.Framework.Scenes
float speed = Velocity.Length(); float speed = Velocity.Length();
float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity); float velocidyDiff = Vector3.Distance(lastVelocitySentToAllClients, Velocity);
// assuming 5 ms. worst case precision for timer, use 2x that
// for distance error threshold
float distanceErrorThreshold = speed * 0.01f;
if (speed < 0.01f // allow rotation updates if avatar position is unchanged if (speed < 0.01f // allow rotation updates if avatar position is unchanged
|| Math.Abs(distanceError) > 0.25f // arbitrary distance error threshold || Math.Abs(distanceError) > distanceErrorThreshold
|| velocidyDiff > 0.01f) // did velocity change from last update? || velocidyDiff > 0.01f) // did velocity change from last update?
{ {
m_perfMonMS = currentTick; m_perfMonMS = currentTick;
@ -3568,7 +3572,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
cAgent.AttachmentObjects = new List<ISceneObject>(); cAgent.AttachmentObjects = new List<ISceneObject>();
cAgent.AttachmentObjectStates = new List<string>(); cAgent.AttachmentObjectStates = new List<string>();
IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>(); // IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>();
m_InTransitScriptStates.Clear(); m_InTransitScriptStates.Clear();
foreach (SceneObjectGroup sog in m_attachments) foreach (SceneObjectGroup sog in m_attachments)
{ {

View File

@ -107,11 +107,10 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
scene.AddCommand( scene.AddCommand(
this, "emergency-monitoring", this, "emergency-monitoring",
"Go on/off emergency monitoring mode", "emergency-monitoring",
"Go on/off emergency monitoring mode", "Go on/off emergency monitoring mode",
"Go on/off emergency monitoring mode", "Go on/off emergency monitoring mode",
EmergencyMonitoring); EmergencyMonitoring);
} }
public void RemoveRegion(Scene scene) public void RemoveRegion(Scene scene)
@ -190,7 +189,7 @@ namespace OpenSim.Region.CoreModules.UDP.Linden
int maxNameLength = 18; int maxNameLength = 18;
int maxRegionNameLength = 14; int maxRegionNameLength = 14;
int maxTypeLength = 4; int maxTypeLength = 4;
int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding; // int totalInfoFieldsLength = maxNameLength + columnPadding + maxRegionNameLength + columnPadding + maxTypeLength + columnPadding;
report.Append(GetColumnEntry("User", maxNameLength, columnPadding)); report.Append(GetColumnEntry("User", maxNameLength, columnPadding));
report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding)); report.Append(GetColumnEntry("Region", maxRegionNameLength, columnPadding));

View File

@ -0,0 +1,122 @@
/*
* 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.Reflection;
using System.Text;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Statistics;
using OpenSim.Region.ClientStack.LindenUDP;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.OptionalModules.Avatar.Appearance
{
/// <summary>
/// A module that just holds commands for inspecting avatar appearance.
/// </summary>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "AppearanceInfoModule")]
public class AppearanceInfoModule : ISharedRegionModule
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
protected IAvatarFactory m_avatarFactory;
public string Name { get { return "Appearance Information Module"; } }
public Type ReplaceableInterface { get { return null; } }
public void Initialise(IConfigSource source)
{
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: INITIALIZED MODULE");
}
public void PostInitialise()
{
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: POST INITIALIZED MODULE");
}
public void Close()
{
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: CLOSED MODULE");
}
public void AddRegion(Scene scene)
{
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
}
public void RemoveRegion(Scene scene)
{
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
lock (m_scenes)
m_scenes.Remove(scene.RegionInfo.RegionID);
}
public void RegionLoaded(Scene scene)
{
// m_log.DebugFormat("[APPEARANCE INFO MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
lock (m_scenes)
m_scenes[scene.RegionInfo.RegionID] = scene;
scene.AddCommand(
this, "appearance show",
"appearance show",
"Show appearance information for each avatar in the simulator. At the moment, ",
ShowAppearanceInfo);
}
protected void ShowAppearanceInfo(string module, string[] cmd)
{
lock (m_scenes)
{
foreach (Scene scene in m_scenes.Values)
{
scene.ForEachClient(
delegate(IClientAPI client)
{
if (client is LLClientView && !((LLClientView)client).ChildAgentStatus())
{
bool bakedTextureValid = scene.AvatarFactory.ValidateBakedTextureCache(client);
MainConsole.Instance.OutputFormat(
"{0} baked apperance texture is {1}", client.Name, bakedTextureValid ? "OK" : "corrupt");
}
});
}
}
}
}
}

View File

@ -13,5 +13,6 @@
<RegionModule id="Concierge" type="OpenSim.Region.OptionalModules.Avatar.Concierge.ConciergeModule" /> <RegionModule id="Concierge" type="OpenSim.Region.OptionalModules.Avatar.Concierge.ConciergeModule" />
<RegionModule id="VivoxVoice" type="OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice.VivoxVoiceModule" /> <RegionModule id="VivoxVoice" type="OpenSim.Region.OptionalModules.Avatar.Voice.VivoxVoice.VivoxVoiceModule" />
<RegionModule id="WorldViewModule" type="OpenSim.Region.OptionalModules.World.WorldView.WorldViewModule" /> <RegionModule id="WorldViewModule" type="OpenSim.Region.OptionalModules.World.WorldView.WorldViewModule" />
<RegionModule id="AutoBackupModule" type="OpenSim.Region.OptionalModules.World.AutoBackup.AutoBackupModule" />
</Extension> </Extension>
</Addin> </Addin>

View File

@ -0,0 +1,929 @@
/*
* 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.Diagnostics;
using System.IO;
using System.Reflection;
using System.Timers;
using System.Text.RegularExpressions;
using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.OptionalModules.World.AutoBackup
{
/// <summary>
/// Choose between ways of naming the backup files that are generated.
/// </summary>
/// <remarks>Time: OARs are named by a timestamp.
/// Sequential: OARs are named by counting (Region_1.oar, Region_2.oar, etc.)
/// Overwrite: Only one file per region is created; it's overwritten each time a backup is made.</remarks>
public enum NamingType
{
Time,
Sequential,
Overwrite
}
///<summary>
/// AutoBackupModule: save OAR region backups to disk periodically
/// </summary>
/// <remarks>
/// Config Settings Documentation.
/// At the TOP LEVEL, e.g. in OpenSim.ini, we have the following options:
/// EACH REGION, in OpenSim.ini, can have the following settings under the [AutoBackupModule] section.
/// IMPORTANT: You may optionally specify the key name as follows for a per-region key: [Region Name].[Key Name]
/// Example: My region is named Foo.
/// If I wanted to specify the "AutoBackupInterval" key just for this region, I would name my key "Foo.AutoBackupInterval", under the [AutoBackupModule] section of OpenSim.ini.
/// Instead of specifying them on a per-region basis, you can also omit the region name to specify the default setting for all regions.
/// Region-specific settings take precedence.
///
/// AutoBackupModuleEnabled: True/False. Default: False. If True, use the auto backup module. This setting does not support per-region basis.
/// All other settings under [AutoBackupModule] are ignored if AutoBackupModuleEnabled is false, even per-region settings!
/// AutoBackup: True/False. Default: False. If True, activate auto backup functionality.
/// This is the only required option for enabling auto-backup; the other options have sane defaults.
/// If False for a particular region, the auto-backup module becomes a no-op for the region, and all other AutoBackup* settings are ignored.
/// If False globally (the default), only regions that specifically override this with "FooRegion.AutoBackup = true" will get AutoBackup functionality.
/// AutoBackupInterval: Double, non-negative value. Default: 720 (12 hours).
/// The number of minutes between each backup attempt.
/// If a negative or zero value is given, it is equivalent to setting AutoBackup = False.
/// AutoBackupBusyCheck: True/False. Default: True.
/// If True, we will only take an auto-backup if a set of conditions are met.
/// These conditions are heuristics to try and avoid taking a backup when the sim is busy.
/// AutoBackupScript: String. Default: not specified (disabled).
/// File path to an executable script or binary to run when an automatic backup is taken.
/// The file should really be (Windows) an .exe or .bat, or (Linux/Mac) a shell script or binary.
/// Trying to "run" directories, or things with weird file associations on Win32, might cause unexpected results!
/// argv[1] of the executed file/script will be the file name of the generated OAR.
/// If the process can't be spawned for some reason (file not found, no execute permission, etc), write a warning to the console.
/// AutoBackupNaming: string. Default: Time.
/// One of three strings (case insensitive):
/// "Time": Current timestamp is appended to file name. An existing file will never be overwritten.
/// "Sequential": A number is appended to the file name. So if RegionName_x.oar exists, we'll save to RegionName_{x+1}.oar next. An existing file will never be overwritten.
/// "Overwrite": Always save to file named "${AutoBackupDir}/RegionName.oar", even if we have to overwrite an existing file.
/// AutoBackupDir: String. Default: "." (the current directory).
/// A directory (absolute or relative) where backups should be saved.
/// AutoBackupDilationThreshold: float. Default: 0.5. Lower bound on time dilation required for BusyCheck heuristics to pass.
/// If the time dilation is below this value, don't take a backup right now.
/// AutoBackupAgentThreshold: int. Default: 10. Upper bound on # of agents in region required for BusyCheck heuristics to pass.
/// If the number of agents is greater than this value, don't take a backup right now
/// Save memory by setting low initial capacities. Minimizes impact in common cases of all regions using same interval, and instances hosting 1 ~ 4 regions.
/// Also helps if you don't want AutoBackup at all.
/// </remarks>
public class AutoBackupModule : ISharedRegionModule
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly Dictionary<Guid, IScene> m_pendingSaves = new Dictionary<Guid, IScene>(1);
private readonly AutoBackupModuleState m_defaultState = new AutoBackupModuleState();
private readonly Dictionary<IScene, AutoBackupModuleState> m_states =
new Dictionary<IScene, AutoBackupModuleState>(1);
private readonly Dictionary<Timer, List<IScene>> m_timerMap =
new Dictionary<Timer, List<IScene>>(1);
private readonly Dictionary<double, Timer> m_timers = new Dictionary<double, Timer>(1);
private delegate T DefaultGetter<T>(string settingName, T defaultValue);
private bool m_enabled;
/// <summary>
/// Whether the shared module should be enabled at all. NOT the same as m_Enabled in AutoBackupModuleState!
/// </summary>
private bool m_closed;
private IConfigSource m_configSource;
/// <summary>
/// Required by framework.
/// </summary>
public bool IsSharedModule
{
get { return true; }
}
#region ISharedRegionModule Members
/// <summary>
/// Identifies the module to the system.
/// </summary>
string IRegionModuleBase.Name
{
get { return "AutoBackupModule"; }
}
/// <summary>
/// We don't implement an interface, this is a single-use module.
/// </summary>
Type IRegionModuleBase.ReplaceableInterface
{
get { return null; }
}
/// <summary>
/// Called once in the lifetime of the module at startup.
/// </summary>
/// <param name="source">The input config source for OpenSim.ini.</param>
void IRegionModuleBase.Initialise(IConfigSource source)
{
// Determine if we have been enabled at all in OpenSim.ini -- this is part and parcel of being an optional module
this.m_configSource = source;
IConfig moduleConfig = source.Configs["AutoBackupModule"];
if (moduleConfig == null)
{
this.m_enabled = false;
return;
}
else
{
this.m_enabled = moduleConfig.GetBoolean("AutoBackupModuleEnabled", false);
if (this.m_enabled)
{
m_log.Info("[AUTO BACKUP]: AutoBackupModule enabled");
}
else
{
return;
}
}
Timer defTimer = new Timer(43200000);
this.m_defaultState.Timer = defTimer;
this.m_timers.Add(43200000, defTimer);
defTimer.Elapsed += this.HandleElapsed;
defTimer.AutoReset = true;
defTimer.Start();
AutoBackupModuleState abms = this.ParseConfig(null, true);
m_log.Debug("[AUTO BACKUP]: Here is the default config:");
m_log.Debug(abms.ToString());
}
/// <summary>
/// Called once at de-init (sim shutting down).
/// </summary>
void IRegionModuleBase.Close()
{
if (!this.m_enabled)
{
return;
}
// We don't want any timers firing while the sim's coming down; strange things may happen.
this.StopAllTimers();
}
/// <summary>
/// Currently a no-op for AutoBackup because we have to wait for region to be fully loaded.
/// </summary>
/// <param name="scene"></param>
void IRegionModuleBase.AddRegion(Scene scene)
{
}
/// <summary>
/// Here we just clean up some resources and stop the OAR backup (if any) for the given scene.
/// </summary>
/// <param name="scene">The scene (region) to stop performing AutoBackup on.</param>
void IRegionModuleBase.RemoveRegion(Scene scene)
{
if (!this.m_enabled)
{
return;
}
if (this.m_states.ContainsKey(scene))
{
AutoBackupModuleState abms = this.m_states[scene];
// Remove this scene out of the timer map list
Timer timer = abms.Timer;
List<IScene> list = this.m_timerMap[timer];
list.Remove(scene);
// Shut down the timer if this was the last scene for the timer
if (list.Count == 0)
{
this.m_timerMap.Remove(timer);
this.m_timers.Remove(timer.Interval);
timer.Close();
}
this.m_states.Remove(scene);
}
}
/// <summary>
/// Most interesting/complex code paths in AutoBackup begin here.
/// We read lots of Nini config, maybe set a timer, add members to state tracking Dictionaries, etc.
/// </summary>
/// <param name="scene">The scene to (possibly) perform AutoBackup on.</param>
void IRegionModuleBase.RegionLoaded(Scene scene)
{
if (!this.m_enabled)
{
return;
}
// This really ought not to happen, but just in case, let's pretend it didn't...
if (scene == null)
{
return;
}
AutoBackupModuleState abms = this.ParseConfig(scene, false);
m_log.Debug("[AUTO BACKUP]: Config for " + scene.RegionInfo.RegionName);
m_log.Debug((abms == null ? "DEFAULT" : abms.ToString()));
}
/// <summary>
/// Currently a no-op.
/// </summary>
void ISharedRegionModule.PostInitialise()
{
}
#endregion
/// <summary>
/// Set up internal state for a given scene. Fairly complex code.
/// When this method returns, we've started auto-backup timers, put members in Dictionaries, and created a State object for this scene.
/// </summary>
/// <param name="scene">The scene to look at.</param>
/// <param name="parseDefault">Whether this call is intended to figure out what we consider the "default" config (applied to all regions unless overridden by per-region settings).</param>
/// <returns>An AutoBackupModuleState contains most information you should need to know relevant to auto-backup, as applicable to a single region.</returns>
private AutoBackupModuleState ParseConfig(IScene scene, bool parseDefault)
{
string sRegionName;
string sRegionLabel;
string prepend;
AutoBackupModuleState state;
if (parseDefault)
{
sRegionName = null;
sRegionLabel = "DEFAULT";
prepend = "";
state = this.m_defaultState;
}
else
{
sRegionName = scene.RegionInfo.RegionName;
sRegionLabel = sRegionName;
prepend = sRegionName + ".";
state = null;
}
// Read the config settings and set variables.
IConfig regionConfig = (scene != null ? scene.Config.Configs[sRegionName] : null);
IConfig config = this.m_configSource.Configs["AutoBackupModule"];
if (config == null)
{
// defaultState would be disabled too if the section doesn't exist.
state = this.m_defaultState;
return state;
}
bool tmpEnabled = ResolveBoolean("AutoBackup", this.m_defaultState.Enabled, config, regionConfig);
if (state == null && tmpEnabled != this.m_defaultState.Enabled)
//Varies from default state
{
state = new AutoBackupModuleState();
}
if (state != null)
{
state.Enabled = tmpEnabled;
}
// If you don't want AutoBackup, we stop.
if ((state == null && !this.m_defaultState.Enabled) || (state != null && !state.Enabled))
{
return state;
}
else
{
m_log.Info("[AUTO BACKUP]: Region " + sRegionLabel + " is AutoBackup ENABLED.");
}
// Borrow an existing timer if one exists for the same interval; otherwise, make a new one.
double interval =
this.ResolveDouble("AutoBackupInterval", this.m_defaultState.IntervalMinutes,
config, regionConfig) * 60000.0;
if (state == null && interval != this.m_defaultState.IntervalMinutes*60000.0)
{
state = new AutoBackupModuleState();
}
if (this.m_timers.ContainsKey(interval))
{
if (state != null)
{
state.Timer = this.m_timers[interval];
}
m_log.Debug("[AUTO BACKUP]: Reusing timer for " + interval + " msec for region " +
sRegionLabel);
}
else
{
// 0 or negative interval == do nothing.
if (interval <= 0.0 && state != null)
{
state.Enabled = false;
return state;
}
if (state == null)
{
state = new AutoBackupModuleState();
}
Timer tim = new Timer(interval);
state.Timer = tim;
//Milliseconds -> minutes
this.m_timers.Add(interval, tim);
tim.Elapsed += this.HandleElapsed;
tim.AutoReset = true;
tim.Start();
}
// Add the current region to the list of regions tied to this timer.
if (scene != null)
{
if (state != null)
{
if (this.m_timerMap.ContainsKey(state.Timer))
{
this.m_timerMap[state.Timer].Add(scene);
}
else
{
List<IScene> scns = new List<IScene>(1);
scns.Add(scene);
this.m_timerMap.Add(state.Timer, scns);
}
}
else
{
if (this.m_timerMap.ContainsKey(this.m_defaultState.Timer))
{
this.m_timerMap[this.m_defaultState.Timer].Add(scene);
}
else
{
List<IScene> scns = new List<IScene>(1);
scns.Add(scene);
this.m_timerMap.Add(this.m_defaultState.Timer, scns);
}
}
}
bool tmpBusyCheck = ResolveBoolean("AutoBackupBusyCheck",
this.m_defaultState.BusyCheck, config, regionConfig);
if (state == null && tmpBusyCheck != this.m_defaultState.BusyCheck)
{
state = new AutoBackupModuleState();
}
if (state != null)
{
state.BusyCheck = tmpBusyCheck;
}
// Set file naming algorithm
string stmpNamingType = ResolveString("AutoBackupNaming",
this.m_defaultState.NamingType.ToString(), config, regionConfig);
NamingType tmpNamingType;
if (stmpNamingType.Equals("Time", StringComparison.CurrentCultureIgnoreCase))
{
tmpNamingType = NamingType.Time;
}
else if (stmpNamingType.Equals("Sequential", StringComparison.CurrentCultureIgnoreCase))
{
tmpNamingType = NamingType.Sequential;
}
else if (stmpNamingType.Equals("Overwrite", StringComparison.CurrentCultureIgnoreCase))
{
tmpNamingType = NamingType.Overwrite;
}
else
{
m_log.Warn("Unknown naming type specified for region " + sRegionLabel + ": " +
stmpNamingType);
tmpNamingType = NamingType.Time;
}
if (state == null && tmpNamingType != this.m_defaultState.NamingType)
{
state = new AutoBackupModuleState();
}
if (state != null)
{
state.NamingType = tmpNamingType;
}
string tmpScript = ResolveString("AutoBackupScript",
this.m_defaultState.Script, config, regionConfig);
if (state == null && tmpScript != this.m_defaultState.Script)
{
state = new AutoBackupModuleState();
}
if (state != null)
{
state.Script = tmpScript;
}
string tmpBackupDir = ResolveString("AutoBackupDir", ".", config, regionConfig);
if (state == null && tmpBackupDir != this.m_defaultState.BackupDir)
{
state = new AutoBackupModuleState();
}
if (state != null)
{
state.BackupDir = tmpBackupDir;
// Let's give the user some convenience and auto-mkdir
if (state.BackupDir != ".")
{
try
{
DirectoryInfo dirinfo = new DirectoryInfo(state.BackupDir);
if (!dirinfo.Exists)
{
dirinfo.Create();
}
}
catch (Exception e)
{
m_log.Warn(
"BAD NEWS. You won't be able to save backups to directory " +
state.BackupDir +
" because it doesn't exist or there's a permissions issue with it. Here's the exception.",
e);
}
}
}
return state;
}
/// <summary>
/// Helper function for ParseConfig.
/// </summary>
/// <param name="settingName"></param>
/// <param name="defaultValue"></param>
/// <param name="global"></param>
/// <param name="local"></param>
/// <returns></returns>
private bool ResolveBoolean(string settingName, bool defaultValue, IConfig global, IConfig local)
{
if(local != null)
{
return local.GetBoolean(settingName, global.GetBoolean(settingName, defaultValue));
}
else
{
return global.GetBoolean(settingName, defaultValue);
}
}
/// <summary>
/// Helper function for ParseConfig.
/// </summary>
/// <param name="settingName"></param>
/// <param name="defaultValue"></param>
/// <param name="global"></param>
/// <param name="local"></param>
/// <returns></returns>
private double ResolveDouble(string settingName, double defaultValue, IConfig global, IConfig local)
{
if (local != null)
{
return local.GetDouble(settingName, global.GetDouble(settingName, defaultValue));
}
else
{
return global.GetDouble(settingName, defaultValue);
}
}
/// <summary>
/// Helper function for ParseConfig.
/// </summary>
/// <param name="settingName"></param>
/// <param name="defaultValue"></param>
/// <param name="global"></param>
/// <param name="local"></param>
/// <returns></returns>
private int ResolveInt(string settingName, int defaultValue, IConfig global, IConfig local)
{
if (local != null)
{
return local.GetInt(settingName, global.GetInt(settingName, defaultValue));
}
else
{
return global.GetInt(settingName, defaultValue);
}
}
/// <summary>
/// Helper function for ParseConfig.
/// </summary>
/// <param name="settingName"></param>
/// <param name="defaultValue"></param>
/// <param name="global"></param>
/// <param name="local"></param>
/// <returns></returns>
private string ResolveString(string settingName, string defaultValue, IConfig global, IConfig local)
{
if (local != null)
{
return local.GetString(settingName, global.GetString(settingName, defaultValue));
}
else
{
return global.GetString(settingName, defaultValue);
}
}
/// <summary>
/// Called when any auto-backup timer expires. This starts the code path for actually performing a backup.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandleElapsed(object sender, ElapsedEventArgs e)
{
// TODO: heuristic thresholds are per-region, so we should probably run heuristics once per region
// XXX: Running heuristics once per region could add undue performance penalty for something that's supposed to
// check whether the region is too busy! Especially on sims with LOTS of regions.
// Alternative: make heuristics thresholds global to the module rather than per-region. Less flexible,
// but would allow us to be semantically correct while being easier on perf.
// Alternative 2: Run heuristics once per unique set of heuristics threshold parameters! Ay yi yi...
// Alternative 3: Don't support per-region heuristics at all; just accept them as a global only parameter.
// Since this is pretty experimental, I haven't decided which alternative makes the most sense.
if (this.m_closed)
{
return;
}
bool heuristicsRun = false;
bool heuristicsPassed = false;
if (!this.m_timerMap.ContainsKey((Timer) sender))
{
m_log.Debug("Code-up error: timerMap doesn't contain timer " + sender);
}
List<IScene> tmap = this.m_timerMap[(Timer) sender];
if (tmap != null && tmap.Count > 0)
{
foreach (IScene scene in tmap)
{
AutoBackupModuleState state = this.m_states[scene];
bool heuristics = state.BusyCheck;
// Fast path: heuristics are on; already ran em; and sim is fine; OR, no heuristics for the region.
if ((heuristics && heuristicsRun && heuristicsPassed) || !heuristics)
{
this.DoRegionBackup(scene);
// Heuristics are on; ran but we're too busy -- keep going. Maybe another region will have heuristics off!
}
else if (heuristicsRun)
{
m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " +
scene.RegionInfo.RegionName + " right now.");
continue;
// Logical Deduction: heuristics are on but haven't been run
}
else
{
heuristicsPassed = this.RunHeuristics(scene);
heuristicsRun = true;
if (!heuristicsPassed)
{
m_log.Info("[AUTO BACKUP]: Heuristics: too busy to backup " +
scene.RegionInfo.RegionName + " right now.");
continue;
}
this.DoRegionBackup(scene);
}
}
}
}
/// <summary>
/// Save an OAR, register for the callback for when it's done, then call the AutoBackupScript (if applicable).
/// </summary>
/// <param name="scene"></param>
private void DoRegionBackup(IScene scene)
{
if (scene.RegionStatus != RegionStatus.Up)
{
// We won't backup a region that isn't operating normally.
m_log.Warn("[AUTO BACKUP]: Not backing up region " + scene.RegionInfo.RegionName +
" because its status is " + scene.RegionStatus);
return;
}
AutoBackupModuleState state = this.m_states[scene];
IRegionArchiverModule iram = scene.RequestModuleInterface<IRegionArchiverModule>();
string savePath = BuildOarPath(scene.RegionInfo.RegionName,
state.BackupDir,
state.NamingType);
if (savePath == null)
{
m_log.Warn("[AUTO BACKUP]: savePath is null in HandleElapsed");
return;
}
Guid guid = Guid.NewGuid();
m_pendingSaves.Add(guid, scene);
state.LiveRequests.Add(guid, savePath);
((Scene) scene).EventManager.OnOarFileSaved += new EventManager.OarFileSaved(EventManager_OnOarFileSaved);
iram.ArchiveRegion(savePath, guid, null);
}
/// <summary>
/// Called by the Event Manager when the OnOarFileSaved event is fired.
/// </summary>
/// <param name="guid"></param>
/// <param name="message"></param>
void EventManager_OnOarFileSaved(Guid guid, string message)
{
// Ignore if the OAR save is being done by some other part of the system
if (m_pendingSaves.ContainsKey(guid))
{
AutoBackupModuleState abms = m_states[(m_pendingSaves[guid])];
ExecuteScript(abms.Script, abms.LiveRequests[guid]);
m_pendingSaves.Remove(guid);
abms.LiveRequests.Remove(guid);
}
}
/// <summary>This format may turn out to be too unwieldy to keep...
/// Besides, that's what ctimes are for. But then how do I name each file uniquely without using a GUID?
/// Sequential numbers, right? We support those, too!</summary>
private static string GetTimeString()
{
StringWriter sw = new StringWriter();
sw.Write("_");
DateTime now = DateTime.Now;
sw.Write(now.Year);
sw.Write("y_");
sw.Write(now.Month);
sw.Write("M_");
sw.Write(now.Day);
sw.Write("d_");
sw.Write(now.Hour);
sw.Write("h_");
sw.Write(now.Minute);
sw.Write("m_");
sw.Write(now.Second);
sw.Write("s");
sw.Flush();
string output = sw.ToString();
sw.Close();
return output;
}
/// <summary>Return value of true ==> not too busy; false ==> too busy to backup an OAR right now, or error.</summary>
private bool RunHeuristics(IScene region)
{
try
{
return this.RunTimeDilationHeuristic(region) && this.RunAgentLimitHeuristic(region);
}
catch (Exception e)
{
m_log.Warn("[AUTO BACKUP]: Exception in RunHeuristics", e);
return false;
}
}
/// <summary>
/// If the time dilation right at this instant is less than the threshold specified in AutoBackupDilationThreshold (default 0.5),
/// then we return false and trip the busy heuristic's "too busy" path (i.e. don't save an OAR).
/// AutoBackupDilationThreshold is a _LOWER BOUND_. Lower Time Dilation is bad, so if you go lower than our threshold, it's "too busy".
/// </summary>
/// <param name="region"></param>
/// <returns>Returns true if we're not too busy; false means we've got worse time dilation than the threshold.</returns>
private bool RunTimeDilationHeuristic(IScene region)
{
string regionName = region.RegionInfo.RegionName;
return region.TimeDilation >=
this.m_configSource.Configs["AutoBackupModule"].GetFloat(
regionName + ".AutoBackupDilationThreshold", 0.5f);
}
/// <summary>
/// If the root agent count right at this instant is less than the threshold specified in AutoBackupAgentThreshold (default 10),
/// then we return false and trip the busy heuristic's "too busy" path (i.e., don't save an OAR).
/// AutoBackupAgentThreshold is an _UPPER BOUND_. Higher Agent Count is bad, so if you go higher than our threshold, it's "too busy".
/// </summary>
/// <param name="region"></param>
/// <returns>Returns true if we're not too busy; false means we've got more agents on the sim than the threshold.</returns>
private bool RunAgentLimitHeuristic(IScene region)
{
string regionName = region.RegionInfo.RegionName;
try
{
Scene scene = (Scene) region;
// TODO: Why isn't GetRootAgentCount() a method in the IScene interface? Seems generally useful...
return scene.GetRootAgentCount() <=
this.m_configSource.Configs["AutoBackupModule"].GetInt(
regionName + ".AutoBackupAgentThreshold", 10);
}
catch (InvalidCastException ice)
{
m_log.Debug(
"[AUTO BACKUP]: I NEED MAINTENANCE: IScene is not a Scene; can't get root agent count!",
ice);
return true;
// Non-obstructionist safest answer...
}
}
/// <summary>
/// Run the script or executable specified by the "AutoBackupScript" config setting.
/// Of course this is a security risk if you let anyone modify OpenSim.ini and they want to run some nasty bash script.
/// But there are plenty of other nasty things that can be done with an untrusted OpenSim.ini, such as running high threat level scripting functions.
/// </summary>
/// <param name="scriptName"></param>
/// <param name="savePath"></param>
private static void ExecuteScript(string scriptName, string savePath)
{
// Do nothing if there's no script.
if (scriptName == null || scriptName.Length <= 0)
{
return;
}
try
{
FileInfo fi = new FileInfo(scriptName);
if (fi.Exists)
{
ProcessStartInfo psi = new ProcessStartInfo(scriptName);
psi.Arguments = savePath;
psi.CreateNoWindow = true;
Process proc = Process.Start(psi);
proc.ErrorDataReceived += HandleProcErrorDataReceived;
}
}
catch (Exception e)
{
m_log.Warn(
"Exception encountered when trying to run script for oar backup " + savePath, e);
}
}
/// <summary>
/// Called if a running script process writes to stderr.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void HandleProcErrorDataReceived(object sender, DataReceivedEventArgs e)
{
m_log.Warn("ExecuteScript hook " + ((Process) sender).ProcessName +
" is yacking on stderr: " + e.Data);
}
/// <summary>
/// Quickly stop all timers from firing.
/// </summary>
private void StopAllTimers()
{
foreach (Timer t in this.m_timerMap.Keys)
{
t.Close();
}
this.m_closed = true;
}
/// <summary>
/// Determine the next unique filename by number, for "Sequential" AutoBackupNamingType.
/// </summary>
/// <param name="dirName"></param>
/// <param name="regionName"></param>
/// <returns></returns>
private static string GetNextFile(string dirName, string regionName)
{
FileInfo uniqueFile = null;
long biggestExistingFile = GetNextOarFileNumber(dirName, regionName);
biggestExistingFile++;
// We don't want to overwrite the biggest existing file; we want to write to the NEXT biggest.
uniqueFile =
new FileInfo(dirName + Path.DirectorySeparatorChar + regionName + "_" +
biggestExistingFile + ".oar");
return uniqueFile.FullName;
}
/// <summary>
/// Top-level method for creating an absolute path to an OAR backup file based on what naming scheme the user wants.
/// </summary>
/// <param name="regionName">Name of the region to save.</param>
/// <param name="baseDir">Absolute or relative path to the directory where the file should reside.</param>
/// <param name="naming">The naming scheme for the file name.</param>
/// <returns></returns>
private static string BuildOarPath(string regionName, string baseDir, NamingType naming)
{
FileInfo path = null;
switch (naming)
{
case NamingType.Overwrite:
path = new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName + ".oar");
return path.FullName;
case NamingType.Time:
path =
new FileInfo(baseDir + Path.DirectorySeparatorChar + regionName +
GetTimeString() + ".oar");
return path.FullName;
case NamingType.Sequential:
// All codepaths in GetNextFile should return a file name ending in .oar
path = new FileInfo(GetNextFile(baseDir, regionName));
return path.FullName;
default:
m_log.Warn("VERY BAD: Unhandled case element " + naming);
break;
}
return null;
}
/// <summary>
/// Helper function for Sequential file naming type (see BuildOarPath and GetNextFile).
/// </summary>
/// <param name="dirName"></param>
/// <param name="regionName"></param>
/// <returns></returns>
private static long GetNextOarFileNumber(string dirName, string regionName)
{
long retval = 1;
DirectoryInfo di = new DirectoryInfo(dirName);
FileInfo[] fi = di.GetFiles(regionName, SearchOption.TopDirectoryOnly);
Array.Sort(fi, (f1, f2) => StringComparer.CurrentCultureIgnoreCase.Compare(f1.Name, f2.Name));
if (fi.LongLength > 0)
{
long subtract = 1L;
bool worked = false;
Regex reg = new Regex(regionName + "_([0-9])+" + ".oar");
while (!worked && subtract <= fi.LongLength)
{
// Pick the file with the last natural ordering
string biggestFileName = fi[fi.LongLength - subtract].Name;
MatchCollection matches = reg.Matches(biggestFileName);
long l = 1;
if (matches.Count > 0 && matches[0].Groups.Count > 0)
{
try
{
long.TryParse(matches[0].Groups[1].Value, out l);
retval = l;
worked = true;
}
catch (FormatException fe)
{
m_log.Warn(
"[AUTO BACKUP]: Error: Can't parse long value from file name to determine next OAR backup file number!",
fe);
subtract++;
}
}
else
{
subtract++;
}
}
}
return retval;
}
}
}

View File

@ -0,0 +1,126 @@
/*
* 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;
namespace OpenSim.Region.OptionalModules.World.AutoBackup
{
/// <summary>AutoBackupModuleState: Auto-Backup state for one region (scene).
/// If you use this class in any way outside of AutoBackupModule, you should treat the class as opaque.
/// Since it is not part of the framework, you really should not rely upon it outside of the AutoBackupModule implementation.
/// </summary>
///
public class AutoBackupModuleState
{
private Dictionary<Guid, string> m_liveRequests = null;
public AutoBackupModuleState()
{
this.Enabled = false;
this.BackupDir = ".";
this.BusyCheck = true;
this.Timer = null;
this.NamingType = NamingType.Time;
this.Script = null;
}
public Dictionary<Guid, string> LiveRequests
{
get {
return this.m_liveRequests ??
(this.m_liveRequests = new Dictionary<Guid, string>(1));
}
}
public bool Enabled
{
get;
set;
}
public System.Timers.Timer Timer
{
get;
set;
}
public double IntervalMinutes
{
get
{
if (this.Timer == null)
{
return -1.0;
}
else
{
return this.Timer.Interval / 60000.0;
}
}
}
public bool BusyCheck
{
get;
set;
}
public string Script
{
get;
set;
}
public string BackupDir
{
get;
set;
}
public NamingType NamingType
{
get;
set;
}
public new string ToString()
{
string retval = "";
retval += "[AUTO BACKUP]: AutoBackup: " + (Enabled ? "ENABLED" : "DISABLED") + "\n";
retval += "[AUTO BACKUP]: Interval: " + IntervalMinutes + " minutes" + "\n";
retval += "[AUTO BACKUP]: Do Busy Check: " + (BusyCheck ? "Yes" : "No") + "\n";
retval += "[AUTO BACKUP]: Naming Type: " + NamingType.ToString() + "\n";
retval += "[AUTO BACKUP]: Backup Dir: " + BackupDir + "\n";
retval += "[AUTO BACKUP]: Script: " + Script + "\n";
return retval;
}
}
}

View File

@ -97,16 +97,76 @@ namespace OpenSim.Server.Base
if (port == 0) if (port == 0)
{ {
System.Console.WriteLine("Port number not specified or 0, server can't start");
Thread.CurrentThread.Abort(); Thread.CurrentThread.Abort();
} }
//
bool ssl_main = networkConfig.GetBoolean("https_main",false);
bool ssl_listener = networkConfig.GetBoolean("https_listener",false);
m_consolePort = (uint)networkConfig.GetInt("ConsolePort", 0); m_consolePort = (uint)networkConfig.GetInt("ConsolePort", 0);
m_Port = port; m_Port = port;
//
// This is where to make the servers:
//
//
// Make the base server according to the port, etc.
// ADD: Possibility to make main server ssl
// Then, check for https settings and ADD a server to
// m_Servers
//
if ( !ssl_main )
{
m_HttpServer = new BaseHttpServer(port);
m_HttpServer = new BaseHttpServer(port); }
else
{
string cert_path = networkConfig.GetString("cert_path",String.Empty);
if ( cert_path == String.Empty )
{
System.Console.WriteLine("Path to X509 certificate is missing, server can't start.");
Thread.CurrentThread.Abort();
}
string cert_pass = networkConfig.GetString("cert_pass",String.Empty);
if ( cert_pass == String.Empty )
{
System.Console.WriteLine("Password for X509 certificate is missing, server can't start.");
Thread.CurrentThread.Abort();
}
m_HttpServer = new BaseHttpServer(port, ssl_main, cert_path, cert_pass);
}
MainServer.Instance = m_HttpServer; MainServer.Instance = m_HttpServer;
// If https_listener = true, then add an ssl listener on the https_port...
if ( ssl_listener == true ) {
uint https_port = (uint)networkConfig.GetInt("https_port", 0);
string cert_path = networkConfig.GetString("cert_path",String.Empty);
if ( cert_path == String.Empty )
{
System.Console.WriteLine("Path to X509 certificate is missing, server can't start.");
Thread.CurrentThread.Abort();
}
string cert_pass = networkConfig.GetString("cert_pass",String.Empty);
if ( cert_pass == String.Empty )
{
System.Console.WriteLine("Password for X509 certificate is missing, server can't start.");
Thread.CurrentThread.Abort();
}
// Add our https_server
BaseHttpServer server = null;
server = new BaseHttpServer(https_port, ssl_listener, cert_path, cert_pass);
if (server != null)
{
m_Log.InfoFormat("[SERVER]: Starting HTTPS server on port {0}", https_port);
m_Servers.Add(https_port,server);
}
else
System.Console.WriteLine(String.Format("Failed to start HTTPS server on port {0}",https_port));
}
} }
protected override void Initialise() protected override void Initialise()
@ -114,6 +174,19 @@ namespace OpenSim.Server.Base
m_Log.InfoFormat("[SERVER]: Starting HTTP server on port {0}", m_HttpServer.Port); m_Log.InfoFormat("[SERVER]: Starting HTTP server on port {0}", m_HttpServer.Port);
m_HttpServer.Start(); m_HttpServer.Start();
if (m_Servers.Count > 0)
{
foreach (BaseHttpServer s in m_Servers.Values)
{
if (!s.UseSSL)
m_Log.InfoFormat("[SERVER]: Starting HTTP server on port {0}", s.Port);
else
m_Log.InfoFormat("[SERVER]: Starting HTTPS server on port {0}", s.Port);
s.Start();
}
}
if (MainConsole.Instance is RemoteConsole) if (MainConsole.Instance is RemoteConsole)
{ {
if (m_consolePort == 0) if (m_consolePort == 0)

View File

@ -26,6 +26,8 @@
*/ */
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection; using System.Reflection;
using Nini.Config; using Nini.Config;
using log4net; using log4net;
@ -61,6 +63,13 @@ namespace OpenSim.Services.AssetService
"delete asset <ID>", "delete asset <ID>",
"Delete asset from database", HandleDeleteAsset); "Delete asset from database", HandleDeleteAsset);
MainConsole.Instance.Commands.AddCommand("kfs", false,
"dump asset",
"dump asset <ID>",
"Dump asset to a file",
"The filename is the same as the ID given.",
HandleDumpAsset);
if (m_AssetLoader != null) if (m_AssetLoader != null)
{ {
IConfig assetConfig = config.Configs["AssetService"]; IConfig assetConfig = config.Configs["AssetService"];
@ -191,6 +200,43 @@ namespace OpenSim.Services.AssetService
return false; return false;
} }
void HandleDumpAsset(string module, string[] args)
{
if (args.Length < 3)
{
MainConsole.Instance.Output("Usage is dump asset <ID>");
return;
}
string rawAssetId = args[2];
UUID assetId;
if (!UUID.TryParse(rawAssetId, out assetId))
{
MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid ID format", rawAssetId);
return;
}
AssetBase asset = m_Database.GetAsset(assetId);
if (asset == null)
{
MainConsole.Instance.OutputFormat("ERROR: No asset found with ID {0}", assetId);
return;
}
string fileName = rawAssetId;
using (FileStream fs = new FileStream(fileName, FileMode.CreateNew))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
bw.Write(asset.Data);
}
}
MainConsole.Instance.OutputFormat("Asset dumped to file {0}", fileName);
}
void HandleShowDigest(string module, string[] args) void HandleShowDigest(string module, string[] args)
{ {
if (args.Length < 3) if (args.Length < 3)
@ -209,11 +255,11 @@ namespace OpenSim.Services.AssetService
int i; int i;
MainConsole.Instance.Output(String.Format("Name: {0}", asset.Name)); MainConsole.Instance.OutputFormat("Name: {0}", asset.Name);
MainConsole.Instance.Output(String.Format("Description: {0}", asset.Description)); MainConsole.Instance.OutputFormat("Description: {0}", asset.Description);
MainConsole.Instance.Output(String.Format("Type: {0}", asset.Type)); MainConsole.Instance.OutputFormat("Type: {0} (type number = {1})", (AssetType)asset.Type, asset.Type);
MainConsole.Instance.Output(String.Format("Content-type: {0}", asset.Metadata.ContentType)); MainConsole.Instance.OutputFormat("Content-type: {0}", asset.Metadata.ContentType);
MainConsole.Instance.Output(String.Format("Flags: {0}", asset.Metadata.Flags.ToString())); MainConsole.Instance.OutputFormat("Flags: {0}", asset.Metadata.Flags);
for (i = 0 ; i < 5 ; i++) for (i = 0 ; i < 5 ; i++)
{ {

View File

@ -291,6 +291,20 @@
http_listener_sslport = 9001 ; Use this port for SSL connections http_listener_sslport = 9001 ; Use this port for SSL connections
http_listener_ssl_cert = "" ; Currently unused, but will be used for OSHttpServer http_listener_ssl_cert = "" ; Currently unused, but will be used for OSHttpServer
; HTTPS for "Out of band" management applications such as the remote
; admin module
;
; Create https_listener = "True" will create a listener on the port
; specified. Provide the path to your server certificate along with it's
; password
; https_listener = False
; Set our listener to this port
; https_port = 0
; Path to X509 certificate
; cert_path = "path/to/cert.p12"
; Password for cert
; cert_pass = "password"
; Hostname to use in llRequestURL/llRequestSecureURL ; Hostname to use in llRequestURL/llRequestSecureURL
; if not defined - default machine name is being used ; if not defined - default machine name is being used
; (on Windows this mean NETBIOS name - useably only inside local network) ; (on Windows this mean NETBIOS name - useably only inside local network)
@ -1345,5 +1359,9 @@
;; default standalone, overridable in StandaloneCommon.ini ;; default standalone, overridable in StandaloneCommon.ini
StorageProvider = "OpenSim.Data.Null.dll:NullRegionData" StorageProvider = "OpenSim.Data.Null.dll:NullRegionData"
[AutoBackupModule]
;; default is module is disabled at the top level
AutoBackupModuleEnabled = false
[Modules] [Modules]
Include-modules = "addon-modules/*/config/*.ini" Include-modules = "addon-modules/*/config/*.ini"

View File

@ -29,6 +29,26 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003
[Network] [Network]
port = 8003 port = 8003
; HTTPS for "Out of band" management applications such as the remote admin
; module. May specify https_main = True to make the main http server
; use https or "False" to make the main server HTTP
; https_main = False
;
; Create https_listener = "True" will create a listener on the port
; specified. Provide the path to your server certificate along with it's
; password
; https_listener = False
;
; Set our listener to this port
; https_port = 0
;
; Path to X509 certificate
; cert_path = "path/to/cert.p12"
;
; Password for cert
; cert_pass = "password"
; * The following are for the remote console ; * The following are for the remote console
; * They have no effect for the local or basic console types ; * They have no effect for the local or basic console types
; * Leave commented to diable logins to the console ; * Leave commented to diable logins to the console

View File

@ -21,6 +21,27 @@ ServiceConnectors = "8003/OpenSim.Server.Handlers.dll:AssetServiceConnector,8003
[Network] [Network]
port = 8003 port = 8003
; HTTPS for "Out of band" management applications such as the remote admin
; module. May specify https_main = True to make the main http server
; use https or "False" to make the main server HTTP
; https_main = False
;
; Create https_listener = "True" will create a listener on the port
; specified. Provide the path to your server certificate along with it's
; password
; https_listener = False
;
; Set our listener to this port
; https_port = 0
;
; Path to X509 certificate
; cert_path = "path/to/cert.p12"
;
; Password for cert
; cert_pass = "password"
; * The following are for the remote console ; * The following are for the remote console
; * They have no effect for the local or basic console types ; * They have no effect for the local or basic console types
; * Leave commented to diable logins to the console ; * Leave commented to diable logins to the console