From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Thu, 3 Nov 2016 21:44:39 +1000
Subject: Initial update to OpenSim 0.8.2.1 source code.
---
OpenSim/Framework/AgentCircuitData.cs | 28 +-
OpenSim/Framework/Animation.cs | 24 +
OpenSim/Framework/AssemblyInfo.cs | 3 +-
OpenSim/Framework/AssetBase.cs | 13 +-
.../Filesystem/Properties/AssemblyInfo.cs | 4 +-
OpenSim/Framework/AvatarAppearance.cs | 335 ++++-
OpenSim/Framework/AvatarWearable.cs | 4 +-
OpenSim/Framework/BasicDOSProtector.cs | 275 ++++
OpenSim/Framework/BlockingQueue.cs | 32 +-
OpenSim/Framework/CachedTextureEventArg.cs | 46 +
OpenSim/Framework/ChildAgentDataUpdate.cs | 60 +-
OpenSim/Framework/CircularBuffer.cs | 312 ++++
OpenSim/Framework/ClientInfo.cs | 16 +-
.../Framework/Communications/GenericAsyncResult.cs | 185 ---
OpenSim/Framework/Communications/IUserService.cs | 157 --
.../Communications/Limit/IRequestLimitStrategy.cs | 66 -
.../Communications/Limit/NullLimitStrategy.cs | 40 -
.../Communications/Limit/RepeatLimitStrategy.cs | 109 --
.../Communications/Limit/TimeLimitStrategy.cs | 140 --
.../Communications/Properties/AssemblyInfo.cs | 65 -
OpenSim/Framework/Communications/RestClient.cs | 438 ------
OpenSim/Framework/Communications/XMPP/XmppError.cs | 39 -
.../Framework/Communications/XMPP/XmppIqStanza.cs | 60 -
.../Communications/XMPP/XmppMessageStanza.cs | 93 --
.../Communications/XMPP/XmppPresenceStanza.cs | 69 -
.../Communications/XMPP/XmppSerializer.cs | 79 -
.../Framework/Communications/XMPP/XmppStanza.cs | 70 -
.../Framework/Communications/XMPP/XmppWriter.cs | 57 -
OpenSim/Framework/ConfigSettings.cs | 1 -
.../Configuration/HTTP/HTTPConfiguration.cs | 119 --
.../Configuration/HTTP/Properties/AssemblyInfo.cs | 33 -
.../Configuration/HTTP/RemoteConfigSettings.cs | 63 -
.../Configuration/XML/Properties/AssemblyInfo.cs | 33 -
.../Configuration/XML/XmlConfiguration.cs | 141 --
OpenSim/Framework/ConfigurationMember.cs | 530 -------
OpenSim/Framework/Console/AssemblyInfo.cs | 2 +-
OpenSim/Framework/Console/CommandConsole.cs | 46 +-
OpenSim/Framework/Console/ConsoleDisplayUtil.cs | 48 +
OpenSim/Framework/Console/ConsoleUtil.cs | 175 ++-
OpenSim/Framework/Console/LocalConsole.cs | 85 +-
OpenSim/Framework/Console/MockConsole.cs | 3 +
OpenSim/Framework/Console/RemoteConsole.cs | 4 +-
OpenSim/Framework/Constants.cs | 11 +-
OpenSim/Framework/DAMap.cs | 328 +++++
OpenSim/Framework/DOMap.cs | 98 ++
OpenSim/Framework/EstateBan.cs | 49 +
OpenSim/Framework/EstateSettings.cs | 147 ++
OpenSim/Framework/ExtraPhysicsData.cs | 50 +
OpenSim/Framework/ForeignUserProfileData.cs | 77 -
OpenSim/Framework/GridInstantMessage.cs | 18 +
OpenSim/Framework/IClientAPI.cs | 29 +-
OpenSim/Framework/ICommandConsole.cs | 11 +-
OpenSim/Framework/IImprovedAssetCache.cs | 27 +-
OpenSim/Framework/ILandChannel.cs | 7 +
OpenSim/Framework/ILandObject.cs | 2 +
OpenSim/Framework/IMoneyModule.cs | 3 +-
OpenSim/Framework/IPeople.cs | 49 +
OpenSim/Framework/IRegionLoader.cs | 37 -
OpenSim/Framework/IScene.cs | 21 +-
OpenSim/Framework/ISceneAgent.cs | 7 +-
OpenSim/Framework/ISceneObject.cs | 2 +
OpenSim/Framework/InventoryCollection.cs | 4 +-
OpenSim/Framework/InventoryFolderBase.cs | 3 +
OpenSim/Framework/InventoryItemBase.cs | 9 +-
OpenSim/Framework/Location.cs | 16 +-
OpenSim/Framework/LogWriter.cs | 181 +++
OpenSim/Framework/MapBlockData.cs | 18 +
OpenSim/Framework/MapItemReplyStruct.cs | 33 +
OpenSim/Framework/MetricsCollector.cs | 223 +++
.../Framework/Monitoring/AssetStatsCollector.cs | 26 +
OpenSim/Framework/Monitoring/BaseStatsCollector.cs | 19 +-
OpenSim/Framework/Monitoring/Checks/Check.cs | 118 ++
OpenSim/Framework/Monitoring/ChecksManager.cs | 262 ++++
.../Monitoring/Interfaces/IStatsCollector.cs | 9 +
OpenSim/Framework/Monitoring/JobEngine.cs | 341 +++++
OpenSim/Framework/Monitoring/MemoryWatchdog.cs | 8 +-
.../Monitoring/Properties/AssemblyInfo.cs | 4 +-
.../Framework/Monitoring/ServerStatsCollector.cs | 346 +++++
.../Framework/Monitoring/SimExtraStatsCollector.cs | 106 +-
OpenSim/Framework/Monitoring/Stats/CounterStat.cs | 119 ++
.../Framework/Monitoring/Stats/EventHistogram.cs | 173 +++
.../Framework/Monitoring/Stats/PercentageStat.cs | 16 +
OpenSim/Framework/Monitoring/Stats/Stat.cs | 102 +-
OpenSim/Framework/Monitoring/StatsLogger.cs | 151 ++
OpenSim/Framework/Monitoring/StatsManager.cs | 403 +++++-
OpenSim/Framework/Monitoring/UserStatsCollector.cs | 18 +
OpenSim/Framework/Monitoring/Watchdog.cs | 106 +-
OpenSim/Framework/Monitoring/WorkManager.cs | 290 ++++
OpenSim/Framework/OutboundUrlFilter.cs | 256 ++++
OpenSim/Framework/PermissionsUtil.cs | 87 ++
OpenSim/Framework/PluginLoader.cs | 17 +-
OpenSim/Framework/PluginManager.cs | 4 +-
OpenSim/Framework/PrimitiveBaseShape.cs | 22 +-
OpenSim/Framework/RegionFlags.cs | 3 +-
OpenSim/Framework/RegionInfo.cs | 463 +++---
.../Filesystem/Properties/AssemblyInfo.cs | 33 -
.../Filesystem/RegionLoaderFileSystem.cs | 116 --
.../RegionLoader/Web/Properties/AssemblyInfo.cs | 33 -
.../RegionLoader/Web/RegionLoaderWebServer.cs | 130 --
OpenSim/Framework/RegionSettings.cs | 23 +-
OpenSim/Framework/RestClient.cs | 676 +++++++++
OpenSim/Framework/SLUtil.cs | 430 ++++--
.../Framework/Serialization/ArchiveConstants.cs | 11 +-
.../External/ExternalRepresentationUtils.cs | 267 +++-
.../Serialization/External/LandDataSerializer.cs | 28 +-
.../External/UserInventoryItemSerializer.cs | 49 +-
.../Serialization/Properties/AssemblyInfo.cs | 4 +-
.../Serialization/Tests/LandDataSerializerTests.cs | 3 +-
OpenSim/Framework/Servers/BaseOpenSimServer.cs | 82 +-
.../Framework/Servers/HttpServer/BaseHttpServer.cs | 383 ++++-
.../Servers/HttpServer/BaseOutputStreamHandler.cs | 60 +
.../Servers/HttpServer/BaseRequestHandler.cs | 23 +
.../Servers/HttpServer/BaseStreamHandler.cs | 49 +-
.../BaseStreamHandlerBasicDOSProtector.cs | 107 ++
.../Servers/HttpServer/BinaryStreamHandler.cs | 2 +-
.../HttpServer/GenericHTTPBasicDOSProtector.cs | 119 ++
.../Servers/HttpServer/Interfaces/IHttpServer.cs | 14 +
.../HttpServer/Interfaces/IStreamHandler.cs | 15 +-
.../Framework/Servers/HttpServer/JsonRPCMethod.cs | 34 +
.../Servers/HttpServer/JsonRpcRequestManager.cs | 190 +++
.../Servers/HttpServer/JsonRpcResponse.cs | 150 ++
.../Framework/Servers/HttpServer/OSHttpRequest.cs | 13 +-
.../Servers/HttpServer/OSHttpRequestPump.cs | 4 +-
.../Framework/Servers/HttpServer/OSHttpServer.cs | 2 +-
.../Servers/HttpServer/PollServiceEventArgs.cs | 31 +-
.../Servers/HttpServer/PollServiceHttpRequest.cs | 45 +
.../HttpServer/PollServiceRequestManager.cs | 318 +++-
.../Servers/HttpServer/PollServiceWorkerThread.cs | 165 ---
.../Servers/HttpServer/Properties/AssemblyInfo.cs | 4 +-
.../Servers/HttpServer/RestDeserialiseHandler.cs | 4 +-
.../Servers/HttpServer/RestObjectPoster.cs | 28 +-
.../Servers/HttpServer/RestObjectPosterResponse.cs | 29 +-
.../Servers/HttpServer/RestSessionService.cs | 89 +-
.../Servers/HttpServer/RestStreamHandler.cs | 2 +-
.../Servers/HttpServer/WebsocketServerHandler.cs | 1159 +++++++++++++++
.../Servers/HttpServer/XmlRpcBasicDOSProtector.cs | 91 ++
OpenSim/Framework/Servers/MainServer.cs | 24 +-
.../Framework/Servers/Properties/AssemblyInfo.cs | 2 +-
OpenSim/Framework/Servers/ServerBase.cs | 381 ++++-
OpenSim/Framework/Servers/Tests/OSHttpTests.cs | 315 +---
.../Framework/Servers/Tests/VersionInfoTests.cs | 2 +-
OpenSim/Framework/Servers/VersionInfo.cs | 77 -
.../ServiceAuth/BasicHttpAuthentication.cs | 113 ++
.../ServiceAuth/CompoundAuthentication.cs | 82 ++
.../Framework/ServiceAuth/DisallowLlHttpRequest.cs | 59 +
OpenSim/Framework/ServiceAuth/IServiceAuth.cs | 48 +
OpenSim/Framework/ServiceAuth/ServiceAuth.cs | 68 +
OpenSim/Framework/TaskInventoryItem.cs | 2 +-
OpenSim/Framework/TerrainData.cs | 464 ++++++
OpenSim/Framework/Tests/AnimationTests.cs | 1 -
OpenSim/Framework/Tests/AssetBaseTest.cs | 4 -
OpenSim/Framework/Tests/LocationTest.cs | 21 +-
OpenSim/Framework/Tests/MundaneFrameworkTests.cs | 2 +-
OpenSim/Framework/Tests/UtilTest.cs | 101 +-
OpenSim/Framework/ThreadSafeRandom.cs | 72 +
OpenSim/Framework/ThrottleOutPacketType.cs | 4 -
OpenSim/Framework/UntrustedWebRequest.cs | 230 ---
OpenSim/Framework/UserProfileData.cs | 14 +-
OpenSim/Framework/UserProfiles.cs | 126 ++
OpenSim/Framework/Util.cs | 1512 ++++++++++++++++----
OpenSim/Framework/VersionInfo.cs | 92 ++
OpenSim/Framework/WearableCacheItem.cs | 157 ++
OpenSim/Framework/WebUtil.cs | 928 +++++++-----
163 files changed, 13403 insertions(+), 5544 deletions(-)
create mode 100644 OpenSim/Framework/BasicDOSProtector.cs
create mode 100644 OpenSim/Framework/CachedTextureEventArg.cs
create mode 100644 OpenSim/Framework/CircularBuffer.cs
delete mode 100644 OpenSim/Framework/Communications/GenericAsyncResult.cs
delete mode 100644 OpenSim/Framework/Communications/IUserService.cs
delete mode 100644 OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs
delete mode 100644 OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs
delete mode 100644 OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs
delete mode 100644 OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs
delete mode 100644 OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
delete mode 100644 OpenSim/Framework/Communications/RestClient.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppError.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppSerializer.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppStanza.cs
delete mode 100644 OpenSim/Framework/Communications/XMPP/XmppWriter.cs
delete mode 100644 OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs
delete mode 100644 OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
delete mode 100644 OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs
delete mode 100644 OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
delete mode 100644 OpenSim/Framework/Configuration/XML/XmlConfiguration.cs
delete mode 100644 OpenSim/Framework/ConfigurationMember.cs
create mode 100644 OpenSim/Framework/Console/ConsoleDisplayUtil.cs
create mode 100644 OpenSim/Framework/DAMap.cs
create mode 100644 OpenSim/Framework/DOMap.cs
create mode 100644 OpenSim/Framework/ExtraPhysicsData.cs
delete mode 100644 OpenSim/Framework/ForeignUserProfileData.cs
create mode 100644 OpenSim/Framework/IPeople.cs
delete mode 100644 OpenSim/Framework/IRegionLoader.cs
create mode 100755 OpenSim/Framework/LogWriter.cs
create mode 100644 OpenSim/Framework/MetricsCollector.cs
create mode 100644 OpenSim/Framework/Monitoring/Checks/Check.cs
create mode 100644 OpenSim/Framework/Monitoring/ChecksManager.cs
create mode 100644 OpenSim/Framework/Monitoring/JobEngine.cs
create mode 100644 OpenSim/Framework/Monitoring/ServerStatsCollector.cs
mode change 100644 => 100755 OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
create mode 100755 OpenSim/Framework/Monitoring/Stats/CounterStat.cs
create mode 100755 OpenSim/Framework/Monitoring/Stats/EventHistogram.cs
create mode 100644 OpenSim/Framework/Monitoring/StatsLogger.cs
create mode 100644 OpenSim/Framework/Monitoring/WorkManager.cs
create mode 100644 OpenSim/Framework/OutboundUrlFilter.cs
create mode 100644 OpenSim/Framework/PermissionsUtil.cs
delete mode 100644 OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
delete mode 100644 OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs
delete mode 100644 OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
delete mode 100644 OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs
create mode 100644 OpenSim/Framework/RestClient.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
delete mode 100644 OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
create mode 100644 OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs
delete mode 100644 OpenSim/Framework/Servers/VersionInfo.cs
create mode 100644 OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs
create mode 100644 OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
create mode 100644 OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs
create mode 100644 OpenSim/Framework/ServiceAuth/IServiceAuth.cs
create mode 100644 OpenSim/Framework/ServiceAuth/ServiceAuth.cs
create mode 100644 OpenSim/Framework/TerrainData.cs
create mode 100644 OpenSim/Framework/ThreadSafeRandom.cs
delete mode 100644 OpenSim/Framework/UntrustedWebRequest.cs
create mode 100644 OpenSim/Framework/UserProfiles.cs
create mode 100644 OpenSim/Framework/VersionInfo.cs
create mode 100644 OpenSim/Framework/WearableCacheItem.cs
(limited to 'OpenSim/Framework')
diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs
index ffcc584..0d053e4 100644
--- a/OpenSim/Framework/AgentCircuitData.cs
+++ b/OpenSim/Framework/AgentCircuitData.cs
@@ -128,7 +128,31 @@ namespace OpenSim.Framework
///
/// Viewer's version string as reported by the viewer at login
///
- public string Viewer;
+ private string m_viewerInternal;
+
+ ///
+ /// Viewer's version string
+ ///
+ public string Viewer
+ {
+ set { m_viewerInternal = value; }
+
+ // Try to return consistent viewer string taking into account
+ // that viewers have chaagned how version is reported
+ // See http://opensimulator.org/mantis/view.php?id=6851
+ get
+ {
+ // Old style version string contains viewer name followed by a space followed by a version number
+ if (m_viewerInternal == null || m_viewerInternal.Contains(" "))
+ {
+ return m_viewerInternal;
+ }
+ else // New style version contains no spaces, just version number
+ {
+ return Channel + " " + m_viewerInternal;
+ }
+ }
+ }
///
/// The channel strinf sent by the viewer at login
@@ -297,6 +321,8 @@ namespace OpenSim.Framework
Mac = args["mac"].AsString();
if (args["id0"] != null)
Id0 = args["id0"].AsString();
+ if (args["teleport_flags"] != null)
+ teleportFlags = args["teleport_flags"].AsUInteger();
if (args["start_pos"] != null)
Vector3.TryParse(args["start_pos"].AsString(), out startpos);
diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs
index 232f5a1..e958b75 100644
--- a/OpenSim/Framework/Animation.cs
+++ b/OpenSim/Framework/Animation.cs
@@ -120,5 +120,29 @@ namespace OpenSim.Framework
sequenceNum = args["seq_num"].AsInteger();
}
+ public override bool Equals(object obj)
+ {
+ Animation other = obj as Animation;
+ if (other != null)
+ {
+ return (other.AnimID.Equals(this.AnimID)
+ && other.SequenceNum == this.SequenceNum
+ && other.ObjectID.Equals(this.ObjectID) );
+ }
+ return base.Equals(obj);
+ }
+
+ public override int GetHashCode()
+ {
+ return base.GetHashCode();
+ }
+
+ public override string ToString()
+ {
+ return "AnimID=" + AnimID.ToString()
+ + "/seq=" + SequenceNum.ToString()
+ + "/objID=" + ObjectID.ToString();
+ }
+
}
}
diff --git a/OpenSim/Framework/AssemblyInfo.cs b/OpenSim/Framework/AssemblyInfo.cs
index 02986d5..a797424 100644
--- a/OpenSim/Framework/AssemblyInfo.cs
+++ b/OpenSim/Framework/AssemblyInfo.cs
@@ -59,5 +59,4 @@ using System.Runtime.InteropServices;
// Revision
//
-[assembly : AssemblyVersion("0.7.5.*")]
-[assembly : AssemblyFileVersion("0.6.5.0")]
\ No newline at end of file
+[assembly : AssemblyVersion("0.8.2.*")]
diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs
index d2c6c57..2f04d2e 100644
--- a/OpenSim/Framework/AssetBase.cs
+++ b/OpenSim/Framework/AssetBase.cs
@@ -50,6 +50,9 @@ namespace OpenSim.Framework
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ public static readonly int MAX_ASSET_NAME = 64;
+ public static readonly int MAX_ASSET_DESC = 64;
+
///
/// Data of the Asset
///
@@ -133,7 +136,7 @@ namespace OpenSim.Framework
get
{
return
- (Type == (sbyte) AssetType.Animation ||
+ (Type == (sbyte)AssetType.Animation ||
Type == (sbyte)AssetType.Gesture ||
Type == (sbyte)AssetType.Simstate ||
Type == (sbyte)AssetType.Unknown ||
@@ -143,13 +146,9 @@ namespace OpenSim.Framework
Type == (sbyte)AssetType.Texture ||
Type == (sbyte)AssetType.TextureTGA ||
Type == (sbyte)AssetType.Folder ||
- Type == (sbyte)AssetType.RootFolder ||
- Type == (sbyte)AssetType.LostAndFoundFolder ||
- Type == (sbyte)AssetType.SnapshotFolder ||
- Type == (sbyte)AssetType.TrashFolder ||
Type == (sbyte)AssetType.ImageJPEG ||
- Type == (sbyte) AssetType.ImageTGA ||
- Type == (sbyte) AssetType.LSLBytecode);
+ Type == (sbyte)AssetType.ImageTGA ||
+ Type == (sbyte)AssetType.LSLBytecode);
}
}
diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
index 0498ed4..76df564 100644
--- a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.8.3.*")]
+
diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs
index 95e9667..26dd5df 100644
--- a/OpenSim/Framework/AvatarAppearance.cs
+++ b/OpenSim/Framework/AvatarAppearance.cs
@@ -40,8 +40,17 @@ namespace OpenSim.Framework
///
public class AvatarAppearance
{
+ // SL box diferent to size
+ const float AVBOXAJUST = 0.2f;
+ // constrains for ubitode physics
+ const float AVBOXMINX = 0.2f;
+ const float AVBOXMINY = 0.3f;
+ const float AVBOXMINZ = 1.2f;
+
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ // this is viewer capabilities and weared things dependent
+ // should be only used as initial default value ( V1 viewers )
public readonly static int VISUALPARAM_COUNT = 218;
public readonly static int TEXTURE_COUNT = 21;
@@ -53,7 +62,15 @@ namespace OpenSim.Framework
protected AvatarWearable[] m_wearables;
protected Dictionary> m_attachments;
protected float m_avatarHeight = 0;
+ protected Vector3 m_avatarSize = new Vector3(0.45f, 0.6f, 1.9f); // sl Z cloud value
+ protected Vector3 m_avatarBoxSize = new Vector3(0.45f, 0.6f, 1.9f);
+ protected float m_avatarFeetOffset = 0;
+ protected float m_avatarAnimOffset = 0;
+ protected WearableCacheItem[] m_cacheitems;
+ protected bool m_cacheItemsDirty = true;
+
+ public bool PackLegacyWearables {get; set; }
public virtual int Serial
{
get { return m_serial; }
@@ -66,6 +83,21 @@ namespace OpenSim.Framework
set { m_visualparams = value; }
}
+ public virtual Vector3 AvatarSize
+ {
+ get { return m_avatarSize; }
+ }
+
+ public virtual Vector3 AvatarBoxSize
+ {
+ get { return m_avatarBoxSize; }
+ }
+
+ public virtual float AvatarFeetOffset
+ {
+ get { return m_avatarFeetOffset + m_avatarAnimOffset; }
+ }
+
public virtual Primitive.TextureEntry Texture
{
get { return m_texture; }
@@ -87,16 +119,29 @@ namespace OpenSim.Framework
get { return m_avatarHeight; }
set { m_avatarHeight = value; }
}
+
+ public virtual WearableCacheItem[] WearableCacheItems
+ {
+ get { return m_cacheitems; }
+ set { m_cacheitems = value; }
+ }
+
+ public virtual bool WearableCacheItemsDirty
+ {
+ get { return m_cacheItemsDirty; }
+ set { m_cacheItemsDirty = value; }
+ }
public AvatarAppearance()
{
// m_log.WarnFormat("[AVATAR APPEARANCE]: create empty appearance");
-
+ PackLegacyWearables = false;
m_serial = 0;
SetDefaultWearables();
SetDefaultTexture();
SetDefaultParams();
- SetHeight();
+// SetHeight();
+ SetSize(new Vector3(0.45f,0.6f,1.9f));
m_attachments = new Dictionary>();
}
@@ -105,7 +150,7 @@ namespace OpenSim.Framework
// m_log.WarnFormat("[AVATAR APPEARANCE]: create appearance from OSDMap");
Unpack(map);
- SetHeight();
+// SetHeight(); done in Unpack
}
public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams)
@@ -129,7 +174,9 @@ namespace OpenSim.Framework
else
SetDefaultParams();
- SetHeight();
+// SetHeight();
+ if(m_avatarHeight == 0)
+ SetSize(new Vector3(0.45f,0.6f,1.9f));
m_attachments = new Dictionary>();
}
@@ -148,7 +195,8 @@ namespace OpenSim.Framework
SetDefaultWearables();
SetDefaultTexture();
SetDefaultParams();
- SetHeight();
+// SetHeight();
+ SetSize(new Vector3(0.45f, 0.6f, 1.9f));
m_attachments = new Dictionary>();
return;
@@ -162,7 +210,10 @@ namespace OpenSim.Framework
if (copyWearables && (appearance.Wearables != null))
{
- for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
+ int len = appearance.Wearables.Length;
+ if(len > AvatarWearable.MAX_WEARABLES)
+ len = AvatarWearable.MAX_WEARABLES;
+ for (int i = 0; i < len; i++)
SetWearable(i,appearance.Wearables[i]);
}
@@ -177,7 +228,8 @@ namespace OpenSim.Framework
if (appearance.VisualParams != null)
m_visualparams = (byte[])appearance.VisualParams.Clone();
- m_avatarHeight = appearance.m_avatarHeight;
+// m_avatarHeight = appearance.m_avatarHeight;
+ SetSize(appearance.AvatarSize);
// Copy the attachment, force append mode since that ensures consistency
m_attachments = new Dictionary>();
@@ -240,6 +292,21 @@ namespace OpenSim.Framework
// }
}
+ ///
+ /// Invalidate all of the baked textures in the appearance, useful
+ /// if you know that none are valid
+ ///
+ public virtual void ResetBakedTextures()
+ {
+ SetDefaultTexture();
+
+ //for (int i = 0; i < BAKE_INDICES.Length; i++)
+ // {
+ // int idx = BAKE_INDICES[i];
+ // m_texture.FaceTextures[idx].TextureID = UUID.Zero;
+ // }
+ }
+
protected virtual void SetDefaultTexture()
{
m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE));
@@ -304,22 +371,33 @@ namespace OpenSim.Framework
// made. We determine if any of the visual parameters actually
// changed to know if the appearance should be saved later
bool changed = false;
- for (int i = 0; i < AvatarAppearance.VISUALPARAM_COUNT; i++)
+
+ int newsize = visualParams.Length;
+
+ if (newsize != m_visualparams.Length)
{
- if (visualParams[i] != m_visualparams[i])
+ changed = true;
+ m_visualparams = (byte[])visualParams.Clone();
+ }
+ else
+ {
+
+ for (int i = 0; i < newsize; i++)
{
-// DEBUG ON
-// m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}",
-// i,m_visualparams[i],visualParams[i]);
-// DEBUG OFF
- m_visualparams[i] = visualParams[i];
- changed = true;
+ if (visualParams[i] != m_visualparams[i])
+ {
+ // DEBUG ON
+ // m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}",
+ // i,m_visualparams[i],visualParams[i]);
+ // DEBUG OFF
+ m_visualparams[i] = visualParams[i];
+ changed = true;
+ }
}
}
-
// Reset the height if the visual parameters actually changed
- if (changed)
- SetHeight();
+// if (changed)
+// SetHeight();
return changed;
}
@@ -335,6 +413,7 @@ namespace OpenSim.Framework
///
public virtual void SetHeight()
{
+/*
// Start with shortest possible female avatar height
m_avatarHeight = 1.14597f;
// Add offset for male avatars
@@ -347,6 +426,35 @@ namespace OpenSim.Framework
+ 0.07f * (float)m_visualparams[(int)VPElement.SHOES_PLATFORM_HEIGHT] / 255.0f
+ 0.08f * (float)m_visualparams[(int)VPElement.SHOES_HEEL_HEIGHT] / 255.0f
+ 0.076f * (float)m_visualparams[(int)VPElement.SHAPE_NECK_LENGTH] / 255.0f;
+*/
+ }
+
+ public void SetSize(Vector3 avSize)
+ {
+ if (avSize.X > 32f)
+ avSize.X = 32f;
+ else if (avSize.X < 0.1f)
+ avSize.X = 0.1f;
+
+ if (avSize.Y > 32f)
+ avSize.Y = 32f;
+ else if (avSize.Y < 0.1f)
+ avSize.Y = 0.1f;
+ if (avSize.Z > 32f)
+ avSize.Z = 32f;
+ else if (avSize.Z < 0.1f)
+ avSize.Z = 0.1f;
+
+ m_avatarSize = avSize;
+ m_avatarBoxSize = avSize;
+ m_avatarBoxSize.Z += AVBOXAJUST;
+ if (m_avatarBoxSize.X < AVBOXMINX)
+ m_avatarBoxSize.X = AVBOXMINX;
+ if (m_avatarBoxSize.Y < AVBOXMINY)
+ m_avatarBoxSize.Y = AVBOXMINY;
+ if (m_avatarBoxSize.Z < AVBOXMINZ)
+ m_avatarBoxSize.Z = AVBOXMINZ;
+ m_avatarHeight = m_avatarSize.Z;
}
public virtual void SetWearable(int wearableId, AvatarWearable wearable)
@@ -355,8 +463,11 @@ namespace OpenSim.Framework
// m_log.WarnFormat("[AVATARAPPEARANCE] set wearable {0} --> {1}:{2}",wearableId,wearable.ItemID,wearable.AssetID);
// DEBUG OFF
m_wearables[wearableId].Clear();
- for (int i = 0; i < wearable.Count; i++)
- m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID);
+ int count = wearable.Count;
+ if (count > AvatarWearable.MAX_WEARABLES)
+ count = AvatarWearable.MAX_WEARABLES;
+ for (int i = 0; i < count; i++)
+ m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID);
}
// DEBUG ON
@@ -377,7 +488,8 @@ namespace OpenSim.Framework
}
s += "Visual Params: ";
- for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++)
+ // for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++)
+ for (uint j = 0; j < m_visualparams.Length; j++)
s += String.Format("{0},",m_visualparams[j]);
s += "\n";
@@ -393,18 +505,16 @@ namespace OpenSim.Framework
///
public List GetAttachments()
{
- List alist = new List();
-
lock (m_attachments)
{
+ List alist = new List();
foreach (KeyValuePair> kvp in m_attachments)
{
foreach (AvatarAttachment attach in kvp.Value)
alist.Add(new AvatarAttachment(attach));
}
- }
-
- return alist;
+ return alist;
+ }
}
internal void AppendAttachment(AvatarAttachment attach)
@@ -418,6 +528,12 @@ namespace OpenSim.Framework
if (!m_attachments.ContainsKey(attach.AttachPoint))
m_attachments[attach.AttachPoint] = new List();
+ foreach (AvatarAttachment prev in m_attachments[attach.AttachPoint])
+ {
+ if (prev.ItemID == attach.ItemID)
+ return;
+ }
+
m_attachments[attach.AttachPoint].Add(attach);
}
}
@@ -459,45 +575,59 @@ namespace OpenSim.Framework
if (attachpoint == 0)
return false;
- if (item == UUID.Zero)
+ lock (m_attachments)
{
- lock (m_attachments)
+ if (item == UUID.Zero)
{
if (m_attachments.ContainsKey(attachpoint))
{
m_attachments.Remove(attachpoint);
return true;
}
+
+ return false;
}
-
- return false;
- }
- // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
- // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
- // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
- // later fail unless the attachment is detached and reattached.
- //
- // Therefore, we will carry on with the set if the existing attachment has no asset id.
- AvatarAttachment existingAttachment = GetAttachmentForItem(item);
- if (existingAttachment != null
- && existingAttachment.AssetID != UUID.Zero
- && existingAttachment.AttachPoint == (attachpoint & 0x7F))
- {
- // m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item);
- return false;
- }
-
- // check if this is an append or a replace, 0x80 marks it as an append
- if ((attachpoint & 0x80) > 0)
- {
- // strip the append bit
- int point = attachpoint & 0x7F;
- AppendAttachment(new AvatarAttachment(point, item, asset));
- }
- else
- {
- ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
+ // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
+ // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
+ // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
+ // later fail unless the attachment is detached and reattached.
+ //
+ // Therefore, we will carry on with the set if the existing attachment has no asset id.
+ AvatarAttachment existingAttachment = GetAttachmentForItem(item);
+ if (existingAttachment != null)
+ {
+// m_log.DebugFormat(
+// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}",
+// existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint);
+
+ if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F))
+ {
+ m_log.DebugFormat(
+ "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}",
+ item, attachpoint);
+
+ return false;
+ }
+ else
+ {
+ // Remove it here so that the later append does not add a second attachment but we still update
+ // the assetID
+ DetachAttachment(existingAttachment.ItemID);
+ }
+ }
+
+ // check if this is an append or a replace, 0x80 marks it as an append
+ if ((attachpoint & 0x80) > 0)
+ {
+ // strip the append bit
+ int point = attachpoint & 0x7F;
+ AppendAttachment(new AvatarAttachment(point, item, asset));
+ }
+ else
+ {
+ ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
+ }
}
return true;
@@ -534,7 +664,6 @@ namespace OpenSim.Framework
return kvp.Key;
}
}
-
return 0;
}
@@ -547,6 +676,10 @@ namespace OpenSim.Framework
int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
if (index >= 0)
{
+// m_log.DebugFormat(
+// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}",
+// m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint);
+
// Remove it from the list of attachments at that attach point
m_attachments[kvp.Key].RemoveAt(index);
@@ -581,8 +714,15 @@ namespace OpenSim.Framework
data["height"] = OSD.FromReal(m_avatarHeight);
// Wearables
- OSDArray wears = new OSDArray(AvatarWearable.MAX_WEARABLES);
- for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
+
+ int wearsCount;
+ if(PackLegacyWearables)
+ wearsCount = AvatarWearable.LEGACY_VERSION_MAX_WEARABLES;
+ else
+ wearsCount = AvatarWearable.MAX_WEARABLES;
+
+ OSDArray wears = new OSDArray(wearsCount);
+ for (int i = 0; i < wearsCount; i++)
wears.Add(m_wearables[i].Pack());
data["wearables"] = wears;
@@ -601,12 +741,14 @@ namespace OpenSim.Framework
OSDBinary visualparams = new OSDBinary(m_visualparams);
data["visualparams"] = visualparams;
- // Attachments
- List attachments = GetAttachments();
- OSDArray attachs = new OSDArray(attachments.Count);
- foreach (AvatarAttachment attach in GetAttachments())
- attachs.Add(attach.Pack());
- data["attachments"] = attachs;
+ lock (m_attachments)
+ {
+ // Attachments
+ OSDArray attachs = new OSDArray(m_attachments.Count);
+ foreach (AvatarAttachment attach in GetAttachments())
+ attachs.Add(attach.Pack());
+ data["attachments"] = attachs;
+ }
return data;
}
@@ -620,7 +762,8 @@ namespace OpenSim.Framework
if ((data != null) && (data["serial"] != null))
m_serial = data["serial"].AsInteger();
if ((data != null) && (data["height"] != null))
- m_avatarHeight = (float)data["height"].AsReal();
+// m_avatarHeight = (float)data["height"].AsReal();
+ SetSize(new Vector3(0.45f,0.6f, (float)data["height"].AsReal()));
try
{
@@ -629,7 +772,12 @@ namespace OpenSim.Framework
if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array)
{
OSDArray wears = (OSDArray)(data["wearables"]);
- for (int i = 0; i < wears.Count; i++)
+
+ int count = wears.Count;
+ if (count > AvatarWearable.MAX_WEARABLES)
+ count = AvatarWearable.MAX_WEARABLES;
+
+ for (int i = 0; i < count; i++)
m_wearables[i] = new AvatarWearable((OSDArray)wears[i]);
}
else
@@ -1453,7 +1601,58 @@ namespace OpenSim.Framework
SHAPE_EYELID_INNER_CORNER_UP = 214,
SKIRT_SKIRT_RED = 215,
SKIRT_SKIRT_GREEN = 216,
- SKIRT_SKIRT_BLUE = 217
+ SKIRT_SKIRT_BLUE = 217,
+
+ ///
+ /// Avatar Physics section. These are 0 type visual params which get transmitted.
+ ///
+
+ ///
+ /// Breast Part 1
+ ///
+ BREAST_PHYSICS_MASS = 218,
+ BREAST_PHYSICS_GRAVITY = 219,
+ BREAST_PHYSICS_DRAG = 220,
+ BREAST_PHYSICS_UPDOWN_MAX_EFFECT = 221,
+ BREAST_PHYSICS_UPDOWN_SPRING = 222,
+ BREAST_PHYSICS_UPDOWN_GAIN = 223,
+ BREAST_PHYSICS_UPDOWN_DAMPING = 224,
+ BREAST_PHYSICS_INOUT_MAX_EFFECT = 225,
+ BREAST_PHYSICS_INOUT_SPRING = 226,
+ BREAST_PHYSICS_INOUT_GAIN = 227,
+ BREAST_PHYSICS_INOUT_DAMPING = 228,
+ ///
+ /// Belly
+ ///
+ BELLY_PHYISCS_MASS = 229,
+ BELLY_PHYSICS_GRAVITY = 230,
+ BELLY_PHYSICS_DRAG = 231,
+ BELLY_PHYISCS_UPDOWN_MAX_EFFECT = 232,
+ BELLY_PHYSICS_UPDOWN_SPRING = 233,
+ BELLY_PHYSICS_UPDOWN_GAIN = 234,
+ BELLY_PHYSICS_UPDOWN_DAMPING = 235,
+
+ ///
+ /// Butt
+ ///
+ BUTT_PHYSICS_MASS = 236,
+ BUTT_PHYSICS_GRAVITY = 237,
+ BUTT_PHYSICS_DRAG = 238,
+ BUTT_PHYSICS_UPDOWN_MAX_EFFECT = 239,
+ BUTT_PHYSICS_UPDOWN_SPRING = 240,
+ BUTT_PHYSICS_UPDOWN_GAIN = 241,
+ BUTT_PHYSICS_UPDOWN_DAMPING = 242,
+ BUTT_PHYSICS_LEFTRIGHT_MAX_EFFECT = 243,
+ BUTT_PHYSICS_LEFTRIGHT_SPRING = 244,
+ BUTT_PHYSICS_LEFTRIGHT_GAIN = 245,
+ BUTT_PHYSICS_LEFTRIGHT_DAMPING = 246,
+ ///
+ /// Breast Part 2
+ ///
+ BREAST_PHYSICS_LEFTRIGHT_MAX_EFFECT = 247,
+ BREAST_PHYSICS_LEFTRIGHT_SPRING= 248,
+ BREAST_PHYSICS_LEFTRIGHT_GAIN = 249,
+ BREAST_PHYSICS_LEFTRIGHT_DAMPING = 250
}
#endregion
}
diff --git a/OpenSim/Framework/AvatarWearable.cs b/OpenSim/Framework/AvatarWearable.cs
index 8e27596..e7615f2 100644
--- a/OpenSim/Framework/AvatarWearable.cs
+++ b/OpenSim/Framework/AvatarWearable.cs
@@ -65,7 +65,9 @@ namespace OpenSim.Framework
public static readonly int ALPHA = 13;
public static readonly int TATTOO = 14;
- public static readonly int MAX_WEARABLES = 15;
+ public static readonly int LEGACY_VERSION_MAX_WEARABLES = 15;
+ public static readonly int PHYSICS = 15;
+ public static readonly int MAX_WEARABLES = 16;
public static readonly UUID DEFAULT_BODY_ITEM = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9");
public static readonly UUID DEFAULT_BODY_ASSET = new UUID("66c41e39-38f9-f75a-024e-585989bfab73");
diff --git a/OpenSim/Framework/BasicDOSProtector.cs b/OpenSim/Framework/BasicDOSProtector.cs
new file mode 100644
index 0000000..89bfa94
--- /dev/null
+++ b/OpenSim/Framework/BasicDOSProtector.cs
@@ -0,0 +1,275 @@
+/*
+ * 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 log4net;
+
+namespace OpenSim.Framework
+{
+
+ public class BasicDOSProtector
+ {
+ public enum ThrottleAction
+ {
+ DoThrottledMethod,
+ DoThrow
+ }
+ private readonly CircularBuffer _generalRequestTimes; // General request checker
+ private readonly BasicDosProtectorOptions _options;
+ private readonly Dictionary> _deeperInspection; // per client request checker
+ private readonly Dictionary _tempBlocked; // blocked list
+ private readonly Dictionary _sessions;
+ private readonly System.Timers.Timer _forgetTimer; // Cleanup timer
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim();
+ private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim();
+ public BasicDOSProtector(BasicDosProtectorOptions options)
+ {
+ _generalRequestTimes = new CircularBuffer(options.MaxRequestsInTimeframe + 1, true);
+ _generalRequestTimes.Put(0);
+ _options = options;
+ _deeperInspection = new Dictionary>();
+ _tempBlocked = new Dictionary();
+ _sessions = new Dictionary();
+ _forgetTimer = new System.Timers.Timer();
+ _forgetTimer.Elapsed += delegate
+ {
+ _forgetTimer.Enabled = false;
+
+ List removes = new List();
+ _blockLockSlim.EnterReadLock();
+ foreach (string str in _tempBlocked.Keys)
+ {
+ if (
+ Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),
+ _tempBlocked[str]) > 0)
+ removes.Add(str);
+ }
+ _blockLockSlim.ExitReadLock();
+ lock (_deeperInspection)
+ {
+ _blockLockSlim.EnterWriteLock();
+ for (int i = 0; i < removes.Count; i++)
+ {
+ _tempBlocked.Remove(removes[i]);
+ _deeperInspection.Remove(removes[i]);
+ _sessions.Remove(removes[i]);
+ }
+ _blockLockSlim.ExitWriteLock();
+ }
+ foreach (string str in removes)
+ {
+ m_log.InfoFormat("[{0}] client: {1} is no longer blocked.",
+ _options.ReportingName, str);
+ }
+ _blockLockSlim.EnterReadLock();
+ if (_tempBlocked.Count > 0)
+ _forgetTimer.Enabled = true;
+ _blockLockSlim.ExitReadLock();
+ };
+
+ _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds;
+ }
+
+ ///
+ /// Given a string Key, Returns if that context is blocked
+ ///
+ /// A Key identifying the context
+ /// bool Yes or No, True or False for blocked
+ public bool IsBlocked(string key)
+ {
+ bool ret = false;
+ _blockLockSlim.EnterReadLock();
+ ret = _tempBlocked.ContainsKey(key);
+ _blockLockSlim.ExitReadLock();
+ return ret;
+ }
+
+ ///
+ /// Process the velocity of this context
+ ///
+ ///
+ ///
+ ///
+ public bool Process(string key, string endpoint)
+ {
+ if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1)
+ return true;
+
+ string clientstring = key;
+
+ _blockLockSlim.EnterReadLock();
+ if (_tempBlocked.ContainsKey(clientstring))
+ {
+ _blockLockSlim.ExitReadLock();
+
+ if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
+ return false;
+ else
+ throw new System.Security.SecurityException("Throttled");
+ }
+
+ _blockLockSlim.ExitReadLock();
+
+ lock (_generalRequestTimes)
+ _generalRequestTimes.Put(Util.EnvironmentTickCount());
+
+ if (_options.MaxConcurrentSessions > 0)
+ {
+ int sessionscount = 0;
+
+ _sessionLockSlim.EnterReadLock();
+ if (_sessions.ContainsKey(key))
+ sessionscount = _sessions[key];
+ _sessionLockSlim.ExitReadLock();
+
+ if (sessionscount > _options.MaxConcurrentSessions)
+ {
+ // Add to blocking and cleanup methods
+ lock (_deeperInspection)
+ {
+ _blockLockSlim.EnterWriteLock();
+ if (!_tempBlocked.ContainsKey(clientstring))
+ {
+ _tempBlocked.Add(clientstring,
+ Util.EnvironmentTickCount() +
+ (int) _options.ForgetTimeSpan.TotalMilliseconds);
+ _forgetTimer.Enabled = true;
+ m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds based on concurrency, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint);
+
+ }
+ else
+ _tempBlocked[clientstring] = Util.EnvironmentTickCount() +
+ (int) _options.ForgetTimeSpan.TotalMilliseconds;
+ _blockLockSlim.ExitWriteLock();
+
+ }
+
+
+ }
+ else
+ ProcessConcurrency(key, endpoint);
+ }
+ if (_generalRequestTimes.Size == _generalRequestTimes.Capacity &&
+ (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) <
+ _options.RequestTimeSpan.TotalMilliseconds))
+ {
+ //Trigger deeper inspection
+ if (DeeperInspection(key, endpoint))
+ return true;
+ if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
+ return false;
+ else
+ throw new System.Security.SecurityException("Throttled");
+ }
+ return true;
+ }
+ private void ProcessConcurrency(string key, string endpoint)
+ {
+ _sessionLockSlim.EnterWriteLock();
+ if (_sessions.ContainsKey(key))
+ _sessions[key] = _sessions[key] + 1;
+ else
+ _sessions.Add(key,1);
+ _sessionLockSlim.ExitWriteLock();
+ }
+ public void ProcessEnd(string key, string endpoint)
+ {
+ _sessionLockSlim.EnterWriteLock();
+ if (_sessions.ContainsKey(key))
+ {
+ _sessions[key]--;
+ if (_sessions[key] <= 0)
+ _sessions.Remove(key);
+ }
+ else
+ _sessions.Add(key, 1);
+
+ _sessionLockSlim.ExitWriteLock();
+ }
+
+ ///
+ /// At this point, the rate limiting code needs to track 'per user' velocity.
+ ///
+ /// Context Key, string representing a rate limiting context
+ ///
+ ///
+ private bool DeeperInspection(string key, string endpoint)
+ {
+ lock (_deeperInspection)
+ {
+ string clientstring = key;
+
+
+ if (_deeperInspection.ContainsKey(clientstring))
+ {
+ _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
+ if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity &&
+ (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) <
+ _options.RequestTimeSpan.TotalMilliseconds))
+ {
+ //Looks like we're over the limit
+ _blockLockSlim.EnterWriteLock();
+ if (!_tempBlocked.ContainsKey(clientstring))
+ _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds);
+ else
+ _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds;
+ _blockLockSlim.ExitWriteLock();
+
+ m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint);
+
+ return false;
+ }
+ //else
+ // return true;
+ }
+ else
+ {
+ _deeperInspection.Add(clientstring, new CircularBuffer(_options.MaxRequestsInTimeframe + 1, true));
+ _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
+ _forgetTimer.Enabled = true;
+ }
+
+ }
+ return true;
+ }
+
+ }
+
+
+ public class BasicDosProtectorOptions
+ {
+ public int MaxRequestsInTimeframe;
+ public TimeSpan RequestTimeSpan;
+ public TimeSpan ForgetTimeSpan;
+ public bool AllowXForwardedFor;
+ public string ReportingName = "BASICDOSPROTECTOR";
+ public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod;
+ public int MaxConcurrentSessions;
+ }
+}
diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs
index 3658161..d11ad11 100644
--- a/OpenSim/Framework/BlockingQueue.cs
+++ b/OpenSim/Framework/BlockingQueue.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Framework
{
lock (m_queueSync)
{
- if (m_queue.Count < 1 && m_pqueue.Count < 1)
+ while (m_queue.Count < 1 && m_pqueue.Count < 1)
{
Monitor.Wait(m_queueSync);
}
@@ -76,9 +76,10 @@ namespace OpenSim.Framework
{
lock (m_queueSync)
{
- if (m_queue.Count < 1 && m_pqueue.Count < 1)
+ bool success = true;
+ while (m_queue.Count < 1 && m_pqueue.Count < 1 && success)
{
- Monitor.Wait(m_queueSync, msTimeout);
+ success = Monitor.Wait(m_queueSync, msTimeout);
}
if (m_pqueue.Count > 0)
@@ -89,28 +90,47 @@ namespace OpenSim.Framework
}
}
+ ///
+ /// Indicate whether this queue contains the given item.
+ ///
+ ///
+ /// This method is not thread-safe. Do not rely on the result without consistent external locking.
+ ///
public bool Contains(T item)
{
lock (m_queueSync)
{
+ if (m_queue.Count < 1 && m_pqueue.Count < 1)
+ return false;
+
if (m_pqueue.Contains(item))
return true;
return m_queue.Contains(item);
}
}
+ ///
+ /// Return a count of the number of requests on this queue.
+ ///
public int Count()
{
lock (m_queueSync)
- {
- return m_queue.Count+m_pqueue.Count;
- }
+ return m_queue.Count + m_pqueue.Count;
}
+ ///
+ /// Return the array of items on this queue.
+ ///
+ ///
+ /// This method is not thread-safe. Do not rely on the result without consistent external locking.
+ ///
public T[] GetQueueArray()
{
lock (m_queueSync)
{
+ if (m_queue.Count < 1 && m_pqueue.Count < 1)
+ return new T[0];
+
return m_queue.ToArray();
}
}
diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs
new file mode 100644
index 0000000..239fc56
--- /dev/null
+++ b/OpenSim/Framework/CachedTextureEventArg.cs
@@ -0,0 +1,46 @@
+/*
+ * 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.Text;
+using OpenMetaverse;
+
+namespace OpenSim.Framework
+{
+ public class CachedTextureRequestArg
+ {
+ public int BakedTextureIndex;
+ public UUID WearableHashID;
+ }
+
+ public class CachedTextureResponseArg
+ {
+ public int BakedTextureIndex;
+ public UUID BakedTextureID;
+ public String HostName;
+ }
+}
diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs
index dfe60aa..1504f21 100644
--- a/OpenSim/Framework/ChildAgentDataUpdate.cs
+++ b/OpenSim/Framework/ChildAgentDataUpdate.cs
@@ -171,9 +171,10 @@ namespace OpenSim.Framework
/// Soon to be decommissioned
///
///
- public void CopyFrom(ChildAgentDataUpdate cAgent)
+ public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid)
{
AgentID = new UUID(cAgent.AgentID);
+ SessionID = sid;
// next: ???
Size = new Vector3();
@@ -229,12 +230,14 @@ namespace OpenSim.Framework
public class ControllerData
{
+ public UUID ObjectID;
public UUID ItemID;
public uint IgnoreControls;
public uint EventControls;
- public ControllerData(UUID item, uint ignore, uint ev)
+ public ControllerData(UUID obj, UUID item, uint ignore, uint ev)
{
+ ObjectID = obj;
ItemID = item;
IgnoreControls = ignore;
EventControls = ev;
@@ -248,6 +251,7 @@ namespace OpenSim.Framework
public OSDMap PackUpdateMessage()
{
OSDMap controldata = new OSDMap();
+ controldata["object"] = OSD.FromUUID(ObjectID);
controldata["item"] = OSD.FromUUID(ItemID);
controldata["ignore"] = OSD.FromInteger(IgnoreControls);
controldata["event"] = OSD.FromInteger(EventControls);
@@ -258,6 +262,8 @@ namespace OpenSim.Framework
public void UnpackUpdateMessage(OSDMap args)
{
+ if (args["object"] != null)
+ ObjectID = args["object"].AsUUID();
if (args["item"] != null)
ItemID = args["item"].AsUUID();
if (args["ignore"] != null)
@@ -286,7 +292,13 @@ namespace OpenSim.Framework
public Vector3 AtAxis;
public Vector3 LeftAxis;
public Vector3 UpAxis;
- public bool ChangedGrid;
+
+ ///
+ /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the
+ /// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after
+ /// establishing the connection triggered by it's receipt of a TeleportFinish EQ message).
+ ///
+ public bool SenderWantsToWaitForRoot;
public float Far;
public float Aspect;
@@ -310,6 +322,8 @@ namespace OpenSim.Framework
public Animation AnimState = null;
public UUID GranterID;
+ public UUID ParentPart;
+ public Vector3 SitOffset;
// Appearance
public AvatarAppearance Appearance;
@@ -355,8 +369,9 @@ namespace OpenSim.Framework
args["left_axis"] = OSD.FromString(LeftAxis.ToString());
args["up_axis"] = OSD.FromString(UpAxis.ToString());
-
- args["changed_grid"] = OSD.FromBoolean(ChangedGrid);
+ //backwards compatibility
+ args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
+ args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
args["far"] = OSD.FromReal(Far);
args["aspect"] = OSD.FromReal(Aspect);
@@ -428,9 +443,18 @@ namespace OpenSim.Framework
// We might not pass this in all cases...
if ((Appearance.Wearables != null) && (Appearance.Wearables.Length > 0))
{
- OSDArray wears = new OSDArray(Appearance.Wearables.Length);
- foreach (AvatarWearable awear in Appearance.Wearables)
- wears.Add(awear.Pack());
+ int wearsCount;
+ if(Appearance.PackLegacyWearables)
+ wearsCount = AvatarWearable.LEGACY_VERSION_MAX_WEARABLES;
+ else
+ wearsCount = AvatarWearable.MAX_WEARABLES;
+
+ if(wearsCount > Appearance.Wearables.Length)
+ wearsCount = Appearance.Wearables.Length;
+
+ OSDArray wears = new OSDArray(wearsCount);
+ for(int i = 0; i < wearsCount ; i++)
+ wears.Add(Appearance.Wearables[i].Pack());
args["wearables"] = wears;
}
@@ -480,6 +504,10 @@ namespace OpenSim.Framework
}
args["attach_objects"] = attObjs;
}
+
+ args["parent_part"] = OSD.FromUUID(ParentPart);
+ args["sit_offset"] = OSD.FromString(SitOffset.ToString());
+
return args;
}
@@ -525,8 +553,8 @@ namespace OpenSim.Framework
if (args["up_axis"] != null)
Vector3.TryParse(args["up_axis"].AsString(), out AtAxis);
- if (args["changed_grid"] != null)
- ChangedGrid = args["changed_grid"].AsBoolean();
+ if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null)
+ SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean();
if (args["far"] != null)
Far = (float)(args["far"].AsReal());
@@ -646,7 +674,12 @@ namespace OpenSim.Framework
if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array)
{
OSDArray wears = (OSDArray)(args["wearables"]);
- for (int i = 0; i < wears.Count / 2; i++)
+
+ int count = wears.Count;
+ if (count > AvatarWearable.MAX_WEARABLES)
+ count = AvatarWearable.MAX_WEARABLES;
+
+ for (int i = 0; i < count / 2; i++)
{
AvatarWearable awear = new AvatarWearable((OSDArray)wears[i]);
Appearance.SetWearable(i,awear);
@@ -711,6 +744,11 @@ namespace OpenSim.Framework
}
}
}
+
+ if (args["parent_part"] != null)
+ ParentPart = args["parent_part"].AsUUID();
+ if (args["sit_offset"] != null)
+ Vector3.TryParse(args["sit_offset"].AsString(), out SitOffset);
}
public AgentData()
diff --git a/OpenSim/Framework/CircularBuffer.cs b/OpenSim/Framework/CircularBuffer.cs
new file mode 100644
index 0000000..e919337
--- /dev/null
+++ b/OpenSim/Framework/CircularBuffer.cs
@@ -0,0 +1,312 @@
+/*
+Copyright (c) 2012, Alex Regueiro
+All rights reserved.
+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.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR 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.Threading;
+
+namespace OpenSim.Framework
+{
+ public class CircularBuffer : ICollection, IEnumerable, ICollection, IEnumerable
+ {
+ private int capacity;
+ private int size;
+ private int head;
+ private int tail;
+ private T[] buffer;
+
+ [NonSerialized()]
+ private object syncRoot;
+
+ public CircularBuffer(int capacity)
+ : this(capacity, false)
+ {
+ }
+
+ public CircularBuffer(int capacity, bool allowOverflow)
+ {
+ if (capacity < 0)
+ throw new ArgumentException("Needs to have at least 1","capacity");
+
+ this.capacity = capacity;
+ size = 0;
+ head = 0;
+ tail = 0;
+ buffer = new T[capacity];
+ AllowOverflow = allowOverflow;
+ }
+
+ public bool AllowOverflow
+ {
+ get;
+ set;
+ }
+
+ public int Capacity
+ {
+ get { return capacity; }
+ set
+ {
+ if (value == capacity)
+ return;
+
+ if (value < size)
+ throw new ArgumentOutOfRangeException("value","Capacity is too small.");
+
+ var dst = new T[value];
+ if (size > 0)
+ CopyTo(dst);
+ buffer = dst;
+
+ capacity = value;
+ }
+ }
+
+ public int Size
+ {
+ get { return size; }
+ }
+
+ public bool Contains(T item)
+ {
+ int bufferIndex = head;
+ var comparer = EqualityComparer.Default;
+ for (int i = 0; i < size; i++, bufferIndex++)
+ {
+ if (bufferIndex == capacity)
+ bufferIndex = 0;
+
+ if (item == null && buffer[bufferIndex] == null)
+ return true;
+ else if ((buffer[bufferIndex] != null) &&
+ comparer.Equals(buffer[bufferIndex], item))
+ return true;
+ }
+
+ return false;
+ }
+
+ public void Clear()
+ {
+ size = 0;
+ head = 0;
+ tail = 0;
+ }
+
+ public int Put(T[] src)
+ {
+ return Put(src, 0, src.Length);
+ }
+
+ public int Put(T[] src, int offset, int count)
+ {
+ if (!AllowOverflow && count > capacity - size)
+ throw new InvalidOperationException("Buffer Overflow");
+
+ int srcIndex = offset;
+ for (int i = 0; i < count; i++, tail++, srcIndex++)
+ {
+ if (tail == capacity)
+ tail = 0;
+ buffer[tail] = src[srcIndex];
+ }
+ size = Math.Min(size + count, capacity);
+ return count;
+ }
+
+ public void Put(T item)
+ {
+ if (!AllowOverflow && size == capacity)
+ throw new InvalidOperationException("Buffer Overflow");
+
+ buffer[tail] = item;
+ if (++tail == capacity)
+ tail = 0;
+ size++;
+ }
+
+ public void Skip(int count)
+ {
+ head += count;
+ if (head >= capacity)
+ head -= capacity;
+ }
+
+ public T[] Get(int count)
+ {
+ var dst = new T[count];
+ Get(dst);
+ return dst;
+ }
+
+ public int Get(T[] dst)
+ {
+ return Get(dst, 0, dst.Length);
+ }
+
+ public int Get(T[] dst, int offset, int count)
+ {
+ int realCount = Math.Min(count, size);
+ int dstIndex = offset;
+ for (int i = 0; i < realCount; i++, head++, dstIndex++)
+ {
+ if (head == capacity)
+ head = 0;
+ dst[dstIndex] = buffer[head];
+ }
+ size -= realCount;
+ return realCount;
+ }
+
+ public T Get()
+ {
+ if (size == 0)
+ throw new InvalidOperationException("Buffer Empty");
+
+ var item = buffer[head];
+ if (++head == capacity)
+ head = 0;
+ size--;
+ return item;
+ }
+
+ public void CopyTo(T[] array)
+ {
+ CopyTo(array, 0);
+ }
+
+ public void CopyTo(T[] array, int arrayIndex)
+ {
+ CopyTo(0, array, arrayIndex, size);
+ }
+
+ public void CopyTo(int index, T[] array, int arrayIndex, int count)
+ {
+ if (count > size)
+ throw new ArgumentOutOfRangeException("count", "Count Too Large");
+
+ int bufferIndex = head;
+ for (int i = 0; i < count; i++, bufferIndex++, arrayIndex++)
+ {
+ if (bufferIndex == capacity)
+ bufferIndex = 0;
+ array[arrayIndex] = buffer[bufferIndex];
+ }
+ }
+
+ public IEnumerator GetEnumerator()
+ {
+ int bufferIndex = head;
+ for (int i = 0; i < size; i++, bufferIndex++)
+ {
+ if (bufferIndex == capacity)
+ bufferIndex = 0;
+
+ yield return buffer[bufferIndex];
+ }
+ }
+
+ public T[] GetBuffer()
+ {
+ return buffer;
+ }
+
+ public T[] ToArray()
+ {
+ var dst = new T[size];
+ CopyTo(dst);
+ return dst;
+ }
+
+ #region ICollection Members
+
+ int ICollection.Count
+ {
+ get { return Size; }
+ }
+
+ bool ICollection.IsReadOnly
+ {
+ get { return false; }
+ }
+
+ void ICollection.Add(T item)
+ {
+ Put(item);
+ }
+
+ bool ICollection.Remove(T item)
+ {
+ if (size == 0)
+ return false;
+
+ Get();
+ return true;
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return GetEnumerator();
+ }
+
+ #endregion
+
+ #region ICollection Members
+
+ int ICollection.Count
+ {
+ get { return Size; }
+ }
+
+ bool ICollection.IsSynchronized
+ {
+ get { return false; }
+ }
+
+ object ICollection.SyncRoot
+ {
+ get
+ {
+ if (syncRoot == null)
+ Interlocked.CompareExchange(ref syncRoot, new object(), null);
+ return syncRoot;
+ }
+ }
+
+ void ICollection.CopyTo(Array array, int arrayIndex)
+ {
+ CopyTo((T[])array, arrayIndex);
+ }
+
+ #endregion
+
+ #region IEnumerable Members
+
+ IEnumerator IEnumerable.GetEnumerator()
+ {
+ return (IEnumerator)GetEnumerator();
+ }
+
+ #endregion
+ }
+}
diff --git a/OpenSim/Framework/ClientInfo.cs b/OpenSim/Framework/ClientInfo.cs
index 62acb70..98e4465 100644
--- a/OpenSim/Framework/ClientInfo.cs
+++ b/OpenSim/Framework/ClientInfo.cs
@@ -33,12 +33,13 @@ namespace OpenSim.Framework
{
public class ClientInfo
{
- public AgentCircuitData agentcircuit;
+ public readonly DateTime StartedTime = DateTime.Now;
+ public AgentCircuitData agentcircuit = null;
public Dictionary needAck;
- public List out_packets;
- public Dictionary pendingAcks;
+ public List out_packets = new List();
+ public Dictionary pendingAcks = new Dictionary();
public EndPoint proxyEP;
public uint sequence;
@@ -53,5 +54,14 @@ namespace OpenSim.Framework
public int assetThrottle;
public int textureThrottle;
public int totalThrottle;
+
+ // Used by adaptive only
+ public int targetThrottle;
+
+ public int maxThrottle;
+
+ public Dictionary SyncRequests = new Dictionary();
+ public Dictionary AsyncRequests = new Dictionary();
+ public Dictionary GenericRequests = new Dictionary();
}
}
diff --git a/OpenSim/Framework/Communications/GenericAsyncResult.cs b/OpenSim/Framework/Communications/GenericAsyncResult.cs
deleted file mode 100644
index 8e3f62b..0000000
--- a/OpenSim/Framework/Communications/GenericAsyncResult.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * 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.Threading;
-
-namespace OpenSim.Framework.Communications
-{
- internal class SimpleAsyncResult : IAsyncResult
- {
- private readonly AsyncCallback m_callback;
-
- ///
- /// Is process completed?
- ///
- /// Should really be boolean, but VolatileRead has no boolean method
- private byte m_completed;
-
- ///
- /// Did process complete synchronously?
- ///
- /// I have a hard time imagining a scenario where this is the case, again, same issue about
- /// booleans and VolatileRead as m_completed
- ///
- private byte m_completedSynchronously;
-
- private readonly object m_asyncState;
- private ManualResetEvent m_waitHandle;
- private Exception m_exception;
-
- internal SimpleAsyncResult(AsyncCallback cb, object state)
- {
- m_callback = cb;
- m_asyncState = state;
- m_completed = 0;
- m_completedSynchronously = 1;
- }
-
- #region IAsyncResult Members
-
- public object AsyncState
- {
- get { return m_asyncState; }
- }
-
- public WaitHandle AsyncWaitHandle
- {
- get
- {
- if (m_waitHandle == null)
- {
- bool done = IsCompleted;
- ManualResetEvent mre = new ManualResetEvent(done);
- if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null)
- {
- mre.Close();
- }
- else
- {
- if (!done && IsCompleted)
- {
- m_waitHandle.Set();
- }
- }
- }
-
- return m_waitHandle;
- }
- }
-
-
- public bool CompletedSynchronously
- {
- get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; }
- }
-
-
- public bool IsCompleted
- {
- get { return Thread.VolatileRead(ref m_completed) == 1; }
- }
-
- #endregion
-
- #region class Methods
-
- internal void SetAsCompleted(bool completedSynchronously)
- {
- m_completed = 1;
- if (completedSynchronously)
- m_completedSynchronously = 1;
- else
- m_completedSynchronously = 0;
-
- SignalCompletion();
- }
-
- internal void HandleException(Exception e, bool completedSynchronously)
- {
- m_completed = 1;
- if (completedSynchronously)
- m_completedSynchronously = 1;
- else
- m_completedSynchronously = 0;
- m_exception = e;
-
- SignalCompletion();
- }
-
- private void SignalCompletion()
- {
- if (m_waitHandle != null) m_waitHandle.Set();
-
- if (m_callback != null) m_callback(this);
- }
-
- public void EndInvoke()
- {
- // This method assumes that only 1 thread calls EndInvoke
- if (!IsCompleted)
- {
- // If the operation isn't done, wait for it
- AsyncWaitHandle.WaitOne();
- AsyncWaitHandle.Close();
- m_waitHandle.Close();
- m_waitHandle = null; // Allow early GC
- }
-
- // Operation is done: if an exception occured, throw it
- if (m_exception != null) throw m_exception;
- }
-
- #endregion
- }
-
- internal class AsyncResult : SimpleAsyncResult
- {
- private T m_result = default(T);
-
- public AsyncResult(AsyncCallback asyncCallback, Object state) :
- base(asyncCallback, state)
- {
- }
-
- public void SetAsCompleted(T result, bool completedSynchronously)
- {
- // Save the asynchronous operation's result
- m_result = result;
-
- // Tell the base class that the operation completed
- // sucessfully (no exception)
- base.SetAsCompleted(completedSynchronously);
- }
-
- public new T EndInvoke()
- {
- base.EndInvoke();
- return m_result;
- }
- }
-}
\ No newline at end of file
diff --git a/OpenSim/Framework/Communications/IUserService.cs b/OpenSim/Framework/Communications/IUserService.cs
deleted file mode 100644
index dfa059d..0000000
--- a/OpenSim/Framework/Communications/IUserService.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * 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 OpenMetaverse;
-using OpenSim.Services.Interfaces;
-
-namespace OpenSim.Framework.Communications
-{
- public interface IUserService
- {
- ///
- /// Add a temporary user profile.
- ///
- /// A temporary user profile is one that should exist only for the lifetime of the process.
- ///
- void AddTemporaryUserProfile(UserProfileData userProfile);
-
- ///
- /// Loads a user profile by name
- ///
- /// First name
- /// Last name
- /// A user profile. Returns null if no profile is found
- UserProfileData GetUserProfile(string firstName, string lastName);
-
- ///
- /// Loads a user profile from a database by UUID
- ///
- /// The target UUID
- /// A user profile. Returns null if no user profile is found.
- UserProfileData GetUserProfile(UUID userId);
-
- UserProfileData GetUserProfile(Uri uri);
-
- Uri GetUserUri(UserProfileData userProfile);
-
- UserAgentData GetAgentByUUID(UUID userId);
-
- void ClearUserAgent(UUID avatarID);
- List GenerateAgentPickerRequestResponse(UUID QueryID, string Query);
-
- UserProfileData SetupMasterUser(string firstName, string lastName);
- UserProfileData SetupMasterUser(string firstName, string lastName, string password);
- UserProfileData SetupMasterUser(UUID userId);
-
- ///
- /// Update the user's profile.
- ///
- /// UserProfileData object with updated data. Should be obtained
- /// via a call to GetUserProfile().
- /// true if the update could be applied, false if it could not be applied.
- bool UpdateUserProfile(UserProfileData data);
-
- ///
- /// Adds a new friend to the database for XUser
- ///
- /// The agent that who's friends list is being added to
- /// The agent that being added to the friends list of the friends list owner
- /// A uint bit vector for set perms that the friend being added has; 0 = none, 1=This friend can see when they sign on, 2 = map, 4 edit objects
- void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms);
-
- ///
- /// Delete friend on friendlistowner's friendlist.
- ///
- /// The agent that who's friends list is being updated
- /// The Ex-friend agent
- void RemoveUserFriend(UUID friendlistowner, UUID friend);
-
- ///
- /// Update permissions for friend on friendlistowner's friendlist.
- ///
- /// The agent that who's friends list is being updated
- /// The agent that is getting or loosing permissions
- /// A uint bit vector for set perms that the friend being added has; 0 = none, 1=This friend can see when they sign on, 2 = map, 4 edit objects
- void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms);
-
- ///
- /// Logs off a user on the user server
- ///
- /// UUID of the user
- /// UUID of the Region
- /// regionhandle
- /// final position
- /// final lookat
- void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, Vector3 position, Vector3 lookat);
-
- ///
- /// Logs off a user on the user server (deprecated as of 2008-08-27)
- ///
- /// UUID of the user
- /// UUID of the Region
- /// regionhandle
- /// final position x
- /// final position y
- /// final position z
- void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, float posx, float posy, float posz);
-
- ///
- /// Returns a list of FriendsListItems that describe the friends and permissions in the friend relationship
- /// for UUID friendslistowner
- ///
- ///
- /// The agent for whom we're retreiving the friends Data.
- ///
- /// A List of FriendListItems that contains info about the user's friends.
- /// Always returns a list even if the user has no friends
- ///
- List GetUserFriendList(UUID friendlistowner);
-
- // This probably shouldn't be here, it belongs to IAuthentication
- // But since Scenes only have IUserService references, I'm placing it here for now.
- bool VerifySession(UUID userID, UUID sessionID);
-
- ///
- /// Authenticate a user by their password.
- ///
- ///
- /// This is used by callers outside the login process that want to
- /// verify a user who has given their password.
- ///
- /// This should probably also be in IAuthentication but is here for the same reasons as VerifySession() is
- ///
- ///
- ///
- ///
- bool AuthenticateUserByPassword(UUID userID, string password);
-
- // Temporary Hack until we move everything to the new service model
- void SetInventoryService(IInventoryService invService);
- }
-}
diff --git a/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs
deleted file mode 100644
index 070d106..0000000
--- a/OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * 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.
- */
-
-namespace OpenSim.Framework.Communications.Limit
-{
- ///
- /// Interface for strategies that can limit requests from the client. Currently only used in the
- /// texture modules to deal with repeated requests for certain textures. However, limiting strategies
- /// could be used with other requests.
- ///
- public interface IRequestLimitStrategy
- {
- ///
- /// Should the request be allowed? If the id is not monitored, then the request is always allowed.
- /// Otherwise, the strategy criteria will be applied.
- ///
- ///
- ///
- bool AllowRequest(TId id);
-
- ///
- /// Has the request been refused just once?
- ///
- /// False if the request has not yet been refused, or if the request has been refused more
- /// than once.
- bool IsFirstRefusal(TId id);
-
- ///
- /// Start monitoring for future AllowRequest calls. If the id is already monitored, then monitoring
- /// continues.
- ///
- ///
- void MonitorRequests(TId id);
-
- ///
- /// Is the id being monitored?
- ///
- ///
- ///
- bool IsMonitoringRequests(TId id);
- }
-}
diff --git a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs
deleted file mode 100644
index 7672653..0000000
--- a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * 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.
- */
-
-namespace OpenSim.Framework.Communications.Limit
-{
- ///
- /// Strategy which polices no limits
- ///
- public class NullLimitStrategy : IRequestLimitStrategy
- {
- public bool AllowRequest(TId id) { return true; }
- public bool IsFirstRefusal(TId id) { return false; }
- public void MonitorRequests(TId id) { /* intentionally blank */ }
- public bool IsMonitoringRequests(TId id) { return false; }
- }
-}
diff --git a/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs
deleted file mode 100644
index 44dd592..0000000
--- a/OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * 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.Collections.Generic;
-
-namespace OpenSim.Framework.Communications.Limit
-{
- ///
- /// Limit requests by discarding them after they've been repeated a certain number of times.
- ///
- public class RepeatLimitStrategy : IRequestLimitStrategy
- {
- ///
- /// Record each asset request that we're notified about.
- ///
- private readonly Dictionary requestCounts = new Dictionary();
-
- ///
- /// The maximum number of requests that can be made before we drop subsequent requests.
- ///
- private readonly int m_maxRequests;
- public int MaxRequests
- {
- get { return m_maxRequests; }
- }
-
- ///
- /// The maximum number of requests that may be served before all further
- /// requests are dropped.
- public RepeatLimitStrategy(int maxRequests)
- {
- m_maxRequests = maxRequests;
- }
-
- ///
- ///
- ///
- public bool AllowRequest(TId id)
- {
- if (requestCounts.ContainsKey(id))
- {
- requestCounts[id] += 1;
-
- if (requestCounts[id] > m_maxRequests)
- {
- return false;
- }
- }
-
- return true;
- }
-
- ///
- ///
- ///
- public bool IsFirstRefusal(TId id)
- {
- if (requestCounts.ContainsKey(id) && m_maxRequests + 1 == requestCounts[id])
- {
- return true;
- }
-
- return false;
- }
-
- ///
- ///
- ///
- public void MonitorRequests(TId id)
- {
- if (!IsMonitoringRequests(id))
- {
- requestCounts.Add(id, 1);
- }
- }
-
- ///
- ///
- ///
- public bool IsMonitoringRequests(TId id)
- {
- return requestCounts.ContainsKey(id);
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs
deleted file mode 100644
index 7ac8293..0000000
--- a/OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * 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.Framework.Communications.Limit
-{
- ///
- /// Limit requests by discarding repeat attempts that occur within a given time period
- ///
- /// XXX Don't use this for limiting texture downloading, at least not until we better handle multiple requests
- /// for the same texture at different resolutions.
- ///
- public class TimeLimitStrategy : IRequestLimitStrategy
- {
- ///
- /// Record the time at which an asset request occurs.
- ///
- private readonly Dictionary requests = new Dictionary();
-
- ///
- /// The minimum time period between which requests for the same data will be serviced.
- ///
- private readonly TimeSpan m_repeatPeriod;
- public TimeSpan RepeatPeriod
- {
- get { return m_repeatPeriod; }
- }
-
- ///
- ///
- public TimeLimitStrategy(TimeSpan repeatPeriod)
- {
- m_repeatPeriod = repeatPeriod;
- }
-
- ///
- ///
- ///
- public bool AllowRequest(TId id)
- {
- if (IsMonitoringRequests(id))
- {
- DateTime now = DateTime.Now;
- TimeSpan elapsed = now - requests[id].Time;
-
- if (elapsed < RepeatPeriod)
- {
- requests[id].Refusals += 1;
- return false;
- }
-
- requests[id].Time = now;
- }
-
- return true;
- }
-
- ///
- ///
- ///
- public bool IsFirstRefusal(TId id)
- {
- if (IsMonitoringRequests(id))
- {
- if (1 == requests[id].Refusals)
- {
- return true;
- }
- }
-
- return false;
- }
-
- ///
- ///
- ///
- public void MonitorRequests(TId id)
- {
- if (!IsMonitoringRequests(id))
- {
- requests.Add(id, new Request(DateTime.Now));
- }
- }
-
- ///
- ///
- ///
- public bool IsMonitoringRequests(TId id)
- {
- return requests.ContainsKey(id);
- }
- }
-
- ///
- /// Private request details.
- ///
- class Request
- {
- ///
- /// Time of last request
- ///
- public DateTime Time;
-
- ///
- /// Number of refusals associated with this request
- ///
- public int Refusals;
-
- public Request(DateTime time)
- {
- Time = time;
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
deleted file mode 100644
index 6d1c03a..0000000
--- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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.Reflection;
-using System.Runtime.InteropServices;
-
-// General information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-
-[assembly : AssemblyTitle("OpenSim.Framework.Communications")]
-[assembly : AssemblyDescription("")]
-[assembly : AssemblyConfiguration("")]
-[assembly : AssemblyCompany("http://opensimulator.org")]
-[assembly : AssemblyProduct("OpenSim")]
-[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
-[assembly : AssemblyTrademark("")]
-[assembly : AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-
-[assembly : ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-
-[assembly : Guid("13e7c396-78a9-4a5c-baf2-6f980ea75d95")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-
-[assembly : AssemblyVersion("0.7.5.*")]
-[assembly : AssemblyFileVersion("0.6.5.0")]
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs
deleted file mode 100644
index 97b3b60..0000000
--- a/OpenSim/Framework/Communications/RestClient.cs
+++ /dev/null
@@ -1,438 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Reflection;
-using System.Text;
-using System.Threading;
-using System.Web;
-using log4net;
-
-namespace OpenSim.Framework.Communications
-{
- ///
- /// Implementation of a generic REST client
- ///
- ///
- /// This class is a generic implementation of a REST (Representational State Transfer) web service. This
- /// class is designed to execute both synchronously and asynchronously.
- ///
- /// Internally the implementation works as a two stage asynchronous web-client.
- /// When the request is initiated, RestClient will query asynchronously for for a web-response,
- /// sleeping until the initial response is returned by the server. Once the initial response is retrieved
- /// the second stage of asynchronous requests will be triggered, in an attempt to read of the response
- /// object into a memorystream as a sequence of asynchronous reads.
- ///
- /// The asynchronisity of RestClient is designed to move as much processing into the back-ground, allowing
- /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be
- /// invoked by the caller in either synchronous mode or asynchronous modes.
- ///
- public class RestClient
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- // private string realuri;
-
- #region member variables
-
- ///
- /// The base Uri of the web-service e.g. http://www.google.com
- ///
- private string _url;
-
- ///
- /// Path elements of the query
- ///
- private List _pathElements = new List();
-
- ///
- /// Parameter elements of the query, e.g. min=34
- ///
- private Dictionary _parameterElements = new Dictionary();
-
- ///
- /// Request method. E.g. GET, POST, PUT or DELETE
- ///
- private string _method;
-
- ///
- /// Temporary buffer used to store bytes temporarily as they come in from the server
- ///
- private byte[] _readbuf;
-
- ///
- /// MemoryStream representing the resultiong resource
- ///
- private Stream _resource;
-
- ///
- /// WebRequest object, held as a member variable
- ///
- private HttpWebRequest _request;
-
- ///
- /// WebResponse object, held as a member variable, so we can close it
- ///
- private HttpWebResponse _response;
-
- ///
- /// This flag will help block the main synchroneous method, in case we run in synchroneous mode
- ///
- //public static ManualResetEvent _allDone = new ManualResetEvent(false);
-
- ///
- /// Default time out period
- ///
- //private const int DefaultTimeout = 10*1000; // 10 seconds timeout
-
- ///
- /// Default Buffer size of a block requested from the web-server
- ///
- private const int BufferSize = 4096; // Read blocks of 4 KB.
-
-
- ///
- /// if an exception occours during async processing, we need to save it, so it can be
- /// rethrown on the primary thread;
- ///
- private Exception _asyncException;
-
- #endregion member variables
-
- #region constructors
-
- ///
- /// Instantiate a new RestClient
- ///
- /// Web-service to query, e.g. http://osgrid.org:8003
- public RestClient(string url)
- {
- _url = url;
- _readbuf = new byte[BufferSize];
- _resource = new MemoryStream();
- _request = null;
- _response = null;
- _lock = new object();
- }
-
- private object _lock;
-
- #endregion constructors
-
- ///
- /// Add a path element to the query, e.g. assets
- ///
- /// path entry
- public void AddResourcePath(string element)
- {
- if (isSlashed(element))
- _pathElements.Add(element.Substring(0, element.Length - 1));
- else
- _pathElements.Add(element);
- }
-
- ///
- /// Add a query parameter to the Url
- ///
- /// Name of the parameter, e.g. min
- /// Value of the parameter, e.g. 42
- public void AddQueryParameter(string name, string value)
- {
- try
- {
- _parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value));
- }
- catch (ArgumentException)
- {
- m_log.Error("[REST]: Query parameter " + name + " is already added.");
- }
- catch (Exception e)
- {
- m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e);
- }
- }
-
- ///
- /// Add a query parameter to the Url
- ///
- /// Name of the parameter, e.g. min
- public void AddQueryParameter(string name)
- {
- try
- {
- _parameterElements.Add(HttpUtility.UrlEncode(name), null);
- }
- catch (ArgumentException)
- {
- m_log.Error("[REST]: Query parameter " + name + " is already added.");
- }
- catch (Exception e)
- {
- m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e);
- }
- }
-
- ///
- /// Web-Request method, e.g. GET, PUT, POST, DELETE
- ///
- public string RequestMethod
- {
- get { return _method; }
- set { _method = value; }
- }
-
- ///
- /// True if string contains a trailing slash '/'
- ///
- /// string to be examined
- /// true if slash is present
- private static bool isSlashed(string s)
- {
- return s.Substring(s.Length - 1, 1) == "/";
- }
-
- ///
- /// Build a Uri based on the initial Url, path elements and parameters
- ///
- /// fully constructed Uri
- private Uri buildUri()
- {
- StringBuilder sb = new StringBuilder();
- sb.Append(_url);
-
- foreach (string e in _pathElements)
- {
- sb.Append("/");
- sb.Append(e);
- }
-
- bool firstElement = true;
- foreach (KeyValuePair kv in _parameterElements)
- {
- if (firstElement)
- {
- sb.Append("?");
- firstElement = false;
- }
- else
- sb.Append("&");
-
- sb.Append(kv.Key);
- if (!string.IsNullOrEmpty(kv.Value))
- {
- sb.Append("=");
- sb.Append(kv.Value);
- }
- }
- // realuri = sb.ToString();
- //m_log.InfoFormat("[REST CLIENT]: RestURL: {0}", realuri);
- return new Uri(sb.ToString());
- }
-
- #region Async communications with server
-
- ///
- /// Async method, invoked when a block of data has been received from the service
- ///
- ///
- private void StreamIsReadyDelegate(IAsyncResult ar)
- {
- try
- {
- Stream s = (Stream) ar.AsyncState;
- int read = s.EndRead(ar);
-
- if (read > 0)
- {
- _resource.Write(_readbuf, 0, read);
- // IAsyncResult asynchronousResult =
- // s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s);
- s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s);
-
- // TODO! Implement timeout, without killing the server
- //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
- }
- else
- {
- s.Close();
- //_allDone.Set();
- }
- }
- catch (Exception e)
- {
- //_allDone.Set();
- _asyncException = e;
- }
- }
-
- #endregion Async communications with server
-
- ///
- /// Perform a synchronous request
- ///
- public Stream Request()
- {
- lock (_lock)
- {
- _request = (HttpWebRequest) WebRequest.Create(buildUri());
- _request.KeepAlive = false;
- _request.ContentType = "application/xml";
- _request.Timeout = 200000;
- _request.Method = RequestMethod;
- _asyncException = null;
-
-// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
- try
- {
- _response = (HttpWebResponse) _request.GetResponse();
- }
- catch (WebException e)
- {
- HttpWebResponse errorResponse = e.Response as HttpWebResponse;
- if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
- {
- m_log.Warn("[REST CLIENT] Resource not found (404)");
- }
- else
- {
- m_log.Error("[REST CLIENT] Error fetching resource from server " + _request.Address.ToString());
- m_log.Debug(e.ToString());
- }
-
- return null;
- }
-
- Stream src = _response.GetResponseStream();
- int length = src.Read(_readbuf, 0, BufferSize);
- while (length > 0)
- {
- _resource.Write(_readbuf, 0, length);
- length = src.Read(_readbuf, 0, BufferSize);
- }
-
-
- // TODO! Implement timeout, without killing the server
- // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
- //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
-
-// _allDone.WaitOne();
- if (_response != null)
- _response.Close();
- if (_asyncException != null)
- throw _asyncException;
-
- if (_resource != null)
- {
- _resource.Flush();
- _resource.Seek(0, SeekOrigin.Begin);
- }
-
- return _resource;
- }
- }
-
- public Stream Request(Stream src)
- {
- _request = (HttpWebRequest) WebRequest.Create(buildUri());
- _request.KeepAlive = false;
- _request.ContentType = "application/xml";
- _request.Timeout = 900000;
- _request.Method = RequestMethod;
- _asyncException = null;
- _request.ContentLength = src.Length;
-
- m_log.InfoFormat("[REST]: Request Length {0}", _request.ContentLength);
- m_log.InfoFormat("[REST]: Sending Web Request {0}", buildUri());
- src.Seek(0, SeekOrigin.Begin);
- m_log.Info("[REST]: Seek is ok");
- Stream dst = _request.GetRequestStream();
- m_log.Info("[REST]: GetRequestStream is ok");
-
- byte[] buf = new byte[1024];
- int length = src.Read(buf, 0, 1024);
- m_log.Info("[REST]: First Read is ok");
- while (length > 0)
- {
- dst.Write(buf, 0, length);
- length = src.Read(buf, 0, 1024);
- }
-
- _response = (HttpWebResponse) _request.GetResponse();
-
-// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
-
- // TODO! Implement timeout, without killing the server
- // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
- //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
-
- return null;
- }
-
- #region Async Invocation
-
- public IAsyncResult BeginRequest(AsyncCallback callback, object state)
- {
- ///
- /// In case, we are invoked asynchroneously this object will keep track of the state
- ///
- AsyncResult ar = new AsyncResult(callback, state);
- Util.FireAndForget(RequestHelper, ar);
- return ar;
- }
-
- public Stream EndRequest(IAsyncResult asyncResult)
- {
- AsyncResult ar = (AsyncResult) asyncResult;
-
- // Wait for operation to complete, then return result or
- // throw exception
- return ar.EndInvoke();
- }
-
- private void RequestHelper(Object asyncResult)
- {
- // We know that it's really an AsyncResult object
- AsyncResult ar = (AsyncResult) asyncResult;
- try
- {
- // Perform the operation; if sucessful set the result
- Stream s = Request();
- ar.SetAsCompleted(s, false);
- }
- catch (Exception e)
- {
- // If operation fails, set the exception
- ar.HandleException(e, false);
- }
- }
-
- #endregion Async Invocation
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppError.cs b/OpenSim/Framework/Communications/XMPP/XmppError.cs
deleted file mode 100644
index 3d36e9c..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppError.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * 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.Xml.Serialization;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- [XmlRoot("error")]
- public class XmppErrorStanza
- {
- public XmppErrorStanza()
- {
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs
deleted file mode 100644
index 12263f4..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.Xml.Serialization;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- ///
- /// An IQ needs to have one of the follow types set.
- ///
- public enum XmppIqType
- {
- [XmlEnum("set")] set,
- [XmlEnum("get")] get,
- [XmlEnum("result")] result,
- [XmlEnum("error")] error,
- }
-
- ///
- /// XmppIqStanza needs to be subclassed as the query content is
- /// specific to the query type.
- ///
- [XmlRoot("iq")]
- public abstract class XmppIqStanza: XmppStanza
- {
- ///
- /// IQ type: one of set, get, result, error
- ///
- [XmlAttribute("type")]
- public XmppIqType Type;
-
- public XmppIqStanza(): base()
- {
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs
deleted file mode 100644
index 1e8c33e..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * 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.Xml.Serialization;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- ///
- /// Message types.
- ///
- public enum XmppMessageType
- {
- [XmlEnum("chat")] chat,
- [XmlEnum("error")] error,
- [XmlEnum("groupchat")] groupchat,
- [XmlEnum("headline")] headline,
- [XmlEnum("normal")] normal,
- }
-
- ///
- /// Message body.
- ///
- public class XmppMessageBody
- {
- [XmlText]
- public string Text;
-
- public XmppMessageBody()
- {
- }
-
- public XmppMessageBody(string message)
- {
- Text = message;
- }
-
- new public string ToString()
- {
- return Text;
- }
- }
-
- [XmlRoot("message")]
- public class XmppMessageStanza: XmppStanza
- {
- ///
- /// IQ type: one of set, get, result, error
- ///
- [XmlAttribute("type")]
- public XmppMessageType MessageType;
-
- // [XmlAttribute("error")]
- // public XmppError Error;
-
- [XmlElement("body")]
- public XmppMessageBody Body;
-
- public XmppMessageStanza() : base()
- {
- }
-
- public XmppMessageStanza(string fromJid, string toJid, XmppMessageType mType, string message) :
- base(fromJid, toJid)
- {
- MessageType = mType;
- Body = new XmppMessageBody(message);
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs
deleted file mode 100644
index 4d45ac0..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * 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.Xml.Serialization;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- ///
- /// Message types.
- ///
- public enum XmppPresenceType
- {
- [XmlEnum("unavailable")] unavailable,
- [XmlEnum("subscribe")] subscribe,
- [XmlEnum("subscribed")] subscribed,
- [XmlEnum("unsubscribe")] unsubscribe,
- [XmlEnum("unsubscribed")] unsubscribed,
- [XmlEnum("probe")] probe,
- [XmlEnum("error")] error,
- }
-
-
- [XmlRoot("message")]
- public class XmppPresenceStanza: XmppStanza
- {
- ///
- /// IQ type: one of set, get, result, error
- ///
- [XmlAttribute("type")]
- public XmppPresenceType PresenceType;
-
- // [XmlAttribute("error")]
- // public XmppError Error;
-
- public XmppPresenceStanza() : base()
- {
- }
-
- public XmppPresenceStanza(string fromJid, string toJid, XmppPresenceType pType) :
- base(fromJid, toJid)
- {
- PresenceType = pType;
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppSerializer.cs b/OpenSim/Framework/Communications/XMPP/XmppSerializer.cs
deleted file mode 100644
index e37ef28..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppSerializer.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.Xml;
-using System.Xml.Serialization;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- public class XmppSerializer
- {
- // private static readonly ILog _log =
- // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- // need to do it this way, as XmlSerializer(type, extratypes)
- // does not work on mono (at least).
- private Dictionary _serializerForType = new Dictionary();
- private Dictionary _serializerForName = new Dictionary();
- private XmlSerializerNamespaces _xmlNs;
- private string _defaultNS;
-
- public XmppSerializer(bool server)
- {
- _xmlNs = new XmlSerializerNamespaces();
- _xmlNs.Add(String.Empty, String.Empty);
- if (server)
- _defaultNS = "jabber:server";
- else
- _defaultNS = "jabber:client";
-
- // TODO: do this via reflection
- _serializerForType[typeof(XmppMessageStanza)] = _serializerForName["message"] =
- new XmlSerializer(typeof(XmppMessageStanza), _defaultNS);
- }
-
- public void Serialize(XmlWriter xw, object o)
- {
- if (!_serializerForType.ContainsKey(o.GetType()))
- throw new ArgumentException(String.Format("no serializer available for type {0}", o.GetType()));
-
- _serializerForType[o.GetType()].Serialize(xw, o, _xmlNs);
- }
-
- public object Deserialize(XmlReader xr)
- {
- // position on next element
- xr.Read();
- if (!_serializerForName.ContainsKey(xr.LocalName))
- throw new ArgumentException(String.Format("no serializer available for name {0}", xr.LocalName));
-
- return _serializerForName[xr.LocalName].Deserialize(xr);
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs b/OpenSim/Framework/Communications/XMPP/XmppStanza.cs
deleted file mode 100644
index 5312a31..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.Xml.Serialization;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- public abstract class XmppStanza
- {
- ///
- /// counter used for generating ID
- ///
- [XmlIgnore]
- private static ulong _ctr = 0;
-
- ///
- /// recipient JID
- ///
- [XmlAttribute("to")]
- public string ToJid;
-
- ///
- /// sender JID
- ///
- [XmlAttribute("from")]
- public string FromJid;
-
- ///
- /// unique ID.
- ///
- [XmlAttribute("id")]
- public string MessageId;
-
- public XmppStanza()
- {
- }
-
- public XmppStanza(string fromJid, string toJid)
- {
- ToJid = toJid;
- FromJid = fromJid;
- MessageId = String.Format("OpenSim_{0}{1}", DateTime.UtcNow.Ticks, _ctr++);
- }
- }
-}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs b/OpenSim/Framework/Communications/XMPP/XmppWriter.cs
deleted file mode 100644
index 415d808..0000000
--- a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.IO;
-using System.Text;
-using System.Xml;
-using IOStream = System.IO.Stream;
-
-namespace OpenSim.Framework.Communications.XMPP
-{
- public class XMPPWriter: XmlTextWriter
- {
- public XMPPWriter(TextWriter textWriter) : base(textWriter)
- {
- }
-
- public XMPPWriter(IOStream stream) : this(stream, Util.UTF8)
- {
- }
-
- public XMPPWriter(IOStream stream, Encoding enc) : base(stream, enc)
- {
- }
-
- public override void WriteStartDocument()
- {
- }
-
- public override void WriteStartDocument(bool standalone)
- {
- }
- }
-}
diff --git a/OpenSim/Framework/ConfigSettings.cs b/OpenSim/Framework/ConfigSettings.cs
index 002a371..108a3e4 100644
--- a/OpenSim/Framework/ConfigSettings.cs
+++ b/OpenSim/Framework/ConfigSettings.cs
@@ -31,7 +31,6 @@ namespace OpenSim.Framework
{
public string PhysicsEngine { get; set; }
public string MeshEngineName { get; set; }
- public string StorageDll { get; set; }
public string ClientstackDll { get; set; }
public string LibrariesXMLFile { get; set; }
diff --git a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs b/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs
deleted file mode 100644
index 3dce578..0000000
--- a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * 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.IO;
-using System.Net;
-using System.Reflection;
-using System.Text;
-using log4net;
-using OpenSim.Framework.Configuration.XML;
-
-namespace OpenSim.Framework.Configuration.HTTP
-{
- public class HTTPConfiguration : IGenericConfig
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- private RemoteConfigSettings remoteConfigSettings;
-
- private XmlConfiguration xmlConfig;
-
- private string configFileName = String.Empty;
-
- public HTTPConfiguration()
- {
- remoteConfigSettings = new RemoteConfigSettings("remoteconfig.xml");
- xmlConfig = new XmlConfiguration();
- }
-
- public void SetFileName(string fileName)
- {
- configFileName = fileName;
- }
-
- public void LoadData()
- {
- try
- {
- StringBuilder sb = new StringBuilder();
-
- byte[] buf = new byte[8192];
- HttpWebRequest request =
- (HttpWebRequest) WebRequest.Create(remoteConfigSettings.baseConfigURL + configFileName);
- HttpWebResponse response = (HttpWebResponse) request.GetResponse();
-
- Stream resStream = response.GetResponseStream();
-
- string tempString = null;
- int count = 0;
-
- do
- {
- count = resStream.Read(buf, 0, buf.Length);
- if (count != 0)
- {
- tempString = Util.UTF8.GetString(buf, 0, count);
- sb.Append(tempString);
- }
- } while (count > 0);
- LoadDataFromString(sb.ToString());
- }
- catch (WebException)
- {
- m_log.Warn("Unable to connect to remote configuration file (" +
- remoteConfigSettings.baseConfigURL + configFileName +
- "). Creating local file instead.");
- xmlConfig.SetFileName(configFileName);
- xmlConfig.LoadData();
- }
- }
-
- public void LoadDataFromString(string data)
- {
- xmlConfig.LoadDataFromString(data);
- }
-
- public string GetAttribute(string attributeName)
- {
- return xmlConfig.GetAttribute(attributeName);
- }
-
- public bool SetAttribute(string attributeName, string attributeValue)
- {
- return true;
- }
-
- public void Commit()
- {
- }
-
- public void Close()
- {
- }
- }
-}
diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
deleted file mode 100644
index 0674656..0000000
--- a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("OpenSim.Framework.Configuration.HTTP")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("http://opensimulator.org")]
-[assembly: AssemblyProduct("OpenSim")]
-[assembly: AssemblyCopyright("OpenSimulator develoeprs")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("cb78b672-d000-4f93-88f9-dae151cc0061")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs b/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs
deleted file mode 100644
index 10bc88a..0000000
--- a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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;
-
-namespace OpenSim.Framework.Configuration.HTTP
-{
- public class RemoteConfigSettings
- {
- private ConfigurationMember configMember;
-
- public string baseConfigURL = String.Empty;
-
- public RemoteConfigSettings(string filename)
- {
- configMember =
- new ConfigurationMember(filename, "REMOTE CONFIG SETTINGS", loadConfigurationOptions,
- handleIncomingConfiguration,true);
- configMember.forceConfigurationPluginLibrary("OpenSim.Framework.Configuration.XML.dll");
- configMember.performConfigurationRetrieve();
- }
-
- public void loadConfigurationOptions()
- {
- configMember.addConfigurationOption("base_config_url",
- ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "URL Containing Configuration Files", "http://localhost/", false);
- }
-
- public bool handleIncomingConfiguration(string configuration_key, object configuration_result)
- {
- if (configuration_key == "base_config_url")
- {
- baseConfigURL = (string) configuration_result;
- }
- return true;
- }
- }
-}
diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
deleted file mode 100644
index 1095b23..0000000
--- a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("OpenSim.Framework.Configuration.XML")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("http://opensimulator.org")]
-[assembly: AssemblyProduct("OpenSim")]
-[assembly: AssemblyCopyright("OpenSimulator developers")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("eeb880df-0112-4c3d-87ed-b2108d614c55")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs b/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs
deleted file mode 100644
index 43162fc..0000000
--- a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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.IO;
-using System.Xml;
-
-namespace OpenSim.Framework.Configuration.XML
-{
- public class XmlConfiguration : IGenericConfig
- {
- private XmlDocument doc;
- private XmlNode rootNode;
- private XmlNode configNode;
- private string fileName;
- private bool createdFile = false;
-
- public void SetFileName(string file)
- {
- fileName = file;
- }
-
- private void LoadDataToClass()
- {
- rootNode = doc.SelectSingleNode("Root");
- if (null == rootNode)
- throw new Exception("Error: Invalid .xml File. Missing ");
-
- configNode = rootNode.SelectSingleNode("Config");
- if (null == configNode)
- throw new Exception("Error: Invalid .xml File. should contain a ");
- }
-
- public void LoadData()
- {
- lock (this)
- {
- doc = new XmlDocument();
- if (File.Exists(fileName))
- {
- XmlTextReader reader = new XmlTextReader(fileName);
- reader.WhitespaceHandling = WhitespaceHandling.None;
- doc.Load(reader);
- reader.Close();
- }
- else
- {
- createdFile = true;
- rootNode = doc.CreateNode(XmlNodeType.Element, "Root", String.Empty);
- doc.AppendChild(rootNode);
- configNode = doc.CreateNode(XmlNodeType.Element, "Config", String.Empty);
- rootNode.AppendChild(configNode);
- }
-
- LoadDataToClass();
-
- if (createdFile)
- {
- Commit();
- }
- }
- }
-
- public void LoadDataFromString(string data)
- {
- doc = new XmlDocument();
- doc.LoadXml(data);
-
- LoadDataToClass();
- }
-
- public string GetAttribute(string attributeName)
- {
- string result = null;
- if (configNode.Attributes[attributeName] != null)
- {
- result = ((XmlAttribute) configNode.Attributes.GetNamedItem(attributeName)).Value;
- }
- return result;
- }
-
- public bool SetAttribute(string attributeName, string attributeValue)
- {
- if (configNode.Attributes[attributeName] != null)
- {
- ((XmlAttribute) configNode.Attributes.GetNamedItem(attributeName)).Value = attributeValue;
- }
- else
- {
- XmlAttribute attri;
- attri = doc.CreateAttribute(attributeName);
- attri.Value = attributeValue;
- configNode.Attributes.Append(attri);
- }
- return true;
- }
-
- public void Commit()
- {
- if (fileName == null || fileName == String.Empty)
- return;
-
- if (!Directory.Exists(Util.configDir()))
- {
- Directory.CreateDirectory(Util.configDir());
- }
- doc.Save(fileName);
- }
-
- public void Close()
- {
- configNode = null;
- rootNode = null;
- doc = null;
- }
- }
-}
diff --git a/OpenSim/Framework/ConfigurationMember.cs b/OpenSim/Framework/ConfigurationMember.cs
deleted file mode 100644
index 7afa68a..0000000
--- a/OpenSim/Framework/ConfigurationMember.cs
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * 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.Globalization;
-using System.Net;
-using System.Reflection;
-using System.Xml;
-using log4net;
-using OpenMetaverse;
-//using OpenSim.Framework.Console;
-
-namespace OpenSim.Framework
-{
- public class ConfigurationMember
- {
- #region Delegates
-
- public delegate bool ConfigurationOptionResult(string configuration_key, object configuration_result);
-
- public delegate void ConfigurationOptionsLoad();
-
- #endregion
-
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- private int cE = 0;
-
- private string configurationDescription = String.Empty;
- private string configurationFilename = String.Empty;
- private XmlNode configurationFromXMLNode = null;
- private List configurationOptions = new List();
- private IGenericConfig configurationPlugin = null;
-
- ///
- /// This is the default configuration DLL loaded
- ///
- private string configurationPluginFilename = "OpenSim.Framework.Configuration.XML.dll";
-
- private ConfigurationOptionsLoad loadFunction;
- private ConfigurationOptionResult resultFunction;
-
- private bool useConsoleToPromptOnError = true;
-
- public ConfigurationMember(string configuration_filename, string configuration_description,
- ConfigurationOptionsLoad load_function, ConfigurationOptionResult result_function, bool use_console_to_prompt_on_error)
- {
- configurationFilename = configuration_filename;
- configurationDescription = configuration_description;
- loadFunction = load_function;
- resultFunction = result_function;
- useConsoleToPromptOnError = use_console_to_prompt_on_error;
- }
-
- public ConfigurationMember(XmlNode configuration_xml, string configuration_description,
- ConfigurationOptionsLoad load_function, ConfigurationOptionResult result_function, bool use_console_to_prompt_on_error)
- {
- configurationFilename = String.Empty;
- configurationFromXMLNode = configuration_xml;
- configurationDescription = configuration_description;
- loadFunction = load_function;
- resultFunction = result_function;
- useConsoleToPromptOnError = use_console_to_prompt_on_error;
- }
-
- public void setConfigurationFilename(string filename)
- {
- configurationFilename = filename;
- }
-
- public void setConfigurationDescription(string desc)
- {
- configurationDescription = desc;
- }
-
- public void setConfigurationResultFunction(ConfigurationOptionResult result)
- {
- resultFunction = result;
- }
-
- public void forceConfigurationPluginLibrary(string dll_filename)
- {
- configurationPluginFilename = dll_filename;
- }
-
- private void checkAndAddConfigOption(ConfigurationOption option)
- {
- if ((option.configurationKey != String.Empty && option.configurationQuestion != String.Empty) ||
- (option.configurationKey != String.Empty && option.configurationUseDefaultNoPrompt))
- {
- if (!configurationOptions.Contains(option))
- {
- configurationOptions.Add(option);
- }
- }
- else
- {
- m_log.Info(
- "Required fields for adding a configuration option is invalid. Will not add this option (" +
- option.configurationKey + ")");
- }
- }
-
- public void addConfigurationOption(string configuration_key,
- ConfigurationOption.ConfigurationTypes configuration_type,
- string configuration_question, string configuration_default,
- bool use_default_no_prompt)
- {
- ConfigurationOption configOption = new ConfigurationOption();
- configOption.configurationKey = configuration_key;
- configOption.configurationQuestion = configuration_question;
- configOption.configurationDefault = configuration_default;
- configOption.configurationType = configuration_type;
- configOption.configurationUseDefaultNoPrompt = use_default_no_prompt;
- configOption.shouldIBeAsked = null; //Assumes true, I can ask whenever
- checkAndAddConfigOption(configOption);
- }
-
- public void addConfigurationOption(string configuration_key,
- ConfigurationOption.ConfigurationTypes configuration_type,
- string configuration_question, string configuration_default,
- bool use_default_no_prompt,
- ConfigurationOption.ConfigurationOptionShouldBeAsked shouldIBeAskedDelegate)
- {
- ConfigurationOption configOption = new ConfigurationOption();
- configOption.configurationKey = configuration_key;
- configOption.configurationQuestion = configuration_question;
- configOption.configurationDefault = configuration_default;
- configOption.configurationType = configuration_type;
- configOption.configurationUseDefaultNoPrompt = use_default_no_prompt;
- configOption.shouldIBeAsked = shouldIBeAskedDelegate;
- checkAndAddConfigOption(configOption);
- }
-
- // TEMP - REMOVE
- public void performConfigurationRetrieve()
- {
- if (cE > 1)
- m_log.Error("READING CONFIGURATION COUT: " + cE.ToString());
-
-
- configurationPlugin = LoadConfigDll(configurationPluginFilename);
- configurationOptions.Clear();
- if (loadFunction == null)
- {
- m_log.Error("Load Function for '" + configurationDescription +
- "' is null. Refusing to run configuration.");
- return;
- }
-
- if (resultFunction == null)
- {
- m_log.Error("Result Function for '" + configurationDescription +
- "' is null. Refusing to run configuration.");
- return;
- }
-
- //m_log.Debug("[CONFIG]: Calling Configuration Load Function...");
- loadFunction();
-
- if (configurationOptions.Count <= 0)
- {
- m_log.Error("[CONFIG]: No configuration options were specified for '" + configurationOptions +
- "'. Refusing to continue configuration.");
- return;
- }
-
- bool useFile = true;
- if (configurationPlugin == null)
- {
- m_log.Error("[CONFIG]: Configuration Plugin NOT LOADED!");
- return;
- }
-
- if (configurationFilename.Trim() != String.Empty)
- {
- configurationPlugin.SetFileName(configurationFilename);
- try
- {
- configurationPlugin.LoadData();
- useFile = true;
- }
- catch (XmlException e)
- {
- m_log.WarnFormat("[CONFIG] Not using {0}: {1}",
- configurationFilename,
- e.Message.ToString());
- //m_log.Error("Error loading " + configurationFilename + ": " + e.ToString());
- useFile = false;
- }
- }
- else
- {
- if (configurationFromXMLNode != null)
- {
- m_log.Info("Loading from XML Node, will not save to the file");
- configurationPlugin.LoadDataFromString(configurationFromXMLNode.OuterXml);
- }
-
- m_log.Info("XML Configuration Filename is not valid; will not save to the file.");
- useFile = false;
- }
-
- foreach (ConfigurationOption configOption in configurationOptions)
- {
- bool convertSuccess = false;
- object return_result = null;
- string errorMessage = String.Empty;
- bool ignoreNextFromConfig = false;
- while (convertSuccess == false)
- {
- string console_result = String.Empty;
- string attribute = null;
- if (useFile || configurationFromXMLNode != null)
- {
- if (!ignoreNextFromConfig)
- {
- attribute = configurationPlugin.GetAttribute(configOption.configurationKey);
- }
- else
- {
- ignoreNextFromConfig = false;
- }
- }
-
- if (attribute == null)
- {
- if (configOption.configurationUseDefaultNoPrompt || useConsoleToPromptOnError == false)
- {
- console_result = configOption.configurationDefault;
- }
- else
- {
- if ((configOption.shouldIBeAsked != null &&
- configOption.shouldIBeAsked(configOption.configurationKey)) ||
- configOption.shouldIBeAsked == null)
- {
- if (configurationDescription.Trim() != String.Empty)
- {
- console_result =
- MainConsole.Instance.CmdPrompt(
- configurationDescription + ": " + configOption.configurationQuestion,
- configOption.configurationDefault);
- }
- else
- {
- console_result =
- MainConsole.Instance.CmdPrompt(configOption.configurationQuestion,
- configOption.configurationDefault);
- }
- }
- else
- {
- //Dont Ask! Just use default
- console_result = configOption.configurationDefault;
- }
- }
- }
- else
- {
- console_result = attribute;
- }
-
- // if the first character is a "$", assume it's the name
- // of an environment variable and substitute with the value of that variable
- if (console_result.StartsWith("$"))
- console_result = Environment.GetEnvironmentVariable(console_result.Substring(1));
-
- switch (configOption.configurationType)
- {
- case ConfigurationOption.ConfigurationTypes.TYPE_STRING:
- return_result = console_result;
- convertSuccess = true;
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY:
- if (console_result.Length > 0)
- {
- return_result = console_result;
- convertSuccess = true;
- }
- errorMessage = "a string that is not empty";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN:
- bool boolResult;
- if (Boolean.TryParse(console_result, out boolResult))
- {
- convertSuccess = true;
- return_result = boolResult;
- }
- errorMessage = "'true' or 'false' (Boolean)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_BYTE:
- byte byteResult;
- if (Byte.TryParse(console_result, out byteResult))
- {
- convertSuccess = true;
- return_result = byteResult;
- }
- errorMessage = "a byte (Byte)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_CHARACTER:
- char charResult;
- if (Char.TryParse(console_result, out charResult))
- {
- convertSuccess = true;
- return_result = charResult;
- }
- errorMessage = "a character (Char)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_INT16:
- short shortResult;
- if (Int16.TryParse(console_result, out shortResult))
- {
- convertSuccess = true;
- return_result = shortResult;
- }
- errorMessage = "a signed 32 bit integer (short)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_INT32:
- int intResult;
- if (Int32.TryParse(console_result, out intResult))
- {
- convertSuccess = true;
- return_result = intResult;
- }
- errorMessage = "a signed 32 bit integer (int)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_INT64:
- long longResult;
- if (Int64.TryParse(console_result, out longResult))
- {
- convertSuccess = true;
- return_result = longResult;
- }
- errorMessage = "a signed 32 bit integer (long)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS:
- IPAddress ipAddressResult;
- if (IPAddress.TryParse(console_result, out ipAddressResult))
- {
- convertSuccess = true;
- return_result = ipAddressResult;
- }
- errorMessage = "an IP Address (IPAddress)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_UUID:
- UUID uuidResult;
- if (UUID.TryParse(console_result, out uuidResult))
- {
- convertSuccess = true;
- return_result = uuidResult;
- }
- errorMessage = "a UUID (UUID)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE:
- UUID uuidResult2;
- if (UUID.TryParse(console_result, out uuidResult2))
- {
- convertSuccess = true;
-
- if (uuidResult2 == UUID.Zero)
- uuidResult2 = UUID.Random();
-
- return_result = uuidResult2;
- }
- errorMessage = "a non-null UUID (UUID)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_Vector3:
- Vector3 vectorResult;
- if (Vector3.TryParse(console_result, out vectorResult))
- {
- convertSuccess = true;
- return_result = vectorResult;
- }
- errorMessage = "a vector (Vector3)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_UINT16:
- ushort ushortResult;
- if (UInt16.TryParse(console_result, out ushortResult))
- {
- convertSuccess = true;
- return_result = ushortResult;
- }
- errorMessage = "an unsigned 16 bit integer (ushort)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_UINT32:
- uint uintResult;
- if (UInt32.TryParse(console_result, out uintResult))
- {
- convertSuccess = true;
- return_result = uintResult;
- }
- errorMessage = "an unsigned 32 bit integer (uint)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_UINT64:
- ulong ulongResult;
- if (UInt64.TryParse(console_result, out ulongResult))
- {
- convertSuccess = true;
- return_result = ulongResult;
- }
- errorMessage = "an unsigned 64 bit integer (ulong)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_FLOAT:
- float floatResult;
- if (
- float.TryParse(console_result, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, Culture.NumberFormatInfo,
- out floatResult))
- {
- convertSuccess = true;
- return_result = floatResult;
- }
- errorMessage = "a single-precision floating point number (float)";
- break;
- case ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE:
- double doubleResult;
- if (
- Double.TryParse(console_result, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, Culture.NumberFormatInfo,
- out doubleResult))
- {
- convertSuccess = true;
- return_result = doubleResult;
- }
- errorMessage = "an double-precision floating point number (double)";
- break;
- }
-
- if (convertSuccess)
- {
- if (useFile)
- {
- configurationPlugin.SetAttribute(configOption.configurationKey, console_result);
- }
-
- if (!resultFunction(configOption.configurationKey, return_result))
- {
- m_log.Info(
- "The handler for the last configuration option denied that input, please try again.");
- convertSuccess = false;
- ignoreNextFromConfig = true;
- }
- }
- else
- {
- if (configOption.configurationUseDefaultNoPrompt)
- {
- m_log.Error(string.Format(
- "[CONFIG]: [{3}]:[{1}] is not valid default for parameter [{0}].\nThe configuration result must be parsable to {2}.\n",
- configOption.configurationKey, console_result, errorMessage,
- configurationFilename));
- convertSuccess = true;
- }
- else
- {
- m_log.Warn(string.Format(
- "[CONFIG]: [{3}]:[{1}] is not a valid value [{0}].\nThe configuration result must be parsable to {2}.\n",
- configOption.configurationKey, console_result, errorMessage,
- configurationFilename));
- ignoreNextFromConfig = true;
- }
- }
- }
- }
-
- if (useFile)
- {
- configurationPlugin.Commit();
- configurationPlugin.Close();
- }
- }
-
- private static IGenericConfig LoadConfigDll(string dllName)
- {
- Assembly pluginAssembly = Assembly.LoadFrom(dllName);
- IGenericConfig plug = null;
-
- foreach (Type pluginType in pluginAssembly.GetTypes())
- {
- if (pluginType.IsPublic)
- {
- if (!pluginType.IsAbstract)
- {
- Type typeInterface = pluginType.GetInterface("IGenericConfig", true);
-
- if (typeInterface != null)
- {
- plug =
- (IGenericConfig) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
- }
- }
- }
- }
-
- pluginAssembly = null;
- return plug;
- }
-
- public void forceSetConfigurationOption(string configuration_key, string configuration_value)
- {
- configurationPlugin.LoadData();
- configurationPlugin.SetAttribute(configuration_key, configuration_value);
- configurationPlugin.Commit();
- configurationPlugin.Close();
- }
- }
-}
diff --git a/OpenSim/Framework/Console/AssemblyInfo.cs b/OpenSim/Framework/Console/AssemblyInfo.cs
index 37c7304..67af471 100644
--- a/OpenSim/Framework/Console/AssemblyInfo.cs
+++ b/OpenSim/Framework/Console/AssemblyInfo.cs
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default):
-[assembly : AssemblyVersion("0.7.5.*")]
+[assembly : AssemblyVersion("0.8.2.*")]
diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs
index b9f402a..0f68afe 100644
--- a/OpenSim/Framework/Console/CommandConsole.cs
+++ b/OpenSim/Framework/Console/CommandConsole.cs
@@ -424,9 +424,9 @@ namespace OpenSim.Framework.Console
return new string[] { new List(current.Keys)[0] };
}
- public string[] Resolve(string[] cmd)
+ private CommandInfo ResolveCommand(string[] cmd, out string[] result)
{
- string[] result = cmd;
+ result = cmd;
int index = -1;
Dictionary current = tree;
@@ -458,7 +458,7 @@ namespace OpenSim.Framework.Console
}
else if (found.Count > 0)
{
- return new string[0];
+ return null;
}
else
{
@@ -467,21 +467,37 @@ namespace OpenSim.Framework.Console
}
if (current.ContainsKey(String.Empty))
+ return (CommandInfo)current[String.Empty];
+
+ return null;
+ }
+
+ public bool HasCommand(string command)
+ {
+ string[] result;
+ return ResolveCommand(Parser.Parse(command), out result) != null;
+ }
+
+ public string[] Resolve(string[] cmd)
+ {
+ string[] result;
+ CommandInfo ci = ResolveCommand(cmd, out result);
+
+ if (ci == null)
+ return new string[0];
+
+ if (ci.fn.Count == 0)
+ return new string[0];
+
+ foreach (CommandDelegate fn in ci.fn)
{
- CommandInfo ci = (CommandInfo)current[String.Empty];
- if (ci.fn.Count == 0)
+ if (fn != null)
+ fn(ci.module, result);
+ else
return new string[0];
- foreach (CommandDelegate fn in ci.fn)
- {
- if (fn != null)
- fn(ci.module, result);
- else
- return new string[0];
- }
- return result;
}
-
- return new string[0];
+
+ return result;
}
public XmlElement GetXml(XmlDocument doc)
diff --git a/OpenSim/Framework/Console/ConsoleDisplayUtil.cs b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs
new file mode 100644
index 0000000..6417663
--- /dev/null
+++ b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs
@@ -0,0 +1,48 @@
+/*
+ * 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;
+
+namespace OpenSim.Framework.Console
+{
+ ///
+ /// This will be a set of typical column sizes to allow greater consistency between console commands.
+ ///
+ public static class ConsoleDisplayUtil
+ {
+ public const int CoordTupleSize = 11;
+ public const int PortSize = 5;
+
+ public const int EstateNameSize = 20;
+ public const int ParcelNameSize = 40;
+ public const int RegionNameSize = 20;
+ public const int UserNameSize = 35;
+
+ public const int UuidSize = 36;
+ public const int VectorSize = 15;
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index dff956a..44f6dc1 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -49,14 +49,14 @@ namespace OpenSim.Framework.Console
= @"Each component of the coord is comma separated. There must be no spaces between the commas.
If you don't care about the z component you can simply omit it.
If you don't care about the x or y components then you can leave them blank (though a comma is still required)
- If you want to specify the maxmimum value of a component then you can use ~ instead of a number
+ If you want to specify the maximum value of a component then you can use ~ instead of a number
If you want to specify the minimum value of a component then you can use -~ instead of a number
e.g.
- delete object pos 20,20,20 to 40,40,40
+ show object pos 20,20,20 to 40,40,40
delete object pos 20,20 to 40,40
- delete object pos ,20,20 to ,40,40
+ show object pos ,20,20 to ,40,40
delete object pos ,,30 to ,,~
- delete object pos ,,-~ to ,,30";
+ show object pos ,,-~ to ,,30";
public const string MinRawConsoleVectorValue = "-~";
public const string MaxRawConsoleVectorValue = "~";
@@ -156,12 +156,32 @@ namespace OpenSim.Framework.Console
}
///
- /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
+ /// Convert a console input to a bool, automatically complaining if a console is given.
///
/// Can be null if no console is available.
/// /param>
///
///
+ public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
+ {
+ if (!bool.TryParse(rawConsoleString, out b))
+ {
+ if (console != null)
+ console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Convert a console input to an int, automatically complaining if a console is given.
+ ///
+ /// Can be null if no console is available.
+ /// /param>
+ ///
+ ///
public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
{
if (!int.TryParse(rawConsoleInt, out i))
@@ -174,6 +194,71 @@ namespace OpenSim.Framework.Console
return true;
}
+
+ ///
+ /// Convert a console input to a float, automatically complaining if a console is given.
+ ///
+ /// Can be null if no console is available.
+ /// /param>
+ ///
+ ///
+ public static bool TryParseConsoleFloat(ICommandConsole console, string rawConsoleInput, out float i)
+ {
+ if (!float.TryParse(rawConsoleInput, out i))
+ {
+ if (console != null)
+ console.OutputFormat("ERROR: {0} is not a valid float", rawConsoleInput);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Convert a console input to a double, automatically complaining if a console is given.
+ ///
+ /// Can be null if no console is available.
+ /// /param>
+ ///
+ ///
+ public static bool TryParseConsoleDouble(ICommandConsole console, string rawConsoleInput, out double i)
+ {
+ if (!double.TryParse(rawConsoleInput, out i))
+ {
+ if (console != null)
+ console.OutputFormat("ERROR: {0} is not a valid double", rawConsoleInput);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Convert a console integer to a natural int, automatically complaining if a console is given.
+ ///
+ /// Can be null if no console is available.
+ /// /param>
+ ///
+ ///
+ public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i)
+ {
+ if (TryParseConsoleInt(console, rawConsoleInt, out i))
+ {
+ if (i < 0)
+ {
+ if (console != null)
+ console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt);
+
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
///
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
@@ -207,24 +292,82 @@ namespace OpenSim.Framework.Console
/// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
/// Other than that, component values must be numeric.
///
- ///
+ ///
+ /// Behaviour if component is blank. If null then conversion fails on a blank component.
+ ///
///
///
public static bool TryParseConsoleVector(
string rawConsoleVector, Func blankComponentFunc, out Vector3 vector)
{
- List components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
-
- if (components.Count < 1 || components.Count > 3)
+ return Vector3.TryParse(CookVector(rawConsoleVector, 3, blankComponentFunc), out vector);
+ }
+
+ ///
+ /// Convert a vector input from the console to an OpenMetaverse.Vector2
+ ///
+ ///
+ /// A string in the form , where there is no space between values.
+ /// Any component can be missing (e.g. ,40). blankComponentFunc is invoked to replace the blank with a suitable value
+ /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40)
+ /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
+ /// Other than that, component values must be numeric.
+ ///
+ ///
+ /// Behaviour if component is blank. If null then conversion fails on a blank component.
+ ///
+ ///
+ ///
+ public static bool TryParseConsole2DVector(
+ string rawConsoleVector, Func blankComponentFunc, out Vector2 vector)
+ {
+ // We don't use Vector2.TryParse() for now because for some reason it expects an input with 3 components
+ // rather than 2.
+ string cookedVector = CookVector(rawConsoleVector, 2, blankComponentFunc);
+
+ if (cookedVector == null)
{
- vector = Vector3.Zero;
+ vector = Vector2.Zero;
+
return false;
}
+ else
+ {
+ string[] cookedComponents = cookedVector.Split(VectorSeparatorChars);
+
+ vector = new Vector2(float.Parse(cookedComponents[0]), float.Parse(cookedComponents[1]));
+
+ return true;
+ }
+
+ //return Vector2.TryParse(CookVector(rawConsoleVector, 2, blankComponentFunc), out vector);
+ }
+
+ ///
+ /// Convert a raw console vector into a vector that can be be parsed by the relevant OpenMetaverse.TryParse()
+ ///
+ ///
+ ///
+ ///
+ /// null if conversion was not possible
+ private static string CookVector(
+ string rawConsoleVector, int dimensions, Func blankComponentFunc)
+ {
+ List components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
- for (int i = components.Count; i < 3; i++)
- components.Add("");
+ if (components.Count < 1 || components.Count > dimensions)
+ return null;
- List semiDigestedComponents
+ if (components.Count < dimensions)
+ {
+ if (blankComponentFunc == null)
+ return null;
+ else
+ for (int i = components.Count; i < dimensions; i++)
+ components.Add("");
+ }
+
+ List cookedComponents
= components.ConvertAll(
c =>
{
@@ -238,11 +381,7 @@ namespace OpenSim.Framework.Console
return c;
});
- string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray());
-
- // m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
-
- return Vector3.TryParse(semiDigestedConsoleVector, out vector);
+ return string.Join(VectorSeparator, cookedComponents.ToArray());
}
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs
index d41481f..28293c0 100644
--- a/OpenSim/Framework/Console/LocalConsole.cs
+++ b/OpenSim/Framework/Console/LocalConsole.cs
@@ -32,6 +32,8 @@ using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
+using System.IO;
+using Nini.Config;
using log4net;
namespace OpenSim.Framework.Console
@@ -41,11 +43,18 @@ namespace OpenSim.Framework.Console
///
public class LocalConsole : CommandConsole
{
-// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private string m_historyPath;
+ private bool m_historyEnable;
// private readonly object m_syncRoot = new object();
private const string LOGLEVEL_NONE = "(none)";
+ // Used to extract categories for colourization.
+ private Regex m_categoryRegex
+ = new Regex(
+ @"^(?.*?)\[(?[^\]]+)\]:?(?.*)", RegexOptions.Singleline | RegexOptions.Compiled);
+
private int m_cursorYPosition = -1;
private int m_cursorXPosition = 0;
private StringBuilder m_commandLine = new StringBuilder();
@@ -74,8 +83,54 @@ namespace OpenSim.Framework.Console
return Colors[(Math.Abs(input.ToUpper().GetHashCode()) % Colors.Length)];
}
- public LocalConsole(string defaultPrompt) : base(defaultPrompt)
+ public LocalConsole(string defaultPrompt, IConfig startupConfig = null) : base(defaultPrompt)
{
+
+ if (startupConfig == null) return;
+
+ m_historyEnable = startupConfig.GetBoolean("ConsoleHistoryFileEnabled", false);
+ if (!m_historyEnable)
+ {
+ m_log.Info("[LOCAL CONSOLE]: Persistent command line history from file is Disabled");
+ return;
+ }
+
+ string m_historyFile = startupConfig.GetString("ConsoleHistoryFile", "OpenSimConsoleHistory.txt");
+ int m_historySize = startupConfig.GetInt("ConsoleHistoryFileLines", 100);
+ m_historyPath = Path.GetFullPath(Path.Combine(Util.configDir(), m_historyFile));
+ m_log.InfoFormat("[LOCAL CONSOLE]: Persistent command line history is Enabled, up to {0} lines from file {1}", m_historySize, m_historyPath);
+
+ if (File.Exists(m_historyPath))
+ {
+ using (StreamReader history_file = new StreamReader(m_historyPath))
+ {
+ string line;
+ while ((line = history_file.ReadLine()) != null)
+ {
+ m_history.Add(line);
+ }
+ }
+
+ if (m_history.Count > m_historySize)
+ {
+ while (m_history.Count > m_historySize)
+ m_history.RemoveAt(0);
+
+ using (StreamWriter history_file = new StreamWriter(m_historyPath))
+ {
+ foreach (string line in m_history)
+ {
+ history_file.WriteLine(line);
+ }
+ }
+ }
+ m_log.InfoFormat("[LOCAL CONSOLE]: Read {0} lines of command line history from file {1}", m_history.Count, m_historyPath);
+ }
+ else
+ {
+ m_log.InfoFormat("[LOCAL CONSOLE]: Creating new empty command line history file {0}", m_historyPath);
+ File.Create(m_historyPath).Dispose();
+ }
}
private void AddToHistory(string text)
@@ -84,6 +139,10 @@ namespace OpenSim.Framework.Console
m_history.RemoveAt(0);
m_history.Add(text);
+ if (m_historyEnable)
+ {
+ File.AppendAllText(m_historyPath, text + Environment.NewLine);
+ }
}
///
@@ -280,11 +339,8 @@ namespace OpenSim.Framework.Console
string outText = text;
if (level != LOGLEVEL_NONE)
- {
- string regex = @"^(?.*?)\[(?[^\]]+)\]:?(?.*)";
-
- Regex RE = new Regex(regex, RegexOptions.Multiline);
- MatchCollection matches = RE.Matches(text);
+ {
+ MatchCollection matches = m_categoryRegex.Matches(text);
if (matches.Count == 1)
{
@@ -426,6 +482,21 @@ namespace OpenSim.Framework.Console
System.Console.Write("{0}", prompt);
break;
+ case ConsoleKey.Delete:
+ if (m_cursorXPosition == m_commandLine.Length)
+ break;
+
+ m_commandLine.Remove(m_cursorXPosition, 1);
+
+ SetCursorLeft(0);
+ m_cursorYPosition = SetCursorTop(m_cursorYPosition);
+
+ if (m_echo)
+ System.Console.Write("{0}{1} ", prompt, m_commandLine);
+ else
+ System.Console.Write("{0}", prompt);
+
+ break;
case ConsoleKey.End:
m_cursorXPosition = m_commandLine.Length;
break;
diff --git a/OpenSim/Framework/Console/MockConsole.cs b/OpenSim/Framework/Console/MockConsole.cs
index 8ba58e4..1a142df 100644
--- a/OpenSim/Framework/Console/MockConsole.cs
+++ b/OpenSim/Framework/Console/MockConsole.cs
@@ -40,7 +40,9 @@ namespace OpenSim.Framework.Console
///
public class MockConsole : ICommandConsole
{
+#pragma warning disable 0067
public event OnOutputDelegate OnOutput;
+#pragma warning restore 0067
private MockCommands m_commands = new MockCommands();
@@ -80,6 +82,7 @@ namespace OpenSim.Framework.Console
public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) {}
public void AddCommand(string module, bool shared, string command, string help, string longhelp, string descriptivehelp, CommandDelegate fn) {}
public string[] FindNextOption(string[] cmd, bool term) { return null; }
+ public bool HasCommand(string cmd) { return false; }
public string[] Resolve(string[] cmd) { return null; }
public XmlElement GetXml(XmlDocument doc) { return null; }
}
diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs
index 27edd4b..8ad7b0d 100644
--- a/OpenSim/Framework/Console/RemoteConsole.cs
+++ b/OpenSim/Framework/Console/RemoteConsole.cs
@@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console
string uri = "/ReadResponses/" + sessionID.ToString() + "/";
m_Server.AddPollServiceHTTPHandler(
- uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID));
+ uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout
XmlDocument xmldoc = new XmlDocument();
XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
@@ -425,7 +425,7 @@ namespace OpenSim.Framework.Console
return false;
}
- private Hashtable GetEvents(UUID RequestID, UUID sessionID, string request)
+ private Hashtable GetEvents(UUID RequestID, UUID sessionID)
{
ConsoleConnection c = null;
diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs
index a2eb5ee..3ba264c 100644
--- a/OpenSim/Framework/Constants.cs
+++ b/OpenSim/Framework/Constants.cs
@@ -30,9 +30,18 @@ namespace OpenSim.Framework
{
public class Constants
{
+ // 'RegionSize' is the legacy region size.
+ // DO NOT USE THIS FOR ANY NEW CODE. Use Scene.RegionInfo.RegionSize[XYZ] as a region might not
+ // be the legacy region size.
public const uint RegionSize = 256;
public const uint RegionHeight = 4096;
- public const byte TerrainPatchSize = 16;
+ // This could be a parameters but, really, a region of greater than this is pretty unmanageable
+ public const uint MaximumRegionSize = 8192;
+
+ // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum
+ public const int MinRegionSize = 16;
+ public const int TerrainPatchSize = 16;
+
public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
public enum EstateAccessCodex : uint
diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs
new file mode 100644
index 0000000..4995a92
--- /dev/null
+++ b/OpenSim/Framework/DAMap.cs
@@ -0,0 +1,328 @@
+/*
+ * 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.Text;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+using log4net;
+using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+
+namespace OpenSim.Framework
+{
+ ///
+ /// This class stores and retrieves dynamic attributes.
+ ///
+ ///
+ /// Modules that want to use dynamic attributes need to do so in a private data store
+ /// which is accessed using a unique name. DAMap provides access to the data stores,
+ /// each of which is an OSDMap. Modules are free to store any type of data they want
+ /// within their data store. However, avoid storing large amounts of data because that
+ /// would slow down database access.
+ ///
+ public class DAMap : IXmlSerializable
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ private static readonly int MIN_NAMESPACE_LENGTH = 4;
+
+ private OSDMap m_map = new OSDMap();
+
+ // WARNING: this is temporary for experimentation only, it will be removed!!!!
+ public OSDMap TopLevelMap
+ {
+ get { return m_map; }
+ set { m_map = value; }
+ }
+
+ public XmlSchema GetSchema() { return null; }
+
+ public static DAMap FromXml(string rawXml)
+ {
+ DAMap map = new DAMap();
+ map.ReadXml(rawXml);
+ return map;
+ }
+
+ public void ReadXml(XmlReader reader)
+ {
+ ReadXml(reader.ReadInnerXml());
+ }
+
+ public void ReadXml(string rawXml)
+ {
+ // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
+
+ lock (this)
+ {
+ m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
+ SanitiseMap(this);
+ }
+ }
+
+ public void WriteXml(XmlWriter writer)
+ {
+ writer.WriteRaw(ToXml());
+ }
+
+ public string ToXml()
+ {
+ lock (this)
+ return OSDParser.SerializeLLSDXmlString(m_map);
+ }
+
+ public void CopyFrom(DAMap other)
+ {
+ // Deep copy
+
+ string data = null;
+ lock (other)
+ {
+ if (other.CountNamespaces > 0)
+ {
+ data = OSDParser.SerializeLLSDXmlString(other.m_map);
+ }
+ }
+
+ lock (this)
+ {
+ if (data == null)
+ Clear();
+ else
+ m_map = (OSDMap)OSDParser.DeserializeLLSDXml(data);
+ }
+ }
+
+ ///
+ /// Sanitise the map to remove any namespaces or stores that are not OSDMap.
+ ///
+ ///
+ ///
+ public static void SanitiseMap(DAMap daMap)
+ {
+ List keysToRemove = null;
+
+ OSDMap namespacesMap = daMap.m_map;
+
+ foreach (string key in namespacesMap.Keys)
+ {
+// Console.WriteLine("Processing ns {0}", key);
+ if (!(namespacesMap[key] is OSDMap))
+ {
+ if (keysToRemove == null)
+ keysToRemove = new List();
+
+ keysToRemove.Add(key);
+ }
+ }
+
+ if (keysToRemove != null)
+ {
+ foreach (string key in keysToRemove)
+ {
+// Console.WriteLine ("Removing bad ns {0}", key);
+ namespacesMap.Remove(key);
+ }
+ }
+
+ foreach (OSD nsOsd in namespacesMap.Values)
+ {
+ OSDMap nsOsdMap = (OSDMap)nsOsd;
+ keysToRemove = null;
+
+ foreach (string key in nsOsdMap.Keys)
+ {
+ if (!(nsOsdMap[key] is OSDMap))
+ {
+ if (keysToRemove == null)
+ keysToRemove = new List();
+
+ keysToRemove.Add(key);
+ }
+ }
+
+ if (keysToRemove != null)
+ foreach (string key in keysToRemove)
+ nsOsdMap.Remove(key);
+ }
+ }
+
+ ///
+ /// Get the number of namespaces
+ ///
+ public int CountNamespaces { get { lock (this) { return m_map.Count; } } }
+
+ ///
+ /// Get the number of stores.
+ ///
+ public int CountStores
+ {
+ get
+ {
+ int count = 0;
+
+ lock (this)
+ {
+ foreach (OSD osdNamespace in m_map)
+ {
+ count += ((OSDMap)osdNamespace).Count;
+ }
+ }
+
+ return count;
+ }
+ }
+
+ ///
+ /// Retrieve a Dynamic Attribute store
+ ///
+ /// namespace for the store - use "OpenSim" for in-core modules
+ /// name of the store within the namespace
+ /// an OSDMap representing the stored data, or null if not found
+ public OSDMap GetStore(string ns, string storeName)
+ {
+ OSD namespaceOsd;
+
+ lock (this)
+ {
+ if (m_map.TryGetValue(ns, out namespaceOsd))
+ {
+ OSD store;
+
+ if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store))
+ return (OSDMap)store;
+ }
+ }
+
+ return null;
+ }
+
+ ///
+ /// Saves a Dynamic attribute store
+ ///
+ /// namespace for the store - use "OpenSim" for in-core modules
+ /// name of the store within the namespace
+ /// an OSDMap representing the data to store
+ public void SetStore(string ns, string storeName, OSDMap store)
+ {
+ ValidateNamespace(ns);
+ OSDMap nsMap;
+
+ lock (this)
+ {
+ if (!m_map.ContainsKey(ns))
+ {
+ nsMap = new OSDMap();
+ m_map[ns] = nsMap;
+ }
+
+ nsMap = (OSDMap)m_map[ns];
+
+// m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName);
+ nsMap[storeName] = store;
+ }
+ }
+
+ ///
+ /// Validate the key used for storing separate data stores.
+ ///
+ ///
+ public static void ValidateNamespace(string ns)
+ {
+ if (ns.Length < MIN_NAMESPACE_LENGTH)
+ throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH);
+ }
+
+ public bool ContainsStore(string ns, string storeName)
+ {
+ OSD namespaceOsd;
+
+ lock (this)
+ {
+ if (m_map.TryGetValue(ns, out namespaceOsd))
+ {
+ return ((OSDMap)namespaceOsd).ContainsKey(storeName);
+ }
+ }
+
+ return false;
+ }
+
+ public bool TryGetStore(string ns, string storeName, out OSDMap store)
+ {
+ OSD namespaceOsd;
+
+ lock (this)
+ {
+ if (m_map.TryGetValue(ns, out namespaceOsd))
+ {
+ OSD storeOsd;
+
+ bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd);
+ store = (OSDMap)storeOsd;
+
+ return result;
+ }
+ }
+
+ store = null;
+ return false;
+ }
+
+ public void Clear()
+ {
+ lock (this)
+ m_map.Clear();
+ }
+
+ public bool RemoveStore(string ns, string storeName)
+ {
+ OSD namespaceOsd;
+
+ lock (this)
+ {
+ if (m_map.TryGetValue(ns, out namespaceOsd))
+ {
+ OSDMap namespaceOsdMap = (OSDMap)namespaceOsd;
+ namespaceOsdMap.Remove(storeName);
+
+ // Don't keep empty namespaces around
+ if (namespaceOsdMap.Count <= 0)
+ m_map.Remove(ns);
+ }
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs
new file mode 100644
index 0000000..f5b650b
--- /dev/null
+++ b/OpenSim/Framework/DOMap.cs
@@ -0,0 +1,98 @@
+/*
+ * 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.Text;
+using System.Xml;
+using System.Xml.Schema;
+using System.Xml.Serialization;
+using OpenMetaverse;
+using OpenMetaverse.StructuredData;
+
+namespace OpenSim.Framework
+{
+ ///
+ /// This class stores and retrieves dynamic objects.
+ ///
+ ///
+ /// Experimental - DO NOT USE. Does not yet have namespace support.
+ ///
+ public class DOMap
+ {
+ private IDictionary m_map;
+
+ public void Add(string ns, string objName, object dynObj)
+ {
+ DAMap.ValidateNamespace(ns);
+
+ lock (this)
+ {
+ if (m_map == null)
+ m_map = new Dictionary();
+
+ m_map.Add(objName, dynObj);
+ }
+ }
+
+ public bool ContainsKey(string key)
+ {
+ return Get(key) != null;
+ }
+
+ ///
+ /// Get a dynamic object
+ ///
+ ///
+ /// Not providing an index method so that users can't casually overwrite each other's objects.
+ ///
+ ///
+ public object Get(string key)
+ {
+ lock (this)
+ {
+ if (m_map == null)
+ return null;
+ else
+ return m_map[key];
+ }
+ }
+
+ public bool Remove(string key)
+ {
+ lock (this)
+ {
+ if (m_map == null)
+ return false;
+ else
+ return m_map.Remove(key);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/EstateBan.cs b/OpenSim/Framework/EstateBan.cs
index de9ebf6..ebed794 100644
--- a/OpenSim/Framework/EstateBan.cs
+++ b/OpenSim/Framework/EstateBan.cs
@@ -25,6 +25,10 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+
using OpenMetaverse;
namespace OpenSim.Framework
@@ -111,5 +115,50 @@ namespace OpenSim.Framework
}
}
+ public EstateBan() { }
+
+ public Dictionary ToMap()
+ {
+ Dictionary map = new Dictionary();
+ PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ foreach (PropertyInfo p in properties)
+ map[p.Name] = p.GetValue(this, null);
+
+ return map;
+ }
+
+ public EstateBan(Dictionary map)
+ {
+ foreach (KeyValuePair kvp in map)
+ {
+ PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance);
+ if (p == null)
+ continue;
+ object value = p.GetValue(this, null);
+ if (value is String)
+ p.SetValue(this, map[p.Name], null);
+ else if (value is UInt32)
+ p.SetValue(this, UInt32.Parse((string)map[p.Name]), null);
+ else if (value is Boolean)
+ p.SetValue(this, Boolean.Parse((string)map[p.Name]), null);
+ else if (value is UUID)
+ p.SetValue(this, UUID.Parse((string)map[p.Name]), null);
+ }
+ }
+
+
+ ///
+ /// For debugging
+ ///
+ ///
+ public override string ToString()
+ {
+ Dictionary map = ToMap();
+ string result = string.Empty;
+ foreach (KeyValuePair kvp in map)
+ result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value, Environment.NewLine);
+
+ return result;
+ }
}
}
diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs
index a92abbf..4df7860 100644
--- a/OpenSim/Framework/EstateSettings.cs
+++ b/OpenSim/Framework/EstateSettings.cs
@@ -28,6 +28,7 @@
using System;
using System.Collections.Generic;
using System.IO;
+using System.Reflection;
using OpenMetaverse;
namespace OpenSim.Framework
@@ -58,6 +59,30 @@ namespace OpenSim.Framework
set { m_EstateName = value; }
}
+ private bool m_AllowLandmark = true;
+
+ public bool AllowLandmark
+ {
+ get { return m_AllowLandmark; }
+ set { m_AllowLandmark = value; }
+ }
+
+ private bool m_AllowParcelChanges = true;
+
+ public bool AllowParcelChanges
+ {
+ get { return m_AllowParcelChanges; }
+ set { m_AllowParcelChanges = value; }
+ }
+
+ private bool m_AllowSetHome = true;
+
+ public bool AllowSetHome
+ {
+ get { return m_AllowSetHome; }
+ set { m_AllowSetHome = value; }
+ }
+
private uint m_ParentEstateID = 1;
public uint ParentEstateID
@@ -374,10 +399,132 @@ namespace OpenSim.Framework
return l_EstateAccess.Contains(user);
}
+ public void SetFromFlags(ulong regionFlags)
+ {
+ ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport);
+ BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell);
+ AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark);
+ AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges);
+ AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome);
+ }
+
public bool GroupAccess(UUID groupID)
{
return l_EstateGroups.Contains(groupID);
}
+ public Dictionary ToMap()
+ {
+ Dictionary map = new Dictionary();
+ PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
+ foreach (PropertyInfo p in properties)
+ {
+ // EstateBans is a complex type, let's treat it as special
+ if (p.Name == "EstateBans")
+ continue;
+
+ object value = p.GetValue(this, null);
+ if (value != null)
+ {
+ if (p.PropertyType.IsArray) // of UUIDs
+ {
+ if (((Array)value).Length > 0)
+ {
+ string[] args = new string[((Array)value).Length];
+ int index = 0;
+ foreach (object o in (Array)value)
+ args[index++] = o.ToString();
+ map[p.Name] = String.Join(",", args);
+ }
+ }
+ else // simple types
+ map[p.Name] = value;
+ }
+ }
+
+ // EstateBans are special
+ if (EstateBans.Length > 0)
+ {
+ Dictionary bans = new Dictionary();
+ int i = 0;
+ foreach (EstateBan ban in EstateBans)
+ bans["ban" + i++] = ban.ToMap();
+ map["EstateBans"] = bans;
+ }
+
+ return map;
+ }
+
+ ///
+ /// For debugging
+ ///
+ ///
+ public override string ToString()
+ {
+ Dictionary map = ToMap();
+ String result = String.Empty;
+
+ foreach (KeyValuePair kvp in map)
+ {
+ if (kvp.Key == "EstateBans")
+ {
+ result += "EstateBans:" + Environment.NewLine;
+ foreach (KeyValuePair ban in (Dictionary)kvp.Value)
+ result += ban.Value.ToString();
+ }
+ else
+ result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value.ToString(), Environment.NewLine);
+ }
+
+ return result;
+ }
+
+ public EstateSettings(Dictionary map)
+ {
+ foreach (KeyValuePair kvp in map)
+ {
+ PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance);
+ if (p == null)
+ continue;
+
+ // EstateBans is a complex type, let's treat it as special
+ if (p.Name == "EstateBans")
+ continue;
+
+ if (p.PropertyType.IsArray)
+ {
+ string[] elements = ((string)map[p.Name]).Split(new char[] { ',' });
+ UUID[] uuids = new UUID[elements.Length];
+ int i = 0;
+ foreach (string e in elements)
+ uuids[i++] = new UUID(e);
+ p.SetValue(this, uuids, null);
+ }
+ else
+ {
+ object value = p.GetValue(this, null);
+ if (value is String)
+ p.SetValue(this, map[p.Name], null);
+ else if (value is UInt32)
+ p.SetValue(this, UInt32.Parse((string)map[p.Name]), null);
+ else if (value is Boolean)
+ p.SetValue(this, Boolean.Parse((string)map[p.Name]), null);
+ else if (value is UUID)
+ p.SetValue(this, UUID.Parse((string)map[p.Name]), null);
+ }
+ }
+
+ // EstateBans are special
+ if (map.ContainsKey("EstateBans"))
+ {
+ var banData = ((Dictionary)map["EstateBans"]).Values;
+ EstateBan[] bans = new EstateBan[banData.Count];
+ int b = 0;
+ foreach (Dictionary ban in banData)
+ bans[b++] = new EstateBan(ban);
+ PropertyInfo bansProperty = this.GetType().GetProperty("EstateBans", BindingFlags.Public | BindingFlags.Instance);
+ bansProperty.SetValue(this, bans, null);
+ }
+ }
}
}
diff --git a/OpenSim/Framework/ExtraPhysicsData.cs b/OpenSim/Framework/ExtraPhysicsData.cs
new file mode 100644
index 0000000..9e7334f
--- /dev/null
+++ b/OpenSim/Framework/ExtraPhysicsData.cs
@@ -0,0 +1,50 @@
+/*
+ * 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 OpenMetaverse;
+
+namespace OpenSim.Framework
+{
+ public enum PhysShapeType : byte
+ {
+ prim = 0,
+ none = 1,
+ convex = 2,
+
+ invalid = 255 // use to mark invalid data in ExtraPhysicsData
+ }
+
+ public struct ExtraPhysicsData
+ {
+ public float Density;
+ public float GravitationModifier;
+ public float Friction;
+ public float Bounce;
+ public PhysShapeType PhysShapeType;
+
+ }
+}
diff --git a/OpenSim/Framework/ForeignUserProfileData.cs b/OpenSim/Framework/ForeignUserProfileData.cs
deleted file mode 100644
index 2beaf80..0000000
--- a/OpenSim/Framework/ForeignUserProfileData.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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;
-
-namespace OpenSim.Framework
-{
- public class ForeignUserProfileData : UserProfileData
- {
- ///
- /// The address of the users home sim, used for foreigners.
- ///
- private string _userUserServerURI = String.Empty;
-
- ///
- /// The address of the users home sim, used for foreigners.
- ///
- private string _userHomeAddress = String.Empty;
-
- ///
- /// The port of the users home sim, used for foreigners.
- ///
- private string _userHomePort = String.Empty;
- ///
- /// The remoting port of the users home sim, used for foreigners.
- ///
- private string _userHomeRemotingPort = String.Empty;
-
- public string UserServerURI
- {
- get { return _userUserServerURI; }
- set { _userUserServerURI = value; }
- }
-
- public string UserHomeAddress
- {
- get { return _userHomeAddress; }
- set { _userHomeAddress = value; }
- }
-
- public string UserHomePort
- {
- get { return _userHomePort; }
- set { _userHomePort = value; }
- }
-
- public string UserHomeRemotingPort
- {
- get { return _userHomeRemotingPort; }
- set { _userHomeRemotingPort = value; }
- }
- }
-}
diff --git a/OpenSim/Framework/GridInstantMessage.cs b/OpenSim/Framework/GridInstantMessage.cs
index 6ae0488..da3690c 100644
--- a/OpenSim/Framework/GridInstantMessage.cs
+++ b/OpenSim/Framework/GridInstantMessage.cs
@@ -53,6 +53,24 @@ namespace OpenSim.Framework
binaryBucket = new byte[0];
}
+ public GridInstantMessage(GridInstantMessage im, bool addTimestamp)
+ {
+ fromAgentID = im.fromAgentID;
+ fromAgentName = im.fromAgentName;
+ toAgentID = im.toAgentID;
+ dialog = im.dialog;
+ fromGroup = im.fromGroup;
+ message = im.message;
+ imSessionID = im.imSessionID;
+ offline = im.offline;
+ Position = im.Position;
+ binaryBucket = im.binaryBucket;
+ RegionID = im.RegionID;
+
+ if (addTimestamp)
+ timestamp = (uint)Util.UnixTimeSinceEpoch();
+ }
+
public GridInstantMessage(IScene scene, UUID _fromAgentID,
string _fromAgentName, UUID _toAgentID,
byte _dialog, bool _fromGroup, string _message,
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index 87433cc..e36edb2 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -64,7 +64,9 @@ namespace OpenSim.Framework
public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes);
- public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams);
+ public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List cachedTextureRequest);
+
+ public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems);
public delegate void StartAnim(IClientAPI remoteClient, UUID animID);
@@ -124,7 +126,7 @@ namespace OpenSim.Framework
public delegate void ObjectDrop(uint localID, IClientAPI remoteClient);
public delegate void UpdatePrimFlags(
- uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient);
+ uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient);
public delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient);
@@ -313,7 +315,7 @@ namespace OpenSim.Framework
public delegate void ObjectPermissions(
IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set);
- public delegate void EconomyDataRequest(UUID agentID);
+ public delegate void EconomyDataRequest(IClientAPI client);
public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID);
@@ -780,6 +782,7 @@ namespace OpenSim.Framework
event EstateChangeInfo OnEstateChangeInfo;
event EstateManageTelehub OnEstateManageTelehub;
// [Obsolete("LLClientView Specific.")]
+ event CachedTextureRequest OnCachedTextureRequest;
event SetAppearance OnSetAppearance;
// [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")]
event AvatarNowWearing OnAvatarNowWearing;
@@ -822,6 +825,8 @@ namespace OpenSim.Framework
///
event UpdateAgent OnAgentUpdate;
+ event UpdateAgent OnAgentCameraUpdate;
+
event AgentRequestSit OnAgentRequestSit;
event AgentSit OnAgentSit;
event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1087,14 +1092,15 @@ namespace OpenSim.Framework
///
void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry);
+ void SendCachedTextureResponse(ISceneEntity avatar, int serial, List cachedTextures);
+
void SendStartPingCheck(byte seq);
///
/// Tell the client that an object has been deleted
///
- ///
///
- void SendKillObject(ulong regionHandle, List localID);
+ void SendKillObject(List localID);
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
@@ -1116,8 +1122,8 @@ namespace OpenSim.Framework
void SendInstantMessage(GridInstantMessage im);
- void SendGenericMessage(string method, List message);
- void SendGenericMessage(string method, List message);
+ void SendGenericMessage(string method, UUID invoice, List message);
+ void SendGenericMessage(string method, UUID invoice, List message);
void SendLayerData(float[] map);
void SendLayerData(int px, int py, float[] map);
@@ -1155,7 +1161,8 @@ namespace OpenSim.Framework
void SendTeleportStart(uint flags);
void SendTeleportProgress(uint flags, string message);
- void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance);
+ void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item);
+
void SendPayPrice(UUID objectID, int[] payPrice);
void SendCoarseLocationUpdate(List users, List CoarseLocations);
@@ -1250,8 +1257,6 @@ namespace OpenSim.Framework
void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch,
string[] buttonlabels);
- bool AddMoney(int debit);
-
///
/// Update the client as to where the sun is currently located.
///
@@ -1356,6 +1361,8 @@ namespace OpenSim.Framework
void SendObjectPropertiesReply(ISceneEntity Entity);
+ void SendPartPhysicsProprieties(ISceneEntity Entity);
+
void SendAgentOffline(UUID[] agentIDs);
void SendAgentOnline(UUID[] agentIDs);
@@ -1469,7 +1476,7 @@ namespace OpenSim.Framework
void SendChangeUserRights(UUID agentID, UUID friendID, int rights);
void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId);
- void StopFlying(ISceneEntity presence);
+ void SendAgentTerseUpdate(ISceneEntity presence);
void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
}
diff --git a/OpenSim/Framework/ICommandConsole.cs b/OpenSim/Framework/ICommandConsole.cs
index a6573f8..3db2765 100644
--- a/OpenSim/Framework/ICommandConsole.cs
+++ b/OpenSim/Framework/ICommandConsole.cs
@@ -67,9 +67,16 @@ namespace OpenSim.Framework
string help, string longhelp, string descriptivehelp,
CommandDelegate fn);
- string[] FindNextOption(string[] cmd, bool term);
+ ///
+ /// Has the given command already been registered?
+ ///
+ ///
+ /// Command.
+ bool HasCommand(string command);
+
+ string[] FindNextOption(string[] command, bool term);
- string[] Resolve(string[] cmd);
+ string[] Resolve(string[] command);
XmlElement GetXml(XmlDocument doc);
}
diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IImprovedAssetCache.cs
index 251215a..a853e90 100644
--- a/OpenSim/Framework/IImprovedAssetCache.cs
+++ b/OpenSim/Framework/IImprovedAssetCache.cs
@@ -31,9 +31,34 @@ namespace OpenSim.Framework
{
public interface IImprovedAssetCache
{
+ ///
+ /// Cache the specified asset.
+ ///
+ ///
void Cache(AssetBase asset);
+
+ ///
+ /// Get an asset by its id.
+ ///
+ ///
+ /// null if the asset does not exist.
AssetBase Get(string id);
+
+ ///
+ /// Check whether an asset with the specified id exists in the cache.
+ ///
+ ///
+ bool Check(string id);
+
+ ///
+ /// Expire an asset from the cache.
+ ///
+ ///
void Expire(string id);
+
+ ///
+ /// Clear the cache.
+ ///
void Clear();
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/ILandChannel.cs b/OpenSim/Framework/ILandChannel.cs
index 869d4c8..c46c03c 100644
--- a/OpenSim/Framework/ILandChannel.cs
+++ b/OpenSim/Framework/ILandChannel.cs
@@ -56,6 +56,13 @@ namespace OpenSim.Region.Framework.Interfaces
ILandObject GetLandObject(float x, float y);
///
+ /// Get the parcel at the specified point
+ ///
+ /// Vector where x and y components are between 0 and 256. z component is ignored.
+ /// Land object at the point supplied
+ ILandObject GetLandObject(Vector3 position);
+
+ ///
/// Get the parcels near the specified point
///
///
diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs
index 4f98d7b..8465c86 100644
--- a/OpenSim/Framework/ILandObject.cs
+++ b/OpenSim/Framework/ILandObject.cs
@@ -38,6 +38,7 @@ namespace OpenSim.Framework
int GetParcelMaxPrimCount();
int GetSimulatorMaxPrimCount();
int GetPrimsFree();
+ Dictionary GetLandObjectOwners();
LandData LandData { get; set; }
bool[,] LandBitmap { get; set; }
@@ -70,6 +71,7 @@ namespace OpenSim.Framework
void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client);
bool IsEitherBannedOrRestricted(UUID avatar);
bool IsBannedFromLand(UUID avatar);
+ bool CanBeOnThisLand(UUID avatar, float posHeight);
bool IsRestrictedFromLand(UUID avatar);
bool IsInLandAccessList(UUID avatar);
void SendLandUpdateToClient(IClientAPI remote_client);
diff --git a/OpenSim/Framework/IMoneyModule.cs b/OpenSim/Framework/IMoneyModule.cs
index 1e09728..52f3e83 100644
--- a/OpenSim/Framework/IMoneyModule.cs
+++ b/OpenSim/Framework/IMoneyModule.cs
@@ -38,7 +38,8 @@ namespace OpenSim.Framework
int GetBalance(UUID agentID);
bool UploadCovered(UUID agentID, int amount);
bool AmountCovered(UUID agentID, int amount);
- void ApplyCharge(UUID agentID, int amount, string text);
+ void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type);
+ void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData);
void ApplyUploadCharge(UUID agentID, int amount, string text);
int UploadCharge { get; }
diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs
new file mode 100644
index 0000000..8d274d0
--- /dev/null
+++ b/OpenSim/Framework/IPeople.cs
@@ -0,0 +1,49 @@
+/*
+ * 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 OpenMetaverse;
+
+namespace OpenSim.Framework
+{
+ public class UserData
+ {
+ public UUID Id { get; set; }
+ public string FirstName { get; set; }
+ public string LastName { get; set; }
+ public string HomeURL { get; set; }
+ public Dictionary ServerURLs { get; set; }
+ public bool IsUnknownUser { get; set; }
+ public bool HasGridUserTried { get; set; }
+ }
+
+ public interface IPeople
+ {
+ List GetUserData(string query, int page_size, int page_number);
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/IRegionLoader.cs b/OpenSim/Framework/IRegionLoader.cs
deleted file mode 100644
index c566fc7..0000000
--- a/OpenSim/Framework/IRegionLoader.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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 Nini.Config;
-
-namespace OpenSim.Framework
-{
- public interface IRegionLoader
- {
- void SetIniConfigSource(IConfigSource configSource);
- RegionInfo[] LoadRegions();
- }
-}
\ No newline at end of file
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index 87ec99e..e1b6d1e 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -86,24 +86,26 @@ namespace OpenSim.Framework
event restart OnRestart;
///
- /// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent
+ /// Add a new agent with an attached client. All agents except initial login clients will starts off as a child agent
/// - the later agent crossing will promote it to a root agent.
///
///
/// The type of agent to add.
///
/// The scene agent if the new client was added or if an agent that already existed.
- ISceneAgent AddNewClient(IClientAPI client, PresenceType type);
+ ISceneAgent AddNewAgent(IClientAPI client, PresenceType type);
///
- /// Remove the given client from the scene.
+ /// Tell a single agent to disconnect from the region.
///
///
- /// Close the neighbour child agents associated with this client.
- void RemoveClient(UUID agentID, bool closeChildAgents);
+ ///
+ /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
+ /// force unless you are absolutely sure that the agent is dead and a normal close is not working.
+ ///
+ bool CloseAgent(UUID agentID, bool force);
void Restart();
- //RegionInfo OtherRegionUp(RegionInfo thisRegion);
string GetSimulatorVersion();
@@ -136,5 +138,10 @@ namespace OpenSim.Framework
ISceneObject DeserializeObject(string representation);
bool CheckClient(UUID agentID, System.Net.IPEndPoint ep);
+
+ ///
+ /// Start the scene and associated scripts within it.
+ ///
+ void Start();
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/ISceneAgent.cs b/OpenSim/Framework/ISceneAgent.cs
index 563d906..ca1399c 100644
--- a/OpenSim/Framework/ISceneAgent.cs
+++ b/OpenSim/Framework/ISceneAgent.cs
@@ -66,12 +66,17 @@ namespace OpenSim.Framework
AvatarAppearance Appearance { get; set; }
///
+ /// Set if initial data about the scene (avatars, objects) has been sent to the client.
+ ///
+ bool SentInitialDataToClient { get; }
+
+ ///
/// Send initial scene data to the client controlling this agent
///
///
/// This includes scene object data and the appearance data of other avatars.
///
- void SendInitialDataToMe();
+ void SendInitialDataToClient();
///
/// Direction in which the scene presence is looking.
diff --git a/OpenSim/Framework/ISceneObject.cs b/OpenSim/Framework/ISceneObject.cs
index afac9b8..754b77b 100644
--- a/OpenSim/Framework/ISceneObject.cs
+++ b/OpenSim/Framework/ISceneObject.cs
@@ -32,6 +32,8 @@ namespace OpenSim.Framework
{
public interface ISceneObject
{
+ string Name { get; }
+
UUID UUID { get; }
///
diff --git a/OpenSim/Framework/InventoryCollection.cs b/OpenSim/Framework/InventoryCollection.cs
index 7049902..59655eb 100644
--- a/OpenSim/Framework/InventoryCollection.cs
+++ b/OpenSim/Framework/InventoryCollection.cs
@@ -37,6 +37,8 @@ namespace OpenSim.Framework
{
public List Folders;
public List Items;
- public UUID UserID;
+ public UUID OwnerID;
+ public UUID FolderID;
+ public int Version;
}
}
diff --git a/OpenSim/Framework/InventoryFolderBase.cs b/OpenSim/Framework/InventoryFolderBase.cs
index b3457a6..fb66056 100644
--- a/OpenSim/Framework/InventoryFolderBase.cs
+++ b/OpenSim/Framework/InventoryFolderBase.cs
@@ -34,6 +34,9 @@ namespace OpenSim.Framework
///
public class InventoryFolderBase : InventoryNodeBase
{
+ public static readonly string ROOT_FOLDER_NAME = "My Inventory";
+ public static readonly string SUITCASE_FOLDER_NAME = "My Suitcase";
+
///
/// The folder this folder is contained in
///
diff --git a/OpenSim/Framework/InventoryItemBase.cs b/OpenSim/Framework/InventoryItemBase.cs
index 3d45e76..f9fd752 100644
--- a/OpenSim/Framework/InventoryItemBase.cs
+++ b/OpenSim/Framework/InventoryItemBase.cs
@@ -34,7 +34,7 @@ namespace OpenSim.Framework
/// Inventory Item - contains all the properties associated with an individual inventory piece.
///
public class InventoryItemBase : InventoryNodeBase, ICloneable
- {
+ {
///
/// The inventory type of the item. This is slightly different from the asset type in some situations.
///
@@ -82,12 +82,15 @@ namespace OpenSim.Framework
set
{
m_creatorId = value;
+
+ if ((m_creatorId == null) || !UUID.TryParse(m_creatorId, out m_creatorIdAsUuid))
+ m_creatorIdAsUuid = UUID.Zero;
}
}
protected string m_creatorId;
///
- /// The CreatorId expressed as a UUID.tely
+ /// The CreatorId expressed as a UUID.
///
public UUID CreatorIdAsUuid
{
@@ -122,7 +125,7 @@ namespace OpenSim.Framework
{
get
{
- if (m_creatorData != null && m_creatorData != string.Empty)
+ if (!string.IsNullOrEmpty(m_creatorData))
return m_creatorId + ';' + m_creatorData;
else
return m_creatorId;
diff --git a/OpenSim/Framework/Location.cs b/OpenSim/Framework/Location.cs
index 9504e03..0b88834 100644
--- a/OpenSim/Framework/Location.cs
+++ b/OpenSim/Framework/Location.cs
@@ -33,10 +33,10 @@ namespace OpenSim.Framework
[Serializable]
public class Location : ICloneable
{
- private readonly int m_x;
- private readonly int m_y;
+ private readonly uint m_x;
+ private readonly uint m_y;
- public Location(int x, int y)
+ public Location(uint x, uint y)
{
m_x = x;
m_y = y;
@@ -44,21 +44,21 @@ namespace OpenSim.Framework
public Location(ulong regionHandle)
{
- m_x = (int) regionHandle;
- m_y = (int) (regionHandle >> 32);
+ m_x = (uint)(regionHandle >> 32);
+ m_y = (uint)(regionHandle & (ulong)uint.MaxValue);
}
public ulong RegionHandle
{
- get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); }
+ get { return Utils.UIntsToLong(m_x, m_y); }
}
- public int X
+ public uint X
{
get { return m_x; }
}
- public int Y
+ public uint Y
{
get { return m_y; }
}
diff --git a/OpenSim/Framework/LogWriter.cs b/OpenSim/Framework/LogWriter.cs
new file mode 100755
index 0000000..2e0bf4a
--- /dev/null
+++ b/OpenSim/Framework/LogWriter.cs
@@ -0,0 +1,181 @@
+/*
+ * 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.IO;
+using System.Text;
+using log4net;
+
+namespace OpenSim.Framework
+{
+ ///
+ /// Class for writing a high performance, high volume log file.
+ /// Sometimes, to debug, one has a high volume logging to do and the regular
+ /// log file output is not appropriate.
+ /// Create a new instance with the parameters needed and
+ /// call Write() to output a line. Call Close() when finished.
+ /// If created with no parameters, it will not log anything.
+ ///
+ public class LogWriter : IDisposable
+ {
+ public bool Enabled { get; private set; }
+
+ private string m_logDirectory = ".";
+ private int m_logMaxFileTimeMin = 5; // 5 minutes
+ public String LogFileHeader { get; set; }
+
+ private StreamWriter m_logFile = null;
+ private TimeSpan m_logFileLife;
+ private DateTime m_logFileEndTime;
+ private Object m_logFileWriteLock = new Object();
+ private bool m_flushWrite;
+
+ // set externally when debugging. If let 'null', this does not write any error messages.
+ public ILog ErrorLogger = null;
+ private string LogHeader = "[LOG WRITER]";
+
+ ///
+ /// Create a log writer that will not write anything. Good for when not enabled
+ /// but the write statements are still in the code.
+ ///
+ public LogWriter()
+ {
+ Enabled = false;
+ m_logFile = null;
+ }
+
+ ///
+ /// Create a log writer instance.
+ ///
+ /// The directory to create the log file in. May be 'null' for default.
+ /// The characters that begin the log file name. May be 'null' for default.
+ /// Maximum age of a log file in minutes. If zero, will set default.
+ /// Whether to do a flush after every log write. Best left off but
+ /// if one is looking for a crash, this is a good thing to turn on.
+ public LogWriter(string dir, string headr, int maxFileTime, bool flushWrite)
+ {
+ m_logDirectory = dir == null ? "." : dir;
+
+ LogFileHeader = headr == null ? "log-" : headr;
+
+ m_logMaxFileTimeMin = maxFileTime;
+ if (m_logMaxFileTimeMin < 1)
+ m_logMaxFileTimeMin = 5;
+
+ m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
+ m_logFileEndTime = DateTime.Now + m_logFileLife;
+
+ m_flushWrite = flushWrite;
+
+ Enabled = true;
+ }
+ // Constructor that assumes flushWrite is off.
+ public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false)
+ {
+ }
+
+ public void Dispose()
+ {
+ this.Close();
+ }
+
+ public void Close()
+ {
+ Enabled = false;
+ if (m_logFile != null)
+ {
+ m_logFile.Close();
+ m_logFile.Dispose();
+ m_logFile = null;
+ }
+ }
+
+ public void Write(string line, params object[] args)
+ {
+ if (!Enabled) return;
+ Write(String.Format(line, args));
+ }
+
+ public void Flush()
+ {
+ if (!Enabled) return;
+ if (m_logFile != null)
+ {
+ m_logFile.Flush();
+ }
+ }
+
+ public void Write(string line)
+ {
+ if (!Enabled) return;
+ try
+ {
+ lock (m_logFileWriteLock)
+ {
+ DateTime now = DateTime.UtcNow;
+ if (m_logFile == null || now > m_logFileEndTime)
+ {
+ if (m_logFile != null)
+ {
+ m_logFile.Close();
+ m_logFile.Dispose();
+ m_logFile = null;
+ }
+
+ // First log file or time has expired, start writing to a new log file
+ m_logFileEndTime = now + m_logFileLife;
+ string path = (m_logDirectory.Length > 0 ? m_logDirectory
+ + System.IO.Path.DirectorySeparatorChar.ToString() : "")
+ + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
+ m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite));
+ }
+ if (m_logFile != null)
+ {
+ StringBuilder buff = new StringBuilder(line.Length + 25);
+ buff.Append(now.ToString("yyyyMMddHHmmssfff"));
+ // buff.Append(now.ToString("yyyyMMddHHmmss"));
+ buff.Append(",");
+ buff.Append(line);
+ buff.Append("\r\n");
+ m_logFile.Write(buff.ToString());
+ if (m_flushWrite)
+ m_logFile.Flush();
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ if (ErrorLogger != null)
+ {
+ ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
+ }
+ Enabled = false;
+ }
+ return;
+ }
+ }
+}
diff --git a/OpenSim/Framework/MapBlockData.cs b/OpenSim/Framework/MapBlockData.cs
index 2298ac5..4bee499 100644
--- a/OpenSim/Framework/MapBlockData.cs
+++ b/OpenSim/Framework/MapBlockData.cs
@@ -27,6 +27,7 @@
using System;
using OpenMetaverse;
+using OpenMetaverse.StructuredData;
namespace OpenSim.Framework
{
@@ -40,9 +41,26 @@ namespace OpenSim.Framework
public byte WaterHeight;
public ushort X;
public ushort Y;
+ public ushort SizeX;
+ public ushort SizeY;
public MapBlockData()
{
}
+
+ public OSDMap ToOSD()
+ {
+ OSDMap map = new OSDMap();
+ map["X"] = X;
+ map["Y"] = Y;
+ map["SizeX"] = SizeX;
+ map["SizeY"] = SizeY;
+ map["Name"] = Name;
+ map["Access"] = Access;
+ map["RegionFlags"] = RegionFlags;
+ map["WaterHeight"] = WaterHeight;
+ map["MapImageID"] = MapImageId;
+ return map;
+ }
}
}
diff --git a/OpenSim/Framework/MapItemReplyStruct.cs b/OpenSim/Framework/MapItemReplyStruct.cs
index 58011bd..c8693ae 100644
--- a/OpenSim/Framework/MapItemReplyStruct.cs
+++ b/OpenSim/Framework/MapItemReplyStruct.cs
@@ -26,6 +26,7 @@
*/
using OpenMetaverse;
+using OpenMetaverse.StructuredData;
namespace OpenSim.Framework
{
@@ -37,5 +38,37 @@ namespace OpenSim.Framework
public int Extra;
public int Extra2;
public string name;
+
+ public mapItemReply(uint pX, uint pY, UUID pId, string pName, int pExt1, int pExt2)
+ {
+ x = pX;
+ y = pY;
+ id = pId;
+ name = pName;
+ Extra = pExt1;
+ Extra2 = pExt2;
+ }
+
+ public OSDMap ToOSD()
+ {
+ OSDMap map = new OSDMap();
+ map["X"] = OSD.FromInteger((int)x);
+ map["Y"] = OSD.FromInteger((int)y);
+ map["ID"] = OSD.FromUUID(id);
+ map["Name"] = OSD.FromString(name);
+ map["Extra"] = OSD.FromInteger(Extra);
+ map["Extra2"] = OSD.FromInteger(Extra2);
+ return map;
+ }
+
+ public void FromOSD(OSDMap map)
+ {
+ x = (uint) map["X"].AsInteger();
+ y = (uint) map["Y"].AsInteger();
+ id = map["ID"].AsUUID();
+ Extra = map["Extra"].AsInteger();
+ Extra2 = map["Extra2"].AsInteger();
+ name = map["Name"].AsString();
+ }
}
}
diff --git a/OpenSim/Framework/MetricsCollector.cs b/OpenSim/Framework/MetricsCollector.cs
new file mode 100644
index 0000000..c8f4a33
--- /dev/null
+++ b/OpenSim/Framework/MetricsCollector.cs
@@ -0,0 +1,223 @@
+using System;
+using System.Diagnostics;
+
+namespace OpenSim.Framework
+{
+ ///
+ /// A MetricsCollector for 'long' values.
+ ///
+ public class MetricsCollectorLong : MetricsCollector
+ {
+ public MetricsCollectorLong(int windowSize, int numBuckets)
+ : base(windowSize, numBuckets)
+ {
+ }
+
+ protected override long GetZero() { return 0; }
+
+ protected override long Add(long a, long b) { return a + b; }
+ }
+
+
+ ///
+ /// A MetricsCollector for time spans.
+ ///
+ public class MetricsCollectorTime : MetricsCollectorLong
+ {
+ public MetricsCollectorTime(int windowSize, int numBuckets)
+ : base(windowSize, numBuckets)
+ {
+ }
+
+ public void AddSample(Stopwatch timer)
+ {
+ long ticks = timer.ElapsedTicks;
+ if (ticks > 0)
+ AddSample(ticks);
+ }
+
+ public TimeSpan GetSumTime()
+ {
+ return TimeSpan.FromMilliseconds((GetSum() * 1000) / Stopwatch.Frequency);
+ }
+ }
+
+
+ struct MetricsBucket
+ {
+ public T value;
+ public int count;
+ }
+
+
+ ///
+ /// Collects metrics in a sliding window.
+ ///
+ ///
+ /// MetricsCollector provides the current Sum of the metrics that it collects. It can easily be extended
+ /// to provide the Average, too. It uses a sliding window to keep these values current.
+ ///
+ /// This class is not thread-safe.
+ ///
+ /// Subclass MetricsCollector to have it use a concrete value type. Override the abstract methods.
+ ///
+ public abstract class MetricsCollector
+ {
+ private int bucketSize; // e.g. 3,000 ms
+
+ private MetricsBucket[] buckets;
+
+ private int NumBuckets { get { return buckets.Length; } }
+
+
+ // The number of the current bucket, if we had an infinite number of buckets and didn't have to wrap around
+ long curBucketGlobal;
+
+ // The total of all the buckets
+ T totalSum;
+ int totalCount;
+
+
+ ///
+ /// Returns the default (zero) value.
+ ///
+ ///
+ protected abstract T GetZero();
+
+ ///
+ /// Adds two values.
+ ///
+ protected abstract T Add(T a, T b);
+
+
+ ///
+ /// Creates a MetricsCollector.
+ ///
+ /// The period of time over which to collect the metrics, in ms. E.g.: 30,000.
+ /// The number of buckets to divide the samples into. E.g.: 10. Using more buckets
+ /// smooths the jarring that occurs whenever we drop an old bucket, but uses more memory.
+ public MetricsCollector(int windowSize, int numBuckets)
+ {
+ bucketSize = windowSize / numBuckets;
+ buckets = new MetricsBucket[numBuckets];
+ Reset();
+ }
+
+ public void Reset()
+ {
+ ZeroBuckets(0, NumBuckets);
+ curBucketGlobal = GetNow() / bucketSize;
+ totalSum = GetZero();
+ totalCount = 0;
+ }
+
+ public void AddSample(T sample)
+ {
+ MoveWindow();
+
+ int curBucket = (int)(curBucketGlobal % NumBuckets);
+ buckets[curBucket].value = Add(buckets[curBucket].value, sample);
+ buckets[curBucket].count++;
+
+ totalSum = Add(totalSum, sample);
+ totalCount++;
+ }
+
+ ///
+ /// Returns the total values in the collection window.
+ ///
+ public T GetSum()
+ {
+ // It might have been a while since we last added a sample, so we may need to adjust the window
+ MoveWindow();
+
+ return totalSum;
+ }
+
+ ///
+ /// Returns the current time in ms.
+ ///
+ private long GetNow()
+ {
+ return DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
+ }
+
+ ///
+ /// Clears the values in buckets [offset, offset+num)
+ ///
+ private void ZeroBuckets(int offset, int num)
+ {
+ for (int i = 0; i < num; i++)
+ {
+ buckets[offset + i].value = GetZero();
+ buckets[offset + i].count = 0;
+ }
+ }
+
+ ///
+ /// Adjusts the buckets so that the "current bucket" corresponds to the current time.
+ /// This may require dropping old buckets.
+ ///
+ ///
+ /// This method allows for the possibility that we don't get new samples for each bucket, so the
+ /// new bucket may be some distance away from the last used bucket.
+ ///
+ private void MoveWindow()
+ {
+ long newBucketGlobal = GetNow() / bucketSize;
+ long bucketsDistance = newBucketGlobal - curBucketGlobal;
+
+ if (bucketsDistance == 0)
+ {
+ // We're still on the same bucket as before
+ return;
+ }
+
+ if (bucketsDistance >= NumBuckets)
+ {
+ // Discard everything
+ Reset();
+ return;
+ }
+
+ int curBucket = (int)(curBucketGlobal % NumBuckets);
+ int newBucket = (int)(newBucketGlobal % NumBuckets);
+
+
+ // Clear all the buckets in this range: (cur, new]
+ int numToClear = (int)bucketsDistance;
+
+ if (curBucket < NumBuckets - 1)
+ {
+ // Clear buckets at the end of the window
+ int num = Math.Min((int)bucketsDistance, NumBuckets - (curBucket + 1));
+ ZeroBuckets(curBucket + 1, num);
+ numToClear -= num;
+ }
+
+ if (numToClear > 0)
+ {
+ // Clear buckets at the beginning of the window
+ ZeroBuckets(0, numToClear);
+ }
+
+ // Move the "current bucket" pointer
+ curBucketGlobal = newBucketGlobal;
+
+ RecalcTotal();
+ }
+
+ private void RecalcTotal()
+ {
+ totalSum = GetZero();
+ totalCount = 0;
+
+ for (int i = 0; i < NumBuckets; i++)
+ {
+ totalSum = Add(totalSum, buckets[i].value);
+ totalCount += buckets[i].count;
+ }
+ }
+
+ }
+}
diff --git a/OpenSim/Framework/Monitoring/AssetStatsCollector.cs b/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
index 2a4d45b..6a0f676 100644
--- a/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/AssetStatsCollector.cs
@@ -28,6 +28,8 @@
using System;
using System.Timers;
+using OpenMetaverse.StructuredData;
+
namespace OpenSim.Framework.Monitoring
{
///
@@ -100,5 +102,29 @@ Asset requests yesterday : {3} ({4} per hour) of which {5} were not found",
AssetRequestsToday, assetRequestsTodayPerHour, AssetRequestsNotFoundToday,
AssetRequestsYesterday, assetRequestsYesterdayPerHour, AssetRequestsNotFoundYesterday);
}
+
+ public override string XReport(string uptime, string version)
+ {
+ return OSDParser.SerializeJsonString(OReport(uptime, version));
+ }
+
+ public override OSDMap OReport(string uptime, string version)
+ {
+ double elapsedHours = (DateTime.Now - startTime).TotalHours;
+ if (elapsedHours <= 0) { elapsedHours = 1; } // prevent divide by zero
+
+ long assetRequestsTodayPerHour = (long)Math.Round(AssetRequestsToday / elapsedHours);
+ long assetRequestsYesterdayPerHour = (long)Math.Round(AssetRequestsYesterday / 24.0);
+
+ OSDMap ret = new OSDMap();
+ ret.Add("AssetRequestsToday", OSD.FromLong(AssetRequestsToday));
+ ret.Add("AssetRequestsTodayPerHour", OSD.FromLong(assetRequestsTodayPerHour));
+ ret.Add("AssetRequestsNotFoundToday", OSD.FromLong(AssetRequestsNotFoundToday));
+ ret.Add("AssetRequestsYesterday", OSD.FromLong(AssetRequestsYesterday));
+ ret.Add("AssetRequestsYesterdayPerHour", OSD.FromLong(assetRequestsYesterdayPerHour));
+ ret.Add("AssetRequestsNotFoundYesterday", OSD.FromLong(assetRequestsNotFoundYesterday));
+
+ return ret;
+ }
}
}
diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
index 2903b6e..20495f6 100644
--- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
@@ -45,16 +45,16 @@ namespace OpenSim.Framework.Monitoring
sb.Append(Environment.NewLine);
sb.AppendFormat(
- "Allocated to OpenSim objects: {0} MB\n",
+ "Heap allocated to OpenSim : {0} MB\n",
Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
sb.AppendFormat(
- "OpenSim last object memory churn : {0} MB/s\n",
- Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3));
+ "Last heap allocation rate : {0} MB/s\n",
+ Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
sb.AppendFormat(
- "OpenSim average object memory churn : {0} MB/s\n",
- Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3));
+ "Average heap allocation rate: {0} MB/s\n",
+ Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
sb.AppendFormat(
"Process memory : {0} MB\n",
@@ -67,5 +67,12 @@ namespace OpenSim.Framework.Monitoring
{
return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ;
}
+
+ public virtual OSDMap OReport(string uptime, string version)
+ {
+ OSDMap ret = new OSDMap();
+ ret.Add("TotalMemory", new OSDReal(Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)));
+ return ret;
+ }
}
}
diff --git a/OpenSim/Framework/Monitoring/Checks/Check.cs b/OpenSim/Framework/Monitoring/Checks/Check.cs
new file mode 100644
index 0000000..594386a
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Checks/Check.cs
@@ -0,0 +1,118 @@
+/*
+ * 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.Text;
+
+namespace OpenSim.Framework.Monitoring
+{
+ public class Check
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public static readonly char[] DisallowedShortNameCharacters = { '.' };
+
+ ///
+ /// Category of this stat (e.g. cache, scene, etc).
+ ///
+ public string Category { get; private set; }
+
+ ///
+ /// Containing name for this stat.
+ /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
+ /// us with a to-be-resolved problem of non-unique region names).
+ ///
+ ///
+ /// The container.
+ ///
+ public string Container { get; private set; }
+
+ ///
+ /// Action used to check whether alert should go off.
+ ///
+ ///
+ /// Should return true if check passes. False otherwise.
+ ///
+ public Func CheckFunc { get; private set; }
+
+ ///
+ /// Message from the last failure, if any. If there is no message or no failure then will be null.
+ ///
+ ///
+ /// Should be set by the CheckFunc when applicable.
+ ///
+ public string LastFailureMessage { get; set; }
+
+ public StatVerbosity Verbosity { get; private set; }
+ public string ShortName { get; private set; }
+ public string Name { get; private set; }
+ public string Description { get; private set; }
+
+ public Check(
+ string shortName,
+ string name,
+ string description,
+ string category,
+ string container,
+ Func checkFunc,
+ StatVerbosity verbosity)
+ {
+ if (ChecksManager.SubCommands.Contains(category))
+ throw new Exception(
+ string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category));
+
+ foreach (char c in DisallowedShortNameCharacters)
+ {
+ if (shortName.IndexOf(c) != -1)
+ throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c));
+ }
+
+ ShortName = shortName;
+ Name = name;
+ Description = description;
+ Category = category;
+ Container = container;
+ CheckFunc = checkFunc;
+ Verbosity = verbosity;
+ }
+
+ public bool CheckIt()
+ {
+ return CheckFunc(this);
+ }
+
+ public virtual string ToConsoleString()
+ {
+ return string.Format(
+ "{0}.{1}.{2} - {3}",
+ Category,
+ Container,
+ ShortName,
+ Description);
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/ChecksManager.cs b/OpenSim/Framework/Monitoring/ChecksManager.cs
new file mode 100644
index 0000000..e4a7f8c
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/ChecksManager.cs
@@ -0,0 +1,262 @@
+/*
+ * 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.Linq;
+using System.Reflection;
+using System.Text;
+using log4net;
+
+namespace OpenSim.Framework.Monitoring
+{
+ ///
+ /// Static class used to register/deregister checks on runtime conditions.
+ ///
+ public static class ChecksManager
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ // Subcommand used to list other stats.
+ public const string ListSubCommand = "list";
+
+ // All subcommands
+ public static HashSet SubCommands = new HashSet { ListSubCommand };
+
+ ///
+ /// Checks categorized by category/container/shortname
+ ///
+ ///
+ /// Do not add or remove directly from this dictionary.
+ ///
+ public static SortedDictionary>> RegisteredChecks
+ = new SortedDictionary>>();
+
+ public static void RegisterConsoleCommands(ICommandConsole console)
+ {
+ console.Commands.AddCommand(
+ "General",
+ false,
+ "show checks",
+ "show checks",
+ "Show checks configured for this server",
+ "If no argument is specified then info on all checks will be shown.\n"
+ + "'list' argument will show check categories.\n"
+ + "THIS FACILITY IS EXPERIMENTAL",
+ HandleShowchecksCommand);
+ }
+
+ public static void HandleShowchecksCommand(string module, string[] cmd)
+ {
+ ICommandConsole con = MainConsole.Instance;
+
+ if (cmd.Length > 2)
+ {
+ foreach (string name in cmd.Skip(2))
+ {
+ string[] components = name.Split('.');
+
+ string categoryName = components[0];
+// string containerName = components.Length > 1 ? components[1] : null;
+
+ if (categoryName == ListSubCommand)
+ {
+ con.Output("check categories available are:");
+
+ foreach (string category in RegisteredChecks.Keys)
+ con.OutputFormat(" {0}", category);
+ }
+// else
+// {
+// SortedDictionary> category;
+// if (!Registeredchecks.TryGetValue(categoryName, out category))
+// {
+// con.OutputFormat("No such category as {0}", categoryName);
+// }
+// else
+// {
+// if (String.IsNullOrEmpty(containerName))
+// {
+// OutputConfiguredToConsole(con, category);
+// }
+// else
+// {
+// SortedDictionary container;
+// if (category.TryGetValue(containerName, out container))
+// {
+// OutputContainerChecksToConsole(con, container);
+// }
+// else
+// {
+// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
+// }
+// }
+// }
+// }
+ }
+ }
+ else
+ {
+ OutputAllChecksToConsole(con);
+ }
+ }
+
+ ///
+ /// Registers a statistic.
+ ///
+ ///
+ ///
+ public static bool RegisterCheck(Check check)
+ {
+ SortedDictionary> category = null, newCategory;
+ SortedDictionary container = null, newContainer;
+
+ lock (RegisteredChecks)
+ {
+ // Check name is not unique across category/container/shortname key.
+ // XXX: For now just return false. This is to avoid problems in regression tests where all tests
+ // in a class are run in the same instance of the VM.
+ if (TryGetCheckParents(check, out category, out container))
+ return false;
+
+ // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
+ // This means that we don't need to lock or copy them on iteration, which will be a much more
+ // common operation after startup.
+ if (container != null)
+ newContainer = new SortedDictionary(container);
+ else
+ newContainer = new SortedDictionary();
+
+ if (category != null)
+ newCategory = new SortedDictionary>(category);
+ else
+ newCategory = new SortedDictionary>();
+
+ newContainer[check.ShortName] = check;
+ newCategory[check.Container] = newContainer;
+ RegisteredChecks[check.Category] = newCategory;
+ }
+
+ return true;
+ }
+
+ ///
+ /// Deregister an check
+ /// >
+ ///
+ ///
+ public static bool DeregisterCheck(Check check)
+ {
+ SortedDictionary> category = null, newCategory;
+ SortedDictionary container = null, newContainer;
+
+ lock (RegisteredChecks)
+ {
+ if (!TryGetCheckParents(check, out category, out container))
+ return false;
+
+ newContainer = new SortedDictionary(container);
+ newContainer.Remove(check.ShortName);
+
+ newCategory = new SortedDictionary>(category);
+ newCategory.Remove(check.Container);
+
+ newCategory[check.Container] = newContainer;
+ RegisteredChecks[check.Category] = newCategory;
+
+ return true;
+ }
+ }
+
+ public static bool TryGetCheckParents(
+ Check check,
+ out SortedDictionary> category,
+ out SortedDictionary container)
+ {
+ category = null;
+ container = null;
+
+ lock (RegisteredChecks)
+ {
+ if (RegisteredChecks.TryGetValue(check.Category, out category))
+ {
+ if (category.TryGetValue(check.Container, out container))
+ {
+ if (container.ContainsKey(check.ShortName))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ public static void CheckChecks()
+ {
+ lock (RegisteredChecks)
+ {
+ foreach (SortedDictionary> category in RegisteredChecks.Values)
+ {
+ foreach (SortedDictionary container in category.Values)
+ {
+ foreach (Check check in container.Values)
+ {
+ if (!check.CheckIt())
+ m_log.WarnFormat(
+ "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage);
+ }
+ }
+ }
+ }
+ }
+
+ private static void OutputAllChecksToConsole(ICommandConsole con)
+ {
+ foreach (var category in RegisteredChecks.Values)
+ {
+ OutputCategoryChecksToConsole(con, category);
+ }
+ }
+
+ private static void OutputCategoryChecksToConsole(
+ ICommandConsole con, SortedDictionary> category)
+ {
+ foreach (var container in category.Values)
+ {
+ OutputContainerChecksToConsole(con, container);
+ }
+ }
+
+ private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary container)
+ {
+ foreach (Check check in container.Values)
+ {
+ con.Output(check.ToConsoleString());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
index 99f75e3..40df562 100644
--- a/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs
@@ -25,6 +25,8 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using OpenMetaverse.StructuredData;
+
namespace OpenSim.Framework.Monitoring
{
///
@@ -45,5 +47,12 @@ namespace OpenSim.Framework.Monitoring
/// A
///
string XReport(string uptime, string version);
+
+ ///
+ /// Report back collected statistical information as an OSDMap of key/values
+ ///
+ ///
+ ///
+ OSDMap OReport(string uptime, string version);
}
}
diff --git a/OpenSim/Framework/Monitoring/JobEngine.cs b/OpenSim/Framework/Monitoring/JobEngine.cs
new file mode 100644
index 0000000..6db9a67
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/JobEngine.cs
@@ -0,0 +1,341 @@
+/*
+ * 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.Concurrent;
+using System.Reflection;
+using System.Threading;
+using log4net;
+using OpenSim.Framework;
+
+namespace OpenSim.Framework.Monitoring
+{
+ public class JobEngine
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public int LogLevel { get; set; }
+
+ public string Name { get; private set; }
+
+ public string LoggingName { get; private set; }
+
+ ///
+ /// Is this engine running?
+ ///
+ public bool IsRunning { get; private set; }
+
+ ///
+ /// The current job that the engine is running.
+ ///
+ ///
+ /// Will be null if no job is currently running.
+ ///
+ public Job CurrentJob { get; private set; }
+
+ ///
+ /// Number of jobs waiting to be processed.
+ ///
+ public int JobsWaiting { get { return m_jobQueue.Count; } }
+
+ ///
+ /// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping.
+ ///
+ public int RequestProcessTimeoutOnStop { get; set; }
+
+ ///
+ /// Controls whether we need to warn in the log about exceeding the max queue size.
+ ///
+ ///
+ /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in
+ /// order to avoid spamming the log with lots of warnings.
+ ///
+ private bool m_warnOverMaxQueue = true;
+
+ private BlockingCollection m_jobQueue;
+
+ private CancellationTokenSource m_cancelSource;
+
+ ///
+ /// Used to signal that we are ready to complete stop.
+ ///
+ private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false);
+
+ public JobEngine(string name, string loggingName)
+ {
+ Name = name;
+ LoggingName = loggingName;
+
+ RequestProcessTimeoutOnStop = 5000;
+ }
+
+ public void Start()
+ {
+ lock (this)
+ {
+ if (IsRunning)
+ return;
+
+ IsRunning = true;
+
+ m_finishedProcessingAfterStop.Reset();
+
+ m_jobQueue = new BlockingCollection(new ConcurrentQueue(), 5000);
+ m_cancelSource = new CancellationTokenSource();
+
+ WorkManager.StartThread(
+ ProcessRequests,
+ Name,
+ ThreadPriority.Normal,
+ false,
+ true,
+ null,
+ int.MaxValue);
+ }
+ }
+
+ public void Stop()
+ {
+ lock (this)
+ {
+ try
+ {
+ if (!IsRunning)
+ return;
+
+ IsRunning = false;
+
+ int requestsLeft = m_jobQueue.Count;
+
+ if (requestsLeft <= 0)
+ {
+ m_cancelSource.Cancel();
+ }
+ else
+ {
+ m_log.InfoFormat("[{0}]: Waiting to write {1} events after stop.", LoggingName, requestsLeft);
+
+ while (requestsLeft > 0)
+ {
+ if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop))
+ {
+ // After timeout no events have been written
+ if (requestsLeft == m_jobQueue.Count)
+ {
+ m_log.WarnFormat(
+ "[{0}]: No requests processed after {1} ms wait. Discarding remaining {2} requests",
+ LoggingName, RequestProcessTimeoutOnStop, requestsLeft);
+
+ break;
+ }
+ }
+
+ requestsLeft = m_jobQueue.Count;
+ }
+ }
+ }
+ finally
+ {
+ m_cancelSource.Dispose();
+ }
+ }
+ }
+
+ ///
+ /// Make a job.
+ ///
+ ///
+ /// We provide this method to replace the constructor so that we can later pool job objects if necessary to
+ /// reduce memory churn. Normally one would directly call QueueJob() with parameters anyway.
+ ///
+ ///
+ /// Name.
+ /// Action.
+ /// Common identifier.
+ public static Job MakeJob(string name, Action action, string commonId = null)
+ {
+ return Job.MakeJob(name, action, commonId);
+ }
+
+ ///
+ /// Remove the next job queued for processing.
+ ///
+ ///
+ /// Returns null if there is no next job.
+ /// Will not remove a job currently being performed.
+ ///
+ public Job RemoveNextJob()
+ {
+ Job nextJob;
+ m_jobQueue.TryTake(out nextJob);
+
+ return nextJob;
+ }
+
+ ///
+ /// Queue the job for processing.
+ ///
+ /// true, if job was queued, false otherwise.
+ /// Name of job. This appears on the console and in logging.
+ /// Action to perform.
+ ///
+ /// Common identifier for a set of jobs. This is allows a set of jobs to be removed
+ /// if required (e.g. all jobs for a given agent. Optional.
+ ///
+ public bool QueueJob(string name, Action action, string commonId = null)
+ {
+ return QueueJob(MakeJob(name, action, commonId));
+ }
+
+ ///
+ /// Queue the job for processing.
+ ///
+ /// true, if job was queued, false otherwise.
+ /// The job
+ ///
+ public bool QueueJob(Job job)
+ {
+ if (m_jobQueue.Count < m_jobQueue.BoundedCapacity)
+ {
+ m_jobQueue.Add(job);
+
+ if (!m_warnOverMaxQueue)
+ m_warnOverMaxQueue = true;
+
+ return true;
+ }
+ else
+ {
+ if (m_warnOverMaxQueue)
+ {
+ m_log.WarnFormat(
+ "[{0}]: Job queue at maximum capacity, not recording job from {1} in {2}",
+ LoggingName, job.Name, Name);
+
+ m_warnOverMaxQueue = false;
+ }
+
+ return false;
+ }
+ }
+
+ private void ProcessRequests()
+ {
+ try
+ {
+ while (IsRunning || m_jobQueue.Count > 0)
+ {
+ try
+ {
+ CurrentJob = m_jobQueue.Take(m_cancelSource.Token);
+ }
+ catch (ObjectDisposedException e)
+ {
+ // If we see this whilst not running then it may be due to a race where this thread checks
+ // IsRunning after the stopping thread sets it to false and disposes of the cancellation source.
+ if (IsRunning)
+ throw e;
+ else
+ break;
+ }
+
+ if (LogLevel >= 1)
+ m_log.DebugFormat("[{0}]: Processing job {1}", LoggingName, CurrentJob.Name);
+
+ try
+ {
+ CurrentJob.Action();
+ }
+ catch (Exception e)
+ {
+ m_log.Error(
+ string.Format(
+ "[{0}]: Job {1} failed, continuing. Exception ", LoggingName, CurrentJob.Name), e);
+ }
+
+ if (LogLevel >= 1)
+ m_log.DebugFormat("[{0}]: Processed job {1}", LoggingName, CurrentJob.Name);
+
+ CurrentJob = null;
+ }
+ }
+ catch (OperationCanceledException)
+ {
+ }
+
+ m_finishedProcessingAfterStop.Set();
+ }
+
+ public class Job
+ {
+ ///
+ /// Name of the job.
+ ///
+ ///
+ /// This appears on console and debug output.
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Common ID for this job.
+ ///
+ ///
+ /// This allows all jobs with a certain common ID (e.g. a client UUID) to be removed en-masse if required.
+ /// Can be null if this is not required.
+ ///
+ public string CommonId { get; private set; }
+
+ ///
+ /// Action to perform when this job is processed.
+ ///
+ public Action Action { get; private set; }
+
+ private Job(string name, string commonId, Action action)
+ {
+ Name = name;
+ CommonId = commonId;
+ Action = action;
+ }
+
+ ///
+ /// Make a job. It needs to be separately queued.
+ ///
+ ///
+ /// We provide this method to replace the constructor so that we can pool job objects if necessary to
+ /// to reduce memory churn. Normally one would directly call JobEngine.QueueJob() with parameters anyway.
+ ///
+ ///
+ /// Name.
+ /// Action.
+ /// Common identifier.
+ public static Job MakeJob(string name, Action action, string commonId = null)
+ {
+ return new Job(name, commonId, action);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
index c6010cd..c474622 100644
--- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
+++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
@@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring
private static bool m_enabled;
///
- /// Last memory churn in bytes per millisecond.
+ /// Average heap allocation rate in bytes per millisecond.
///
- public static double AverageMemoryChurn
+ public static double AverageHeapAllocationRate
{
get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
}
///
- /// Average memory churn in bytes per millisecond.
+ /// Last heap allocation in bytes
///
- public static double LastMemoryChurn
+ public static double LastHeapAllocationRate
{
get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
}
diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
index 1f2bb40..a617b93 100644
--- a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.8.3.*")]
+
diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs
new file mode 100644
index 0000000..77315bb
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs
@@ -0,0 +1,346 @@
+/*
+ * 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.Linq;
+using System.Net.NetworkInformation;
+using System.Text;
+using System.Threading;
+using log4net;
+using Nini.Config;
+using OpenMetaverse.StructuredData;
+using OpenSim.Framework;
+
+namespace OpenSim.Framework.Monitoring
+{
+ public class ServerStatsCollector
+ {
+ private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ private readonly string LogHeader = "[SERVER STATS]";
+
+ public bool Enabled = false;
+ private static Dictionary RegisteredStats = new Dictionary();
+
+ public readonly string CategoryServer = "server";
+
+ public readonly string ContainerThreadpool = "threadpool";
+ public readonly string ContainerProcessor = "processor";
+ public readonly string ContainerMemory = "memory";
+ public readonly string ContainerNetwork = "network";
+ public readonly string ContainerProcess = "process";
+
+ public string NetworkInterfaceTypes = "Ethernet";
+
+ readonly int performanceCounterSampleInterval = 500;
+// int lastperformanceCounterSampleTime = 0;
+
+ private class PerfCounterControl
+ {
+ public PerformanceCounter perfCounter;
+ public int lastFetch;
+ public string name;
+ public PerfCounterControl(PerformanceCounter pPc)
+ : this(pPc, String.Empty)
+ {
+ }
+ public PerfCounterControl(PerformanceCounter pPc, string pName)
+ {
+ perfCounter = pPc;
+ lastFetch = 0;
+ name = pName;
+ }
+ }
+
+ PerfCounterControl processorPercentPerfCounter = null;
+
+ // IRegionModuleBase.Initialize
+ public void Initialise(IConfigSource source)
+ {
+ if (source == null)
+ return;
+
+ IConfig cfg = source.Configs["Monitoring"];
+
+ if (cfg != null)
+ Enabled = cfg.GetBoolean("ServerStatsEnabled", true);
+
+ if (Enabled)
+ {
+ NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet");
+ }
+ }
+
+ public void Start()
+ {
+ if (RegisteredStats.Count == 0)
+ RegisterServerStats();
+ }
+
+ public void Close()
+ {
+ if (RegisteredStats.Count > 0)
+ {
+ foreach (Stat stat in RegisteredStats.Values)
+ {
+ StatsManager.DeregisterStat(stat);
+ stat.Dispose();
+ }
+ RegisteredStats.Clear();
+ }
+ }
+
+ private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act)
+ {
+ MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None);
+ }
+
+ private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action act, MeasuresOfInterest moi)
+ {
+ string desc = pDesc;
+ if (desc == null)
+ desc = pName;
+ Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug);
+ StatsManager.RegisterStat(stat);
+ RegisteredStats.Add(pName, stat);
+ }
+
+ public void RegisterServerStats()
+ {
+// lastperformanceCounterSampleTime = Util.EnvironmentTickCount();
+ PerformanceCounter tempPC;
+ Stat tempStat;
+ string tempName;
+
+ try
+ {
+ tempName = "CPUPercent";
+ tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total");
+ processorPercentPerfCounter = new PerfCounterControl(tempPC);
+ // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy.
+ tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor,
+ StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter); },
+ StatVerbosity.Info);
+ StatsManager.RegisterStat(tempStat);
+ RegisteredStats.Add(tempName, tempStat);
+
+ MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
+ (s) => { s.Value = Math.Round(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds, 3); });
+
+ MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
+ (s) => { s.Value = Math.Round(Process.GetCurrentProcess().UserProcessorTime.TotalSeconds, 3); });
+
+ MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
+ (s) => { s.Value = Math.Round(Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds, 3); });
+
+ MakeStat("Threads", null, "threads", ContainerProcessor,
+ (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e);
+ }
+
+ MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool,
+ s =>
+ {
+ int workerThreads, iocpThreads;
+ ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
+ s.Value = workerThreads;
+ });
+
+ MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool,
+ s =>
+ {
+ int workerThreads, iocpThreads;
+ ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
+ s.Value = iocpThreads;
+ });
+
+ if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null)
+ {
+ MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads);
+ MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads);
+ MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems);
+ MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads);
+ MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads);
+ MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks);
+ }
+
+ MakeStat(
+ "HTTPRequestsMade",
+ "Number of outbound HTTP requests made",
+ "requests",
+ ContainerNetwork,
+ s => s.Value = WebUtil.RequestNumber,
+ MeasuresOfInterest.AverageChangeOverTime);
+
+ try
+ {
+ List okInterfaceTypes = new List(NetworkInterfaceTypes.Split(','));
+
+ IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces();
+ foreach (NetworkInterface nic in nics)
+ {
+ if (nic.OperationalStatus != OperationalStatus.Up)
+ continue;
+
+ string nicInterfaceType = nic.NetworkInterfaceType.ToString();
+ if (!okInterfaceTypes.Contains(nicInterfaceType))
+ {
+ m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
+ LogHeader, nic.Name, nicInterfaceType);
+ m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
+ LogHeader, NetworkInterfaceTypes);
+ continue;
+ }
+
+ if (nic.Supports(NetworkInterfaceComponent.IPv4))
+ {
+ IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
+ if (nicStats != null)
+ {
+ MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
+ (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
+ MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
+ (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
+ MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
+ (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
+ }
+ }
+ // TODO: add IPv6 (it may actually happen someday)
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
+ }
+
+ MakeStat("ProcessMemory", null, "MB", ContainerMemory,
+ (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); });
+ MakeStat("HeapMemory", null, "MB", ContainerMemory,
+ (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); });
+ MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory,
+ (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
+ MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory,
+ (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
+ }
+
+ // Notes on performance counters:
+ // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx
+ // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c
+ // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters
+ private delegate double PerfCounterNextValue();
+
+ private void GetNextValue(Stat stat, PerfCounterControl perfControl)
+ {
+ if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval)
+ {
+ if (perfControl != null && perfControl.perfCounter != null)
+ {
+ try
+ {
+ stat.Value = Math.Round(perfControl.perfCounter.NextValue(), 3);
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e);
+ }
+
+ perfControl.lastFetch = Util.EnvironmentTickCount();
+ }
+ }
+ }
+
+ // Lookup the nic that goes with this stat and set the value by using a fetch action.
+ // Not sure about closure with delegates inside delegates.
+ private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
+ private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
+ {
+ // Get the one nic that has the name of this stat
+ IEnumerable nics = NetworkInterface.GetAllNetworkInterfaces().Where(
+ (network) => network.Name == stat.Description);
+ try
+ {
+ foreach (NetworkInterface nic in nics)
+ {
+ IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
+ if (intrStats != null)
+ {
+ double newVal = Math.Round(getter(intrStats) / factor, 3);
+ stat.Value = newVal;
+ }
+ break;
+ }
+ }
+ catch
+ {
+ // There are times interfaces go away so we just won't update the stat for this
+ m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description);
+ }
+ }
+ }
+
+ public class ServerStatsAggregator : Stat
+ {
+ public ServerStatsAggregator(
+ string shortName,
+ string name,
+ string description,
+ string unitName,
+ string category,
+ string container
+ )
+ : base(
+ shortName,
+ name,
+ description,
+ unitName,
+ category,
+ container,
+ StatType.Push,
+ MeasuresOfInterest.None,
+ null,
+ StatVerbosity.Info)
+ {
+ }
+ public override string ToConsoleString()
+ {
+ StringBuilder sb = new StringBuilder();
+
+ return sb.ToString();
+ }
+
+ public override OSDMap ToOSDMap()
+ {
+ OSDMap ret = new OSDMap();
+
+ return ret;
+ }
+ }
+}
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
old mode 100644
new mode 100755
index aa86202..e4df7ee
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -27,6 +27,8 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
@@ -39,8 +41,6 @@ namespace OpenSim.Framework.Monitoring
///
public class SimExtraStatsCollector : BaseStatsCollector
{
- private long abnormalClientThreadTerminations;
-
// private long assetsInCache;
// private long texturesInCache;
// private long assetCacheMemoryUsage;
@@ -72,11 +72,11 @@ namespace OpenSim.Framework.Monitoring
private volatile float pendingUploads;
private volatile float activeScripts;
private volatile float scriptLinesPerSecond;
-
- ///
- /// Number of times that a client thread terminated because of an exception
- ///
- public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } }
+ private volatile float m_frameDilation;
+ private volatile float m_usersLoggingIn;
+ private volatile float m_totalGeoPrims;
+ private volatile float m_totalMeshes;
+ private volatile float m_inUseThreads;
// ///
// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the
@@ -166,11 +166,6 @@ namespace OpenSim.Framework.Monitoring
private IDictionary packetQueueStatsCollectors
= new Dictionary();
- public void AddAbnormalClientThreadTermination()
- {
- abnormalClientThreadTerminations++;
- }
-
// public void AddAsset(AssetBase asset)
// {
// assetsInCache++;
@@ -260,6 +255,10 @@ namespace OpenSim.Framework.Monitoring
{
// FIXME: SimStats shouldn't allow an arbitrary stat packing order (which is inherited from the original
// SimStatsPacket that was being used).
+
+ // For an unknown reason the original designers decided not to
+ // include the spare MS statistic inside of this class, this is
+ // located inside the StatsBlock at location 21, thus it is skipped
timeDilation = stats.StatsBlock[0].StatValue;
simFps = stats.StatsBlock[1].StatValue;
physicsFps = stats.StatsBlock[2].StatValue;
@@ -281,6 +280,11 @@ namespace OpenSim.Framework.Monitoring
pendingUploads = stats.StatsBlock[18].StatValue;
activeScripts = stats.StatsBlock[19].StatValue;
scriptLinesPerSecond = stats.StatsBlock[20].StatValue;
+ m_frameDilation = stats.StatsBlock[22].StatValue;
+ m_usersLoggingIn = stats.StatsBlock[23].StatValue;
+ m_totalGeoPrims = stats.StatsBlock[24].StatValue;
+ m_totalMeshes = stats.StatsBlock[25].StatValue;
+ m_inUseThreads = stats.StatsBlock[26].StatValue;
}
///
@@ -324,10 +328,12 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine);
sb.Append("CONNECTION STATISTICS");
sb.Append(Environment.NewLine);
- sb.Append(
- string.Format(
- "Abnormal client thread terminations: {0}" + Environment.NewLine,
- abnormalClientThreadTerminations));
+
+ List stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
+
+ sb.AppendFormat(
+ "Client logouts due to no data receive timeout: {0}\n\n",
+ stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
// sb.Append(Environment.NewLine);
// sb.Append("INVENTORY STATISTICS");
@@ -338,7 +344,7 @@ Asset service request failures: {3}" + Environment.NewLine,
// InventoryServiceRetrievalFailures));
sb.Append(Environment.NewLine);
- sb.Append("FRAME STATISTICS");
+ sb.Append("SAMPLE FRAME STATISTICS");
sb.Append(Environment.NewLine);
sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
sb.Append(Environment.NewLine);
@@ -359,11 +365,12 @@ Asset service request failures: {3}" + Environment.NewLine,
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
- Dictionary> sceneStats;
-
+ /* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by
+ * the two formatted printouts above.
+ SortedDictionary> sceneStats;
if (StatsManager.TryGetStats("scene", out sceneStats))
{
- foreach (KeyValuePair> kvp in sceneStats)
+ foreach (KeyValuePair> kvp in sceneStats)
{
foreach (Stat stat in kvp.Value.Values)
{
@@ -374,6 +381,7 @@ Asset service request failures: {3}" + Environment.NewLine,
}
}
}
+ */
/*
sb.Append(Environment.NewLine);
@@ -405,6 +413,36 @@ Asset service request failures: {3}" + Environment.NewLine,
///
public override string XReport(string uptime, string version)
{
+ return OSDParser.SerializeJsonString(OReport(uptime, version));
+ }
+
+ ///
+ /// Report back collected statistical information as an OSDMap
+ ///
+ ///
+ public override OSDMap OReport(string uptime, string version)
+ {
+ // Get the amount of physical memory, allocated with the instance of this program, in kilobytes;
+ // the working set is the set of memory pages currently visible to this program in physical RAM
+ // memory and includes both shared (e.g. system libraries) and private data
+ double memUsage = Process.GetCurrentProcess().WorkingSet64 / 1024.0;
+
+ // Get the number of threads from the system that are currently
+ // running
+ int numberThreadsRunning = 0;
+ foreach (ProcessThread currentThread in
+ Process.GetCurrentProcess().Threads)
+ {
+ // A known issue with the current process .Threads property is
+ // that it can return null threads, thus don't count those as
+ // running threads and prevent the program function from failing
+ if (currentThread != null &&
+ currentThread.ThreadState == ThreadState.Running)
+ {
+ numberThreadsRunning++;
+ }
+ }
+
OSDMap args = new OSDMap(30);
// args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache));
// args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}",
@@ -441,14 +479,28 @@ Asset service request failures: {3}" + Environment.NewLine,
args["Memory"] = OSD.FromString (base.XReport (uptime, version));
args["Uptime"] = OSD.FromString (uptime);
args["Version"] = OSD.FromString (version);
-
- string strBuffer = "";
- strBuffer = OSDParser.SerializeJsonString(args);
- return strBuffer;
+ args["FrameDilatn"] = OSD.FromString(String.Format("{0:0.##}", m_frameDilation));
+ args["Logging in Users"] = OSD.FromString(String.Format("{0:0.##}",
+ m_usersLoggingIn));
+ args["GeoPrims"] = OSD.FromString(String.Format("{0:0.##}",
+ m_totalGeoPrims));
+ args["Mesh Objects"] = OSD.FromString(String.Format("{0:0.##}",
+ m_totalMeshes));
+ args["XEngine Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
+ m_inUseThreads));
+ args["Util Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
+ Util.GetSmartThreadPoolInfo().InUseThreads));
+ args["System Thread Count"] = OSD.FromString(String.Format(
+ "{0:0.##}", numberThreadsRunning));
+ args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}",
+ memUsage));
+
+ return args;
}
}
+
///
/// Pull packet queue stats from packet queues and report
///
@@ -474,5 +526,11 @@ Asset service request failures: {3}" + Environment.NewLine,
{
return "";
}
+
+ public OSDMap OReport(string uptime, string version)
+ {
+ OSDMap ret = new OSDMap();
+ return ret;
+ }
}
}
diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
new file mode 100755
index 0000000..318cf1c
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
@@ -0,0 +1,119 @@
+/*
+ * 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.Linq;
+using System.Text;
+
+using OpenMetaverse.StructuredData;
+
+namespace OpenSim.Framework.Monitoring
+{
+// A statistic that wraps a counter.
+// Built this way mostly so histograms and history can be created.
+public class CounterStat : Stat
+{
+ private SortedDictionary m_histograms;
+ private object counterLock = new object();
+
+ public CounterStat(
+ string shortName,
+ string name,
+ string description,
+ string unitName,
+ string category,
+ string container,
+ StatVerbosity verbosity)
+ : base(shortName, name, description, unitName, category, container, StatType.Push, null, verbosity)
+ {
+ m_histograms = new SortedDictionary();
+ }
+
+ // Histograms are presumably added at intialization time and the list does not change thereafter.
+ // Thus no locking of the histogram list.
+ public void AddHistogram(string histoName, EventHistogram histo)
+ {
+ m_histograms.Add(histoName, histo);
+ }
+
+ public delegate void ProcessHistogram(string name, EventHistogram histo);
+ public void ForEachHistogram(ProcessHistogram process)
+ {
+ foreach (KeyValuePair kvp in m_histograms)
+ {
+ process(kvp.Key, kvp.Value);
+ }
+ }
+
+ public void Event()
+ {
+ this.Event(1);
+ }
+
+ // Count the underlying counter.
+ public void Event(int cnt)
+ {
+ lock (counterLock)
+ {
+ base.Value += cnt;
+
+ foreach (EventHistogram histo in m_histograms.Values)
+ {
+ histo.Event(cnt);
+ }
+ }
+ }
+
+ // CounterStat is a basic stat plus histograms
+ public override OSDMap ToOSDMap()
+ {
+ // Get the foundational instance
+ OSDMap map = base.ToOSDMap();
+
+ map["StatType"] = "CounterStat";
+
+ // If there are any histograms, add a new field that is an array of histograms as OSDMaps
+ if (m_histograms.Count > 0)
+ {
+ lock (counterLock)
+ {
+ if (m_histograms.Count > 0)
+ {
+ OSDArray histos = new OSDArray();
+ foreach (EventHistogram histo in m_histograms.Values)
+ {
+ histos.Add(histo.GetHistogramAsOSDMap());
+ }
+ map.Add("Histograms", histos);
+ }
+ }
+ }
+ return map;
+ }
+}
+}
diff --git a/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs
new file mode 100755
index 0000000..f51f322
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs
@@ -0,0 +1,173 @@
+/*
+ * 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.Linq;
+using System.Text;
+
+using OpenMetaverse.StructuredData;
+
+namespace OpenSim.Framework.Monitoring
+{
+// Create a time histogram of events. The histogram is built in a wrap-around
+// array of equally distributed buckets.
+// For instance, a minute long histogram of second sized buckets would be:
+// new EventHistogram(60, 1000)
+public class EventHistogram
+{
+ private int m_timeBase;
+ private int m_numBuckets;
+ private int m_bucketMilliseconds;
+ private int m_lastBucket;
+ private int m_totalHistogramMilliseconds;
+ private long[] m_histogram;
+ private object histoLock = new object();
+
+ public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
+ {
+ m_numBuckets = numberOfBuckets;
+ m_bucketMilliseconds = millisecondsPerBucket;
+ m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
+
+ m_histogram = new long[m_numBuckets];
+ Zero();
+ m_lastBucket = 0;
+ m_timeBase = Util.EnvironmentTickCount();
+ }
+
+ public void Event()
+ {
+ this.Event(1);
+ }
+
+ // Record an event at time 'now' in the histogram.
+ public void Event(int cnt)
+ {
+ lock (histoLock)
+ {
+ // The time as displaced from the base of the histogram
+ int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
+
+ // If more than the total time of the histogram, we just start over
+ if (bucketTime > m_totalHistogramMilliseconds)
+ {
+ Zero();
+ m_lastBucket = 0;
+ m_timeBase = Util.EnvironmentTickCount();
+ }
+ else
+ {
+ // To which bucket should we add this event?
+ int bucket = bucketTime / m_bucketMilliseconds;
+
+ // Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
+ while (bucket != m_lastBucket)
+ {
+ // Zero from just after the last bucket to the new bucket or the end
+ for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
+ {
+ m_histogram[jj] = 0;
+ }
+ m_lastBucket = bucket;
+ // If the new bucket is off the end, wrap around to the beginning
+ if (bucket > m_numBuckets)
+ {
+ bucket -= m_numBuckets;
+ m_lastBucket = 0;
+ m_histogram[m_lastBucket] = 0;
+ m_timeBase += m_totalHistogramMilliseconds;
+ }
+ }
+ }
+ m_histogram[m_lastBucket] += cnt;
+ }
+ }
+
+ // Get a copy of the current histogram
+ public long[] GetHistogram()
+ {
+ long[] ret = new long[m_numBuckets];
+ lock (histoLock)
+ {
+ int indx = m_lastBucket + 1;
+ for (int ii = 0; ii < m_numBuckets; ii++, indx++)
+ {
+ if (indx >= m_numBuckets)
+ indx = 0;
+ ret[ii] = m_histogram[indx];
+ }
+ }
+ return ret;
+ }
+
+ public OSDMap GetHistogramAsOSDMap()
+ {
+ OSDMap ret = new OSDMap();
+
+ ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
+ ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
+ ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
+
+ // Compute a number for the first bucket in the histogram.
+ // This will allow readers to know how this histogram relates to any previously read histogram.
+ int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
+ ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
+
+ ret.Add("Values", GetHistogramAsOSDArray());
+
+ return ret;
+ }
+ // Get a copy of the current histogram
+ public OSDArray GetHistogramAsOSDArray()
+ {
+ OSDArray ret = new OSDArray(m_numBuckets);
+ lock (histoLock)
+ {
+ int indx = m_lastBucket + 1;
+ for (int ii = 0; ii < m_numBuckets; ii++, indx++)
+ {
+ if (indx >= m_numBuckets)
+ indx = 0;
+ ret[ii] = OSD.FromLong(m_histogram[indx]);
+ }
+ }
+ return ret;
+ }
+
+ // Zero out the histogram
+ public void Zero()
+ {
+ lock (histoLock)
+ {
+ for (int ii = 0; ii < m_numBuckets; ii++)
+ m_histogram[ii] = 0;
+ }
+ }
+}
+
+}
diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
index 60bed55..55ddf06 100644
--- a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
@@ -29,6 +29,8 @@ using System;
using System.Collections.Generic;
using System.Text;
+using OpenMetaverse.StructuredData;
+
namespace OpenSim.Framework.Monitoring
{
public class PercentageStat : Stat
@@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring
return sb.ToString();
}
+
+ // PercentageStat is a basic stat plus percent calc
+ public override OSDMap ToOSDMap()
+ {
+ // Get the foundational instance
+ OSDMap map = base.ToOSDMap();
+
+ map["StatType"] = "PercentageStat";
+
+ map.Add("Antecedent", OSD.FromLong(Antecedent));
+ map.Add("Consequent", OSD.FromLong(Consequent));
+
+ return map;
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs
index f91251b..a7cb2a6 100644
--- a/OpenSim/Framework/Monitoring/Stats/Stat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs
@@ -27,15 +27,23 @@
using System;
using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
using System.Text;
+using log4net;
+using OpenMetaverse.StructuredData;
namespace OpenSim.Framework.Monitoring
{
///
/// Holds individual statistic details
///
- public class Stat
+ public class Stat : IDisposable
{
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public static readonly char[] DisallowedShortNameCharacters = { '.' };
+
///
/// Category of this stat (e.g. cache, scene, etc).
///
@@ -93,7 +101,7 @@ namespace OpenSim.Framework.Monitoring
///
/// Will be null if no measures of interest require samples.
///
- private static Queue m_samples;
+ private Queue m_samples;
///
/// Maximum number of statistical samples.
@@ -160,6 +168,13 @@ namespace OpenSim.Framework.Monitoring
throw new Exception(
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
+ foreach (char c in DisallowedShortNameCharacters)
+ {
+ if (shortName.IndexOf(c) != -1)
+ shortName = shortName.Replace(c, '#');
+// throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
+ }
+
ShortName = shortName;
Name = name;
Description = description;
@@ -181,6 +196,12 @@ namespace OpenSim.Framework.Monitoring
Verbosity = verbosity;
}
+ // IDisposable.Dispose()
+ public virtual void Dispose()
+ {
+ return;
+ }
+
///
/// Record a value in the sample set.
///
@@ -196,6 +217,8 @@ namespace OpenSim.Framework.Monitoring
if (m_samples.Count >= m_maxSamples)
m_samples.Dequeue();
+// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name);
+
m_samples.Enqueue(newValue);
}
}
@@ -203,35 +226,100 @@ namespace OpenSim.Framework.Monitoring
public virtual string ToConsoleString()
{
StringBuilder sb = new StringBuilder();
- sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName);
+ sb.AppendFormat(
+ "{0}.{1}.{2} : {3}{4}",
+ Category,
+ Container,
+ ShortName,
+ Value,
+ string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName));
AppendMeasuresOfInterest(sb);
return sb.ToString();
}
- protected void AppendMeasuresOfInterest(StringBuilder sb)
+ public virtual OSDMap ToOSDMap()
{
- if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
- == MeasuresOfInterest.AverageChangeOverTime)
+ OSDMap ret = new OSDMap();
+ ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
+
+ ret.Add("Category", OSD.FromString(Category));
+ ret.Add("Container", OSD.FromString(Container));
+ ret.Add("ShortName", OSD.FromString(ShortName));
+ ret.Add("Name", OSD.FromString(Name));
+ ret.Add("Description", OSD.FromString(Description));
+ ret.Add("UnitName", OSD.FromString(UnitName));
+ ret.Add("Value", OSD.FromReal(Value));
+
+ double lastChangeOverTime, averageChangeOverTime;
+ if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
+ {
+ ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime));
+ ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime));
+ }
+
+ return ret;
+ }
+
+ // Compute the averages over time and return same.
+ // Return 'true' if averages were actually computed. 'false' if no average info.
+ public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
+ {
+ bool ret = false;
+ lastChangeOverTime = 0;
+ averageChangeOverTime = 0;
+
+ if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
{
double totalChange = 0;
+ double? penultimateSample = null;
double? lastSample = null;
lock (m_samples)
{
+ // m_log.DebugFormat(
+ // "[STAT]: Samples for {0} are {1}",
+ // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
+
foreach (double s in m_samples)
{
if (lastSample != null)
totalChange += s - (double)lastSample;
+ penultimateSample = lastSample;
lastSample = s;
}
}
+ if (lastSample != null && penultimateSample != null)
+ {
+ lastChangeOverTime
+ = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
+ }
+
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
- sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
+ averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
+ ret = true;
+ }
+
+ return ret;
+ }
+
+ protected void AppendMeasuresOfInterest(StringBuilder sb)
+ {
+ double lastChangeOverTime = 0;
+ double averageChangeOverTime = 0;
+
+ if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
+ {
+ sb.AppendFormat(
+ ", {0:0.##}{1}/s, {2:0.##}{3}/s",
+ lastChangeOverTime,
+ string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName),
+ averageChangeOverTime,
+ string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName));
}
}
}
diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs
new file mode 100644
index 0000000..15a37aa
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/StatsLogger.cs
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+using System.Timers;
+using log4net;
+
+namespace OpenSim.Framework.Monitoring
+{
+ ///
+ /// Provides a means to continuously log stats for debugging purposes.
+ ///
+ public static class StatsLogger
+ {
+ private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger");
+
+ private static Timer m_loggingTimer;
+ private static int m_statsLogIntervalMs = 5000;
+
+ public static void RegisterConsoleCommands(ICommandConsole console)
+ {
+ console.Commands.AddCommand(
+ "General",
+ false,
+ "stats record",
+ "stats record start|stop",
+ "Control whether stats are being regularly recorded to a separate file.",
+ "For debug purposes. Experimental.",
+ HandleStatsRecordCommand);
+
+ console.Commands.AddCommand(
+ "General",
+ false,
+ "stats save",
+ "stats save ",
+ "Save stats snapshot to a file. If the file already exists, then the report is appended.",
+ "For debug purposes. Experimental.",
+ HandleStatsSaveCommand);
+ }
+
+ public static void HandleStatsRecordCommand(string module, string[] cmd)
+ {
+ ICommandConsole con = MainConsole.Instance;
+
+ if (cmd.Length != 3)
+ {
+ con.Output("Usage: stats record start|stop");
+ return;
+ }
+
+ if (cmd[2] == "start")
+ {
+ Start();
+ con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs);
+ }
+ else if (cmd[2] == "stop")
+ {
+ Stop();
+ con.Output("Stopped recording stats to file.");
+ }
+ }
+
+ public static void HandleStatsSaveCommand(string module, string[] cmd)
+ {
+ ICommandConsole con = MainConsole.Instance;
+
+ if (cmd.Length != 3)
+ {
+ con.Output("Usage: stats save ");
+ return;
+ }
+
+ string path = cmd[2];
+
+ using (StreamWriter sw = new StreamWriter(path, true))
+ {
+ foreach (string line in GetReport())
+ sw.WriteLine(line);
+ }
+
+ MainConsole.Instance.OutputFormat("Stats saved to file {0}", path);
+ }
+
+ public static void Start()
+ {
+ if (m_loggingTimer != null)
+ Stop();
+
+ m_loggingTimer = new Timer(m_statsLogIntervalMs);
+ m_loggingTimer.AutoReset = false;
+ m_loggingTimer.Elapsed += Log;
+ m_loggingTimer.Start();
+ }
+
+ public static void Stop()
+ {
+ if (m_loggingTimer != null)
+ {
+ m_loggingTimer.Stop();
+ }
+ }
+
+ private static void Log(object sender, ElapsedEventArgs e)
+ {
+ foreach (string line in GetReport())
+ m_statsLog.Info(line);
+
+ m_loggingTimer.Start();
+ }
+
+ private static List GetReport()
+ {
+ List lines = new List();
+
+ lines.Add(string.Format("*** STATS REPORT AT {0} ***", DateTime.Now));
+
+ foreach (string report in StatsManager.GetAllStatsReports())
+ lines.Add(report);
+
+ return lines;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 0762b01..3136ee8 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -26,15 +26,20 @@
*/
using System;
+using System.Collections;
using System.Collections.Generic;
+using System.Linq;
using System.Text;
+using OpenSim.Framework;
+using OpenMetaverse.StructuredData;
+
namespace OpenSim.Framework.Monitoring
{
///
- /// Singleton used to provide access to statistics reporters
+ /// Static class used to register/deregister/fetch statistics
///
- public class StatsManager
+ public static class StatsManager
{
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
@@ -51,31 +56,43 @@ namespace OpenSim.Framework.Monitoring
///
/// Do not add or remove directly from this dictionary.
///
- public static Dictionary>> RegisteredStats
- = new Dictionary>>();
+ public static SortedDictionary>> RegisteredStats
+ = new SortedDictionary>>();
- private static AssetStatsCollector assetStats;
- private static UserStatsCollector userStats;
- private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
+// private static AssetStatsCollector assetStats;
+// private static UserStatsCollector userStats;
+// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
- public static AssetStatsCollector AssetStats { get { return assetStats; } }
- public static UserStatsCollector UserStats { get { return userStats; } }
- public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
+// public static AssetStatsCollector AssetStats { get { return assetStats; } }
+// public static UserStatsCollector UserStats { get { return userStats; } }
+ public static SimExtraStatsCollector SimExtraStats { get; set; }
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
- "show stats",
- "show stats [list|all|]",
+ "stats show",
+ "stats show [list|all|([.])+",
"Show statistical information for this server",
"If no final argument is specified then legacy statistics information is currently shown.\n"
- + "If list is specified then statistic categories are shown.\n"
- + "If all is specified then all registered statistics are shown.\n"
- + "If a category name is specified then only statistics from that category are shown.\n"
+ + "'list' argument will show statistic categories.\n"
+ + "'all' will show all statistics.\n"
+ + "A name will show statistics from that category.\n"
+ + "A . name will show statistics from that category in that container.\n"
+ + "More than one name can be given separated by spaces.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
+
+ console.Commands.AddCommand(
+ "General",
+ false,
+ "show stats",
+ "show stats [list|all|([.])+",
+ "Alias for 'stats show' command",
+ HandleShowStatsCommand);
+
+ StatsLogger.RegisterConsoleCommands(console);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
@@ -84,105 +101,286 @@ namespace OpenSim.Framework.Monitoring
if (cmd.Length > 2)
{
- var categoryName = cmd[2];
-
- if (categoryName == AllSubCommand)
+ foreach (string name in cmd.Skip(2))
{
- foreach (var category in RegisteredStats.Values)
+ string[] components = name.Split('.');
+
+ string categoryName = components[0];
+ string containerName = components.Length > 1 ? components[1] : null;
+ string statName = components.Length > 2 ? components[2] : null;
+
+ if (categoryName == AllSubCommand)
{
- OutputCategoryStatsToConsole(con, category);
+ OutputAllStatsToConsole(con);
}
- }
- else if (categoryName == ListSubCommand)
- {
- con.Output("Statistic categories available are:");
- foreach (string category in RegisteredStats.Keys)
- con.OutputFormat(" {0}", category);
- }
- else
- {
- Dictionary> category;
- if (!RegisteredStats.TryGetValue(categoryName, out category))
+ else if (categoryName == ListSubCommand)
{
- con.OutputFormat("No such category as {0}", categoryName);
+ con.Output("Statistic categories available are:");
+ foreach (string category in RegisteredStats.Keys)
+ con.OutputFormat(" {0}", category);
}
else
{
- OutputCategoryStatsToConsole(con, category);
+ SortedDictionary> category;
+ if (!RegisteredStats.TryGetValue(categoryName, out category))
+ {
+ con.OutputFormat("No such category as {0}", categoryName);
+ }
+ else
+ {
+ if (String.IsNullOrEmpty(containerName))
+ {
+ OutputCategoryStatsToConsole(con, category);
+ }
+ else
+ {
+ SortedDictionary container;
+ if (category.TryGetValue(containerName, out container))
+ {
+ if (String.IsNullOrEmpty(statName))
+ {
+ OutputContainerStatsToConsole(con, container);
+ }
+ else
+ {
+ Stat stat;
+ if (container.TryGetValue(statName, out stat))
+ {
+ OutputStatToConsole(con, stat);
+ }
+ else
+ {
+ con.OutputFormat(
+ "No such stat {0} in {1}.{2}", statName, categoryName, containerName);
+ }
+ }
+ }
+ else
+ {
+ con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
+ }
+ }
+ }
}
}
}
else
{
// Legacy
- con.Output(SimExtraStats.Report());
+ if (SimExtraStats != null)
+ con.Output(SimExtraStats.Report());
+ else
+ OutputAllStatsToConsole(con);
}
}
- private static void OutputCategoryStatsToConsole(
- ICommandConsole con, Dictionary> category)
+ public static List GetAllStatsReports()
+ {
+ List reports = new List();
+
+ foreach (var category in RegisteredStats.Values)
+ reports.AddRange(GetCategoryStatsReports(category));
+
+ return reports;
+ }
+
+ private static void OutputAllStatsToConsole(ICommandConsole con)
{
+ foreach (string report in GetAllStatsReports())
+ con.Output(report);
+ }
+
+ private static List GetCategoryStatsReports(
+ SortedDictionary> category)
+ {
+ List reports = new List();
+
foreach (var container in category.Values)
+ reports.AddRange(GetContainerStatsReports(container));
+
+ return reports;
+ }
+
+ private static void OutputCategoryStatsToConsole(
+ ICommandConsole con, SortedDictionary> category)
+ {
+ foreach (string report in GetCategoryStatsReports(category))
+ con.Output(report);
+ }
+
+ private static List GetContainerStatsReports(SortedDictionary container)
+ {
+ List reports = new List();
+
+ foreach (Stat stat in container.Values)
+ reports.Add(stat.ToConsoleString());
+
+ return reports;
+ }
+
+ private static void OutputContainerStatsToConsole(
+ ICommandConsole con, SortedDictionary container)
+ {
+ foreach (string report in GetContainerStatsReports(container))
+ con.Output(report);
+ }
+
+ private static void OutputStatToConsole(ICommandConsole con, Stat stat)
+ {
+ con.Output(stat.ToConsoleString());
+ }
+
+ // Creates an OSDMap of the format:
+ // { categoryName: {
+ // containerName: {
+ // statName: {
+ // "Name": name,
+ // "ShortName": shortName,
+ // ...
+ // },
+ // statName: {
+ // "Name": name,
+ // "ShortName": shortName,
+ // ...
+ // },
+ // ...
+ // },
+ // containerName: {
+ // ...
+ // },
+ // ...
+ // },
+ // categoryName: {
+ // ...
+ // },
+ // ...
+ // }
+ // The passed in parameters will filter the categories, containers and stats returned. If any of the
+ // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned.
+ // Case matters.
+ public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName)
+ {
+ OSDMap map = new OSDMap();
+
+ foreach (string catName in RegisteredStats.Keys)
{
- foreach (Stat stat in container.Values)
+ // Do this category if null spec, "all" subcommand or category name matches passed parameter.
+ // Skip category if none of the above.
+ if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName))
+ continue;
+
+ OSDMap contMap = new OSDMap();
+ foreach (string contName in RegisteredStats[catName].Keys)
{
- con.Output(stat.ToConsoleString());
+ if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName))
+ continue;
+
+ OSDMap statMap = new OSDMap();
+
+ SortedDictionary theStats = RegisteredStats[catName][contName];
+ foreach (string statName in theStats.Keys)
+ {
+ if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName))
+ continue;
+
+ statMap.Add(statName, theStats[statName].ToOSDMap());
+ }
+
+ contMap.Add(contName, statMap);
}
+ map.Add(catName, contMap);
}
+
+ return map;
}
- ///
- /// Start collecting statistics related to assets.
- /// Should only be called once.
- ///
- public static AssetStatsCollector StartCollectingAssetStats()
+ public static Hashtable HandleStatsRequest(Hashtable request)
{
- assetStats = new AssetStatsCollector();
+ Hashtable responsedata = new Hashtable();
+// string regpath = request["uri"].ToString();
+ int response_code = 200;
+ string contenttype = "text/json";
- return assetStats;
- }
+ string pCategoryName = StatsManager.AllSubCommand;
+ string pContainerName = StatsManager.AllSubCommand;
+ string pStatName = StatsManager.AllSubCommand;
- ///
- /// Start collecting statistics related to users.
- /// Should only be called once.
- ///
- public static UserStatsCollector StartCollectingUserStats()
- {
- userStats = new UserStatsCollector();
+ if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString();
+ if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString();
+ if (request.ContainsKey("stat")) pStatName = request["stat"].ToString();
- return userStats;
+ string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString();
+
+ // If requestor wants it as a callback function, build response as a function rather than just the JSON string.
+ if (request.ContainsKey("callback"))
+ {
+ strOut = request["callback"].ToString() + "(" + strOut + ");";
+ }
+
+ // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}",
+ // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut);
+
+ responsedata["int_response_code"] = response_code;
+ responsedata["content_type"] = contenttype;
+ responsedata["keepalive"] = false;
+ responsedata["str_response_string"] = strOut;
+ responsedata["access_control_allow_origin"] = "*";
+
+ return responsedata;
}
+// ///
+// /// Start collecting statistics related to assets.
+// /// Should only be called once.
+// ///
+// public static AssetStatsCollector StartCollectingAssetStats()
+// {
+// assetStats = new AssetStatsCollector();
+//
+// return assetStats;
+// }
+//
+// ///
+// /// Start collecting statistics related to users.
+// /// Should only be called once.
+// ///
+// public static UserStatsCollector StartCollectingUserStats()
+// {
+// userStats = new UserStatsCollector();
+//
+// return userStats;
+// }
+
///
- /// Registers a statistic.
+ /// Register a statistic.
///
///
///
public static bool RegisterStat(Stat stat)
{
- Dictionary> category = null, newCategory;
- Dictionary container = null, newContainer;
+ SortedDictionary> category = null, newCategory;
+ SortedDictionary container = null, newContainer;
lock (RegisteredStats)
{
// Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
- if (TryGetStat(stat, out category, out container))
+ if (TryGetStatParents(stat, out category, out container))
return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
- newContainer = new Dictionary(container);
+ newContainer = new SortedDictionary(container);
else
- newContainer = new Dictionary();
+ newContainer = new SortedDictionary();
if (category != null)
- newCategory = new Dictionary>(category);
+ newCategory = new SortedDictionary>(category);
else
- newCategory = new Dictionary>();
+ newCategory = new SortedDictionary>();
newContainer[stat.ShortName] = stat;
newCategory[stat.Container] = newContainer;
@@ -196,21 +394,21 @@ namespace OpenSim.Framework.Monitoring
/// Deregister a statistic
/// >
///
- ///
public static bool DeregisterStat(Stat stat)
{
- Dictionary> category = null, newCategory;
- Dictionary container = null, newContainer;
+ SortedDictionary> category = null, newCategory;
+ SortedDictionary container = null, newContainer;
lock (RegisteredStats)
{
- if (!TryGetStat(stat, out category, out container))
+ if (!TryGetStatParents(stat, out category, out container))
return false;
- newContainer = new Dictionary(container);
+ newContainer = new SortedDictionary(container);
newContainer.Remove(stat.ShortName);
- newCategory = new Dictionary>(category);
+ newCategory = new SortedDictionary>(category);
newCategory.Remove(stat.Container);
newCategory[stat.Container] = newContainer;
@@ -220,15 +418,70 @@ namespace OpenSim.Framework.Monitoring
}
}
- public static bool TryGetStats(string category, out Dictionary> stats)
+ public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
{
- return RegisteredStats.TryGetValue(category, out stats);
+ stat = null;
+ SortedDictionary> categoryStats;
+
+ lock (RegisteredStats)
+ {
+ if (!TryGetStatsForCategory(category, out categoryStats))
+ return false;
+
+ SortedDictionary containerStats;
+
+ if (!categoryStats.TryGetValue(container, out containerStats))
+ return false;
+
+ return containerStats.TryGetValue(statShortName, out stat);
+ }
+ }
+
+ public static bool TryGetStatsForCategory(
+ string category, out SortedDictionary> stats)
+ {
+ lock (RegisteredStats)
+ return RegisteredStats.TryGetValue(category, out stats);
+ }
+
+ ///
+ /// Get the same stat for each container in a given category.
+ ///
+ ///
+ /// The stats if there were any to fetch. Otherwise null.
+ ///
+ ///
+ ///
+ public static List GetStatsFromEachContainer(string category, string statShortName)
+ {
+ SortedDictionary> categoryStats;
+
+ lock (RegisteredStats)
+ {
+ if (!RegisteredStats.TryGetValue(category, out categoryStats))
+ return null;
+
+ List stats = null;
+
+ foreach (SortedDictionary containerStats in categoryStats.Values)
+ {
+ if (containerStats.ContainsKey(statShortName))
+ {
+ if (stats == null)
+ stats = new List();
+
+ stats.Add(containerStats[statShortName]);
+ }
+ }
+
+ return stats;
+ }
}
- public static bool TryGetStat(
+ public static bool TryGetStatParents(
Stat stat,
- out Dictionary> category,
- out Dictionary container)
+ out SortedDictionary> category,
+ out SortedDictionary container)
{
category = null;
container = null;
@@ -252,9 +505,9 @@ namespace OpenSim.Framework.Monitoring
{
lock (RegisteredStats)
{
- foreach (Dictionary> category in RegisteredStats.Values)
+ foreach (SortedDictionary> category in RegisteredStats.Values)
{
- foreach (Dictionary container in category.Values)
+ foreach (SortedDictionary container in category.Values)
{
foreach (Stat stat in container.Values)
{
diff --git a/OpenSim/Framework/Monitoring/UserStatsCollector.cs b/OpenSim/Framework/Monitoring/UserStatsCollector.cs
index e89c8e6..81e0fa4 100644
--- a/OpenSim/Framework/Monitoring/UserStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/UserStatsCollector.cs
@@ -27,6 +27,8 @@
using System.Timers;
+using OpenMetaverse.StructuredData;
+
namespace OpenSim.Framework.Monitoring
{
///
@@ -88,5 +90,21 @@ namespace OpenSim.Framework.Monitoring
Logouts total : {3}",
SuccessfulLogins, SuccessfulLoginsToday, SuccessfulLoginsYesterday, Logouts);
}
+
+ public override string XReport(string uptime, string version)
+ {
+ return OSDParser.SerializeJsonString(OReport(uptime, version));
+ }
+
+ public override OSDMap OReport(string uptime, string version)
+ {
+ OSDMap ret = new OSDMap();
+ ret.Add("SuccessfulLogins", OSD.FromInteger(SuccessfulLogins));
+ ret.Add("SuccessfulLoginsToday", OSD.FromInteger(SuccessfulLoginsToday));
+ ret.Add("SuccessfulLoginsYesterday", OSD.FromInteger(SuccessfulLoginsYesterday));
+ ret.Add("Logouts", OSD.FromInteger(Logouts));
+
+ return ret;
+ }
}
}
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
index 3f992b1..a644fa5 100644
--- a/OpenSim/Framework/Monitoring/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -38,6 +38,8 @@ namespace OpenSim.Framework.Monitoring
///
public static class Watchdog
{
+ private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
/// Timer interval in milliseconds for the watchdog timer
public const double WATCHDOG_INTERVAL_MS = 2500.0d;
@@ -82,12 +84,32 @@ namespace OpenSim.Framework.Monitoring
///
public Func AlarmMethod { get; set; }
- public ThreadWatchdogInfo(Thread thread, int timeout)
+ ///
+ /// Stat structure associated with this thread.
+ ///
+ public Stat Stat { get; set; }
+
+ public ThreadWatchdogInfo(Thread thread, int timeout, string name)
{
Thread = thread;
Timeout = timeout;
FirstTick = Environment.TickCount & Int32.MaxValue;
LastTick = FirstTick;
+
+ Stat
+ = new Stat(
+ name,
+ string.Format("Last update of thread {0}", name),
+ "",
+ "ms",
+ "server",
+ "thread",
+ StatType.Pull,
+ MeasuresOfInterest.None,
+ stat => stat.Value = Environment.TickCount & Int32.MaxValue - LastTick,
+ StatVerbosity.Debug);
+
+ StatsManager.RegisterStat(Stat);
}
public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi)
@@ -100,6 +122,11 @@ namespace OpenSim.Framework.Monitoring
AlarmIfTimeout = previousTwi.AlarmIfTimeout;
AlarmMethod = previousTwi.AlarmMethod;
}
+
+ public void Cleanup()
+ {
+ StatsManager.DeregisterStat(Stat);
+ }
}
///
@@ -116,7 +143,7 @@ namespace OpenSim.Framework.Monitoring
get { return m_enabled; }
set
{
-// m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value);
+ // m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value);
if (value == m_enabled)
return;
@@ -132,9 +159,8 @@ namespace OpenSim.Framework.Monitoring
m_watchdogTimer.Enabled = m_enabled;
}
}
- private static bool m_enabled;
- private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+ private static bool m_enabled;
private static Dictionary m_threads;
private static System.Timers.Timer m_watchdogTimer;
@@ -155,57 +181,19 @@ namespace OpenSim.Framework.Monitoring
}
///
- /// Start a new thread that is tracked by the watchdog timer.
- ///
- /// The method that will be executed in a new thread
- /// A name to give to the new thread
- /// Priority to run the thread at
- /// True to run this thread as a background thread, otherwise false
- /// Trigger an alarm function is we have timed out
- /// The newly created Thread object
- public static Thread StartThread(
- ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout)
- {
- return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS);
- }
-
- ///
- /// Start a new thread that is tracked by the watchdog timer
+ /// Add a thread to the watchdog tracker.
///
- /// The method that will be executed in a new thread
- /// A name to give to the new thread
- /// Priority to run the thread at
- /// True to run this thread as a background
- /// thread, otherwise false
- /// Trigger an alarm function is we have timed out
- ///
- /// Alarm method to call if alarmIfTimeout is true and there is a timeout.
- /// Normally, this will just return some useful debugging information.
- ///
- /// Number of milliseconds to wait until we issue a warning about timeout.
- /// The newly created Thread object
- public static Thread StartThread(
- ThreadStart start, string name, ThreadPriority priority, bool isBackground,
- bool alarmIfTimeout, Func alarmMethod, int timeout)
+ /// Information about the thread.
+ /// Name of the thread.
+ /// If true then creation of thread is logged.
+ public static void AddThread(ThreadWatchdogInfo info, string name, bool log = true)
{
- Thread thread = new Thread(start);
- thread.Name = name;
- thread.Priority = priority;
- thread.IsBackground = isBackground;
-
- ThreadWatchdogInfo twi
- = new ThreadWatchdogInfo(thread, timeout)
- { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
-
- m_log.DebugFormat(
- "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
+ if (log)
+ m_log.DebugFormat(
+ "[WATCHDOG]: Started tracking thread {0}, ID {1}", name, info.Thread.ManagedThreadId);
lock (m_threads)
- m_threads.Add(twi.Thread.ManagedThreadId, twi);
-
- thread.Start();
-
- return thread;
+ m_threads.Add(info.Thread.ManagedThreadId, info);
}
///
@@ -219,25 +207,28 @@ namespace OpenSim.Framework.Monitoring
///
/// Stops watchdog tracking on the current thread
///
+ /// If true then normal events in thread removal are not logged.
///
/// True if the thread was removed from the list of tracked
/// threads, otherwise false
///
- public static bool RemoveThread()
+ public static bool RemoveThread(bool log = true)
{
- return RemoveThread(Thread.CurrentThread.ManagedThreadId);
+ return RemoveThread(Thread.CurrentThread.ManagedThreadId, log);
}
- private static bool RemoveThread(int threadID)
+ private static bool RemoveThread(int threadID, bool log = true)
{
lock (m_threads)
{
ThreadWatchdogInfo twi;
if (m_threads.TryGetValue(threadID, out twi))
{
- m_log.DebugFormat(
- "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
+ if (log)
+ m_log.DebugFormat(
+ "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
+ twi.Cleanup();
m_threads.Remove(threadID);
return true;
@@ -293,7 +284,7 @@ namespace OpenSim.Framework.Monitoring
}
catch { }
}
-
+
///
/// Get currently watched threads for diagnostic purposes
///
@@ -380,6 +371,7 @@ namespace OpenSim.Framework.Monitoring
if (MemoryWatchdog.Enabled)
MemoryWatchdog.Update();
+ ChecksManager.CheckChecks();
StatsManager.RecordStats();
m_watchdogTimer.Start();
diff --git a/OpenSim/Framework/Monitoring/WorkManager.cs b/OpenSim/Framework/Monitoring/WorkManager.cs
new file mode 100644
index 0000000..d1a74ce
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/WorkManager.cs
@@ -0,0 +1,290 @@
+/*
+ * 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.Reflection;
+using System.Threading;
+using log4net;
+
+namespace OpenSim.Framework.Monitoring
+{
+ ///
+ /// Manages various work items in the simulator.
+ ///
+ ///
+ /// Currently, here work can be started
+ /// * As a long-running and monitored thread.
+ /// * In a thread that will never timeout but where the job is expected to eventually complete.
+ /// * In a threadpool thread that will timeout if it takes a very long time to complete (> 10 mins).
+ /// * As a job which will be run in a single-threaded job engine. Such jobs must not incorporate delays (sleeps,
+ /// network waits, etc.).
+ ///
+ /// This is an evolving approach to better manage the work that OpenSimulator is asked to do from a very diverse
+ /// range of sources (client actions, incoming network, outgoing network calls, etc.).
+ ///
+ /// Util.FireAndForget is still available to insert jobs in the threadpool, though this is equivalent to
+ /// WorkManager.RunInThreadPool().
+ ///
+ public static class WorkManager
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+
+ public static JobEngine JobEngine { get; private set; }
+
+ static WorkManager()
+ {
+ JobEngine = new JobEngine("Non-blocking non-critical job engine", "JOB ENGINE");
+
+ StatsManager.RegisterStat(
+ new Stat(
+ "JobsWaiting",
+ "Number of jobs waiting for processing.",
+ "",
+ "",
+ "server",
+ "jobengine",
+ StatType.Pull,
+ MeasuresOfInterest.None,
+ stat => stat.Value = JobEngine.JobsWaiting,
+ StatVerbosity.Debug));
+
+ MainConsole.Instance.Commands.AddCommand(
+ "Debug",
+ false,
+ "debug jobengine",
+ "debug jobengine ",
+ "Start, stop, get status or set logging level of the job engine.",
+ "If stopped then all outstanding jobs are processed immediately.",
+ HandleControlCommand);
+ }
+
+ ///
+ /// Start a new long-lived thread.
+ ///
+ /// The method that will be executed in a new thread
+ /// A name to give to the new thread
+ /// Priority to run the thread at
+ /// True to run this thread as a background thread, otherwise false
+ /// Trigger an alarm function is we have timed out
+ /// If true then creation of thread is logged.
+ /// The newly created Thread object
+ public static Thread StartThread(
+ ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, bool log = true)
+ {
+ return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS, log);
+ }
+
+ ///
+ /// Start a new thread that is tracked by the watchdog
+ ///
+ /// The method that will be executed in a new thread
+ /// A name to give to the new thread
+ /// Priority to run the thread at
+ /// True to run this thread as a background
+ /// thread, otherwise false
+ /// Trigger an alarm function is we have timed out
+ ///
+ /// Alarm method to call if alarmIfTimeout is true and there is a timeout.
+ /// Normally, this will just return some useful debugging information.
+ ///
+ /// Number of milliseconds to wait until we issue a warning about timeout.
+ /// If true then creation of thread is logged.
+ /// The newly created Thread object
+ public static Thread StartThread(
+ ThreadStart start, string name, ThreadPriority priority, bool isBackground,
+ bool alarmIfTimeout, Func alarmMethod, int timeout, bool log = true)
+ {
+ Thread thread = new Thread(start);
+ thread.Priority = priority;
+ thread.IsBackground = isBackground;
+
+ Watchdog.ThreadWatchdogInfo twi
+ = new Watchdog.ThreadWatchdogInfo(thread, timeout, name)
+ { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
+
+ Watchdog.AddThread(twi, name, log:log);
+
+ thread.Start();
+ thread.Name = name;
+
+ return thread;
+ }
+
+ ///
+ /// Run the callback in a new thread immediately. If the thread exits with an exception log it but do
+ /// not propogate it.
+ ///
+ /// Code for the thread to execute.
+ /// Object to pass to the thread.
+ /// Name of the thread
+ public static void RunInThread(WaitCallback callback, object obj, string name, bool log = false)
+ {
+ if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
+ {
+ Culture.SetCurrentCulture();
+ callback(obj);
+ return;
+ }
+
+ ThreadStart ts = new ThreadStart(delegate()
+ {
+ try
+ {
+ Culture.SetCurrentCulture();
+ callback(obj);
+ Watchdog.RemoveThread(log:false);
+ }
+ catch (Exception e)
+ {
+ m_log.Error(string.Format("[WATCHDOG]: Exception in thread {0}.", name), e);
+ }
+ });
+
+ StartThread(ts, name, ThreadPriority.Normal, true, false, log:log);
+ }
+
+ ///
+ /// Run the callback via a threadpool thread.
+ ///
+ ///
+ /// Such jobs may run after some delay but must always complete.
+ ///
+ ///
+ ///
+ /// The name of the job. This is used in monitoring and debugging.
+ public static void RunInThreadPool(System.Threading.WaitCallback callback, object obj, string name)
+ {
+ Util.FireAndForget(callback, obj, name);
+ }
+
+ ///
+ /// Run a job.
+ ///
+ ///
+ /// This differs from direct scheduling (e.g. Util.FireAndForget) in that a job can be run in the job
+ /// engine if it is running, where all jobs are currently performed in sequence on a single thread. This is
+ /// to prevent observed overload and server freeze problems when there are hundreds of connections which all attempt to
+ /// perform work at once (e.g. in conference situations). With lower numbers of connections, the small
+ /// delay in performing jobs in sequence rather than concurrently has not been notiecable in testing, though a future more
+ /// sophisticated implementation could perform jobs concurrently when the server is under low load.
+ ///
+ /// However, be advised that some callers of this function rely on all jobs being performed in sequence if any
+ /// jobs are performed in sequence (i.e. if jobengine is active or not). Therefore, expanding the jobengine
+ /// beyond a single thread will require considerable thought.
+ ///
+ /// Also, any jobs submitted must be guaranteed to complete within a reasonable timeframe (e.g. they cannot
+ /// incorporate a network delay with a long timeout). At the moment, work that could suffer such issues
+ /// should still be run directly with RunInThread(), Util.FireAndForget(), etc. This is another area where
+ /// the job engine could be improved and so CPU utilization improved by better management of concurrency within
+ /// OpenSimulator.
+ ///
+ /// General classification for the job (e.g. "RezAttachments").
+ /// Callback for job.
+ /// Object to pass to callback when run
+ /// Specific name of job (e.g. "RezAttachments for Joe Bloggs"
+ /// If set to true then the job may be run in ths calling thread.
+ /// If the true then the job must never timeout.
+ /// If set to true then extra logging is performed.
+ public static void RunJob(
+ string jobType, WaitCallback callback, object obj, string name,
+ bool canRunInThisThread = false, bool mustNotTimeout = false,
+ bool log = false)
+ {
+ if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
+ {
+ Culture.SetCurrentCulture();
+ callback(obj);
+ return;
+ }
+
+ if (JobEngine.IsRunning)
+ JobEngine.QueueJob(name, () => callback(obj));
+ else if (canRunInThisThread)
+ callback(obj);
+ else if (mustNotTimeout)
+ RunInThread(callback, obj, name, log);
+ else
+ Util.FireAndForget(callback, obj, name);
+ }
+
+ private static void HandleControlCommand(string module, string[] args)
+ {
+ // if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
+ // return;
+
+ if (args.Length < 3)
+ {
+ MainConsole.Instance.Output("Usage: debug jobengine ");
+ return;
+ }
+
+ string subCommand = args[2];
+
+ if (subCommand == "stop")
+ {
+ JobEngine.Stop();
+ MainConsole.Instance.OutputFormat("Stopped job engine.");
+ }
+ else if (subCommand == "start")
+ {
+ JobEngine.Start();
+ MainConsole.Instance.OutputFormat("Started job engine.");
+ }
+ else if (subCommand == "status")
+ {
+ MainConsole.Instance.OutputFormat("Job engine running: {0}", JobEngine.IsRunning);
+
+ JobEngine.Job job = JobEngine.CurrentJob;
+ MainConsole.Instance.OutputFormat("Current job {0}", job != null ? job.Name : "none");
+
+ MainConsole.Instance.OutputFormat(
+ "Jobs waiting: {0}", JobEngine.IsRunning ? JobEngine.JobsWaiting.ToString() : "n/a");
+ MainConsole.Instance.OutputFormat("Log Level: {0}", JobEngine.LogLevel);
+ }
+ else if (subCommand == "log")
+ {
+ if (args.Length < 4)
+ {
+ MainConsole.Instance.Output("Usage: debug jobengine log ");
+ return;
+ }
+
+ // int logLevel;
+ int logLevel = int.Parse(args[3]);
+ // if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel))
+ // {
+ JobEngine.LogLevel = logLevel;
+ MainConsole.Instance.OutputFormat("Set debug log level to {0}", JobEngine.LogLevel);
+ // }
+ }
+ else
+ {
+ MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/OutboundUrlFilter.cs b/OpenSim/Framework/OutboundUrlFilter.cs
new file mode 100644
index 0000000..baa3647
--- /dev/null
+++ b/OpenSim/Framework/OutboundUrlFilter.cs
@@ -0,0 +1,256 @@
+/*
+ * 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.Linq;
+using System.Net;
+using System.Reflection;
+using log4net;
+using LukeSkywalker.IPNetwork;
+using Nini.Config;
+
+namespace OpenSim.Framework
+{
+ public class OutboundUrlFilter
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public string Name { get; private set; }
+
+ private List m_blacklistNetworks;
+ private List m_blacklistEndPoints;
+
+ private List m_blacklistExceptionNetworks;
+ private List m_blacklistExceptionEndPoints;
+
+ public OutboundUrlFilter(
+ string name,
+ List blacklistNetworks, List blacklistEndPoints,
+ List blacklistExceptionNetworks, List blacklistExceptionEndPoints)
+ {
+ Name = name;
+
+ m_blacklistNetworks = blacklistNetworks;
+ m_blacklistEndPoints = blacklistEndPoints;
+ m_blacklistExceptionNetworks = blacklistExceptionNetworks;
+ m_blacklistExceptionEndPoints = blacklistExceptionEndPoints;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Name of the filter for logging purposes.
+ /// Filter configuration
+ public OutboundUrlFilter(string name, IConfigSource config)
+ {
+ Name = name;
+
+ string configBlacklist
+ = "0.0.0.0/8|10.0.0.0/8|100.64.0.0/10|127.0.0.0/8|169.254.0.0/16|172.16.0.0/12|192.0.0.0/24|192.0.2.0/24|192.88.99.0/24|192.168.0.0/16|198.18.0.0/15|198.51.100.0/24|203.0.113.0/24|224.0.0.0/4|240.0.0.0/4|255.255.255.255/32";
+ string configBlacklistExceptions = "";
+
+ IConfig networkConfig = config.Configs["Network"];
+
+ if (networkConfig != null)
+ {
+ configBlacklist = networkConfig.GetString("OutboundDisallowForUserScripts", configBlacklist);
+ configBlacklistExceptions
+ = networkConfig.GetString("OutboundDisallowForUserScriptsExcept", configBlacklistExceptions);
+ }
+
+ m_log.DebugFormat(
+ "[OUTBOUND URL FILTER]: OutboundDisallowForUserScripts for {0} is [{1}]", Name, configBlacklist);
+ m_log.DebugFormat(
+ "[OUTBOUND URL FILTER]: OutboundDisallowForUserScriptsExcept for {0} is [{1}]", Name, configBlacklistExceptions);
+
+ OutboundUrlFilter.ParseConfigList(
+ configBlacklist, Name, out m_blacklistNetworks, out m_blacklistEndPoints);
+ OutboundUrlFilter.ParseConfigList(
+ configBlacklistExceptions, Name, out m_blacklistExceptionNetworks, out m_blacklistExceptionEndPoints);
+ }
+
+ private static void ParseConfigList(
+ string fullConfigEntry, string filterName, out List networks, out List endPoints)
+ {
+ // Parse blacklist
+ string[] configBlacklistEntries
+ = fullConfigEntry.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
+
+ configBlacklistEntries = configBlacklistEntries.Select(e => e.Trim()).ToArray();
+
+ networks = new List();
+ endPoints = new List();
+
+ foreach (string configEntry in configBlacklistEntries)
+ {
+ if (configEntry.Contains("/"))
+ {
+ IPNetwork network;
+
+ if (!IPNetwork.TryParse(configEntry, out network))
+ {
+ m_log.ErrorFormat(
+ "[OUTBOUND URL FILTER]: Entry [{0}] is invalid network for {1}", configEntry, filterName);
+
+ continue;
+ }
+
+ networks.Add(network);
+ }
+ else
+ {
+ Uri configEntryUri;
+
+ if (!Uri.TryCreate("http://" + configEntry, UriKind.Absolute, out configEntryUri))
+ {
+ m_log.ErrorFormat(
+ "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}",
+ configEntry, filterName);
+
+ continue;
+ }
+
+ IPAddress[] addresses = Dns.GetHostAddresses(configEntryUri.Host);
+
+ foreach (IPAddress addr in addresses)
+ {
+ if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
+ {
+ // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}] in config", addr);
+
+ IPEndPoint configEntryEp = new IPEndPoint(addr, configEntryUri.Port);
+ endPoints.Add(configEntryEp);
+
+ // m_log.DebugFormat("[OUTBOUND URL FILTER]: Added blacklist exception [{0}]", configEntryEp);
+ }
+ }
+ }
+ }
+ }
+
+ ///
+ /// Determines if an url is in a list of networks and endpoints.
+ ///
+ ///
+ /// IP address
+ ///
+ /// Networks.
+ /// End points.
+ /// Filter name.
+ private static bool IsInNetwork(
+ IPAddress addr, int port, List networks, List endPoints, string filterName)
+ {
+ foreach (IPNetwork ipn in networks)
+ {
+// m_log.DebugFormat(
+// "[OUTBOUND URL FILTER]: Checking [{0}] against network [{1}]", addr, ipn);
+
+ if (IPNetwork.Contains(ipn, addr))
+ {
+// m_log.DebugFormat(
+// "[OUTBOUND URL FILTER]: Found [{0}] in network [{1}]", addr, ipn);
+
+ return true;
+ }
+ }
+
+ // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr);
+
+ foreach (IPEndPoint ep in endPoints)
+ {
+// m_log.DebugFormat(
+// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]",
+// addr, port, ep);
+
+ if (addr.Equals(ep.Address) && port == ep.Port)
+ {
+// m_log.DebugFormat(
+// "[OUTBOUND URL FILTER]: Found [{0}:{1}] in endpoint [{2}]", addr, port, ep);
+
+ return true;
+ }
+ }
+
+// m_log.DebugFormat("[OUTBOUND URL FILTER]: Did not find [{0}:{1}] in list", addr, port);
+
+ return false;
+ }
+
+ ///
+ /// Checks whether the given url is allowed by the filter.
+ ///
+ ///
+ public bool CheckAllowed(Uri url)
+ {
+ bool allowed = true;
+
+ // Check that we are permitted to make calls to this endpoint.
+ bool foundIpv4Address = false;
+
+ IPAddress[] addresses = Dns.GetHostAddresses(url.Host);
+
+ foreach (IPAddress addr in addresses)
+ {
+ if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
+ {
+// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr);
+
+ foundIpv4Address = true;
+
+ // Check blacklist
+ if (OutboundUrlFilter.IsInNetwork(addr, url.Port, m_blacklistNetworks, m_blacklistEndPoints, Name))
+ {
+// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in blacklist for {1}", url, Name);
+
+ // Check blacklist exceptions
+ allowed
+ = OutboundUrlFilter.IsInNetwork(
+ addr, url.Port, m_blacklistExceptionNetworks, m_blacklistExceptionEndPoints, Name);
+
+// if (allowed)
+// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in whitelist for {1}", url, Name);
+ }
+ }
+
+ // Found at least one address in a blacklist and not a blacklist exception
+ if (!allowed)
+ return false;
+// else
+// m_log.DebugFormat("[OUTBOUND URL FILTER]: URL [{0}] not in blacklist for {1}", url, Name);
+ }
+
+ // We do not know how to handle IPv6 securely yet.
+ if (!foundIpv4Address)
+ return false;
+
+// m_log.DebugFormat("[OUTBOUND URL FILTER]: Allowing request [{0}]", url);
+
+ return allowed;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/PermissionsUtil.cs b/OpenSim/Framework/PermissionsUtil.cs
new file mode 100644
index 0000000..d785a78
--- /dev/null
+++ b/OpenSim/Framework/PermissionsUtil.cs
@@ -0,0 +1,87 @@
+/*
+ * 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;
+
+namespace OpenSim.Framework
+{
+ public static class PermissionsUtil
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Logs permissions flags. Useful when debugging permission problems.
+ ///
+ ///
+ public static void LogPermissions(String name, String message, uint basePerm, uint curPerm, uint nextPerm)
+ {
+ m_log.DebugFormat("Permissions of \"{0}\" at \"{1}\": Base {2} ({3:X4}), Current {4} ({5:X4}), NextOwner {6} ({7:X4})",
+ name, message,
+ PermissionsToString(basePerm), basePerm, PermissionsToString(curPerm), curPerm, PermissionsToString(nextPerm), nextPerm);
+ }
+
+ ///
+ /// Converts a permissions bit-mask to a string (e.g., "MCT").
+ ///
+ private static string PermissionsToString(uint perms)
+ {
+ string str = "";
+ if ((perms & (int)PermissionMask.Modify) != 0)
+ str += "M";
+ if ((perms & (int)PermissionMask.Copy) != 0)
+ str += "C";
+ if ((perms & (int)PermissionMask.Transfer) != 0)
+ str += "T";
+ if (str == "")
+ str = ".";
+ return str;
+ }
+
+ ///
+ /// Applies an object's folded permissions to its regular permissions.
+ ///
+ /// The folded permissions. Only the lowest 7 bits are examined.
+ /// The permissions variable to modify.
+ public static void ApplyFoldedPermissions(uint foldedPerms, ref uint mainPerms)
+ {
+ if ((foldedPerms & 7) == 0)
+ return; // assume that if the folded permissions are 0 then this means that they weren't actually recorded
+
+ if ((foldedPerms & ((uint)PermissionMask.Copy >> 13)) == 0)
+ mainPerms &= ~(uint)PermissionMask.Copy;
+ if ((foldedPerms & ((uint)PermissionMask.Transfer >> 13)) == 0)
+ mainPerms &= ~(uint)PermissionMask.Transfer;
+ if ((foldedPerms & ((uint)PermissionMask.Modify >> 13)) == 0)
+ mainPerms &= ~(uint)PermissionMask.Modify;
+ }
+
+ }
+}
diff --git a/OpenSim/Framework/PluginLoader.cs b/OpenSim/Framework/PluginLoader.cs
index 819cb7b..d12aa61 100644
--- a/OpenSim/Framework/PluginLoader.cs
+++ b/OpenSim/Framework/PluginLoader.cs
@@ -215,12 +215,12 @@ namespace OpenSim.Framework
AddinManager.AddinLoadError += on_addinloaderror_;
AddinManager.AddinLoaded += on_addinloaded_;
- clear_registry_();
+ //clear_registry_(dir);
- suppress_console_output_(true);
+ //suppress_console_output_(true);
AddinManager.Initialize(dir);
AddinManager.Registry.Update(null);
- suppress_console_output_(false);
+ //suppress_console_output_(false);
}
private void on_addinloaded_(object sender, AddinEventArgs args)
@@ -239,18 +239,19 @@ namespace OpenSim.Framework
+ args.Exception.StackTrace);
}
- private void clear_registry_()
+ private void clear_registry_(string dir)
{
// The Mono addin manager (in Mono.Addins.dll version 0.2.0.0)
// occasionally seems to corrupt its addin cache
// Hence, as a temporary solution we'll remove it before each startup
+
try
{
- if (Directory.Exists("addin-db-000"))
- Directory.Delete("addin-db-000", true);
+ if (Directory.Exists(dir + "/addin-db-000"))
+ Directory.Delete(dir + "/addin-db-000", true);
- if (Directory.Exists("addin-db-001"))
- Directory.Delete("addin-db-001", true);
+ if (Directory.Exists(dir + "/addin-db-001"))
+ Directory.Delete(dir + "/addin-db-001", true);
}
catch (IOException)
{
diff --git a/OpenSim/Framework/PluginManager.cs b/OpenSim/Framework/PluginManager.cs
index 00263f5..0117096 100644
--- a/OpenSim/Framework/PluginManager.cs
+++ b/OpenSim/Framework/PluginManager.cs
@@ -218,7 +218,7 @@ namespace OpenSim.Framework
Console.WriteLine ("Looking for updates...");
Repositories.UpdateAllRepositories (ps);
Console.WriteLine ("Available add-in updates:");
- bool found = false;
+
AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
foreach (AddinRepositoryEntry entry in entries)
@@ -541,7 +541,7 @@ namespace OpenSim.Framework
{
list.AddRange(PluginRegistry.GetAddins());
}
- catch(Exception e)
+ catch (Exception)
{
Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
return x;
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs
index 4c36819..c8a5376 100644
--- a/OpenSim/Framework/PrimitiveBaseShape.cs
+++ b/OpenSim/Framework/PrimitiveBaseShape.cs
@@ -105,6 +105,7 @@ namespace OpenSim.Framework
private ushort _profileHollow;
private Vector3 _scale;
private byte _state;
+ private byte _lastattach;
private ProfileShape _profileShape;
private HollowShape _hollowShape;
@@ -207,6 +208,7 @@ namespace OpenSim.Framework
PCode = (byte)prim.PrimData.PCode;
State = prim.PrimData.State;
+ LastAttachPoint = prim.PrimData.State;
PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd);
PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX);
@@ -583,6 +585,15 @@ namespace OpenSim.Framework
}
}
+ public byte LastAttachPoint {
+ get {
+ return _lastattach;
+ }
+ set {
+ _lastattach = value;
+ }
+ }
+
public ProfileShape ProfileShape {
get {
return _profileShape;
@@ -622,6 +633,8 @@ namespace OpenSim.Framework
}
}
+ // This is only used at runtime. For sculpties this holds the texture data, and for meshes
+ // the mesh data.
public byte[] SculptData
{
get
@@ -1147,14 +1160,13 @@ namespace OpenSim.Framework
public void ReadSculptData(byte[] data, int pos)
{
- byte[] SculptTextureUUID = new byte[16];
- UUID SculptUUID = UUID.Zero;
- byte SculptTypel = data[16+pos];
+ UUID SculptUUID;
+ byte SculptTypel;
- if (data.Length+pos >= 17)
+ if (data.Length-pos >= 17)
{
_sculptEntry = true;
- SculptTextureUUID = new byte[16];
+ byte[] SculptTextureUUID = new byte[16];
SculptTypel = data[16 + pos];
Array.Copy(data, pos, SculptTextureUUID,0, 16);
SculptUUID = new UUID(SculptTextureUUID, 0);
diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs
index a3089b0..7c6569e 100644
--- a/OpenSim/Framework/RegionFlags.cs
+++ b/OpenSim/Framework/RegionFlags.cs
@@ -48,6 +48,7 @@ namespace OpenSim.Framework
NoMove = 64, // Don't allow moving this region
Reservation = 128, // This is an inactive reservation
Authenticate = 256, // Require authentication
- Hyperlink = 512 // Record represents a HG link
+ Hyperlink = 512, // Record represents a HG link
+ DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only.
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs
index 016f2a6..79fbd96 100644
--- a/OpenSim/Framework/RegionInfo.cs
+++ b/OpenSim/Framework/RegionInfo.cs
@@ -99,9 +99,8 @@ namespace OpenSim.Framework
public class RegionInfo
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly string LogHeader = "[REGION INFO]";
- public bool commFailTF = false;
- public ConfigurationMember configMember;
public string RegionFile = String.Empty;
public bool isSandbox = false;
public bool Persistent = true;
@@ -126,8 +125,8 @@ namespace OpenSim.Framework
private int m_physPrimMax = 0;
private bool m_clampPrimSize = false;
private int m_objectCapacity = 0;
+ private int m_maxPrimsPerUser = -1;
private int m_linksetCapacity = 0;
- private int m_agentCapacity = 0;
private string m_regionType = String.Empty;
private RegionLightShareData m_windlight = new RegionLightShareData();
protected uint m_httpPort;
@@ -137,15 +136,41 @@ namespace OpenSim.Framework
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;
+ private UUID m_maptileStaticUUID = UUID.Zero;
- private Dictionary m_otherSettings = new Dictionary();
+ public uint WorldLocX = 0;
+ public uint WorldLocY = 0;
+ public uint WorldLocZ = 0;
+ ///
+ /// X dimension of the region.
+ ///
+ ///
+ /// If this is a varregion then the default size set here will be replaced when we load the region config.
+ ///
+ public uint RegionSizeX = Constants.RegionSize;
+
+ ///
+ /// X dimension of the region.
+ ///
+ ///
+ /// If this is a varregion then the default size set here will be replaced when we load the region config.
+ ///
+ public uint RegionSizeY = Constants.RegionSize;
+
+ ///
+ /// Z dimension of the region.
+ ///
+ ///
+ /// XXX: Unknown if this accounts for regions with negative Z.
+ ///
+ public uint RegionSizeZ = Constants.RegionHeight;
+
+ private Dictionary m_extraSettings = new Dictionary();
// Apparently, we're applying the same estatesettings regardless of whether it's local or remote.
@@ -197,7 +222,6 @@ namespace OpenSim.Framework
try
{
// This will throw if it's not legal Nini XML format
- // and thereby toss it to the legacy loader
//
IConfigSource xmlsource = new XmlConfigSource(filename);
@@ -210,29 +234,27 @@ namespace OpenSim.Framework
catch (Exception)
{
}
-
- configMember =
- new ConfigurationMember(filename, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig);
- configMember.performConfigurationRetrieve();
- RegionFile = filename;
}
// The web loader uses this
//
public RegionInfo(string description, XmlNode xmlNode, bool skipConsoleConfig, IConfigSource configSource)
{
- // m_configSource = configSource;
- configMember =
- new ConfigurationMember(xmlNode, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig);
- configMember.performConfigurationRetrieve();
+ XmlElement elem = (XmlElement)xmlNode;
+ string name = elem.GetAttribute("Name");
+ string xmlstr = "" + xmlNode.OuterXml + "";
+ XmlConfigSource source = new XmlConfigSource(XmlReader.Create(new StringReader(xmlstr)));
+ ReadNiniConfig(source, name);
+
m_serverURI = string.Empty;
}
- public RegionInfo(uint regionLocX, uint regionLocY, IPEndPoint internalEndPoint, string externalUri)
+ public RegionInfo(uint legacyRegionLocX, uint legacyRegionLocY, IPEndPoint internalEndPoint, string externalUri)
{
- m_regionLocX = regionLocX;
- m_regionLocY = regionLocY;
-
+ RegionLocX = legacyRegionLocX;
+ RegionLocY = legacyRegionLocY;
+ RegionSizeX = Constants.RegionSize;
+ RegionSizeY = Constants.RegionSize;
m_internalEndPoint = internalEndPoint;
m_externalHostName = externalUri;
m_serverURI = string.Empty;
@@ -318,16 +340,18 @@ namespace OpenSim.Framework
get { return m_objectCapacity; }
}
- public int LinksetCapacity
+ public int MaxPrimsPerUser
{
- get { return m_linksetCapacity; }
+ get { return m_maxPrimsPerUser; }
}
- public int AgentCapacity
+ public int LinksetCapacity
{
- get { return m_agentCapacity; }
+ get { return m_linksetCapacity; }
}
+ public int AgentCapacity { get; set; }
+
public byte AccessLevel
{
get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); }
@@ -338,6 +362,13 @@ namespace OpenSim.Framework
get { return m_regionType; }
}
+ public UUID MaptileStaticUUID
+ {
+ get { return m_maptileStaticUUID; }
+ }
+
+ public string MaptileStaticFile { get; private set; }
+
///
/// The port by which http communication occurs with the region (most noticeably, CAPS communication)
///
@@ -441,25 +472,42 @@ namespace OpenSim.Framework
///
/// The x co-ordinate of this region in map tiles (e.g. 1000).
+ /// Coordinate is scaled as world coordinates divided by the legacy region size
+ /// and is thus is the number of legacy regions.
///
public uint RegionLocX
{
- get { return m_regionLocX.Value; }
- set { m_regionLocX = value; }
+ get { return WorldLocX / Constants.RegionSize; }
+ set { WorldLocX = value * Constants.RegionSize; }
}
///
/// The y co-ordinate of this region in map tiles (e.g. 1000).
+ /// Coordinate is scaled as world coordinates divided by the legacy region size
+ /// and is thus is the number of legacy regions.
///
public uint RegionLocY
{
- get { return m_regionLocY.Value; }
- set { m_regionLocY = value; }
+ get { return WorldLocY / Constants.RegionSize; }
+ set { WorldLocY = value * Constants.RegionSize; }
+ }
+
+ public void SetDefaultRegionSize()
+ {
+ WorldLocX = 0;
+ WorldLocY = 0;
+ WorldLocZ = 0;
+ RegionSizeX = Constants.RegionSize;
+ RegionSizeY = Constants.RegionSize;
+ RegionSizeZ = Constants.RegionHeight;
}
+ // A unique region handle is created from the region's world coordinates.
+ // This cannot be changed because some code expects to receive the region handle and then
+ // compute the region coordinates from it.
public ulong RegionHandle
{
- get { return Util.UIntsToLong((RegionLocX * (uint) Constants.RegionSize), (RegionLocY * (uint) Constants.RegionSize)); }
+ get { return Util.UIntsToLong(WorldLocX, WorldLocY); }
}
public void SetEndPoint(string ipaddr, int port)
@@ -469,20 +517,20 @@ namespace OpenSim.Framework
m_internalEndPoint = tmpEPE;
}
- public string GetOtherSetting(string key)
+ public string GetSetting(string key)
{
string val;
string keylower = key.ToLower();
- if (m_otherSettings.TryGetValue(keylower, out val))
+ if (m_extraSettings.TryGetValue(keylower, out val))
return val;
m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key);
return null;
}
- public void SetOtherSetting(string key, string value)
+ private void SetExtraSetting(string key, string value)
{
string keylower = key.ToLower();
- m_otherSettings[keylower] = value;
+ m_extraSettings[keylower] = value;
}
private void ReadNiniConfig(IConfigSource source, string name)
@@ -566,8 +614,25 @@ namespace OpenSim.Framework
string[] locationElements = location.Split(new char[] {','});
- m_regionLocX = Convert.ToUInt32(locationElements[0]);
- m_regionLocY = Convert.ToUInt32(locationElements[1]);
+ RegionLocX = Convert.ToUInt32(locationElements[0]);
+ RegionLocY = Convert.ToUInt32(locationElements[1]);
+
+ // Region size
+ // Default to legacy region size if not specified.
+ allKeys.Remove("SizeX");
+ string configSizeX = config.GetString("SizeX", Constants.RegionSize.ToString());
+ config.Set("SizeX", configSizeX);
+ RegionSizeX = Convert.ToUInt32(configSizeX);
+ allKeys.Remove("SizeY");
+ string configSizeY = config.GetString("SizeY", Constants.RegionSize.ToString());
+ config.Set("SizeY", configSizeX);
+ RegionSizeY = Convert.ToUInt32(configSizeY);
+ allKeys.Remove("SizeZ");
+ string configSizeZ = config.GetString("SizeZ", Constants.RegionHeight.ToString());
+ config.Set("SizeZ", configSizeX);
+ RegionSizeZ = Convert.ToUInt32(configSizeZ);
+
+ DoRegionSizeSanityChecks();
// InternalAddress
//
@@ -641,7 +706,7 @@ namespace OpenSim.Framework
m_regionType = config.GetString("RegionType", String.Empty);
allKeys.Remove("RegionType");
- #region Prim stuff
+ #region Prim and map stuff
m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
allKeys.Remove("NonPhysicalPrimMin");
@@ -661,12 +726,25 @@ namespace OpenSim.Framework
m_objectCapacity = config.GetInt("MaxPrims", 15000);
allKeys.Remove("MaxPrims");
+ m_maxPrimsPerUser = config.GetInt("MaxPrimsPerUser", -1);
+ allKeys.Remove("MaxPrimsPerUser");
+
m_linksetCapacity = config.GetInt("LinksetPrims", 0);
allKeys.Remove("LinksetPrims");
+
+ allKeys.Remove("MaptileStaticUUID");
+ string mapTileStaticUUID = config.GetString("MaptileStaticUUID", UUID.Zero.ToString());
+ if (UUID.TryParse(mapTileStaticUUID.Trim(), out m_maptileStaticUUID))
+ {
+ config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
+ }
+
+ MaptileStaticFile = config.GetString("MaptileStaticFile", String.Empty);
+ allKeys.Remove("MaptileStaticFile");
#endregion
- m_agentCapacity = config.GetInt("MaxAgents", 100);
+ AgentCapacity = config.GetInt("MaxAgents", 100);
allKeys.Remove("MaxAgents");
// Multi-tenancy
@@ -676,7 +754,58 @@ namespace OpenSim.Framework
foreach (String s in allKeys)
{
- SetOtherSetting(s, config.GetString(s));
+ SetExtraSetting(s, config.GetString(s));
+ }
+ }
+
+ // Make sure user specified region sizes are sane.
+ // Must be multiples of legacy region size (256).
+ private void DoRegionSizeSanityChecks()
+ {
+ if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize)
+ {
+ // Doing non-legacy region sizes.
+ // Enforce region size to be multiples of the legacy region size (256)
+ uint partial = RegionSizeX % Constants.RegionSize;
+ if (partial != 0)
+ {
+ RegionSizeX -= partial;
+ if (RegionSizeX == 0)
+ RegionSizeX = Constants.RegionSize;
+ m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeX={3} instead of specified {4}",
+ LogHeader, Constants.RegionSize, m_regionName, RegionSizeX, RegionSizeX + partial);
+ }
+ partial = RegionSizeY % Constants.RegionSize;
+ if (partial != 0)
+ {
+ RegionSizeY -= partial;
+ if (RegionSizeY == 0)
+ RegionSizeY = Constants.RegionSize;
+ m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeY={3} instead of specified {4}",
+ LogHeader, Constants.RegionSize, m_regionName, RegionSizeY, RegionSizeY + partial);
+ }
+
+ // Because of things in the viewer, regions MUST be square.
+ // Remove this check when viewers have been updated.
+ if (RegionSizeX != RegionSizeY)
+ {
+ uint minSize = Math.Min(RegionSizeX, RegionSizeY);
+ RegionSizeX = minSize;
+ RegionSizeY = minSize;
+ m_log.ErrorFormat("{0} Regions must be square until viewers are updated. Forcing region {1} size to <{2},{3}>",
+ LogHeader, m_regionName, RegionSizeX, RegionSizeY);
+ }
+
+ // There is a practical limit to region size.
+ if (RegionSizeX > Constants.MaximumRegionSize || RegionSizeY > Constants.MaximumRegionSize)
+ {
+ RegionSizeX = Util.Clamp(RegionSizeX, Constants.RegionSize, Constants.MaximumRegionSize);
+ RegionSizeY = Util.Clamp(RegionSizeY, Constants.RegionSize, Constants.MaximumRegionSize);
+ m_log.ErrorFormat("{0} Region dimensions must be less than {1}. Clamping {2}'s size to <{3},{4}>",
+ LogHeader, Constants.MaximumRegionSize, m_regionName, RegionSizeX, RegionSizeY);
+ }
+
+ m_log.InfoFormat("{0} Region {1} size set to <{2},{3}>", LogHeader, m_regionName, RegionSizeX, RegionSizeY);
}
}
@@ -691,9 +820,18 @@ namespace OpenSim.Framework
config.Set("RegionUUID", RegionID.ToString());
- string location = String.Format("{0},{1}", m_regionLocX, m_regionLocY);
+ string location = String.Format("{0},{1}", RegionLocX, RegionLocY);
config.Set("Location", location);
+ if (RegionSizeX > 0)
+ config.Set("SizeX", RegionSizeX);
+
+ if (RegionSizeY > 0)
+ config.Set("SizeY", RegionSizeY);
+
+// if (RegionSizeZ > 0)
+// config.Set("SizeZ", RegionSizeZ);
+
config.Set("InternalAddress", m_internalEndPoint.Address.ToString());
config.Set("InternalPort", m_internalEndPoint.Port);
@@ -718,22 +856,26 @@ namespace OpenSim.Framework
if (m_objectCapacity > 0)
config.Set("MaxPrims", m_objectCapacity);
+ if (m_maxPrimsPerUser > -1)
+ config.Set("MaxPrimsPerUser", m_maxPrimsPerUser);
+
if (m_linksetCapacity > 0)
config.Set("LinksetPrims", m_linksetCapacity);
- if (m_agentCapacity > 0)
- config.Set("MaxAgents", m_agentCapacity);
+ if (AgentCapacity > 0)
+ config.Set("MaxAgents", AgentCapacity);
if (ScopeID != UUID.Zero)
config.Set("ScopeID", ScopeID.ToString());
if (RegionType != String.Empty)
config.Set("RegionType", RegionType);
- }
- public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result)
- {
- return true;
+ if (m_maptileStaticUUID != UUID.Zero)
+ config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
+
+ if (MaptileStaticFile != null && MaptileStaticFile != String.Empty)
+ config.Set("MaptileStaticFile", MaptileStaticFile);
}
public void SaveRegionToFile(string description, string filename)
@@ -755,215 +897,14 @@ namespace OpenSim.Framework
return;
}
- else if (filename.ToLower().EndsWith(".xml"))
- {
- configMember = new ConfigurationMember(filename, description, loadConfigurationOptionsFromMe,
- ignoreIncomingConfiguration, false);
- configMember.performConfigurationRetrieve();
- RegionFile = filename;
- }
else
throw new Exception("Invalid file type for region persistence.");
}
- public void loadConfigurationOptionsFromMe()
- {
- configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE,
- "UUID of Region (Default is recommended, random UUID)",
- RegionID.ToString(), true);
- configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "Region Name", RegionName, true);
- configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
- "Grid Location (X Axis)", m_regionLocX.ToString(), true);
- configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
- "Grid Location (Y Axis)", m_regionLocY.ToString(), true);
- //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false);
- configMember.addConfigurationOption("internal_ip_address",
- ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS,
- "Internal IP Address for incoming UDP client connections",
- m_internalEndPoint.Address.ToString(),
- true);
- configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Internal IP Port for incoming UDP client connections",
- m_internalEndPoint.Port.ToString(), true);
- configMember.addConfigurationOption("allow_alternate_ports",
- ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
- "Allow sim to find alternate UDP ports when ports are in use?",
- m_allow_alternate_ports.ToString(), true);
- configMember.addConfigurationOption("external_host_name",
- ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "External Host Name", m_externalHostName, true);
- configMember.addConfigurationOption("lastmap_uuid", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
- "Last Map UUID", lastMapUUID.ToString(), true);
- configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
-
- configMember.addConfigurationOption("nonphysical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
- "Minimum size for nonphysical prims", m_nonphysPrimMin.ToString(), true);
-
- configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true);
-
- configMember.addConfigurationOption("physical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
- "Minimum size for nonphysical prims", m_physPrimMin.ToString(), true);
-
- configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Maximum size for physical prims", m_physPrimMax.ToString(), true);
-
- configMember.addConfigurationOption("clamp_prim_size", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
- "Clamp prims to max size", m_clampPrimSize.ToString(), true);
-
- configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Max objects this sim will hold", m_objectCapacity.ToString(), true);
-
- configMember.addConfigurationOption("linkset_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Max prims an object will hold", m_linksetCapacity.ToString(), true);
-
- configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Max avatars this sim will hold", m_agentCapacity.ToString(), true);
-
- configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
- "Scope ID for this region", ScopeID.ToString(), true);
-
- configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
- "Free form string describing the type of region", String.Empty, true);
- }
-
- public void loadConfigurationOptions()
- {
- configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
- "UUID of Region (Default is recommended, random UUID)",
- UUID.Random().ToString(), true);
- configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "Region Name", "OpenSim Test", false);
- configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
- "Grid Location (X Axis)", "1000", false);
- configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
- "Grid Location (Y Axis)", "1000", false);
- //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false);
- configMember.addConfigurationOption("internal_ip_address",
- ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS,
- "Internal IP Address for incoming UDP client connections", "0.0.0.0",
- false);
- configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Internal IP Port for incoming UDP client connections",
- ConfigSettings.DefaultRegionHttpPort.ToString(), false);
- configMember.addConfigurationOption("allow_alternate_ports", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
- "Allow sim to find alternate UDP ports when ports are in use?",
- "false", true);
- configMember.addConfigurationOption("external_host_name",
- ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "External Host Name", "127.0.0.1", false);
- configMember.addConfigurationOption("lastmap_uuid", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
- "Last Map UUID", lastMapUUID.ToString(), true);
-
- configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
- "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
-
- configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Maximum size for nonphysical prims", "0", true);
-
- configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Maximum size for physical prims", "0", true);
-
- configMember.addConfigurationOption("clamp_prim_size", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
- "Clamp prims to max size", "false", true);
-
- configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Max objects this sim will hold", "15000", true);
-
- configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
- "Max avatars this sim will hold", "100", true);
-
- configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
- "Scope ID for this region", UUID.Zero.ToString(), true);
-
- configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
- "Region Type", String.Empty, true);
- }
-
- public bool handleIncomingConfiguration(string configuration_key, object configuration_result)
- {
- switch (configuration_key)
- {
- case "sim_UUID":
- RegionID = (UUID) configuration_result;
- originRegionID = (UUID) configuration_result;
- break;
- case "sim_name":
- RegionName = (string) configuration_result;
- break;
- case "sim_location_x":
- m_regionLocX = (uint) configuration_result;
- break;
- case "sim_location_y":
- m_regionLocY = (uint) configuration_result;
- break;
- case "internal_ip_address":
- IPAddress address = (IPAddress) configuration_result;
- m_internalEndPoint = new IPEndPoint(address, 0);
- break;
- case "internal_ip_port":
- m_internalEndPoint.Port = (int) configuration_result;
- break;
- case "allow_alternate_ports":
- m_allow_alternate_ports = (bool) configuration_result;
- break;
- case "external_host_name":
- if ((string) configuration_result != "SYSTEMIP")
- {
- m_externalHostName = (string) configuration_result;
- }
- else
- {
- m_externalHostName = Util.GetLocalHost().ToString();
- }
- break;
- case "lastmap_uuid":
- lastMapUUID = (UUID)configuration_result;
- break;
- case "lastmap_refresh":
- lastMapRefresh = (string)configuration_result;
- break;
- case "nonphysical_prim_max":
- m_nonphysPrimMax = (int)configuration_result;
- break;
- case "physical_prim_max":
- m_physPrimMax = (int)configuration_result;
- break;
- case "clamp_prim_size":
- m_clampPrimSize = (bool)configuration_result;
- break;
- case "object_capacity":
- m_objectCapacity = (int)configuration_result;
- break;
- case "linkset_capacity":
- m_linksetCapacity = (int)configuration_result;
- break;
- case "agent_capacity":
- m_agentCapacity = (int)configuration_result;
- break;
- case "scope_id":
- ScopeID = (UUID)configuration_result;
- break;
- case "region_type":
- m_regionType = (string)configuration_result;
- break;
- }
-
- return true;
- }
-
public void SaveLastMapUUID(UUID mapUUID)
{
lastMapUUID = mapUUID;
lastMapRefresh = Util.UnixTimeSinceEpoch().ToString();
-
- if (configMember == null)
- return;
-
- configMember.forceSetConfigurationOption("lastmap_uuid", mapUUID.ToString());
- configMember.forceSetConfigurationOption("lastmap_refresh", lastMapRefresh);
}
public OSDMap PackRegionInfoData()
@@ -975,8 +916,13 @@ namespace OpenSim.Framework
args["external_host_name"] = OSD.FromString(ExternalHostName);
args["http_port"] = OSD.FromString(HttpPort.ToString());
args["server_uri"] = OSD.FromString(ServerURI);
+
args["region_xloc"] = OSD.FromString(RegionLocX.ToString());
args["region_yloc"] = OSD.FromString(RegionLocY.ToString());
+ args["region_size_x"] = OSD.FromString(RegionSizeX.ToString());
+ args["region_size_y"] = OSD.FromString(RegionSizeY.ToString());
+ args["region_size_z"] = OSD.FromString(RegionSizeZ.ToString());
+
args["internal_ep_address"] = OSD.FromString(InternalEndPoint.Address.ToString());
args["internal_ep_port"] = OSD.FromString(InternalEndPoint.Port.ToString());
if ((RemotingAddress != null) && !RemotingAddress.Equals(""))
@@ -1015,6 +961,13 @@ namespace OpenSim.Framework
UInt32.TryParse(args["region_yloc"].AsString(), out locy);
RegionLocY = locy;
}
+ if (args.ContainsKey("region_size_x"))
+ RegionSizeX = (uint)args["region_size_x"].AsInteger();
+ if (args.ContainsKey("region_size_y"))
+ RegionSizeY = (uint)args["region_size_y"].AsInteger();
+ if (args.ContainsKey("region_size_z"))
+ RegionSizeZ = (uint)args["region_size_z"].AsInteger();
+
IPAddress ip_addr = null;
if (args["internal_ep_address"] != null)
{
@@ -1051,23 +1004,5 @@ namespace OpenSim.Framework
regionInfo.ServerURI = serverURI;
return regionInfo;
}
-
- public Dictionary ToKeyValuePairs()
- {
- Dictionary kvp = new Dictionary();
- 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;
- }
}
}
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
deleted file mode 100644
index d670f2f..0000000
--- a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("OpenSim.Framework.RegionLoader.Filesystem")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("http://opensimulator.org")]
-[assembly: AssemblyProduct("OpenSim")]
-[assembly: AssemblyCopyright("OpenSimulator developers")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("4ab5c74b-e886-40a1-b67d-a04df285e706")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs b/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs
deleted file mode 100644
index 8332c14..0000000
--- a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * 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 log4net;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using Nini.Config;
-
-namespace OpenSim.Framework.RegionLoader.Filesystem
-{
- public class RegionLoaderFileSystem : IRegionLoader
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- private IConfigSource m_configSource;
-
- public void SetIniConfigSource(IConfigSource configSource)
- {
- m_configSource = configSource;
- }
-
- public RegionInfo[] LoadRegions()
- {
- string regionConfigPath = Path.Combine(Util.configDir(), "Regions");
- bool allowRegionless = false;
-
- try
- {
- IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"];
- regionConfigPath = startupConfig.GetString("regionload_regionsdir", regionConfigPath).Trim();
- allowRegionless = startupConfig.GetBoolean("allow_regionless", false);
- }
- catch (Exception)
- {
- // No INI setting recorded.
- }
-
- if (!Directory.Exists(regionConfigPath))
- {
- Directory.CreateDirectory(regionConfigPath);
- }
-
- string[] configFiles = Directory.GetFiles(regionConfigPath, "*.xml");
- string[] iniFiles = Directory.GetFiles(regionConfigPath, "*.ini");
-
- // Create an empty Regions.ini if there are no existing config files.
- if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0)
- {
- new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource);
- iniFiles = Directory.GetFiles(regionConfigPath, "*.ini");
- }
-
- m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config files from {0}", regionConfigPath);
-
- List regionInfos = new List();
-
- int i = 0;
- foreach (string file in iniFiles)
- {
- m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file);
-
- IConfigSource source = new IniConfigSource(file);
-
- foreach (IConfig config in source.Configs)
- {
- RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource, config.Name);
- regionInfos.Add(regionInfo);
-
- m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName);
-
- i++;
- }
- }
-
- foreach (string file in configFiles)
- {
- m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file);
-
- RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource);
- regionInfos.Add(regionInfo);
-
- m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName);
-
- i++;
- }
-
- return regionInfos.ToArray();
- }
- }
-}
\ No newline at end of file
diff --git a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
deleted file mode 100644
index 7309a12..0000000
--- a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,33 +0,0 @@
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("OpenSim.Framework.RegionLoader.Web")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("http://opensimulator.org")]
-[assembly: AssemblyProduct("OpenSim")]
-[assembly: AssemblyCopyright("OpenSimulator developers")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Setting ComVisible to false makes the types in this assembly not visible
-// to COM components. If you need to access a type in this assembly from
-// COM, set the ComVisible attribute to true on that type.
-[assembly: ComVisible(false)]
-
-// The following GUID is for the ID of the typelib if this project is exposed to COM
-[assembly: Guid("985afff8-e7ed-4056-acce-39abf7a43d33")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs
deleted file mode 100644
index a2f5d9c..0000000
--- a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * 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.IO;
-using System.Net;
-using System.Reflection;
-using System.Xml;
-using log4net;
-using Nini.Config;
-
-namespace OpenSim.Framework.RegionLoader.Web
-{
- public class RegionLoaderWebServer : IRegionLoader
- {
- private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
-
- private IConfigSource m_configSource;
-
- public void SetIniConfigSource(IConfigSource configSource)
- {
- m_configSource = configSource;
- }
-
- public RegionInfo[] LoadRegions()
- {
- if (m_configSource == null)
- {
- m_log.Error("[WEBLOADER]: Unable to load configuration source!");
- return null;
- }
- else
- {
- IConfig startupConfig = (IConfig) m_configSource.Configs["Startup"];
- string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim();
- bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false);
-
- if (url == String.Empty)
- {
- m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty.");
- return null;
- }
- else
- {
- RegionInfo[] regionInfos = new RegionInfo[] {};
- int regionCount = 0;
- HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url);
- webRequest.Timeout = 30000; //30 Second Timeout
- m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url);
-
- try
- {
- HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse();
- m_log.Debug("[WEBLOADER]: Downloading region information...");
- StreamReader reader = new StreamReader(webResponse.GetResponseStream());
- string xmlSource = String.Empty;
- string tempStr = reader.ReadLine();
- while (tempStr != null)
- {
- xmlSource = xmlSource + tempStr;
- tempStr = reader.ReadLine();
- }
- m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " +
- xmlSource.Length);
- XmlDocument xmlDoc = new XmlDocument();
- xmlDoc.LoadXml(xmlSource);
- if (xmlDoc.FirstChild.Name == "Regions")
- {
- regionCount = xmlDoc.FirstChild.ChildNodes.Count;
-
- if (regionCount > 0)
- {
- regionInfos = new RegionInfo[regionCount];
- int i;
- for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++)
- {
- m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml);
- regionInfos[i] =
- new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource);
- }
- }
- }
- }
- catch (WebException ex)
- {
- if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound)
- {
- if (!allowRegionless)
- throw ex;
- }
- else
- throw ex;
- }
-
- if (regionCount > 0 | allowRegionless)
- return regionInfos;
- else
- {
- m_log.Error("[WEBLOADER]: No region configs were available.");
- return null;
- }
- }
- }
- }
- }
-}
diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs
index 47dbcec..a895c40 100644
--- a/OpenSim/Framework/RegionSettings.cs
+++ b/OpenSim/Framework/RegionSettings.cs
@@ -200,7 +200,7 @@ namespace OpenSim.Framework
set { m_ObjectBonus = value; }
}
- private int m_Maturity = 1;
+ private int m_Maturity = 0;
public int Maturity
{
@@ -482,21 +482,14 @@ namespace OpenSim.Framework
set { m_LoadedCreationID = value; }
}
- // Connected Telehub object
- private UUID m_TelehubObject = UUID.Zero;
- public UUID TelehubObject
- {
- get
- {
- return m_TelehubObject;
- }
- set
- {
- m_TelehubObject = value;
- }
- }
+ ///
+ /// Connected Telehub object
+ ///
+ public UUID TelehubObject { get; set; }
- // Our Connected Telehub's SpawnPoints
+ ///
+ /// Our connected Telehub's SpawnPoints
+ ///
public List l_SpawnPoints = new List();
// Add a SpawnPoint
diff --git a/OpenSim/Framework/RestClient.cs b/OpenSim/Framework/RestClient.cs
new file mode 100644
index 0000000..7080ca5
--- /dev/null
+++ b/OpenSim/Framework/RestClient.cs
@@ -0,0 +1,676 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Reflection;
+using System.Text;
+using System.Threading;
+using System.Web;
+using log4net;
+
+using OpenSim.Framework.ServiceAuth;
+
+namespace OpenSim.Framework
+{
+ ///
+ /// Implementation of a generic REST client
+ ///
+ ///
+ /// This class is a generic implementation of a REST (Representational State Transfer) web service. This
+ /// class is designed to execute both synchronously and asynchronously.
+ ///
+ /// Internally the implementation works as a two stage asynchronous web-client.
+ /// When the request is initiated, RestClient will query asynchronously for for a web-response,
+ /// sleeping until the initial response is returned by the server. Once the initial response is retrieved
+ /// the second stage of asynchronous requests will be triggered, in an attempt to read of the response
+ /// object into a memorystream as a sequence of asynchronous reads.
+ ///
+ /// The asynchronisity of RestClient is designed to move as much processing into the back-ground, allowing
+ /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be
+ /// invoked by the caller in either synchronous mode or asynchronous modes.
+ ///
+ public class RestClient : IDisposable
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ // private string realuri;
+
+ #region member variables
+
+ ///
+ /// The base Uri of the web-service e.g. http://www.google.com
+ ///
+ private string _url;
+
+ ///
+ /// Path elements of the query
+ ///
+ private List _pathElements = new List();
+
+ ///
+ /// Parameter elements of the query, e.g. min=34
+ ///
+ private Dictionary _parameterElements = new Dictionary();
+
+ ///
+ /// Request method. E.g. GET, POST, PUT or DELETE
+ ///
+ private string _method;
+
+ ///
+ /// Temporary buffer used to store bytes temporarily as they come in from the server
+ ///
+ private byte[] _readbuf;
+
+ ///
+ /// MemoryStream representing the resulting resource
+ ///
+ private Stream _resource;
+
+ ///
+ /// WebRequest object, held as a member variable
+ ///
+ private HttpWebRequest _request;
+
+ ///
+ /// WebResponse object, held as a member variable, so we can close it
+ ///
+ private HttpWebResponse _response;
+
+ ///
+ /// This flag will help block the main synchroneous method, in case we run in synchroneous mode
+ ///
+ //public static ManualResetEvent _allDone = new ManualResetEvent(false);
+
+ ///
+ /// Default time out period
+ ///
+ //private const int DefaultTimeout = 10*1000; // 10 seconds timeout
+
+ ///
+ /// Default Buffer size of a block requested from the web-server
+ ///
+ private const int BufferSize = 4096; // Read blocks of 4 KB.
+
+
+ ///
+ /// if an exception occours during async processing, we need to save it, so it can be
+ /// rethrown on the primary thread;
+ ///
+ private Exception _asyncException;
+
+ #endregion member variables
+
+ #region constructors
+
+ ///
+ /// Instantiate a new RestClient
+ ///
+ /// Web-service to query, e.g. http://osgrid.org:8003
+ public RestClient(string url)
+ {
+ _url = url;
+ _readbuf = new byte[BufferSize];
+ _resource = new MemoryStream();
+ _request = null;
+ _response = null;
+ _lock = new object();
+ }
+
+ private object _lock;
+
+ #endregion constructors
+
+
+ #region Dispose
+
+ private bool disposed = false;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposed)
+ return;
+
+ if (disposing)
+ {
+ _resource.Dispose();
+ }
+
+ disposed = true;
+ }
+
+ #endregion Dispose
+
+
+ ///
+ /// Add a path element to the query, e.g. assets
+ ///
+ /// path entry
+ public void AddResourcePath(string element)
+ {
+ if (isSlashed(element))
+ _pathElements.Add(element.Substring(0, element.Length - 1));
+ else
+ _pathElements.Add(element);
+ }
+
+ ///
+ /// Add a query parameter to the Url
+ ///
+ /// Name of the parameter, e.g. min
+ /// Value of the parameter, e.g. 42
+ public void AddQueryParameter(string name, string value)
+ {
+ try
+ {
+ _parameterElements.Add(HttpUtility.UrlEncode(name), HttpUtility.UrlEncode(value));
+ }
+ catch (ArgumentException)
+ {
+ m_log.Error("[REST]: Query parameter " + name + " is already added.");
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e);
+ }
+ }
+
+ ///
+ /// Add a query parameter to the Url
+ ///
+ /// Name of the parameter, e.g. min
+ public void AddQueryParameter(string name)
+ {
+ try
+ {
+ _parameterElements.Add(HttpUtility.UrlEncode(name), null);
+ }
+ catch (ArgumentException)
+ {
+ m_log.Error("[REST]: Query parameter " + name + " is already added.");
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[REST]: An exception was raised adding query parameter to dictionary. Exception: {0}",e);
+ }
+ }
+
+ ///
+ /// Web-Request method, e.g. GET, PUT, POST, DELETE
+ ///
+ public string RequestMethod
+ {
+ get { return _method; }
+ set { _method = value; }
+ }
+
+ ///
+ /// True if string contains a trailing slash '/'
+ ///
+ /// string to be examined
+ /// true if slash is present
+ private static bool isSlashed(string s)
+ {
+ return s.Substring(s.Length - 1, 1) == "/";
+ }
+
+ ///
+ /// Build a Uri based on the initial Url, path elements and parameters
+ ///
+ /// fully constructed Uri
+ private Uri buildUri()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append(_url);
+
+ foreach (string e in _pathElements)
+ {
+ sb.Append("/");
+ sb.Append(e);
+ }
+
+ bool firstElement = true;
+ foreach (KeyValuePair kv in _parameterElements)
+ {
+ if (firstElement)
+ {
+ sb.Append("?");
+ firstElement = false;
+ }
+ else
+ sb.Append("&");
+
+ sb.Append(kv.Key);
+ if (!string.IsNullOrEmpty(kv.Value))
+ {
+ sb.Append("=");
+ sb.Append(kv.Value);
+ }
+ }
+ // realuri = sb.ToString();
+ //m_log.InfoFormat("[REST CLIENT]: RestURL: {0}", realuri);
+ return new Uri(sb.ToString());
+ }
+
+ #region Async communications with server
+
+ ///
+ /// Async method, invoked when a block of data has been received from the service
+ ///
+ ///
+ private void StreamIsReadyDelegate(IAsyncResult ar)
+ {
+ try
+ {
+ Stream s = (Stream) ar.AsyncState;
+ int read = s.EndRead(ar);
+
+ if (read > 0)
+ {
+ _resource.Write(_readbuf, 0, read);
+ // IAsyncResult asynchronousResult =
+ // s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s);
+ s.BeginRead(_readbuf, 0, BufferSize, new AsyncCallback(StreamIsReadyDelegate), s);
+
+ // TODO! Implement timeout, without killing the server
+ //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
+ }
+ else
+ {
+ s.Close();
+ //_allDone.Set();
+ }
+ }
+ catch (Exception e)
+ {
+ //_allDone.Set();
+ _asyncException = e;
+ }
+ }
+
+ #endregion Async communications with server
+
+ ///
+ /// Perform a synchronous request
+ ///
+ public Stream Request()
+ {
+ return Request(null);
+ }
+
+ ///
+ /// Perform a synchronous request
+ ///
+ public Stream Request(IServiceAuth auth)
+ {
+ lock (_lock)
+ {
+ _request = (HttpWebRequest) WebRequest.Create(buildUri());
+ _request.KeepAlive = false;
+ _request.ContentType = "application/xml";
+ _request.Timeout = 200000;
+ _request.Method = RequestMethod;
+ _asyncException = null;
+ if (auth != null)
+ auth.AddAuthorization(_request.Headers);
+
+ int reqnum = WebUtil.RequestNumber++;
+ if (WebUtil.DebugLevel >= 3)
+ m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
+
+// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
+
+ try
+ {
+ using (_response = (HttpWebResponse) _request.GetResponse())
+ {
+ using (Stream src = _response.GetResponseStream())
+ {
+ int length = src.Read(_readbuf, 0, BufferSize);
+ while (length > 0)
+ {
+ _resource.Write(_readbuf, 0, length);
+ length = src.Read(_readbuf, 0, BufferSize);
+ }
+
+ // TODO! Implement timeout, without killing the server
+ // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
+ //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
+
+ // _allDone.WaitOne();
+ }
+ }
+ }
+ catch (WebException e)
+ {
+ using (HttpWebResponse errorResponse = e.Response as HttpWebResponse)
+ {
+ if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
+ {
+ // This is often benign. E.g., requesting a missing asset will return 404.
+ m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString());
+ }
+ else
+ {
+ m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e);
+ }
+ }
+
+ return null;
+ }
+
+ if (_asyncException != null)
+ throw _asyncException;
+
+ if (_resource != null)
+ {
+ _resource.Flush();
+ _resource.Seek(0, SeekOrigin.Begin);
+ }
+
+ if (WebUtil.DebugLevel >= 5)
+ WebUtil.LogResponseDetail(reqnum, _resource);
+
+ return _resource;
+ }
+ }
+
+ public Stream Request(Stream src, IServiceAuth auth)
+ {
+ _request = (HttpWebRequest) WebRequest.Create(buildUri());
+ _request.KeepAlive = false;
+ _request.ContentType = "application/xml";
+ _request.Timeout = 900000;
+ _request.Method = RequestMethod;
+ _asyncException = null;
+ _request.ContentLength = src.Length;
+ if (auth != null)
+ auth.AddAuthorization(_request.Headers);
+
+ src.Seek(0, SeekOrigin.Begin);
+
+ int reqnum = WebUtil.RequestNumber++;
+ if (WebUtil.DebugLevel >= 3)
+ m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
+ if (WebUtil.DebugLevel >= 5)
+ WebUtil.LogOutgoingDetail(string.Format("SEND {0}: ", reqnum), src);
+
+ Stream dst = _request.GetRequestStream();
+
+ byte[] buf = new byte[1024];
+ int length = src.Read(buf, 0, 1024);
+ while (length > 0)
+ {
+ dst.Write(buf, 0, length);
+ length = src.Read(buf, 0, 1024);
+ }
+
+ try
+ {
+ _response = (HttpWebResponse)_request.GetResponse();
+ }
+ catch (WebException e)
+ {
+ m_log.WarnFormat("[REST]: Request {0} {1} failed with status {2} and message {3}",
+ RequestMethod, _request.RequestUri, e.Status, e.Message);
+ return null;
+ }
+ catch (Exception e)
+ {
+ m_log.WarnFormat(
+ "[REST]: Request {0} {1} failed with exception {2} {3}",
+ RequestMethod, _request.RequestUri, e.Message, e.StackTrace);
+ return null;
+ }
+
+ if (WebUtil.DebugLevel >= 5)
+ {
+ using (Stream responseStream = _response.GetResponseStream())
+ {
+ using (StreamReader reader = new StreamReader(responseStream))
+ {
+ string responseStr = reader.ReadToEnd();
+ WebUtil.LogResponseDetail(reqnum, responseStr);
+ }
+ }
+ }
+
+ _response.Close();
+
+// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
+
+ // TODO! Implement timeout, without killing the server
+ // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
+ //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
+
+ return null;
+ }
+
+ #region Async Invocation
+
+ public IAsyncResult BeginRequest(AsyncCallback callback, object state)
+ {
+ ///
+ /// In case, we are invoked asynchroneously this object will keep track of the state
+ ///
+ AsyncResult ar = new AsyncResult(callback, state);
+ Util.FireAndForget(RequestHelper, ar, "RestClient.BeginRequest");
+ return ar;
+ }
+
+ public Stream EndRequest(IAsyncResult asyncResult)
+ {
+ AsyncResult ar = (AsyncResult) asyncResult;
+
+ // Wait for operation to complete, then return result or
+ // throw exception
+ return ar.EndInvoke();
+ }
+
+ private void RequestHelper(Object asyncResult)
+ {
+ // We know that it's really an AsyncResult object
+ AsyncResult ar = (AsyncResult) asyncResult;
+ try
+ {
+ // Perform the operation; if sucessful set the result
+ Stream s = Request(null);
+ ar.SetAsCompleted(s, false);
+ }
+ catch (Exception e)
+ {
+ // If operation fails, set the exception
+ ar.HandleException(e, false);
+ }
+ }
+
+ #endregion Async Invocation
+ }
+
+ internal class SimpleAsyncResult : IAsyncResult
+ {
+ private readonly AsyncCallback m_callback;
+
+ ///
+ /// Is process completed?
+ ///
+ /// Should really be boolean, but VolatileRead has no boolean method
+ private byte m_completed;
+
+ ///
+ /// Did process complete synchronously?
+ ///
+ /// I have a hard time imagining a scenario where this is the case, again, same issue about
+ /// booleans and VolatileRead as m_completed
+ ///
+ private byte m_completedSynchronously;
+
+ private readonly object m_asyncState;
+ private ManualResetEvent m_waitHandle;
+ private Exception m_exception;
+
+ internal SimpleAsyncResult(AsyncCallback cb, object state)
+ {
+ m_callback = cb;
+ m_asyncState = state;
+ m_completed = 0;
+ m_completedSynchronously = 1;
+ }
+
+ #region IAsyncResult Members
+
+ public object AsyncState
+ {
+ get { return m_asyncState; }
+ }
+
+ public WaitHandle AsyncWaitHandle
+ {
+ get
+ {
+ if (m_waitHandle == null)
+ {
+ bool done = IsCompleted;
+ ManualResetEvent mre = new ManualResetEvent(done);
+ if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null)
+ {
+ mre.Close();
+ }
+ else
+ {
+ if (!done && IsCompleted)
+ {
+ m_waitHandle.Set();
+ }
+ }
+ }
+
+ return m_waitHandle;
+ }
+ }
+
+
+ public bool CompletedSynchronously
+ {
+ get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; }
+ }
+
+
+ public bool IsCompleted
+ {
+ get { return Thread.VolatileRead(ref m_completed) == 1; }
+ }
+
+ #endregion
+
+ #region class Methods
+
+ internal void SetAsCompleted(bool completedSynchronously)
+ {
+ m_completed = 1;
+ if (completedSynchronously)
+ m_completedSynchronously = 1;
+ else
+ m_completedSynchronously = 0;
+
+ SignalCompletion();
+ }
+
+ internal void HandleException(Exception e, bool completedSynchronously)
+ {
+ m_completed = 1;
+ if (completedSynchronously)
+ m_completedSynchronously = 1;
+ else
+ m_completedSynchronously = 0;
+ m_exception = e;
+
+ SignalCompletion();
+ }
+
+ private void SignalCompletion()
+ {
+ if (m_waitHandle != null) m_waitHandle.Set();
+
+ if (m_callback != null) m_callback(this);
+ }
+
+ public void EndInvoke()
+ {
+ // This method assumes that only 1 thread calls EndInvoke
+ if (!IsCompleted)
+ {
+ // If the operation isn't done, wait for it
+ AsyncWaitHandle.WaitOne();
+ AsyncWaitHandle.Close();
+ m_waitHandle.Close();
+ m_waitHandle = null; // Allow early GC
+ }
+
+ // Operation is done: if an exception occured, throw it
+ if (m_exception != null) throw m_exception;
+ }
+
+ #endregion
+ }
+
+ internal class AsyncResult : SimpleAsyncResult
+ {
+ private T m_result = default(T);
+
+ public AsyncResult(AsyncCallback asyncCallback, Object state) :
+ base(asyncCallback, state)
+ {
+ }
+
+ public void SetAsCompleted(T result, bool completedSynchronously)
+ {
+ // Save the asynchronous operation's result
+ m_result = result;
+
+ // Tell the base class that the operation completed
+ // sucessfully (no exception)
+ base.SetAsCompleted(completedSynchronously);
+ }
+
+ public new T EndInvoke()
+ {
+ base.EndInvoke();
+ return m_result;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs
index 537de7a..e66d5be 100644
--- a/OpenSim/Framework/SLUtil.cs
+++ b/OpenSim/Framework/SLUtil.cs
@@ -25,13 +25,9 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+using OpenMetaverse;
using System;
using System.Collections.Generic;
-using System.IO;
-using System.Reflection;
-using System.Xml;
-using log4net;
-using OpenMetaverse;
namespace OpenSim.Framework
{
@@ -39,12 +35,36 @@ namespace OpenSim.Framework
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ ///
+ /// Asset types used only in OpenSim.
+ /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here.
+ ///
+ public enum OpenSimAssetType : sbyte
+ {
+ Material = -2
+ }
+
+
#region SL / file extension / content-type conversions
+ ///
+ /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs
+ /// to the AssetType or OpenSimAssetType enums.
+ ///
+ public static object AssetTypeFromCode(sbyte assetType)
+ {
+ if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
+ return (OpenMetaverse.AssetType)assetType;
+ else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType))
+ return (OpenSimAssetType)assetType;
+ else
+ return OpenMetaverse.AssetType.Unknown;
+ }
+
private class TypeMapping
{
private sbyte assetType;
- private InventoryType inventoryType;
+ private sbyte inventoryType;
private string contentType;
private string contentType2;
private string extension;
@@ -56,15 +76,10 @@ namespace OpenSim.Framework
public object AssetType
{
- get {
- if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
- return (OpenMetaverse.AssetType)assetType;
- else
- return OpenMetaverse.AssetType.Unknown;
- }
+ get { return AssetTypeFromCode(assetType); }
}
- public InventoryType InventoryType
+ public sbyte InventoryType
{
get { return inventoryType; }
}
@@ -84,7 +99,7 @@ namespace OpenSim.Framework
get { return extension; }
}
- private TypeMapping(sbyte assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
+ private TypeMapping(sbyte assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
{
this.assetType = assetType;
this.inventoryType = inventoryType;
@@ -93,13 +108,28 @@ namespace OpenSim.Framework
this.extension = extension;
}
- public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
+ public TypeMapping(AssetType assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
: this((sbyte)assetType, inventoryType, contentType, contentType2, extension)
{
}
+ public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
+ : this((sbyte)assetType, (sbyte)inventoryType, contentType, contentType2, extension)
+ {
+ }
+
public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension)
- : this((sbyte)assetType, inventoryType, contentType, null, extension)
+ : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
+ {
+ }
+
+ public TypeMapping(AssetType assetType, FolderType inventoryType, string contentType, string extension)
+ : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
+ {
+ }
+
+ public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension)
+ : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
{
}
}
@@ -125,51 +155,65 @@ namespace OpenSim.Framework
new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"),
- new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
- new TypeMapping(AssetType.RootFolder, InventoryType.RootCategory, "application/vnd.ll.rootfolder", "rootfolder"),
new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"),
new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"),
new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"),
- new TypeMapping(AssetType.TrashFolder, InventoryType.Folder, "application/vnd.ll.trashfolder", "trashfolder"),
- new TypeMapping(AssetType.SnapshotFolder, InventoryType.Folder, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
- new TypeMapping(AssetType.LostAndFoundFolder, InventoryType.Folder, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"),
new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"),
new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"),
- new TypeMapping(AssetType.FavoriteFolder, InventoryType.Unknown, "application/vnd.ll.favoritefolder", "favoritefolder"),
new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"),
new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"),
- new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"),
- new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"),
- new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"),
- new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm")
+ new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"),
+
+ // The next few items are about inventory folders
+ new TypeMapping(AssetType.Folder, FolderType.None, "application/vnd.ll.folder", "folder"),
+ new TypeMapping(AssetType.Folder, FolderType.Root, "application/vnd.ll.rootfolder", "rootfolder"),
+ new TypeMapping(AssetType.Folder, FolderType.Trash, "application/vnd.ll.trashfolder", "trashfolder"),
+ new TypeMapping(AssetType.Folder, FolderType.Snapshot, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
+ new TypeMapping(AssetType.Folder, FolderType.LostAndFound, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
+ new TypeMapping(AssetType.Folder, FolderType.Favorites, "application/vnd.ll.favoritefolder", "favoritefolder"),
+ new TypeMapping(AssetType.Folder, FolderType.CurrentOutfit, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"),
+ new TypeMapping(AssetType.Folder, FolderType.Outfit, "application/vnd.ll.outfitfolder", "outfitfolder"),
+ new TypeMapping(AssetType.Folder, FolderType.MyOutfits, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"),
+
+ // This next mappping is an asset to inventory item mapping.
+ // Note: LL stores folders as assets of type Folder = 8, and it has a corresponding InventoryType = 8
+ // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server
+ new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
+
+ // OpenSim specific
+ new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material")
};
private static Dictionary asset2Content;
private static Dictionary asset2Extension;
- private static Dictionary inventory2Content;
+ private static Dictionary inventory2Content;
private static Dictionary content2Asset;
- private static Dictionary content2Inventory;
+ private static Dictionary content2Inventory;
static SLUtil()
{
asset2Content = new Dictionary();
asset2Extension = new Dictionary();
- inventory2Content = new Dictionary();
+ inventory2Content = new Dictionary();
content2Asset = new Dictionary();
- content2Inventory = new Dictionary();
+ content2Inventory = new Dictionary();
foreach (TypeMapping mapping in MAPPINGS)
{
sbyte assetType = mapping.AssetTypeCode;
if (!asset2Content.ContainsKey(assetType))
asset2Content.Add(assetType, mapping.ContentType);
+
if (!asset2Extension.ContainsKey(assetType))
asset2Extension.Add(assetType, mapping.Extension);
+
if (!inventory2Content.ContainsKey(mapping.InventoryType))
inventory2Content.Add(mapping.InventoryType, mapping.ContentType);
+
if (!content2Asset.ContainsKey(mapping.ContentType))
content2Asset.Add(mapping.ContentType, assetType);
+
if (!content2Inventory.ContainsKey(mapping.ContentType))
content2Inventory.Add(mapping.ContentType, mapping.InventoryType);
@@ -194,8 +238,8 @@ namespace OpenSim.Framework
public static string SLInvTypeToContentType(int invType)
{
string contentType;
- if (!inventory2Content.TryGetValue((InventoryType)invType, out contentType))
- contentType = inventory2Content[InventoryType.Unknown];
+ if (!inventory2Content.TryGetValue((sbyte)invType, out contentType))
+ contentType = inventory2Content[(sbyte)InventoryType.Unknown];
return contentType;
}
@@ -209,9 +253,9 @@ namespace OpenSim.Framework
public static sbyte ContentTypeToSLInvType(string contentType)
{
- InventoryType invType;
+ sbyte invType;
if (!content2Inventory.TryGetValue(contentType, out invType))
- invType = InventoryType.Unknown;
+ invType = (sbyte)InventoryType.Unknown;
return (sbyte)invType;
}
@@ -225,106 +269,270 @@ namespace OpenSim.Framework
#endregion SL / file extension / content-type conversions
- ///
- /// Parse a notecard in Linden format to a string of ordinary text.
- ///
- ///
- ///
- public static string ParseNotecardToString(string rawInput)
+ private class NotecardReader
{
- string[] output = ParseNotecardToList(rawInput).ToArray();
+ private string rawInput;
+ private int lineNumber;
-// foreach (string line in output)
-// m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line);
-
- return string.Join("\n", output);
+ public int LineNumber
+ {
+ get
+ {
+ return lineNumber;
+ }
+ }
+
+ public NotecardReader(string _rawInput)
+ {
+ rawInput = (string)_rawInput.Clone();
+ lineNumber = 0;
+ }
+
+ public string getLine()
+ {
+ if(rawInput.Length == 0)
+ {
+ throw new NotANotecardFormatException(lineNumber + 1);
+ }
+
+ int pos = rawInput.IndexOf('\n');
+ if(pos < 0)
+ {
+ pos = rawInput.Length;
+ }
+
+ /* cut line from rest */
+ ++lineNumber;
+ string line = rawInput.Substring(0, pos);
+ if (pos + 1 >= rawInput.Length)
+ {
+ rawInput = string.Empty;
+ }
+ else
+ {
+ rawInput = rawInput.Substring(pos + 1);
+ }
+ /* clean up line from double spaces and tabs */
+ line = line.Replace("\t", " ");
+ while(line.IndexOf(" ") >= 0)
+ {
+ line = line.Replace(" ", " ");
+ }
+ return line.Replace("\r", "").Trim();
+ }
+
+ public string getBlock(int length)
+ {
+ /* cut line from rest */
+ if(length > rawInput.Length)
+ {
+ throw new NotANotecardFormatException(lineNumber);
+ }
+ string line = rawInput.Substring(0, length);
+ rawInput = rawInput.Substring(length);
+ return line;
+ }
}
-
- ///
- /// Parse a notecard in Linden format to a list of ordinary lines.
- ///
- ///
- ///
- public static List ParseNotecardToList(string rawInput)
+
+ public class NotANotecardFormatException : Exception
+ {
+ public int lineNumber;
+ public NotANotecardFormatException(int _lineNumber)
+ : base()
+ {
+ lineNumber = _lineNumber;
+ }
+ }
+
+ private static void skipSection(NotecardReader reader)
{
- string[] input = rawInput.Replace("\r", "").Split('\n');
- int idx = 0;
- int level = 0;
- List output = new List();
- string[] words;
+ if (reader.getLine() != "{")
+ throw new NotANotecardFormatException(reader.LineNumber);
- while (idx < input.Length)
+ string line;
+ while ((line = reader.getLine()) != "}")
{
- if (input[idx] == "{")
+ if(line.IndexOf('{')>=0)
+ {
+ throw new NotANotecardFormatException(reader.LineNumber);
+ }
+ }
+ }
+
+ private static void skipInventoryItem(NotecardReader reader)
+ {
+ if (reader.getLine() != "{")
+ throw new NotANotecardFormatException(reader.LineNumber);
+
+ string line;
+ while((line = reader.getLine()) != "}")
+ {
+ string[] data = line.Split(' ');
+ if(data.Length == 0)
{
- level++;
- idx++;
continue;
}
+ if(data[0] == "permissions")
+ {
+ skipSection(reader);
+ }
+ else if(data[0] == "sale_info")
+ {
+ skipSection(reader);
+ }
+ else if (line.IndexOf('{') >= 0)
+ {
+ throw new NotANotecardFormatException(reader.LineNumber);
+ }
+ }
+ }
+
+ private static void skipInventoryItems(NotecardReader reader)
+ {
+ if(reader.getLine() != "{")
+ {
+ throw new NotANotecardFormatException(reader.LineNumber);
+ }
- if (input[idx]== "}")
+ string line;
+ while((line = reader.getLine()) != "}")
+ {
+ string[] data = line.Split(' ');
+ if(data.Length == 0)
{
- level--;
- idx++;
continue;
}
- switch (level)
+ if(data[0] == "inv_item")
+ {
+ skipInventoryItem(reader);
+ }
+ else if (line.IndexOf('{') >= 0)
+ {
+ throw new NotANotecardFormatException(reader.LineNumber);
+ }
+
+ }
+ }
+
+ private static void skipInventory(NotecardReader reader)
+ {
+ if (reader.getLine() != "{")
+ throw new NotANotecardFormatException(reader.LineNumber);
+
+ string line;
+ while((line = reader.getLine()) != "}")
+ {
+ string[] data = line.Split(' ');
+ if(data[0] == "count")
{
- case 0:
- words = input[idx].Split(' '); // Linden text ver
- // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard)
- if (words.Length < 3)
- return output;
-
- int version = int.Parse(words[3]);
- if (version != 2)
- return output;
- break;
- case 1:
- words = input[idx].Split(' ');
- if (words[0] == "LLEmbeddedItems")
- break;
- if (words[0] == "Text")
+ int count = Int32.Parse(data[1]);
+ for(int i = 0; i < count; ++i)
{
- int len = int.Parse(words[2]);
- idx++;
+ skipInventoryItems(reader);
+ }
+ }
+ else if (line.IndexOf('{') >= 0)
+ {
+ throw new NotANotecardFormatException(reader.LineNumber);
+ }
+ }
+ }
+
+ private static string readNotecardText(NotecardReader reader)
+ {
+ if (reader.getLine() != "{")
+ throw new NotANotecardFormatException(reader.LineNumber);
+
+ string notecardString = string.Empty;
+ string line;
+ while((line = reader.getLine()) != "}")
+ {
+ string[] data = line.Split(' ');
+ if (data.Length == 0)
+ {
+ continue;
+ }
- int count = -1;
+ if (data[0] == "LLEmbeddedItems")
+ {
+ skipInventory(reader);
+ }
+ else if(data[0] == "Text" && data.Length == 3)
+ {
+ int length = Int32.Parse(data[2]);
+ notecardString = reader.getBlock(length);
+ }
+ else if (line.IndexOf('{') >= 0)
+ {
+ throw new NotANotecardFormatException(reader.LineNumber);
+ }
- while (count < len && idx < input.Length)
- {
- // int l = input[idx].Length;
- string ln = input[idx];
+ }
+ return notecardString;
+ }
- int need = len-count-1;
- if (ln.Length > need)
- ln = ln.Substring(0, need);
+ private static string readNotecard(byte[] rawInput)
+ {
+ string rawIntermedInput = string.Empty;
-// m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", ln);
- output.Add(ln);
- count += ln.Length + 1;
- idx++;
- }
+ /* make up a Raw Encoding here */
+ foreach(byte c in rawInput)
+ {
+ char d = (char)c;
+ rawIntermedInput += d;
+ }
- return output;
- }
- break;
- case 2:
- words = input[idx].Split(' '); // count
- if (words[0] == "count")
- {
- int c = int.Parse(words[1]);
- if (c > 0)
- return output;
- break;
- }
- break;
+ NotecardReader reader = new NotecardReader(rawIntermedInput);
+ string line;
+ try
+ {
+ line = reader.getLine();
+ }
+ catch(Exception)
+ {
+ return System.Text.Encoding.UTF8.GetString(rawInput);
+ }
+ string[] versioninfo = line.Split(' ');
+ if(versioninfo.Length < 3)
+ {
+ return System.Text.Encoding.UTF8.GetString(rawInput);
+ }
+ else if(versioninfo[0] != "Linden" || versioninfo[1] != "text")
+ {
+ return System.Text.Encoding.UTF8.GetString(rawInput);
+ }
+ else
+ {
+ /* now we actually decode the Encoding, before we needed it in raw */
+ string o = readNotecardText(reader);
+ byte[] a = new byte[o.Length];
+ for(int i = 0; i < o.Length; ++i)
+ {
+ a[i] = (byte)o[i];
}
- idx++;
+ return System.Text.Encoding.UTF8.GetString(a);
}
-
- return output;
+ }
+
+ ///
+ /// Parse a notecard in Linden format to a string of ordinary text.
+ ///
+ ///
+ ///
+ public static string ParseNotecardToString(byte[] rawInput)
+ {
+ return readNotecard(rawInput);
+ }
+
+ ///
+ /// Parse a notecard in Linden format to a list of ordinary lines.
+ ///
+ ///
+ ///
+ public static string[] ParseNotecardToArray(byte[] rawInput)
+ {
+ return readNotecard(rawInput).Replace("\r", "").Split('\n');
}
}
}
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs
index 0c12787..ab3c285 100644
--- a/OpenSim/Framework/Serialization/ArchiveConstants.cs
+++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs
@@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse;
+using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType;
namespace OpenSim.Framework.Serialization
{
@@ -114,20 +115,17 @@ namespace OpenSim.Framework.Serialization
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt";
- ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Mesh] = ASSET_EXTENSION_SEPARATOR + "mesh.llmesh";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml";
- ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this
- ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2";
ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga";
- ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this
+ ASSET_TYPE_TO_EXTENSION[(sbyte)OpenSimAssetType.Material] = ASSET_EXTENSION_SEPARATOR + "material.xml"; // Not sure if we'll ever see this
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart;
@@ -138,20 +136,17 @@ namespace OpenSim.Framework.Serialization
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = (sbyte)AssetType.ImageJPEG;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = (sbyte)AssetType.ImageTGA;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = (sbyte)AssetType.Landmark;
- EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = (sbyte)AssetType.LostAndFoundFolder;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = (sbyte)AssetType.LSLBytecode;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = (sbyte)AssetType.LSLText;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "mesh.llmesh"] = (sbyte)AssetType.Mesh;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = (sbyte)AssetType.Notecard;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = (sbyte)AssetType.Object;
- EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = (sbyte)AssetType.RootFolder;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = (sbyte)AssetType.Simstate;
- EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = (sbyte)AssetType.SnapshotFolder;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = (sbyte)AssetType.Sound;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = (sbyte)AssetType.SoundWAV;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture;
EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA;
- EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder;
+ EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "material.xml"] = (sbyte)OpenSimAssetType.Material;
}
public static string CreateOarLandDataPath(LandData ld)
diff --git a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs
index c56f213..55640ac 100644
--- a/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs
+++ b/OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs
@@ -1,4 +1,4 @@
-/*
+/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
@@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Xml;
@@ -47,20 +48,20 @@ namespace OpenSim.Framework.Serialization.External
/// Populate a node with data read from xml using a dictinoary of processors
///
///
- /// /param>
+ ///
///
/// true on successful, false if there were any processing failures
public static bool ExecuteReadProcessors(
- NodeType nodeToFill, Dictionary> processors, XmlTextReader xtr)
+ NodeType nodeToFill, Dictionary> processors, XmlReader xtr)
{
return ExecuteReadProcessors(
nodeToFill,
processors,
xtr,
- (o, name, e)
- => m_log.DebugFormat(
- "[ExternalRepresentationUtils]: Exception while parsing element {0}, continuing. Exception {1}{2}",
- name, e.Message, e.StackTrace));
+ (o, nodeName, e) => {
+ m_log.Debug(string.Format("[ExternalRepresentationUtils]: Error while parsing element {0} ",
+ nodeName), e);
+ });
}
///
@@ -75,23 +76,27 @@ namespace OpenSim.Framework.Serialization.External
/// true on successful, false if there were any processing failures
public static bool ExecuteReadProcessors(
NodeType nodeToFill,
- Dictionary> processors,
- XmlTextReader xtr,
+ Dictionary> processors,
+ XmlReader xtr,
Action parseExceptionAction)
{
bool errors = false;
+ int numErrors = 0;
+
+ Stopwatch timer = new Stopwatch();
+ timer.Start();
string nodeName = string.Empty;
while (xtr.NodeType != XmlNodeType.EndElement)
{
nodeName = xtr.Name;
-// m_log.DebugFormat("[ExternalRepresentationUtils]: Processing: {0}", nodeName);
+ // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing node: {0}", nodeName);
- Action p = null;
+ Action p = null;
if (processors.TryGetValue(xtr.Name, out p))
{
-// m_log.DebugFormat("[ExternalRepresentationUtils]: Found {0} processor, nodeName);
+ // m_log.DebugFormat("[ExternalRepresentationUtils]: Found processor for {0}", nodeName);
try
{
@@ -101,6 +106,18 @@ namespace OpenSim.Framework.Serialization.External
{
errors = true;
parseExceptionAction(nodeToFill, nodeName, e);
+
+ if (xtr.EOF)
+ {
+ m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to unexpected end of XML");
+ break;
+ }
+
+ if (++numErrors == 10)
+ {
+ m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to too many parsing errors");
+ break;
+ }
if (xtr.NodeType == XmlNodeType.EndElement)
xtr.Read();
@@ -108,9 +125,16 @@ namespace OpenSim.Framework.Serialization.External
}
else
{
- // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName);
+ // m_log.DebugFormat("[ExternalRepresentationUtils]: found unknown element \"{0}\"", nodeName);
xtr.ReadOuterXml(); // ignore
}
+
+ if (timer.Elapsed.TotalSeconds >= 60)
+ {
+ m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to timeout");
+ errors = true;
+ break;
+ }
}
return errors;
@@ -125,7 +149,8 @@ namespace OpenSim.Framework.Serialization.External
/// The service for retrieving user account information
/// The scope of the user account information (Grid ID)
/// The SceneObjectPart represented in XML2
- public static string RewriteSOP(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
+ [Obsolete("This method is deprecated. Use RewriteSOP instead.")]
+ public static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
{
if (xml == string.Empty || homeURL == string.Empty || userService == null)
return xml;
@@ -161,7 +186,7 @@ namespace OpenSim.Framework.Serialization.External
if (!hasCreatorData && creator != null)
{
XmlElement creatorData = doc.CreateElement("CreatorData");
- creatorData.InnerText = homeURL + ";" + creator.FirstName + " " + creator.LastName;
+ creatorData.InnerText = CalcCreatorData(homeURL, creator.FirstName + " " + creator.LastName);
sop.AppendChild(creatorData);
}
}
@@ -172,5 +197,215 @@ namespace OpenSim.Framework.Serialization.External
return wr.ToString();
}
}
+
+ ///
+ /// Takes a XML representation of a SceneObjectPart and returns another XML representation
+ /// with creator data added to it.
+ ///
+ /// The SceneObjectPart represented in XML2
+ /// An identifier for the component that's calling this function
+ /// The URL of the user agents service (home) for the creator
+ /// The service for retrieving user account information
+ /// The scope of the user account information (Grid ID)
+ /// The SceneObjectPart represented in XML2
+ public static string RewriteSOP(string xmlData, string sceneName, string homeURL, IUserAccountService userService, UUID scopeID)
+ {
+ // Console.WriteLine("Input XML [{0}]", xmlData);
+ if (xmlData == string.Empty || homeURL == string.Empty || userService == null)
+ return xmlData;
+
+ // Deal with bug
+ xmlData = ExternalRepresentationUtils.SanitizeXml(xmlData);
+
+ using (StringWriter sw = new StringWriter())
+ using (XmlTextWriter writer = new XmlTextWriter(sw))
+ using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
+ using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
+ {
+ TransformXml(reader, writer, sceneName, homeURL, userService, scopeID);
+
+ // Console.WriteLine("Output: [{0}]", sw.ToString());
+
+ return sw.ToString();
+ }
+ }
+
+ protected static void TransformXml(XmlReader reader, XmlWriter writer, string sceneName, string homeURI, IUserAccountService userAccountService, UUID scopeID)
+ {
+ // m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML");
+
+ int sopDepth = -1;
+ UserAccount creator = null;
+ bool hasCreatorData = false;
+
+ while (reader.Read())
+ {
+ // Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name);
+
+ switch (reader.NodeType)
+ {
+ case XmlNodeType.Attribute:
+ // Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name);
+ writer.WriteAttributeString(reader.Name, reader.Value);
+ break;
+
+ case XmlNodeType.CDATA:
+ writer.WriteCData(reader.Value);
+ break;
+
+ case XmlNodeType.Comment:
+ writer.WriteComment(reader.Value);
+ break;
+
+ case XmlNodeType.DocumentType:
+ writer.WriteDocType(reader.Name, reader.Value, null, null);
+ break;
+
+ case XmlNodeType.Element:
+ // m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name);
+
+ writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
+
+ if (reader.HasAttributes)
+ {
+ while (reader.MoveToNextAttribute())
+ writer.WriteAttributeString(reader.Name, reader.Value);
+
+ reader.MoveToElement();
+ }
+
+ if (reader.LocalName == "SceneObjectPart")
+ {
+ if (sopDepth < 0)
+ {
+ sopDepth = reader.Depth;
+ // m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth);
+ }
+ }
+ else
+ {
+ if (sopDepth >= 0 && reader.Depth == sopDepth + 1)
+ {
+ if (reader.Name == "CreatorID")
+ {
+ reader.Read();
+ if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID")
+ {
+ reader.Read();
+
+ if (reader.NodeType == XmlNodeType.Text)
+ {
+ UUID uuid = UUID.Zero;
+ UUID.TryParse(reader.Value, out uuid);
+ creator = userAccountService.GetUserAccount(scopeID, uuid);
+ writer.WriteElementString("UUID", reader.Value);
+ reader.Read();
+ }
+ else
+ {
+ // If we unexpected run across mixed content in this node, still carry on
+ // transforming the subtree (this replicates earlier behaviour).
+ TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
+ }
+ }
+ else
+ {
+ // If we unexpected run across mixed content in this node, still carry on
+ // transforming the subtree (this replicates earlier behaviour).
+ TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
+ }
+ }
+ else if (reader.Name == "CreatorData")
+ {
+ reader.Read();
+ if (reader.NodeType == XmlNodeType.Text)
+ {
+ hasCreatorData = true;
+ writer.WriteString(reader.Value);
+ }
+ else
+ {
+ // If we unexpected run across mixed content in this node, still carry on
+ // transforming the subtree (this replicates earlier behaviour).
+ TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
+ }
+ }
+ }
+ }
+
+ if (reader.IsEmptyElement)
+ {
+ // m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name);
+ writer.WriteEndElement();
+ }
+
+ break;
+
+ case XmlNodeType.EndElement:
+ // m_log.DebugFormat("Depth {0} at EndElement", reader.Depth);
+ if (sopDepth == reader.Depth)
+ {
+ if (!hasCreatorData && creator != null)
+ writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", homeURI, creator.FirstName, creator.LastName));
+
+ // m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth");
+ sopDepth = -1;
+ creator = null;
+ hasCreatorData = false;
+ }
+ writer.WriteEndElement();
+ break;
+
+ case XmlNodeType.EntityReference:
+ writer.WriteEntityRef(reader.Name);
+ break;
+
+ case XmlNodeType.ProcessingInstruction:
+ writer.WriteProcessingInstruction(reader.Name, reader.Value);
+ break;
+
+ case XmlNodeType.Text:
+ writer.WriteString(reader.Value);
+ break;
+
+ case XmlNodeType.XmlDeclaration:
+ // For various reasons, not all serializations have xml declarations (or consistent ones)
+ // and as it's embedded inside a byte stream we don't need it anyway, so ignore.
+ break;
+
+ default:
+ m_log.WarnFormat(
+ "[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}",
+ reader.NodeType, sceneName);
+ break;
+ }
+ }
+ }
+
+ public static string CalcCreatorData(string homeURL, string name)
+ {
+ return homeURL + ";" + name;
+ }
+
+ internal static string CalcCreatorData(string homeURL, UUID uuid, string name)
+ {
+ return homeURL + "/" + uuid + ";" + name;
+ }
+
+ ///
+ /// Sanitation for bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
+ ///
+ ///
+ ///
+ public static string SanitizeXml(string xmlData)
+ {
+ string fixedData = xmlData;
+ if (fixedData != null)
+ // Loop, because it may contain multiple
+ while (fixedData.Contains("xmlns:xmlns:"))
+ fixedData = fixedData.Replace("xmlns:xmlns:", "xmlns:");
+ return fixedData;
+ }
+
}
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs
index 709b516..e42d56f 100644
--- a/OpenSim/Framework/Serialization/External/LandDataSerializer.cs
+++ b/OpenSim/Framework/Serialization/External/LandDataSerializer.cs
@@ -44,11 +44,11 @@ namespace OpenSim.Framework.Serialization.External
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- private static Dictionary> m_ldProcessors
- = new Dictionary>();
+ private static Dictionary> m_ldProcessors
+ = new Dictionary>();
- private static Dictionary> m_laeProcessors
- = new Dictionary>();
+ private static Dictionary> m_laeProcessors
+ = new Dictionary>();
static LandDataSerializer()
{
@@ -134,7 +134,7 @@ namespace OpenSim.Framework.Serialization.External
"AccessList", (lae, xtr) => lae.Flags = (AccessList)Convert.ToUInt32(xtr.ReadElementString("AccessList")));
}
- public static void ProcessParcelAccessList(LandData ld, XmlTextReader xtr)
+ public static void ProcessParcelAccessList(LandData ld, XmlReader xtr)
{
if (!xtr.IsEmptyElement)
{
@@ -213,8 +213,13 @@ namespace OpenSim.Framework.Serialization.External
xtw.WriteElementString("ClaimDate", Convert.ToString(landData.ClaimDate));
xtw.WriteElementString("ClaimPrice", Convert.ToString(landData.ClaimPrice));
xtw.WriteElementString("GlobalID", landData.GlobalID.ToString());
- xtw.WriteElementString("GroupID", landData.GroupID.ToString());
- xtw.WriteElementString("IsGroupOwned", Convert.ToString(landData.IsGroupOwned));
+
+ UUID groupID = options.ContainsKey("wipe-owners") ? UUID.Zero : landData.GroupID;
+ xtw.WriteElementString("GroupID", groupID.ToString());
+
+ bool isGroupOwned = options.ContainsKey("wipe-owners") ? false : landData.IsGroupOwned;
+ xtw.WriteElementString("IsGroupOwned", Convert.ToString(isGroupOwned));
+
xtw.WriteElementString("Bitmap", Convert.ToBase64String(landData.Bitmap));
xtw.WriteElementString("Description", landData.Description);
xtw.WriteElementString("Flags", Convert.ToString((uint)landData.Flags));
@@ -227,13 +232,8 @@ namespace OpenSim.Framework.Serialization.External
xtw.WriteElementString("MediaURL", landData.MediaURL);
xtw.WriteElementString("MusicURL", landData.MusicURL);
- UUID ownerIdToWrite;
- if (options != null && options.ContainsKey("wipe-owners"))
- ownerIdToWrite = UUID.Zero;
- else
- ownerIdToWrite = landData.OwnerID;
-
- xtw.WriteElementString("OwnerID", ownerIdToWrite.ToString());
+ UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : landData.OwnerID;
+ xtw.WriteElementString("OwnerID", ownerID.ToString());
xtw.WriteStartElement("ParcelAccessList");
foreach (LandAccessEntry pal in landData.ParcelAccessList)
diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs
index 88f9581..994cede 100644
--- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs
+++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs
@@ -46,8 +46,8 @@ namespace OpenSim.Framework.Serialization.External
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
- private static Dictionary> m_InventoryItemXmlProcessors
- = new Dictionary>();
+ private static Dictionary> m_InventoryItemXmlProcessors
+ = new Dictionary>();
#region InventoryItemBase Processor initialization
static UserInventoryItemSerializer()
@@ -76,103 +76,103 @@ namespace OpenSim.Framework.Serialization.External
#endregion
#region InventoryItemBase Processors
- private static void ProcessName(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessName(InventoryItemBase item, XmlReader reader)
{
item.Name = reader.ReadElementContentAsString("Name", String.Empty);
}
- private static void ProcessID(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessID(InventoryItemBase item, XmlReader reader)
{
item.ID = Util.ReadUUID(reader, "ID");
}
- private static void ProcessInvType(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessInvType(InventoryItemBase item, XmlReader reader)
{
item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty);
}
- private static void ProcessCreatorUUID(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessCreatorUUID(InventoryItemBase item, XmlReader reader)
{
item.CreatorId = reader.ReadElementContentAsString("CreatorUUID", String.Empty);
}
- private static void ProcessCreatorID(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessCreatorID(InventoryItemBase item, XmlReader reader)
{
// when it exists, this overrides the previous
item.CreatorId = reader.ReadElementContentAsString("CreatorID", String.Empty);
}
- private static void ProcessCreationDate(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessCreationDate(InventoryItemBase item, XmlReader reader)
{
item.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty);
}
- private static void ProcessOwner(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessOwner(InventoryItemBase item, XmlReader reader)
{
item.Owner = Util.ReadUUID(reader, "Owner");
}
- private static void ProcessDescription(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessDescription(InventoryItemBase item, XmlReader reader)
{
item.Description = reader.ReadElementContentAsString("Description", String.Empty);
}
- private static void ProcessAssetType(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessAssetType(InventoryItemBase item, XmlReader reader)
{
item.AssetType = reader.ReadElementContentAsInt("AssetType", String.Empty);
}
- private static void ProcessAssetID(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessAssetID(InventoryItemBase item, XmlReader reader)
{
item.AssetID = Util.ReadUUID(reader, "AssetID");
}
- private static void ProcessSaleType(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessSaleType(InventoryItemBase item, XmlReader reader)
{
item.SaleType = (byte)reader.ReadElementContentAsInt("SaleType", String.Empty);
}
- private static void ProcessSalePrice(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessSalePrice(InventoryItemBase item, XmlReader reader)
{
item.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty);
}
- private static void ProcessBasePermissions(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessBasePermissions(InventoryItemBase item, XmlReader reader)
{
item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty);
}
- private static void ProcessCurrentPermissions(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessCurrentPermissions(InventoryItemBase item, XmlReader reader)
{
item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty);
}
- private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlReader reader)
{
item.EveryOnePermissions = (uint)reader.ReadElementContentAsInt("EveryOnePermissions", String.Empty);
}
- private static void ProcessNextPermissions(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessNextPermissions(InventoryItemBase item, XmlReader reader)
{
item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty);
}
- private static void ProcessFlags(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessFlags(InventoryItemBase item, XmlReader reader)
{
item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty);
}
- private static void ProcessGroupID(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessGroupID(InventoryItemBase item, XmlReader reader)
{
item.GroupID = Util.ReadUUID(reader, "GroupID");
}
- private static void ProcessGroupOwned(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessGroupOwned(InventoryItemBase item, XmlReader reader)
{
item.GroupOwned = Util.ReadBoolean(reader);
}
- private static void ProcessCreatorData(InventoryItemBase item, XmlTextReader reader)
+ private static void ProcessCreatorData(InventoryItemBase item, XmlReader reader)
{
item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty);
}
@@ -277,7 +277,7 @@ namespace OpenSim.Framework.Serialization.External
writer.WriteStartElement("GroupOwned");
writer.WriteString(inventoryItem.GroupOwned.ToString());
writer.WriteEndElement();
- if (options.ContainsKey("creators") && inventoryItem.CreatorData != null && inventoryItem.CreatorData != string.Empty)
+ if (options.ContainsKey("creators") && !string.IsNullOrEmpty(inventoryItem.CreatorData))
writer.WriteElementString("CreatorData", inventoryItem.CreatorData);
else if (options.ContainsKey("home"))
{
@@ -286,7 +286,8 @@ namespace OpenSim.Framework.Serialization.External
UserAccount account = userAccountService.GetUserAccount(UUID.Zero, inventoryItem.CreatorIdAsUuid);
if (account != null)
{
- writer.WriteElementString("CreatorData", (string)options["home"] + "/" + inventoryItem.CreatorIdAsUuid + ";" + account.FirstName + " " + account.LastName);
+ string creatorData = ExternalRepresentationUtils.CalcCreatorData((string)options["home"], inventoryItem.CreatorIdAsUuid, account.FirstName + " " + account.LastName);
+ writer.WriteElementString("CreatorData", creatorData);
}
writer.WriteElementString("CreatorID", inventoryItem.CreatorId);
}
diff --git a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
index 11efa4b..acec20f 100644
--- a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.8.3.*")]
+
diff --git a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
index ea100ee..e81cb78 100644
--- a/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
+++ b/OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs
@@ -121,7 +121,8 @@ namespace OpenSim.Framework.Serialization.Tests
TestHelpers.InMethod();
// log4net.Config.XmlConfigurator.Configure();
- LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, null));
+ Dictionary options = new Dictionary();
+ LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, options));
Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null");
// Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax));
// Assert.That(ld.AABBMin, Is.EqualTo(land.AABBMin));
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index c0dc907..828a852 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -45,6 +45,7 @@ using OpenSim.Framework.Monitoring;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using Timer=System.Timers.Timer;
+using Nini.Config;
namespace OpenSim.Framework.Servers
{
@@ -56,9 +57,15 @@ namespace OpenSim.Framework.Servers
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
///
+ /// Used by tests to suppress Environment.Exit(0) so that post-run operations are possible.
+ ///
+ public bool SuppressExit { get; set; }
+
+ ///
/// This will control a periodic log printout of the current 'show stats' (if they are active) for this
/// server.
///
+ private int m_periodDiagnosticTimerMS = 60 * 60 * 1000;
private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000);
///
@@ -77,8 +84,6 @@ namespace OpenSim.Framework.Servers
// Random uuid for private data
m_osSecret = UUID.Random().ToString();
- m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
- m_periodicDiagnosticsTimer.Enabled = true;
}
///
@@ -86,26 +91,34 @@ namespace OpenSim.Framework.Servers
///
protected virtual void StartupSpecific()
{
- if (m_console == null)
- return;
-
+ StatsManager.SimExtraStats = new SimExtraStatsCollector();
RegisterCommonCommands();
-
- m_console.Commands.AddCommand("General", false, "quit",
- "quit",
- "Quit the application", HandleQuit);
+ RegisterCommonComponents(Config);
+
+ IConfig startupConfig = Config.Configs["Startup"];
+ int logShowStatsSeconds = startupConfig.GetInt("LogShowStatsSeconds", m_periodDiagnosticTimerMS / 1000);
+ m_periodDiagnosticTimerMS = logShowStatsSeconds * 1000;
+ m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
+ if (m_periodDiagnosticTimerMS != 0)
+ {
+ m_periodicDiagnosticsTimer.Interval = m_periodDiagnosticTimerMS;
+ m_periodicDiagnosticsTimer.Enabled = true;
+ }
+ }
+
+ protected override void ShutdownSpecific()
+ {
+ m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
- m_console.Commands.AddCommand("General", false, "shutdown",
- "shutdown",
- "Quit the application", HandleQuit);
+ RemovePIDFile();
+
+ base.ShutdownSpecific();
+
+ if (!SuppressExit)
+ Environment.Exit(0);
}
///
- /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
- ///
- public virtual void ShutdownSpecific() {}
-
- ///
/// Provides a list of help topics that are available. Overriding classes should append their topics to the
/// information returned when the base method is called.
///
@@ -133,45 +146,18 @@ namespace OpenSim.Framework.Servers
/// Performs initialisation of the scene, such as loading configuration from disk.
///
public virtual void Startup()
- {
- m_log.Info("[STARTUP]: Beginning startup processing");
-
- m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
- // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
- // the clr version number doesn't match the project version number under Mono.
- //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
- m_log.InfoFormat(
- "[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n",
- Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
-
+ {
StartupSpecific();
TimeSpan timeTaken = DateTime.Now - m_startuptime;
- m_log.InfoFormat(
- "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.",
+ MainConsole.Instance.OutputFormat(
+ "PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED. Non-script portion of startup took {0}m {1}s.",
timeTaken.Minutes, timeTaken.Seconds);
}
- ///
- /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
- ///
- public virtual void Shutdown()
+ public string osSecret
{
- ShutdownSpecific();
-
- m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
- RemovePIDFile();
-
- Environment.Exit(0);
- }
-
- private void HandleQuit(string module, string[] args)
- {
- Shutdown();
- }
-
- public string osSecret {
// Secret uuid for the simulator
get { return m_osSecret; }
}
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index aa49343..f252bd5 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -46,6 +46,7 @@ using CoolHTTPListener = HttpServer.HttpListener;
using HttpListener=System.Net.HttpListener;
using LogPrio=HttpServer.LogPrio;
using OpenSim.Framework.Monitoring;
+using System.IO.Compression;
namespace OpenSim.Framework.Servers.HttpServer
{
@@ -53,6 +54,16 @@ namespace OpenSim.Framework.Servers.HttpServer
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
+ private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false);
+
+ ///
+ /// This is a pending websocket request before it got an sucessful upgrade response.
+ /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to
+ /// start the connection and optionally provide an origin authentication method.
+ ///
+ ///
+ ///
+ public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler);
///
/// Gets or sets the debug level.
@@ -71,12 +82,18 @@ namespace OpenSim.Framework.Servers.HttpServer
///
public int RequestNumber { get; private set; }
+ ///
+ /// Statistic for holding number of requests processed.
+ ///
+ private Stat m_requestsProcessedStat;
+
private volatile int NotSocketErrors = 0;
public volatile bool HTTPDRunning = false;
// protected HttpListener m_httpListener;
protected CoolHTTPListener m_httpListener2;
protected Dictionary m_rpcHandlers = new Dictionary();
+ protected Dictionary jsonRpcHandlers = new Dictionary();
protected Dictionary m_rpcHandlersKeepAlive = new Dictionary();
protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
protected Dictionary m_llsdHandlers = new Dictionary();
@@ -86,6 +103,9 @@ namespace OpenSim.Framework.Servers.HttpServer
protected Dictionary m_pollHandlers =
new Dictionary();
+ protected Dictionary m_WebSocketHandlers =
+ new Dictionary();
+
protected uint m_port;
protected uint m_sslport;
protected bool m_ssl;
@@ -95,7 +115,7 @@ namespace OpenSim.Framework.Servers.HttpServer
protected IPAddress m_listenIPAddress = IPAddress.Any;
- private PollServiceRequestManager m_PollServiceManager;
+ public PollServiceRequestManager PollServiceRequestManager { get; private set; }
public uint SSLPort
{
@@ -169,6 +189,22 @@ namespace OpenSim.Framework.Servers.HttpServer
}
}
+ public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
+ {
+ lock (m_WebSocketHandlers)
+ {
+ if (!m_WebSocketHandlers.ContainsKey(servicepath))
+ m_WebSocketHandlers.Add(servicepath, handler);
+ }
+ }
+
+ public void RemoveWebSocketHandler(string servicepath)
+ {
+ lock (m_WebSocketHandlers)
+ if (m_WebSocketHandlers.ContainsKey(servicepath))
+ m_WebSocketHandlers.Remove(servicepath);
+ }
+
public List GetStreamHandlerKeys()
{
lock (m_streamHandlers)
@@ -217,6 +253,37 @@ namespace OpenSim.Framework.Servers.HttpServer
return new List(m_rpcHandlers.Keys);
}
+ // JsonRPC
+ public bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
+ {
+ lock(jsonRpcHandlers)
+ {
+ jsonRpcHandlers.Add(method, handler);
+ }
+ return true;
+ }
+
+ public JsonRPCMethod GetJsonRPCHandler(string method)
+ {
+ lock (jsonRpcHandlers)
+ {
+ if (jsonRpcHandlers.ContainsKey(method))
+ {
+ return jsonRpcHandlers[method];
+ }
+ else
+ {
+ return null;
+ }
+ }
+ }
+
+ public List GetJsonRpcHandlerKeys()
+ {
+ lock (jsonRpcHandlers)
+ return new List(jsonRpcHandlers.Keys);
+ }
+
public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
{
//m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
@@ -309,7 +376,7 @@ namespace OpenSim.Framework.Servers.HttpServer
return true;
}
- private void OnRequest(object source, RequestEventArgs args)
+ public void OnRequest(object source, RequestEventArgs args)
{
RequestNumber++;
@@ -322,6 +389,8 @@ namespace OpenSim.Framework.Servers.HttpServer
if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs))
{
+ psEvArgs.RequestsReceived++;
+
PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request);
if (psEvArgs.Request != null)
@@ -362,7 +431,7 @@ namespace OpenSim.Framework.Servers.HttpServer
psEvArgs.Request(psreq.RequestID, keysvals);
}
- m_PollServiceManager.Enqueue(psreq);
+ PollServiceRequestManager.Enqueue(psreq);
}
else
{
@@ -375,11 +444,24 @@ namespace OpenSim.Framework.Servers.HttpServer
}
}
- public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
+ private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
{
OSHttpRequest req = new OSHttpRequest(context, request);
+ WebSocketRequestDelegate dWebSocketRequestDelegate = null;
+ lock (m_WebSocketHandlers)
+ {
+ if (m_WebSocketHandlers.ContainsKey(req.RawUrl))
+ dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl];
+ }
+ if (dWebSocketRequestDelegate != null)
+ {
+ dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192));
+ return;
+ }
+
OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
- HandleRequest(req, resp);
+ resp.ReuseContext = true;
+ HandleRequest(req, resp);
// !!!HACK ALERT!!!
// There seems to be a bug in the underlying http code that makes subsequent requests
@@ -410,7 +492,9 @@ namespace OpenSim.Framework.Servers.HttpServer
{
try
{
- SendHTML500(response);
+ byte[] buffer500 = SendHTML500(response);
+ response.OutputStream.Write(buffer500, 0, buffer500.Length);
+ response.Send();
}
catch
{
@@ -468,7 +552,7 @@ namespace OpenSim.Framework.Servers.HttpServer
LogIncomingToStreamHandler(request, requestHandler);
response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
-
+
if (requestHandler is IStreamedRequestHandler)
{
IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
@@ -556,10 +640,18 @@ namespace OpenSim.Framework.Servers.HttpServer
buffer = HandleLLSDRequests(request, response);
break;
+
+ case "application/json-rpc":
+ if (DebugLevel >= 3)
+ LogIncomingToContentTypeHandler(request);
+
+ buffer = HandleJsonRpcRequests(request, response);
+ break;
case "text/xml":
case "application/xml":
case "application/json":
+
default:
//m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
// Point of note.. the DoWeHaveA methods check for an EXACT path
@@ -600,7 +692,24 @@ namespace OpenSim.Framework.Servers.HttpServer
if (buffer != null)
{
- if (!response.SendChunked)
+ if (WebUtil.DebugLevel >= 5)
+ {
+ string output = System.Text.Encoding.UTF8.GetString(buffer);
+
+ if (WebUtil.DebugLevel >= 6)
+ {
+ // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name.
+ if ((requestHandler != null && requestHandler.Name == "GetMesh"))
+ {
+ if (output.Length > WebUtil.MaxRequestDiagLength)
+ output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "...";
+ }
+ }
+
+ WebUtil.LogResponseDetail(RequestNumber, output);
+ }
+
+ if (!response.SendChunked && response.ContentLength64 <= 0)
response.ContentLength64 = buffer.LongLength;
response.OutputStream.Write(buffer, 0, buffer.Length);
@@ -630,12 +739,20 @@ namespace OpenSim.Framework.Servers.HttpServer
}
catch (IOException e)
{
- m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
+ m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
}
catch (Exception e)
{
- m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
- SendHTML500(response);
+ m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
+ try
+ {
+ byte[] buffer500 = SendHTML500(response);
+ response.OutputStream.Write(buffer500, 0, buffer500.Length);
+ response.Send();
+ }
+ catch
+ {
+ }
}
finally
{
@@ -645,7 +762,7 @@ namespace OpenSim.Framework.Servers.HttpServer
if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture")
{
m_log.InfoFormat(
- "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
+ "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
RequestNumber,
requestMethod,
uriString,
@@ -657,7 +774,7 @@ namespace OpenSim.Framework.Servers.HttpServer
else if (DebugLevel >= 4)
{
m_log.DebugFormat(
- "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms",
+ "[LOGHTTP] HTTP IN {0} :{1} took {2}ms",
RequestNumber,
Port,
tickdiff);
@@ -668,7 +785,7 @@ namespace OpenSim.Framework.Servers.HttpServer
private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
{
m_log.DebugFormat(
- "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
+ "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
RequestNumber,
Port,
request.HttpMethod,
@@ -684,10 +801,10 @@ namespace OpenSim.Framework.Servers.HttpServer
private void LogIncomingToContentTypeHandler(OSHttpRequest request)
{
m_log.DebugFormat(
- "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
+ "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
RequestNumber,
Port,
- (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType,
+ string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType,
request.HttpMethod,
request.Url.PathAndQuery,
request.RemoteIPEndPoint);
@@ -699,7 +816,7 @@ namespace OpenSim.Framework.Servers.HttpServer
private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
{
m_log.DebugFormat(
- "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
+ "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
RequestNumber,
Port,
request.HttpMethod,
@@ -712,29 +829,49 @@ namespace OpenSim.Framework.Servers.HttpServer
private void LogIncomingInDetail(OSHttpRequest request)
{
- using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8))
- {
- string output;
+ if (request.ContentType == "application/octet-stream")
+ return; // never log these; they're just binary data
- if (DebugLevel == 5)
+ Stream inputStream = Util.Copy(request.InputStream);
+ Stream innerStream = null;
+ try
+ {
+ if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip"))
{
- const int sampleLength = 80;
- char[] sampleChars = new char[sampleLength + 3];
- reader.Read(sampleChars, 0, sampleLength);
- sampleChars[80] = '.';
- sampleChars[81] = '.';
- sampleChars[82] = '.';
- output = new string(sampleChars);
+ innerStream = inputStream;
+ inputStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
}
- else
+
+ using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8))
{
- output = reader.ReadToEnd();
- }
+ string output;
- m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n"));
+ if (DebugLevel == 5)
+ {
+ char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed
+ int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1);
+ output = new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength));
+ if (len > WebUtil.MaxRequestDiagLength)
+ output += "...";
+ }
+ else
+ {
+ output = reader.ReadToEnd();
+ }
+
+ m_log.DebugFormat("[LOGHTTP] {0}", Util.BinaryToASCII(output));
+ }
+ }
+ finally
+ {
+ if (innerStream != null)
+ innerStream.Dispose();
+ inputStream.Dispose();
}
}
+ private readonly string HANDLER_SEPARATORS = "/?-";
+
private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler)
{
string bestMatch = null;
@@ -743,7 +880,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{
foreach (string pattern in m_streamHandlers.Keys)
{
- if (handlerKey.StartsWith(pattern))
+ if ((handlerKey == pattern)
+ || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
{
if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
{
@@ -773,7 +911,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{
foreach (string pattern in m_pollHandlers.Keys)
{
- if (handlerKey.StartsWith(pattern))
+ if ((handlerKey == pattern)
+ || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
{
if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
{
@@ -805,7 +944,8 @@ namespace OpenSim.Framework.Servers.HttpServer
{
foreach (string pattern in m_HTTPHandlers.Keys)
{
- if (handlerKey.StartsWith(pattern))
+ if ((handlerKey == pattern)
+ || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
{
if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
{
@@ -854,16 +994,33 @@ namespace OpenSim.Framework.Servers.HttpServer
///
private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response)
{
+ String requestBody;
+
Stream requestStream = request.InputStream;
+ Stream innerStream = null;
+ try
+ {
+ if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip"))
+ {
+ innerStream = requestStream;
+ requestStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
+ }
- Encoding encoding = Encoding.UTF8;
- StreamReader reader = new StreamReader(requestStream, encoding);
+ using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8))
+ {
+ requestBody = reader.ReadToEnd();
+ }
+ }
+ finally
+ {
+ if (innerStream != null)
+ innerStream.Dispose();
+ requestStream.Dispose();
+ }
- string requestBody = reader.ReadToEnd();
- reader.Close();
- requestStream.Close();
//m_log.Debug(requestBody);
requestBody = requestBody.Replace("", "");
+
string responseString = String.Empty;
XmlRpcRequest xmlRprcRequest = null;
@@ -958,7 +1115,19 @@ namespace OpenSim.Framework.Servers.HttpServer
}
response.ContentType = "text/xml";
- responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse);
+ using (MemoryStream outs = new MemoryStream())
+ using (XmlTextWriter writer = new XmlTextWriter(outs, UTF8NoBOM))
+ {
+ writer.Formatting = Formatting.None;
+ XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse);
+ writer.Flush();
+ outs.Flush();
+ outs.Position = 0;
+ using (StreamReader sr = new StreamReader(outs))
+ {
+ responseString = sr.ReadToEnd();
+ }
+ }
}
else
{
@@ -985,6 +1154,93 @@ namespace OpenSim.Framework.Servers.HttpServer
return buffer;
}
+ // JsonRpc (v2.0 only)
+ // Batch requests not yet supported
+ private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
+ {
+ Stream requestStream = request.InputStream;
+ JsonRpcResponse jsonRpcResponse = new JsonRpcResponse();
+ OSDMap jsonRpcRequest = null;
+
+ try
+ {
+ jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream);
+ }
+ catch (LitJson.JsonException e)
+ {
+ jsonRpcResponse.Error.Code = ErrorCode.InternalError;
+ jsonRpcResponse.Error.Message = e.Message;
+ }
+
+ requestStream.Close();
+
+ if (jsonRpcRequest != null)
+ {
+ if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0")
+ {
+ jsonRpcResponse.JsonRpc = "2.0";
+
+ // If we have no id, then it's a "notification"
+ if (jsonRpcRequest.ContainsKey("id"))
+ {
+ jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
+ }
+
+ string methodname = jsonRpcRequest["method"];
+ JsonRPCMethod method;
+
+ if (jsonRpcHandlers.ContainsKey(methodname))
+ {
+ lock(jsonRpcHandlers)
+ {
+ jsonRpcHandlers.TryGetValue(methodname, out method);
+ }
+ bool res = false;
+ try
+ {
+ res = method(jsonRpcRequest, ref jsonRpcResponse);
+ if(!res)
+ {
+ // The handler sent back an unspecified error
+ if(jsonRpcResponse.Error.Code == 0)
+ {
+ jsonRpcResponse.Error.Code = ErrorCode.InternalError;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
+ m_log.Error(ErrorMessage);
+ jsonRpcResponse.Error.Code = ErrorCode.InternalError;
+ jsonRpcResponse.Error.Message = ErrorMessage;
+ }
+ }
+ else // Error no hanlder defined for requested method
+ {
+ jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
+ jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname);
+ }
+ }
+ else // not json-rpc 2.0 could be v1
+ {
+ jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
+ jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
+
+ if (jsonRpcRequest.ContainsKey("id"))
+ jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
+ }
+ }
+
+ response.KeepAlive = true;
+ string responseData = string.Empty;
+
+ responseData = jsonRpcResponse.Serialize();
+
+ byte[] buffer = Encoding.UTF8.GetBytes(responseData);
+ return buffer;
+ }
+
private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
{
//m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
@@ -1575,16 +1831,24 @@ namespace OpenSim.Framework.Servers.HttpServer
response.SendChunked = false;
response.ContentLength64 = buffer.Length;
response.ContentEncoding = Encoding.UTF8;
-
+
+
return buffer;
}
public void Start()
{
- StartHTTP();
+ Start(true);
}
- private void StartHTTP()
+ ///
+ /// Start the http server
+ ///
+ ///
+ /// If true then poll responses are performed asynchronsly.
+ /// Option exists to allow regression tests to perform processing synchronously.
+ ///
+ public void Start(bool performPollResponsesAsync)
{
m_log.InfoFormat(
"[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
@@ -1622,8 +1886,9 @@ namespace OpenSim.Framework.Servers.HttpServer
m_httpListener2.Start(64);
// Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
- m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
- m_PollServiceManager.Start();
+ PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000);
+ PollServiceRequestManager.Start();
+
HTTPDRunning = true;
//HttpListenerContext context;
@@ -1642,6 +1907,21 @@ namespace OpenSim.Framework.Servers.HttpServer
// useful without inbound HTTP.
throw e;
}
+
+ m_requestsProcessedStat
+ = new Stat(
+ "HTTPRequestsServed",
+ "Number of inbound HTTP requests processed",
+ "",
+ "requests",
+ "httpserver",
+ Port.ToString(),
+ StatType.Pull,
+ MeasuresOfInterest.AverageChangeOverTime,
+ stat => stat.Value = RequestNumber,
+ StatVerbosity.Debug);
+
+ StatsManager.RegisterStat(m_requestsProcessedStat);
}
public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
@@ -1672,9 +1952,12 @@ namespace OpenSim.Framework.Servers.HttpServer
public void Stop()
{
HTTPDRunning = false;
+
+ StatsManager.DeregisterStat(m_requestsProcessedStat);
+
try
{
- m_PollServiceManager.Stop();
+ PollServiceRequestManager.Stop();
m_httpListener2.ExceptionThrown -= httpServerException;
//m_httpListener2.DisconnectHandler = null;
@@ -1741,6 +2024,12 @@ namespace OpenSim.Framework.Servers.HttpServer
m_rpcHandlers.Remove(method);
}
+ public void RemoveJsonRPCHandler(string method)
+ {
+ lock(jsonRpcHandlers)
+ jsonRpcHandlers.Remove(method);
+ }
+
public bool RemoveLLSDHandler(string path, LLSDMethod handler)
{
lock (m_llsdHandlers)
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
new file mode 100644
index 0000000..72b3065
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
@@ -0,0 +1,60 @@
+/*
+ * 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.IO;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ ///
+ /// Base handler for writing to an output stream
+ ///
+ ///
+ /// Inheriting classes should override ProcessRequest() rather than Handle()
+ ///
+ public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler
+ {
+ protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
+
+ protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description)
+ : base(httpMethod, path, name, description) {}
+
+ public virtual void Handle(
+ string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ RequestsReceived++;
+
+ ProcessRequest(path, request, response, httpRequest, httpResponse);
+
+ RequestsHandled++;
+ }
+
+ protected virtual void ProcessRequest(
+ string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs
index ae7aaf2..d4a1ec3 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs
@@ -26,11 +26,16 @@
*/
using System;
+using OpenSim.Framework.Monitoring;
namespace OpenSim.Framework.Servers.HttpServer
{
public abstract class BaseRequestHandler
{
+ public int RequestsReceived { get; protected set; }
+
+ public int RequestsHandled { get; protected set; }
+
public virtual string ContentType
{
get { return "application/xml"; }
@@ -57,6 +62,24 @@ namespace OpenSim.Framework.Servers.HttpServer
Description = description;
m_httpMethod = httpMethod;
m_path = path;
+
+ // FIXME: A very temporary measure to stop the simulator stats being overwhelmed with user CAPS info.
+ // Needs to be fixed properly in stats display
+ if (!path.StartsWith("/CAPS/"))
+ {
+ StatsManager.RegisterStat(
+ new Stat(
+ "requests",
+ "requests",
+ "Number of requests received by this service endpoint",
+ "requests",
+ "service",
+ string.Format("{0}:{1}", httpMethod, path),
+ StatType.Pull,
+ MeasuresOfInterest.AverageChangeOverTime,
+ s => s.Value = RequestsReceived,
+ StatVerbosity.Debug));
+ }
}
public virtual string Path
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs
index 6342983..41aa19b 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs
@@ -26,17 +26,60 @@
*/
using System.IO;
+using System.Net;
+using OpenSim.Framework.ServiceAuth;
namespace OpenSim.Framework.Servers.HttpServer
{
+ ///
+ /// Base streamed request handler.
+ ///
+ ///
+ /// Inheriting classes should override ProcessRequest() rather than Handle()
+ ///
public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler
{
- public abstract byte[] Handle(string path, Stream request,
- IOSHttpRequest httpRequest, IOSHttpResponse httpResponse);
+ protected IServiceAuth m_Auth;
- protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
+ protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) { }
protected BaseStreamHandler(string httpMethod, string path, string name, string description)
: base(httpMethod, path, name, description) {}
+
+ protected BaseStreamHandler(string httpMethod, string path, IServiceAuth auth)
+ : base(httpMethod, path, null, null)
+ {
+ m_Auth = auth;
+ }
+
+ public virtual byte[] Handle(
+ string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ RequestsReceived++;
+
+ if (m_Auth != null)
+ {
+ HttpStatusCode statusCode;
+
+ if (!m_Auth.Authenticate(httpRequest.Headers, httpResponse.AddHeader, out statusCode))
+ {
+ httpResponse.StatusCode = (int)statusCode;
+ httpResponse.ContentType = "text/plain";
+ return new byte[0];
+ }
+ }
+
+ byte[] result = ProcessRequest(path, request, httpRequest, httpResponse);
+
+ RequestsHandled++;
+
+ return result;
+ }
+
+ protected virtual byte[] ProcessRequest(
+ string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ return null;
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs
new file mode 100644
index 0000000..1b88545
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs
@@ -0,0 +1,107 @@
+/*
+ * 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 OpenSim.Framework;
+using System.IO;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ ///
+ /// BaseStreamHandlerBasicDOSProtector Base streamed request handler.
+ ///
+ ///
+ /// Inheriting classes should override ProcessRequest() rather than Handle()
+ ///
+ public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler
+ {
+
+ private readonly BasicDosProtectorOptions _options;
+ private readonly BasicDOSProtector _dosProtector;
+
+ protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, BasicDosProtectorOptions options) : this(httpMethod, path, null, null, options) {}
+
+ protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, string name, string description, BasicDosProtectorOptions options)
+ : base(httpMethod, path, name, description)
+ {
+ _options = options;
+ _dosProtector = new BasicDOSProtector(_options);
+ }
+
+ public virtual byte[] Handle(
+ string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ byte[] result;
+ RequestsReceived++;
+ string clientstring = GetClientString(httpRequest);
+ string endpoint = GetRemoteAddr(httpRequest);
+ if (_dosProtector.Process(clientstring, endpoint))
+ result = ProcessRequest(path, request, httpRequest, httpResponse);
+ else
+ result = ThrottledRequest(path, request, httpRequest, httpResponse);
+ if (_options.MaxConcurrentSessions > 0)
+ _dosProtector.ProcessEnd(clientstring, endpoint);
+
+ RequestsHandled++;
+
+ return result;
+ }
+
+ protected virtual byte[] ProcessRequest(
+ string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ return null;
+ }
+
+ protected virtual byte[] ThrottledRequest(
+ string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ {
+ return new byte[0];
+ }
+
+
+ private string GetRemoteAddr(IOSHttpRequest httpRequest)
+ {
+ string remoteaddr = string.Empty;
+ if (httpRequest.Headers["remote_addr"] != null)
+ remoteaddr = httpRequest.Headers["remote_addr"];
+
+ return remoteaddr;
+ }
+
+ private string GetClientString(IOSHttpRequest httpRequest)
+ {
+ string clientstring = string.Empty;
+
+ if (_options.AllowXForwardedFor && httpRequest.Headers["x-forwarded-for"] != null)
+ clientstring = httpRequest.Headers["x-forwarded-for"];
+ else
+ clientstring = GetRemoteAddr(httpRequest);
+
+ return clientstring;
+
+ }
+ }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs
index b94bfb4..1b03f54 100644
--- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer
m_method = binaryMethod;
}
- public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
byte[] data = ReadFully(request);
string param = GetParam(path);
diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs
new file mode 100644
index 0000000..cd4b8ff
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs
@@ -0,0 +1,119 @@
+/*
+ * 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.Collections;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ public class GenericHTTPDOSProtector
+ {
+ private readonly GenericHTTPMethod _normalMethod;
+ private readonly GenericHTTPMethod _throttledMethod;
+
+ private readonly BasicDosProtectorOptions _options;
+ private readonly BasicDOSProtector _dosProtector;
+
+ public GenericHTTPDOSProtector(GenericHTTPMethod normalMethod, GenericHTTPMethod throttledMethod, BasicDosProtectorOptions options)
+ {
+ _normalMethod = normalMethod;
+ _throttledMethod = throttledMethod;
+
+ _options = options;
+ _dosProtector = new BasicDOSProtector(_options);
+ }
+ public Hashtable Process(Hashtable request)
+ {
+ Hashtable process = null;
+ string clientstring= GetClientString(request);
+ string endpoint = GetRemoteAddr(request);
+ if (_dosProtector.Process(clientstring, endpoint))
+ process = _normalMethod(request);
+ else
+ process = _throttledMethod(request);
+
+ if (_options.MaxConcurrentSessions>0)
+ _dosProtector.ProcessEnd(clientstring, endpoint);
+
+ return process;
+ }
+
+ private string GetRemoteAddr(Hashtable request)
+ {
+ string remoteaddr = "";
+ if (!request.ContainsKey("headers"))
+ return remoteaddr;
+ Hashtable requestinfo = (Hashtable)request["headers"];
+ if (!requestinfo.ContainsKey("remote_addr"))
+ return remoteaddr;
+ object remote_addrobj = requestinfo["remote_addr"];
+ if (remote_addrobj != null)
+ {
+ if (!string.IsNullOrEmpty(remote_addrobj.ToString()))
+ {
+ remoteaddr = remote_addrobj.ToString();
+ }
+
+ }
+ return remoteaddr;
+ }
+
+ private string GetClientString(Hashtable request)
+ {
+ string clientstring = "";
+ if (!request.ContainsKey("headers"))
+ return clientstring;
+
+ Hashtable requestinfo = (Hashtable)request["headers"];
+ if (_options.AllowXForwardedFor && requestinfo.ContainsKey("x-forwarded-for"))
+ {
+ object str = requestinfo["x-forwarded-for"];
+ if (str != null)
+ {
+ if (!string.IsNullOrEmpty(str.ToString()))
+ {
+ return str.ToString();
+ }
+ }
+ }
+ if (!requestinfo.ContainsKey("remote_addr"))
+ return clientstring;
+
+ object remote_addrobj = requestinfo["remote_addr"];
+ if (remote_addrobj != null)
+ {
+ if (!string.IsNullOrEmpty(remote_addrobj.ToString()))
+ {
+ clientstring = remote_addrobj.ToString();
+ }
+ }
+
+ return clientstring;
+
+ }
+
+ }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
index 0bd3aae..d162bc1 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs
@@ -97,6 +97,18 @@ namespace OpenSim.Framework.Servers.HttpServer
bool AddXmlRPCHandler(string method, XmlRpcMethod handler);
bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive);
+ bool AddJsonRPCHandler(string method, JsonRPCMethod handler);
+
+ ///
+ /// Websocket HTTP server handlers.
+ ///
+ ///
+ ///
+ void AddWebSocketHandler(string servicepath, BaseHttpServer.WebSocketRequestDelegate handler);
+
+
+ void RemoveWebSocketHandler(string servicepath);
+
///
/// Gets the XML RPC handler for given method name
///
@@ -128,6 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer
void RemoveStreamHandler(string httpMethod, string path);
void RemoveXmlRPCHandler(string method);
+
+ void RemoveJsonRPCHandler(string method);
string GetHTTP404(string host);
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs
index cb5cce5..b8541cb 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs
@@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer
{
public interface IRequestHandler
{
-
///
/// Name for this handler.
///
@@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer
// Return path
string Path { get; }
+
+ ///
+ /// Number of requests received by this handler
+ ///
+ int RequestsReceived { get; }
+
+ ///
+ /// Number of requests handled.
+ ///
+ ///
+ /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock.
+ ///
+ int RequestsHandled { get; }
}
public interface IStreamedRequestHandler : IRequestHandler
@@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer
public interface IStreamHandler : IRequestHandler
{
- // Handle request stream, return byte array
void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse);
}
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
new file mode 100644
index 0000000..5bab508
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
@@ -0,0 +1,34 @@
+/*
+ * 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.Net;
+using OpenMetaverse.StructuredData;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response);
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs
new file mode 100644
index 0000000..2fe1a7d
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs
@@ -0,0 +1,190 @@
+/*
+ * 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.Net;
+using System.Net.Sockets;
+using System.Reflection;
+using System.Text;
+using System.IO;
+using OpenMetaverse.StructuredData;
+using OpenMetaverse;
+using log4net;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ ///
+ /// Json rpc request manager.
+ ///
+ public class JsonRpcRequestManager
+ {
+ static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public JsonRpcRequestManager()
+ {
+ }
+
+ ///
+ /// Sends json-rpc request with a serializable type.
+ ///
+ ///
+ /// OSD Map.
+ ///
+ ///
+ /// Serializable type .
+ ///
+ ///
+ /// Json-rpc method to call.
+ ///
+ ///
+ /// URI of json-rpc service.
+ ///
+ ///
+ /// Id for our call.
+ ///
+ public bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId)
+ {
+ if (jsonId == null)
+ throw new ArgumentNullException("jsonId");
+ if (uri == null)
+ throw new ArgumentNullException("uri");
+ if (method == null)
+ throw new ArgumentNullException("method");
+ if (parameters == null)
+ throw new ArgumentNullException("parameters");
+
+ OSDMap request = new OSDMap();
+ request.Add("jsonrpc", OSD.FromString("2.0"));
+ request.Add("id", OSD.FromString(jsonId));
+ request.Add("method", OSD.FromString(method));
+ request.Add("params", OSD.SerializeMembers(parameters));
+
+ OSDMap response;
+ try
+ {
+ response = WebUtil.PostToService(uri, request, 10000, true);
+ }
+ catch (Exception e)
+ {
+ m_log.Debug(string.Format("JsonRpc request '{0}' to {1} failed", method, uri), e);
+ return false;
+ }
+
+ if (!response.ContainsKey("_Result"))
+ {
+ m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}",
+ method, uri, OSDParser.SerializeJsonString(response));
+ return false;
+ }
+ response = (OSDMap)response["_Result"];
+
+ OSD data;
+
+ if (response.ContainsKey("error"))
+ {
+ data = response["error"];
+ m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an error: {2}",
+ method, uri, OSDParser.SerializeJsonString(data));
+ return false;
+ }
+
+ if (!response.ContainsKey("result"))
+ {
+ m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}",
+ method, uri, OSDParser.SerializeJsonString(response));
+ return false;
+ }
+
+ data = response["result"];
+ OSD.DeserializeMembers(ref parameters, (OSDMap)data);
+
+ return true;
+ }
+
+ ///
+ /// Sends json-rpc request with OSD parameter.
+ ///
+ ///
+ /// The rpc request.
+ ///
+ ///
+ /// data - incoming as parameters, outgoing as result/error
+ ///
+ ///
+ /// Json-rpc method to call.
+ ///
+ ///
+ /// URI of json-rpc service.
+ ///
+ ///
+ /// If set to true json identifier.
+ ///
+ public bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId)
+ {
+ if (string.IsNullOrEmpty(jsonId))
+ jsonId = UUID.Random().ToString();
+
+ OSDMap request = new OSDMap();
+ request.Add("jsonrpc", OSD.FromString("2.0"));
+ request.Add("id", OSD.FromString(jsonId));
+ request.Add("method", OSD.FromString(method));
+ request.Add("params", data);
+
+ OSDMap response;
+ try
+ {
+ response = WebUtil.PostToService(uri, request, 10000, true);
+ }
+ catch (Exception e)
+ {
+ m_log.Debug(string.Format("JsonRpc request '{0}' to {1} failed", method, uri), e);
+ return false;
+ }
+
+ if (!response.ContainsKey("_Result"))
+ {
+ m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}",
+ method, uri, OSDParser.SerializeJsonString(response));
+ return false;
+ }
+ response = (OSDMap)response["_Result"];
+
+ if (response.ContainsKey("error"))
+ {
+ data = response["error"];
+ m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an error: {2}",
+ method, uri, OSDParser.SerializeJsonString(data));
+ return false;
+ }
+
+ data = response;
+
+ return true;
+ }
+
+ }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
new file mode 100644
index 0000000..2c50587
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs
@@ -0,0 +1,150 @@
+/*
+ * 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.Net;
+using OpenMetaverse.StructuredData;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ public sealed class ErrorCode
+ {
+ private ErrorCode() {}
+
+ public const int ParseError = -32700;
+ public const int InvalidRequest = -32600;
+ public const int MethodNotFound = -32601;
+ public const int InvalidParams = -32602;
+ public const int InternalError = -32604;
+
+ }
+
+ public class JsonRpcError
+ {
+ internal OSDMap Error = new OSDMap();
+
+ public int Code
+ {
+ get
+ {
+ if (Error.ContainsKey("code"))
+ return Error["code"].AsInteger();
+ else
+ return 0;
+ }
+ set
+ {
+ Error["code"] = OSD.FromInteger(value);
+ }
+ }
+
+ public string Message
+ {
+ get
+ {
+ if (Error.ContainsKey("message"))
+ return Error["message"].AsString();
+ else
+ return null;
+ }
+ set
+ {
+ Error["message"] = OSD.FromString(value);
+ }
+ }
+
+ public OSD Data
+ {
+ get; set;
+ }
+ }
+
+ public class JsonRpcResponse
+ {
+ public string JsonRpc
+ {
+ get
+ {
+ return Reply["jsonrpc"].AsString();
+ }
+ set
+ {
+ Reply["jsonrpc"] = OSD.FromString(value);
+ }
+ }
+
+ public string Id
+ {
+ get
+ {
+ return Reply["id"].AsString();
+ }
+ set
+ {
+ Reply["id"] = OSD.FromString(value);
+ }
+ }
+
+ public OSD Result
+ {
+ get; set;
+ }
+
+ public JsonRpcError Error
+ {
+ get; set;
+ }
+
+ public OSDMap Reply = new OSDMap();
+
+ public JsonRpcResponse()
+ {
+ Error = new JsonRpcError();
+ }
+
+ public string Serialize()
+ {
+ if (Result != null)
+ Reply["result"] = Result;
+
+ if (Error.Code != 0)
+ {
+ Reply["error"] = (OSD)Error.Error;
+ }
+
+ string result = string.Empty;
+ try
+ {
+ result = OSDParser.SerializeJsonString(Reply);
+ }
+ catch
+ {
+
+ }
+ return result;
+ }
+ }
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs
index 3171759..05ec6dc 100644
--- a/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs
+++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs
@@ -182,11 +182,22 @@ namespace OpenSim.Framework.Servers.HttpServer
_context = context;
if (null != req.Headers["content-encoding"])
- _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]);
+ {
+ try
+ {
+ _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]);
+ }
+ catch (Exception)
+ {
+ // ignore
+ }
+ }
+
if (null != req.Headers["content-type"])
_contentType = _request.Headers["content-type"];
if (null != req.Headers["user-agent"])
_userAgent = req.Headers["user-agent"];
+
if (null != req.Headers["remote_addr"])
{
try
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs
index 77cfb7e..bdea278 100644
--- a/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs
+++ b/OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs
@@ -70,9 +70,9 @@ namespace OpenSim.Framework.Servers.HttpServer
_id = id;
_engine = new Thread(new ThreadStart(Engine));
- _engine.Name = EngineID;
_engine.IsBackground = true;
_engine.Start();
+ _engine.Name = string.Format ("Engine:{0}",EngineID);
ThreadTracker.Add(_engine);
}
@@ -91,9 +91,9 @@ namespace OpenSim.Framework.Servers.HttpServer
public void Start()
{
_engine = new Thread(new ThreadStart(Engine));
- _engine.Name = EngineID;
_engine.IsBackground = true;
_engine.Start();
+ _engine.Name = string.Format ("Engine:{0}",EngineID);
ThreadTracker.Add(_engine);
}
diff --git a/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs
index 84aa31b..cd62842 100644
--- a/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs
@@ -150,9 +150,9 @@ namespace OpenSim.Framework.Servers.HttpServer
public void Start()
{
_engine = new Thread(new ThreadStart(Engine));
- _engine.Name = _engineId;
_engine.IsBackground = true;
_engine.Start();
+ _engine.Name = string.Format ("Engine:{0}",_engineId);
ThreadTracker.Add(_engine);
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index 3089351..9477100 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -34,7 +34,7 @@ namespace OpenSim.Framework.Servers.HttpServer
public delegate void RequestMethod(UUID requestID, Hashtable request);
public delegate bool HasEventsMethod(UUID requestID, UUID pId);
- public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId, string request);
+ public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId);
public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId);
@@ -45,17 +45,42 @@ namespace OpenSim.Framework.Servers.HttpServer
public NoEventsMethod NoEvents;
public RequestMethod Request;
public UUID Id;
+ public int TimeOutms;
+ public EventType Type;
+
+ public enum EventType : int
+ {
+ LongPoll = 0,
+ LslHttp = 1,
+ Inventory = 2
+ }
+
+ public string Url { get; set; }
+
+ ///
+ /// Number of requests received for this poll service.
+ ///
+ public int RequestsReceived { get; set; }
+
+ ///
+ /// Number of requests handled by this poll service.
+ ///
+ public int RequestsHandled { get; set; }
public PollServiceEventArgs(
RequestMethod pRequest,
+ string pUrl,
HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
- UUID pId)
+ UUID pId, int pTimeOutms)
{
Request = pRequest;
+ Url = pUrl;
HasEvents = pHasEvents;
GetEvents = pGetEvents;
NoEvents = pNoEvents;
Id = pId;
+ TimeOutms = pTimeOutms;
+ Type = EventType.LongPoll;
}
}
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
index 723530a..caf0e98 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
@@ -26,13 +26,19 @@
*/
using System;
+using System.Collections;
+using System.Reflection;
+using System.Text;
using HttpServer;
+using log4net;
using OpenMetaverse;
namespace OpenSim.Framework.Servers.HttpServer
{
public class PollServiceHttpRequest
{
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
public readonly PollServiceEventArgs PollServiceArgs;
public readonly IHttpClientContext HttpContext;
public readonly IHttpRequest Request;
@@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer
RequestTime = System.Environment.TickCount;
RequestID = UUID.Random();
}
+
+ internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata)
+ {
+ OSHttpResponse response
+ = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext);
+
+ byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
+
+ response.SendChunked = false;
+ response.ContentLength64 = buffer.Length;
+ response.ContentEncoding = Encoding.UTF8;
+
+ try
+ {
+ response.OutputStream.Write(buffer, 0, buffer.Length);
+ }
+ catch (Exception ex)
+ {
+ m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex);
+ }
+ finally
+ {
+ //response.OutputStream.Close();
+ try
+ {
+ response.OutputStream.Flush();
+ response.Send();
+
+ //if (!response.KeepAlive && response.ReuseContext)
+ // response.FreeContext();
+ }
+ catch (Exception e)
+ {
+ m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", e);
+ }
+
+ PollServiceArgs.RequestsHandled++;
+ }
+ }
}
}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 3e84c55..28bba70 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -33,132 +33,298 @@ using log4net;
using HttpServer;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
+using Amib.Threading;
+using System.IO;
+using System.Text;
+using System.Collections.Generic;
namespace OpenSim.Framework.Servers.HttpServer
{
public class PollServiceRequestManager
{
-// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ ///
+ /// Is the poll service request manager running?
+ ///
+ ///
+ /// Can be running either synchronously or asynchronously
+ ///
+ public bool IsRunning { get; private set; }
+
+ ///
+ /// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via
+ /// external calls)?
+ ///
+ public bool PerformResponsesAsync { get; private set; }
+
+ ///
+ /// Number of responses actually processed and sent to viewer (or aborted due to error).
+ ///
+ public int ResponsesProcessed { get; private set; }
private readonly BaseHttpServer m_server;
- private static Queue m_requests = Queue.Synchronized(new Queue());
+
+ private BlockingQueue m_requests = new BlockingQueue();
+ private static List m_longPollRequests = new List();
+
private uint m_WorkerThreadCount = 0;
private Thread[] m_workerThreads;
- private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
- private volatile bool m_running = true;
- private int m_pollTimeout;
- public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
+ private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
+
+// private int m_timeout = 1000; // increase timeout 250; now use the event one
+
+ public PollServiceRequestManager(
+ BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout)
{
m_server = pSrv;
+ PerformResponsesAsync = performResponsesAsync;
m_WorkerThreadCount = pWorkerThreadCount;
- m_pollTimeout = pTimeout;
+ m_workerThreads = new Thread[m_WorkerThreadCount];
+
+ StatsManager.RegisterStat(
+ new Stat(
+ "QueuedPollResponses",
+ "Number of poll responses queued for processing.",
+ "",
+ "",
+ "httpserver",
+ m_server.Port.ToString(),
+ StatType.Pull,
+ MeasuresOfInterest.AverageChangeOverTime,
+ stat => stat.Value = m_requests.Count(),
+ StatVerbosity.Debug));
+
+ StatsManager.RegisterStat(
+ new Stat(
+ "ProcessedPollResponses",
+ "Number of poll responses processed.",
+ "",
+ "",
+ "httpserver",
+ m_server.Port.ToString(),
+ StatType.Pull,
+ MeasuresOfInterest.AverageChangeOverTime,
+ stat => stat.Value = ResponsesProcessed,
+ StatVerbosity.Debug));
}
public void Start()
{
- m_running = true;
- m_workerThreads = new Thread[m_WorkerThreadCount];
- m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
+ IsRunning = true;
- //startup worker threads
- for (uint i = 0; i < m_WorkerThreadCount; i++)
+ if (PerformResponsesAsync)
{
- m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
- m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
-
- m_workerThreads[i]
- = Watchdog.StartThread(
- m_PollServiceWorkerThreads[i].ThreadStart,
- String.Format("PollServiceWorkerThread{0}", i),
- ThreadPriority.Normal,
- false,
- true,
- null,
- int.MaxValue);
- }
+ //startup worker threads
+ for (uint i = 0; i < m_WorkerThreadCount; i++)
+ {
+ m_workerThreads[i]
+ = WorkManager.StartThread(
+ PoolWorkerJob,
+ string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
+ ThreadPriority.Normal,
+ false,
+ false,
+ null,
+ int.MaxValue);
+ }
- Watchdog.StartThread(
- this.ThreadStart,
- "PollServiceWatcherThread",
- ThreadPriority.Normal,
- false,
- true,
- null,
- 1000 * 60 * 10);
+ WorkManager.StartThread(
+ this.CheckLongPollThreads,
+ string.Format("LongPollServiceWatcherThread:{0}", m_server.Port),
+ ThreadPriority.Normal,
+ false,
+ true,
+ null,
+ 1000 * 60 * 10);
+ }
}
- internal void ReQueueEvent(PollServiceHttpRequest req)
+ private void ReQueueEvent(PollServiceHttpRequest req)
{
- // Do accounting stuff here
- Enqueue(req);
- }
+ if (IsRunning)
+ {
+ // delay the enqueueing for 100ms. There's no need to have the event
+ // actively on the queue
+ Timer t = new Timer(self => {
+ ((Timer)self).Dispose();
+ m_requests.Enqueue(req);
+ });
- public void Enqueue(PollServiceHttpRequest req)
- {
- lock (m_requests)
- m_requests.Enqueue(req);
+ t.Change(100, Timeout.Infinite);
+
+ }
}
- public void ThreadStart()
+ public void Enqueue(PollServiceHttpRequest req)
{
- while (m_running)
+ if (IsRunning)
{
- Watchdog.UpdateThread();
- ProcessQueuedRequests();
- Thread.Sleep(1000);
+ if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
+ {
+ lock (m_longPollRequests)
+ m_longPollRequests.Add(req);
+ }
+ else
+ m_requests.Enqueue(req);
}
}
- private void ProcessQueuedRequests()
+ private void CheckLongPollThreads()
{
- lock (m_requests)
+ // The only purpose of this thread is to check the EQs for events.
+ // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests.
+ // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests.
+ // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
+ // so if they aren't ready to be served by a worker thread (no events), they are placed
+ // directly back in the "ready-to-serve" queue by the worker thread.
+ while (IsRunning)
{
- if (m_requests.Count == 0)
- return;
-
-// m_log.DebugFormat("[POLL SERVICE REQUEST MANAGER]: Processing {0} requests", m_requests.Count);
-
- int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1;
+ Thread.Sleep(500);
+ Watchdog.UpdateThread();
- // For Each WorkerThread
- for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++)
+// List not_ready = new List();
+ lock (m_longPollRequests)
{
- //Loop over number of requests each thread handles.
- for (int i = 0; i < reqperthread && m_requests.Count > 0; i++)
+ if (m_longPollRequests.Count > 0 && IsRunning)
{
- try
- {
- m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue());
- }
- catch (InvalidOperationException)
- {
- // The queue is empty, we did our calculations wrong!
- return;
- }
-
+ List ready = m_longPollRequests.FindAll(req =>
+ (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
+ (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout
+ );
+
+ ready.ForEach(req =>
+ {
+ m_requests.Enqueue(req);
+ m_longPollRequests.Remove(req);
+ });
+
}
+
}
}
-
}
public void Stop()
{
- m_running = false;
+ IsRunning = false;
+// m_timeout = -10000; // cause all to expire
+ Thread.Sleep(1000); // let the world move
+
+ foreach (Thread t in m_workerThreads)
+ Watchdog.AbortThread(t.ManagedThreadId);
+
+ PollServiceHttpRequest wreq;
- foreach (object o in m_requests)
+ lock (m_longPollRequests)
{
- PollServiceHttpRequest req = (PollServiceHttpRequest) o;
- PollServiceWorkerThread.DoHTTPGruntWork(
- m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
+ if (m_longPollRequests.Count > 0 && IsRunning)
+ m_longPollRequests.ForEach(req => m_requests.Enqueue(req));
}
+ while (m_requests.Count() > 0)
+ {
+ try
+ {
+ wreq = m_requests.Dequeue(0);
+ ResponsesProcessed++;
+ wreq.DoHTTPGruntWork(
+ m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id));
+ }
+ catch
+ {
+ }
+ }
+
+ m_longPollRequests.Clear();
m_requests.Clear();
+ }
- foreach (Thread t in m_workerThreads)
+ // work threads
+
+ private void PoolWorkerJob()
+ {
+ while (IsRunning)
{
- t.Abort();
+ Watchdog.UpdateThread();
+ WaitPerformResponse();
+ }
+ }
+
+ public void WaitPerformResponse()
+ {
+ PollServiceHttpRequest req = m_requests.Dequeue(5000);
+// m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
+
+ if (req != null)
+ {
+ try
+ {
+ if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
+ {
+ Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
+
+ if (responsedata == null)
+ return;
+
+ // This is the event queue.
+ // Even if we're not running we can still perform responses by explicit request.
+ if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll
+ || !PerformResponsesAsync)
+ {
+ try
+ {
+ ResponsesProcessed++;
+ req.DoHTTPGruntWork(m_server, responsedata);
+ }
+ catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
+ {
+ // Ignore it, no need to reply
+ m_log.Error(e);
+ }
+ }
+ else
+ {
+ m_threadPool.QueueWorkItem(x =>
+ {
+ try
+ {
+ ResponsesProcessed++;
+ req.DoHTTPGruntWork(m_server, responsedata);
+ }
+ catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
+ {
+ // Ignore it, no need to reply
+ m_log.Error(e);
+ }
+ catch (Exception e)
+ {
+ m_log.Error(e);
+ }
+
+ return null;
+ }, null);
+ }
+ }
+ else
+ {
+ if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
+ {
+ ResponsesProcessed++;
+ req.DoHTTPGruntWork(
+ m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
+ }
+ else
+ {
+ ReQueueEvent(req);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
+ }
}
}
}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
deleted file mode 100644
index 5adbcd1..0000000
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * 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.Text;
-using HttpServer;
-using OpenMetaverse;
-using System.Reflection;
-using log4net;
-using OpenSim.Framework.Monitoring;
-
-namespace OpenSim.Framework.Servers.HttpServer
-{
- public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req);
-
- public class PollServiceWorkerThread
- {
- private static readonly ILog m_log =
- LogManager.GetLogger(
- MethodBase.GetCurrentMethod().DeclaringType);
-
- public event ReQueuePollServiceItem ReQueue;
-
- private readonly BaseHttpServer m_server;
- private BlockingQueue m_request;
- private bool m_running = true;
- private int m_timeout = 250;
-
- public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout)
- {
- m_request = new BlockingQueue();
- m_server = pSrv;
- m_timeout = pTimeout;
- }
-
- public void ThreadStart()
- {
- Run();
- }
-
- public void Run()
- {
- while (m_running)
- {
- PollServiceHttpRequest req = m_request.Dequeue();
-
- Watchdog.UpdateThread();
-
- try
- {
- if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
- {
- StreamReader str;
- try
- {
- str = new StreamReader(req.Request.Body);
- }
- catch (System.ArgumentException)
- {
- // Stream was not readable means a child agent
- // was closed due to logout, leaving the
- // Event Queue request orphaned.
- continue;
- }
-
- Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd());
- DoHTTPGruntWork(m_server, req, responsedata);
- }
- else
- {
- if ((Environment.TickCount - req.RequestTime) > m_timeout)
- {
- DoHTTPGruntWork(
- m_server,
- req,
- req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
- }
- else
- {
- ReQueuePollServiceItem reQueueItem = ReQueue;
- if (reQueueItem != null)
- reQueueItem(req);
- }
- }
- }
- catch (Exception e)
- {
- m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
- }
- }
- }
-
- internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest)
- {
- m_request.Enqueue(pPollServiceHttpRequest);
- }
-
- ///
- /// FIXME: This should be part of BaseHttpServer
- ///
- internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata)
- {
- OSHttpResponse response
- = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext);
-
- byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
-
- response.SendChunked = false;
- response.ContentLength64 = buffer.Length;
- response.ContentEncoding = Encoding.UTF8;
-
- try
- {
- response.OutputStream.Write(buffer, 0, buffer.Length);
- }
- catch (Exception ex)
- {
- m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex));
- }
- finally
- {
- //response.OutputStream.Close();
- try
- {
- response.OutputStream.Flush();
- response.Send();
-
- //if (!response.KeepAlive && response.ReuseContext)
- // response.FreeContext();
- }
- catch (Exception e)
- {
- m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e));
- }
- }
- }
- }
-}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
index 02ecc25..5e630dc 100644
--- a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.7.5.*")]
-[assembly: AssemblyFileVersion("1.0.0.0")]
+[assembly: AssemblyVersion("0.8.3.*")]
+
diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs
index 07082a8..bd55657 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs
@@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer
{
public delegate TResponse RestDeserialiseMethod(TRequest request);
- public class RestDeserialiseHandler : BaseRequestHandler, IStreamHandler
+ public class RestDeserialiseHandler : BaseOutputStreamHandler, IStreamHandler
where TRequest : new()
{
private RestDeserialiseMethod m_method;
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
m_method = method;
}
- public void Handle(string path, Stream request, Stream responseStream,
+ protected override void ProcessRequest(string path, Stream request, Stream responseStream,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
TRequest deserial;
diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs
index 48ced19..afe052f 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs
@@ -52,23 +52,25 @@ namespace OpenSim.Framework.Servers.HttpServer
request.Method = verb;
request.ContentType = "text/xml";
- MemoryStream buffer = new MemoryStream();
+ using (MemoryStream buffer = new MemoryStream())
+ {
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Encoding = Encoding.UTF8;
- XmlWriterSettings settings = new XmlWriterSettings();
- settings.Encoding = Encoding.UTF8;
+ using (XmlWriter writer = XmlWriter.Create(buffer, settings))
+ {
+ XmlSerializer serializer = new XmlSerializer(type);
+ serializer.Serialize(writer, obj);
+ writer.Flush();
+ }
- using (XmlWriter writer = XmlWriter.Create(buffer, settings))
- {
- XmlSerializer serializer = new XmlSerializer(type);
- serializer.Serialize(writer, obj);
- writer.Flush();
- }
+ int length = (int)buffer.Length;
+ request.ContentLength = length;
- int length = (int) buffer.Length;
- request.ContentLength = length;
+ using (Stream requestStream = request.GetRequestStream())
+ requestStream.Write(buffer.ToArray(), 0, length);
+ }
- Stream requestStream = request.GetRequestStream();
- requestStream.Write(buffer.ToArray(), 0, length);
// IAsyncResult result = request.BeginGetResponse(AsyncCallback, request);
request.BeginGetResponse(AsyncCallback, request);
}
diff --git a/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs
index 451745c..a911b9f 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs
@@ -60,24 +60,25 @@ namespace OpenSim.Framework.Servers.HttpServer
request.ContentType = "text/xml";
request.Timeout = 10000;
- MemoryStream buffer = new MemoryStream();
+ using (MemoryStream buffer = new MemoryStream())
+ {
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Encoding = Encoding.UTF8;
+
+ using (XmlWriter writer = XmlWriter.Create(buffer, settings))
+ {
+ XmlSerializer serializer = new XmlSerializer(type);
+ serializer.Serialize(writer, obj);
+ writer.Flush();
+ }
- XmlWriterSettings settings = new XmlWriterSettings();
- settings.Encoding = Encoding.UTF8;
+ int length = (int)buffer.Length;
+ request.ContentLength = length;
- using (XmlWriter writer = XmlWriter.Create(buffer, settings))
- {
- XmlSerializer serializer = new XmlSerializer(type);
- serializer.Serialize(writer, obj);
- writer.Flush();
+ using (Stream requestStream = request.GetRequestStream())
+ requestStream.Write(buffer.ToArray(), 0, length);
}
- int length = (int) buffer.Length;
- request.ContentLength = length;
-
- Stream requestStream = request.GetRequestStream();
- requestStream.Write(buffer.ToArray(), 0, length);
- requestStream.Close();
// IAsyncResult result = request.BeginGetResponse(AsyncCallback, request);
request.BeginGetResponse(AsyncCallback, request);
}
diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
index 19c03a8..ad69cd2 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
@@ -77,44 +77,34 @@ namespace OpenSim.Framework.Servers.HttpServer
request.ContentType = "text/xml";
request.Timeout = 20000;
- MemoryStream buffer = new MemoryStream();
-
- XmlWriterSettings settings = new XmlWriterSettings();
- settings.Encoding = Encoding.UTF8;
-
- using (XmlWriter writer = XmlWriter.Create(buffer, settings))
+ using (MemoryStream buffer = new MemoryStream())
{
- XmlSerializer serializer = new XmlSerializer(type);
- serializer.Serialize(writer, sobj);
- writer.Flush();
- }
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Encoding = Encoding.UTF8;
- int length = (int)buffer.Length;
- request.ContentLength = length;
+ using (XmlWriter writer = XmlWriter.Create(buffer, settings))
+ {
+ XmlSerializer serializer = new XmlSerializer(type);
+ serializer.Serialize(writer, sobj);
+ writer.Flush();
+ }
- Stream requestStream = request.GetRequestStream();
- requestStream.Write(buffer.ToArray(), 0, length);
- buffer.Close();
- requestStream.Close();
+ int length = (int)buffer.Length;
+ request.ContentLength = length;
+
+ using (Stream requestStream = request.GetRequestStream())
+ requestStream.Write(buffer.ToArray(), 0, length);
+ }
TResponse deserial = default(TResponse);
using (WebResponse resp = request.GetResponse())
{
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
- Stream respStream = null;
- try
- {
- respStream = resp.GetResponseStream();
+
+ using (Stream respStream = resp.GetResponseStream())
deserial = (TResponse)deserializer.Deserialize(respStream);
- }
- catch { }
- finally
- {
- if (respStream != null)
- respStream.Close();
- resp.Close();
- }
}
+
return deserial;
}
}
@@ -142,25 +132,25 @@ namespace OpenSim.Framework.Servers.HttpServer
request.ContentType = "text/xml";
request.Timeout = 10000;
- MemoryStream buffer = new MemoryStream();
+ using (MemoryStream buffer = new MemoryStream())
+ {
+ XmlWriterSettings settings = new XmlWriterSettings();
+ settings.Encoding = Encoding.UTF8;
- XmlWriterSettings settings = new XmlWriterSettings();
- settings.Encoding = Encoding.UTF8;
+ using (XmlWriter writer = XmlWriter.Create(buffer, settings))
+ {
+ XmlSerializer serializer = new XmlSerializer(type);
+ serializer.Serialize(writer, sobj);
+ writer.Flush();
+ }
- using (XmlWriter writer = XmlWriter.Create(buffer, settings))
- {
- XmlSerializer serializer = new XmlSerializer(type);
- serializer.Serialize(writer, sobj);
- writer.Flush();
- }
- buffer.Close();
+ int length = (int)buffer.Length;
+ request.ContentLength = length;
- int length = (int)buffer.Length;
- request.ContentLength = length;
+ using (Stream requestStream = request.GetRequestStream())
+ requestStream.Write(buffer.ToArray(), 0, length);
+ }
- Stream requestStream = request.GetRequestStream();
- requestStream.Write(buffer.ToArray(), 0, length);
- requestStream.Close();
// IAsyncResult result = request.BeginGetResponse(AsyncCallback, request);
request.BeginGetResponse(AsyncCallback, request);
}
@@ -192,7 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer
public delegate bool CheckIdentityMethod(string sid, string aid);
- public class RestDeserialiseSecureHandler : BaseRequestHandler, IStreamHandler
+ public class RestDeserialiseSecureHandler : BaseOutputStreamHandler, IStreamHandler
where TRequest : new()
{
private static readonly ILog m_log
@@ -210,7 +200,7 @@ namespace OpenSim.Framework.Servers.HttpServer
m_method = method;
}
- public void Handle(string path, Stream request, Stream responseStream,
+ protected override void ProcessRequest(string path, Stream request, Stream responseStream,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
RestSessionObject deserial = default(RestSessionObject);
@@ -246,7 +236,7 @@ namespace OpenSim.Framework.Servers.HttpServer
public delegate bool CheckTrustedSourceMethod(IPEndPoint peer);
- public class RestDeserialiseTrustedHandler : BaseRequestHandler, IStreamHandler
+ public class RestDeserialiseTrustedHandler : BaseOutputStreamHandler, IStreamHandler
where TRequest : new()
{
private static readonly ILog m_log
@@ -269,7 +259,7 @@ namespace OpenSim.Framework.Servers.HttpServer
m_method = method;
}
- public void Handle(string path, Stream request, Stream responseStream,
+ protected override void ProcessRequest(string path, Stream request, Stream responseStream,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
TRequest deserial = default(TRequest);
@@ -301,6 +291,5 @@ namespace OpenSim.Framework.Servers.HttpServer
serializer.Serialize(xmlWriter, response);
}
}
- }
-
-}
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs
index 1f17fee..0305dee 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
m_restMethod = restMethod;
}
- public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
+ protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
Encoding encoding = Encoding.UTF8;
StreamReader streamReader = new StreamReader(request, encoding);
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
new file mode 100644
index 0000000..c2925e3
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
@@ -0,0 +1,1159 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using HttpServer;
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ // Sealed class. If you're going to unseal it, implement IDisposable.
+ ///
+ /// This class implements websockets. It grabs the network context from C#Webserver and utilizes it directly as a tcp streaming service
+ ///
+ public sealed class WebSocketHttpServerHandler : BaseRequestHandler
+ {
+
+ private class WebSocketState
+ {
+ public List ReceivedBytes;
+ public int ExpectedBytes;
+ public WebsocketFrameHeader Header;
+ public bool FrameComplete;
+ public WebSocketFrame ContinuationFrame;
+ }
+
+ ///
+ /// Binary Data will trigger this event
+ ///
+ public event DataDelegate OnData;
+
+ ///
+ /// Textual Data will trigger this event
+ ///
+ public event TextDelegate OnText;
+
+ ///
+ /// A ping request form the other side will trigger this event.
+ /// This class responds to the ping automatically. You shouldn't send a pong.
+ /// it's informational.
+ ///
+ public event PingDelegate OnPing;
+
+ ///
+ /// This is a response to a ping you sent.
+ ///
+ public event PongDelegate OnPong;
+
+ ///
+ /// This is a regular HTTP Request... This may be removed in the future.
+ ///
+// public event RegularHttpRequestDelegate OnRegularHttpRequest;
+
+ ///
+ /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired
+ ///
+ public event UpgradeCompletedDelegate OnUpgradeCompleted;
+
+ ///
+ /// If the upgrade failed, this will be fired
+ ///
+ public event UpgradeFailedDelegate OnUpgradeFailed;
+
+ ///
+ /// When the websocket is closed, this will be fired.
+ ///
+ public event CloseDelegate OnClose;
+
+ ///
+ /// Set this delegate to allow your module to validate the origin of the
+ /// Websocket request. Primary line of defense against cross site scripting
+ ///
+ public ValidateHandshake HandshakeValidateMethodOverride = null;
+
+ private ManualResetEvent _receiveDone = new ManualResetEvent(false);
+
+ private OSHttpRequest _request;
+ private HTTPNetworkContext _networkContext;
+ private IHttpClientContext _clientContext;
+
+ private int _pingtime = 0;
+ private byte[] _buffer;
+ private int _bufferPosition;
+ private int _bufferLength;
+ private bool _closing;
+ private bool _upgraded;
+ private int _maxPayloadBytes = 41943040;
+ private int _initialMsgTimeout = 0;
+ private int _defaultReadTimeout = 10000;
+
+ private const string HandshakeAcceptText =
+ "HTTP/1.1 101 Switching Protocols\r\n" +
+ "upgrade: websocket\r\n" +
+ "Connection: Upgrade\r\n" +
+ "sec-websocket-accept: {0}\r\n\r\n";// +
+ //"{1}";
+
+ private const string HandshakeDeclineText =
+ "HTTP/1.1 {0} {1}\r\n" +
+ "Connection: close\r\n\r\n";
+
+ ///
+ /// Mysterious constant defined in RFC6455 to append to the client provided security key
+ ///
+ private const string WebsocketHandshakeAcceptHashConstant = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
+
+ public WebSocketHttpServerHandler(OSHttpRequest preq, IHttpClientContext pContext, int bufferlen)
+ : base(preq.HttpMethod, preq.Url.OriginalString)
+ {
+ _request = preq;
+ _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing();
+ _networkContext.Stream.ReadTimeout = _defaultReadTimeout;
+ _clientContext = pContext;
+ _bufferLength = bufferlen;
+ _buffer = new byte[_bufferLength];
+ }
+
+ // Sealed class implments destructor and an internal dispose method. complies with C# unmanaged resource best practices.
+ ~WebSocketHttpServerHandler()
+ {
+ Dispose();
+
+ }
+
+ ///
+ /// Sets the length of the stream buffer
+ ///
+ /// Byte length.
+ public void SetChunksize(int pChunk)
+ {
+ if (!_upgraded)
+ {
+ _buffer = new byte[pChunk];
+ }
+ else
+ {
+ throw new InvalidOperationException("You must set the chunksize before the connection is upgraded");
+ }
+ }
+
+ ///
+ /// This is the famous nagle.
+ ///
+ public bool NoDelay_TCP_Nagle
+ {
+ get
+ {
+ if (_networkContext != null && _networkContext.Socket != null)
+ {
+ return _networkContext.Socket.NoDelay;
+ }
+ else
+ {
+ throw new InvalidOperationException("The socket has been shutdown");
+ }
+ }
+ set
+ {
+ if (_networkContext != null && _networkContext.Socket != null)
+ _networkContext.Socket.NoDelay = value;
+ else
+ {
+ throw new InvalidOperationException("The socket has been shutdown");
+ }
+ }
+ }
+
+ ///
+ /// This triggers the websocket to start the upgrade process...
+ /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead
+ /// of the more context appropriate HandshakeAndUpgrade()
+ ///
+ public void Start()
+ {
+ HandshakeAndUpgrade();
+ }
+
+ ///
+ /// Max Payload Size in bytes. Defaults to 40MB, but could be set upon connection before calling handshake and upgrade.
+ ///
+ public int MaxPayloadSize
+ {
+ get { return _maxPayloadBytes; }
+ set { _maxPayloadBytes = value; }
+ }
+
+ ///
+ /// Set this to the maximum amount of milliseconds to wait for the first complete message to be sent or received on the websocket after upgrading
+ /// Default, it waits forever. Use this when your Websocket consuming code opens a connection and waits for a message from the other side to avoid a Denial of Service vector.
+ ///
+ public int InitialMsgTimeout
+ {
+ get { return _initialMsgTimeout; }
+ set { _initialMsgTimeout = value; }
+ }
+
+ ///
+ /// This triggers the websocket start the upgrade process
+ ///
+ public void HandshakeAndUpgrade()
+ {
+ string webOrigin = string.Empty;
+ string websocketKey = string.Empty;
+ string acceptKey = string.Empty;
+ string accepthost = string.Empty;
+ if (!string.IsNullOrEmpty(_request.Headers["origin"]))
+ webOrigin = _request.Headers["origin"];
+
+ if (!string.IsNullOrEmpty(_request.Headers["sec-websocket-key"]))
+ websocketKey = _request.Headers["sec-websocket-key"];
+
+ if (!string.IsNullOrEmpty(_request.Headers["host"]))
+ accepthost = _request.Headers["host"];
+
+ if (string.IsNullOrEmpty(_request.Headers["upgrade"]))
+ {
+ FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no upgrade request submitted");
+ }
+
+ string connectionheader = _request.Headers["upgrade"];
+ if (connectionheader.ToLower() != "websocket")
+ {
+ FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no connection upgrade request submitted");
+ }
+
+ // If the object consumer provided a method to validate the origin, we should call it and give the client a success or fail.
+ // If not.. we should accept any. The assumption here is that there would be no Websocket handlers registered in baseHTTPServer unless
+ // Something asked for it...
+ if (HandshakeValidateMethodOverride != null)
+ {
+ if (HandshakeValidateMethodOverride(webOrigin, websocketKey, accepthost))
+ {
+ acceptKey = GenerateAcceptKey(websocketKey);
+ string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
+ SendUpgradeSuccess(rawaccept);
+
+
+ }
+ else
+ {
+ FailUpgrade(OSHttpStatusCode.ClientErrorForbidden, "Origin Validation Failed");
+ }
+ }
+ else
+ {
+ acceptKey = GenerateAcceptKey(websocketKey);
+ string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
+ SendUpgradeSuccess(rawaccept);
+ }
+ }
+ public IPEndPoint GetRemoteIPEndpoint()
+ {
+ return _request.RemoteIPEndPoint;
+ }
+
+ ///
+ /// Generates a handshake response key string based on the client's
+ /// provided key to prove to the client that we're allowing the Websocket
+ /// upgrade of our own free will and we were not coerced into doing it.
+ ///
+ /// Client provided security key
+ ///
+ private static string GenerateAcceptKey(string key)
+ {
+ if (string.IsNullOrEmpty(key))
+ return string.Empty;
+
+ string acceptkey = key + WebsocketHandshakeAcceptHashConstant;
+
+ SHA1 hashobj = SHA1.Create();
+ string ret = Convert.ToBase64String(hashobj.ComputeHash(Encoding.UTF8.GetBytes(acceptkey)));
+ hashobj.Clear();
+
+ return ret;
+ }
+
+ ///
+ /// Informs the otherside that we accepted their upgrade request
+ ///
+ /// The HTTP 1.1 101 response that says Yay \o/
+ private void SendUpgradeSuccess(string pHandshakeResponse)
+ {
+ // Create a new websocket state so we can keep track of data in between network reads.
+ WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true};
+
+ byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse);
+
+
+
+
+ try
+ {
+ if (_initialMsgTimeout > 0)
+ {
+ _receiveDone.Reset();
+ }
+ // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream.
+ _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState);
+
+ // Write the upgrade handshake success message
+ _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
+ _networkContext.Stream.Flush();
+ _upgraded = true;
+ UpgradeCompletedDelegate d = OnUpgradeCompleted;
+ if (d != null)
+ d(this, new UpgradeCompletedEventArgs());
+ if (_initialMsgTimeout > 0)
+ {
+ if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout)))
+ Close(string.Empty);
+ }
+ }
+ catch (IOException)
+ {
+ Close(string.Empty);
+ }
+ catch (ObjectDisposedException)
+ {
+ Close(string.Empty);
+ }
+ }
+
+ ///
+ /// The server has decided not to allow the upgrade to a websocket for some reason. The Http 1.1 response that says Nay >:(
+ ///
+ /// HTTP Status reflecting the reason why
+ /// Textual reason for the upgrade fail
+ private void FailUpgrade(OSHttpStatusCode pCode, string pMessage )
+ {
+ string handshakeResponse = string.Format(HandshakeDeclineText, (int)pCode, pMessage.Replace("\n", string.Empty).Replace("\r", string.Empty));
+ byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(handshakeResponse);
+ _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
+ _networkContext.Stream.Flush();
+ _networkContext.Stream.Dispose();
+
+ UpgradeFailedDelegate d = OnUpgradeFailed;
+ if (d != null)
+ d(this,new UpgradeFailedEventArgs());
+ }
+
+
+ ///
+ /// This is our ugly Async OnReceive event handler.
+ /// This chunks the input stream based on the length of the provided buffer and processes out
+ /// as many frames as it can. It then moves the unprocessed data to the beginning of the buffer.
+ ///
+ /// Our Async State from beginread
+ private void OnReceive(IAsyncResult ar)
+ {
+ WebSocketState _socketState = ar.AsyncState as WebSocketState;
+ try
+ {
+ int bytesRead = _networkContext.Stream.EndRead(ar);
+ if (bytesRead == 0)
+ {
+ // Do Disconnect
+ _networkContext.Stream.Dispose();
+ _networkContext = null;
+ return;
+ }
+ _bufferPosition += bytesRead;
+
+ if (_bufferPosition > _bufferLength)
+ {
+ // Message too big for chunksize.. not sure how this happened...
+ //Close(string.Empty);
+ }
+
+ int offset = 0;
+ bool headerread = true;
+ int headerforwardposition = 0;
+ while (headerread && offset < bytesRead)
+ {
+ if (_socketState.FrameComplete)
+ {
+ WebsocketFrameHeader pheader = WebsocketFrameHeader.ZeroHeader;
+
+ headerread = WebSocketReader.TryReadHeader(_buffer, offset, _bufferPosition - offset, out pheader,
+ out headerforwardposition);
+ offset += headerforwardposition;
+
+ if (headerread)
+ {
+ _socketState.FrameComplete = false;
+ if (pheader.PayloadLen > (ulong) _maxPayloadBytes)
+ {
+ Close("Invalid Payload size");
+
+ return;
+ }
+ if (pheader.PayloadLen > 0)
+ {
+ if ((int) pheader.PayloadLen > _bufferPosition - offset)
+ {
+ byte[] writebytes = new byte[_bufferPosition - offset];
+
+ Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition - offset);
+ _socketState.ExpectedBytes = (int) pheader.PayloadLen;
+ _socketState.ReceivedBytes.AddRange(writebytes);
+ _socketState.Header = pheader; // We need to add the header so that we can unmask it
+ offset += (int) _bufferPosition - offset;
+ }
+ else
+ {
+ byte[] writebytes = new byte[pheader.PayloadLen];
+ Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) pheader.PayloadLen);
+ WebSocketReader.Mask(pheader.Mask, writebytes);
+ pheader.IsMasked = false;
+ _socketState.FrameComplete = true;
+ _socketState.ReceivedBytes.AddRange(writebytes);
+ _socketState.Header = pheader;
+ offset += (int) pheader.PayloadLen;
+ }
+ }
+ else
+ {
+ pheader.Mask = 0;
+ _socketState.FrameComplete = true;
+ _socketState.Header = pheader;
+ }
+
+ if (_socketState.FrameComplete)
+ {
+ ProcessFrame(_socketState);
+ _socketState.Header.SetDefault();
+ _socketState.ReceivedBytes.Clear();
+ _socketState.ExpectedBytes = 0;
+
+ }
+ }
+ }
+ else
+ {
+ WebsocketFrameHeader frameHeader = _socketState.Header;
+ int bytesleft = _socketState.ExpectedBytes - _socketState.ReceivedBytes.Count;
+
+ if (bytesleft > _bufferPosition)
+ {
+ byte[] writebytes = new byte[_bufferPosition];
+
+ Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
+ _socketState.ReceivedBytes.AddRange(writebytes);
+ _socketState.Header = frameHeader; // We need to add the header so that we can unmask it
+ offset += (int) _bufferPosition;
+ }
+ else
+ {
+ byte[] writebytes = new byte[_bufferPosition];
+ Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
+ _socketState.FrameComplete = true;
+ _socketState.ReceivedBytes.AddRange(writebytes);
+ _socketState.Header = frameHeader;
+ offset += (int) _bufferPosition;
+ }
+ if (_socketState.FrameComplete)
+ {
+ ProcessFrame(_socketState);
+ _socketState.Header.SetDefault();
+ _socketState.ReceivedBytes.Clear();
+ _socketState.ExpectedBytes = 0;
+ // do some processing
+ }
+ }
+ }
+ if (offset > 0)
+ {
+ // If the buffer is maxed out.. we can just move the cursor. Nothing to move to the beginning.
+ if (offset <_buffer.Length)
+ Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bufferPosition - offset);
+ _bufferPosition -= offset;
+ }
+ if (_networkContext.Stream != null && _networkContext.Stream.CanRead && !_closing)
+ {
+ _networkContext.Stream.BeginRead(_buffer, _bufferPosition, _bufferLength - _bufferPosition, OnReceive,
+ _socketState);
+ }
+ else
+ {
+ // We can't read the stream anymore...
+ }
+ }
+ catch (IOException)
+ {
+ Close(string.Empty);
+ }
+ catch (ObjectDisposedException)
+ {
+ Close(string.Empty);
+ }
+ }
+
+ ///
+ /// Sends a string to the other side
+ ///
+ /// the string message that is to be sent
+ public void SendMessage(string message)
+ {
+ if (_initialMsgTimeout > 0)
+ {
+ _receiveDone.Set();
+ _initialMsgTimeout = 0;
+ }
+ byte[] messagedata = Encoding.UTF8.GetBytes(message);
+ WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata };
+ textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text;
+ textMessageFrame.Header.IsEnd = true;
+ SendSocket(textMessageFrame.ToBytes());
+
+ }
+
+ public void SendData(byte[] data)
+ {
+ if (_initialMsgTimeout > 0)
+ {
+ _receiveDone.Set();
+ _initialMsgTimeout = 0;
+ }
+ WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data};
+ dataMessageFrame.Header.IsEnd = true;
+ dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary;
+ SendSocket(dataMessageFrame.ToBytes());
+
+ }
+
+ ///
+ /// Writes raw bytes to the websocket. Unframed data will cause disconnection
+ ///
+ ///
+ private void SendSocket(byte[] data)
+ {
+ if (!_closing)
+ {
+ try
+ {
+
+ _networkContext.Stream.Write(data, 0, data.Length);
+ }
+ catch (IOException)
+ {
+
+ }
+ }
+ }
+
+ ///
+ /// Sends a Ping check to the other side. The other side SHOULD respond as soon as possible with a pong frame. This interleaves with incoming fragmented frames.
+ ///
+ public void SendPingCheck()
+ {
+ if (_initialMsgTimeout > 0)
+ {
+ _receiveDone.Set();
+ _initialMsgTimeout = 0;
+ }
+ WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] };
+ pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping;
+ pingFrame.Header.IsEnd = true;
+ _pingtime = Util.EnvironmentTickCount();
+ SendSocket(pingFrame.ToBytes());
+ }
+
+ ///
+ /// Closes the websocket connection. Sends a close message to the other side if it hasn't already done so.
+ ///
+ ///
+ public void Close(string message)
+ {
+ if (_initialMsgTimeout > 0)
+ {
+ _receiveDone.Set();
+ _initialMsgTimeout = 0;
+ }
+ if (_networkContext == null)
+ return;
+ if (_networkContext.Stream != null)
+ {
+ if (_networkContext.Stream.CanWrite)
+ {
+ byte[] messagedata = Encoding.UTF8.GetBytes(message);
+ WebSocketFrame closeResponseFrame = new WebSocketFrame()
+ {
+ Header = WebsocketFrameHeader.HeaderDefault(),
+ WebSocketPayload = messagedata
+ };
+ closeResponseFrame.Header.Opcode = WebSocketReader.OpCode.Close;
+ closeResponseFrame.Header.PayloadLen = (ulong) messagedata.Length;
+ closeResponseFrame.Header.IsEnd = true;
+ SendSocket(closeResponseFrame.ToBytes());
+ }
+ }
+ CloseDelegate closeD = OnClose;
+ if (closeD != null)
+ {
+ closeD(this, new CloseEventArgs());
+ }
+
+ _closing = true;
+ }
+
+ ///
+ /// Processes a websocket frame and triggers consumer events
+ ///
+ /// We need to modify the websocket state here depending on the frame
+ private void ProcessFrame(WebSocketState psocketState)
+ {
+ if (psocketState.Header.IsMasked)
+ {
+ byte[] unmask = psocketState.ReceivedBytes.ToArray();
+ WebSocketReader.Mask(psocketState.Header.Mask, unmask);
+ psocketState.ReceivedBytes = new List(unmask);
+ }
+ if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0)
+ {
+ _receiveDone.Set();
+ _initialMsgTimeout = 0;
+ }
+ switch (psocketState.Header.Opcode)
+ {
+ case WebSocketReader.OpCode.Ping:
+ PingDelegate pingD = OnPing;
+ if (pingD != null)
+ {
+ pingD(this, new PingEventArgs());
+ }
+
+ WebSocketFrame pongFrame = new WebSocketFrame(){Header = WebsocketFrameHeader.HeaderDefault(),WebSocketPayload = new byte[0]};
+ pongFrame.Header.Opcode = WebSocketReader.OpCode.Pong;
+ pongFrame.Header.IsEnd = true;
+ SendSocket(pongFrame.ToBytes());
+ break;
+ case WebSocketReader.OpCode.Pong:
+
+ PongDelegate pongD = OnPong;
+ if (pongD != null)
+ {
+ pongD(this, new PongEventArgs(){PingResponseMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),_pingtime)});
+ }
+ break;
+ case WebSocketReader.OpCode.Binary:
+ if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
+ {
+ psocketState.ContinuationFrame = new WebSocketFrame
+ {
+ Header = psocketState.Header,
+ WebSocketPayload =
+ psocketState.ReceivedBytes.ToArray()
+ };
+ }
+ else
+ {
+ // Send Done Event!
+ DataDelegate dataD = OnData;
+ if (dataD != null)
+ {
+ dataD(this,new WebsocketDataEventArgs(){Data = psocketState.ReceivedBytes.ToArray()});
+ }
+ }
+ break;
+ case WebSocketReader.OpCode.Text:
+ if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
+ {
+ psocketState.ContinuationFrame = new WebSocketFrame
+ {
+ Header = psocketState.Header,
+ WebSocketPayload =
+ psocketState.ReceivedBytes.ToArray()
+ };
+ }
+ else
+ {
+ TextDelegate textD = OnText;
+ if (textD != null)
+ {
+ textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray()) });
+ }
+
+ // Send Done Event!
+ }
+ break;
+ case WebSocketReader.OpCode.Continue: // Continuation. Multiple frames worth of data for one message. Only valid when not using Control Opcodes
+ //Console.WriteLine("currhead " + psocketState.Header.IsEnd);
+ //Console.WriteLine("Continuation! " + psocketState.ContinuationFrame.Header.IsEnd);
+ byte[] combineddata = new byte[psocketState.ReceivedBytes.Count+psocketState.ContinuationFrame.WebSocketPayload.Length];
+ byte[] newdata = psocketState.ReceivedBytes.ToArray();
+ Buffer.BlockCopy(psocketState.ContinuationFrame.WebSocketPayload, 0, combineddata, 0, psocketState.ContinuationFrame.WebSocketPayload.Length);
+ Buffer.BlockCopy(newdata, 0, combineddata,
+ psocketState.ContinuationFrame.WebSocketPayload.Length, newdata.Length);
+ psocketState.ContinuationFrame.WebSocketPayload = combineddata;
+ psocketState.Header.PayloadLen = (ulong)combineddata.Length;
+ if (psocketState.Header.IsEnd)
+ {
+ if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text)
+ {
+ // Send Done event
+ TextDelegate textD = OnText;
+ if (textD != null)
+ {
+ textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(combineddata) });
+ }
+ }
+ else if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Binary)
+ {
+ // Send Done event
+ DataDelegate dataD = OnData;
+ if (dataD != null)
+ {
+ dataD(this, new WebsocketDataEventArgs() { Data = combineddata });
+ }
+ }
+ else
+ {
+ // protocol violation
+ }
+ psocketState.ContinuationFrame = null;
+ }
+ break;
+ case WebSocketReader.OpCode.Close:
+ Close(string.Empty);
+
+ break;
+
+ }
+ psocketState.Header.SetDefault();
+ psocketState.ReceivedBytes.Clear();
+ psocketState.ExpectedBytes = 0;
+ }
+ public void Dispose()
+ {
+ if (_initialMsgTimeout > 0)
+ {
+ _receiveDone.Set();
+ _initialMsgTimeout = 0;
+ }
+ if (_networkContext != null && _networkContext.Stream != null)
+ {
+ if (_networkContext.Stream.CanWrite)
+ _networkContext.Stream.Flush();
+ _networkContext.Stream.Close();
+ _networkContext.Stream.Dispose();
+ _networkContext.Stream = null;
+ }
+
+ if (_request != null && _request.InputStream != null)
+ {
+ _request.InputStream.Close();
+ _request.InputStream.Dispose();
+ _request = null;
+ }
+
+ if (_clientContext != null)
+ {
+ _clientContext.Close();
+ _clientContext = null;
+ }
+ }
+ }
+
+ ///
+ /// Reads a byte stream and returns Websocket frames.
+ ///
+ public class WebSocketReader
+ {
+ ///
+ /// Bit to determine if the frame read on the stream is the last frame in a sequence of fragmented frames
+ ///
+ private const byte EndBit = 0x80;
+
+ ///
+ /// These are the Frame Opcodes
+ ///
+ public enum OpCode
+ {
+ // Data Opcodes
+ Continue = 0x0,
+ Text = 0x1,
+ Binary = 0x2,
+
+ // Control flow Opcodes
+ Close = 0x8,
+ Ping = 0x9,
+ Pong = 0xA
+ }
+
+ ///
+ /// Masks and Unmasks data using the frame mask. Mask is applied per octal
+ /// Note: Frames from clients MUST be masked
+ /// Note: Frames from servers MUST NOT be masked
+ ///
+ /// Int representing 32 bytes of mask data. Mask is applied per octal
+ ///
+ public static void Mask(int pMask, byte[] pBuffer)
+ {
+ byte[] maskKey = BitConverter.GetBytes(pMask);
+ int currentMaskIndex = 0;
+ for (int i = 0; i < pBuffer.Length; i++)
+ {
+ pBuffer[i] = (byte)(pBuffer[i] ^ maskKey[currentMaskIndex]);
+ if (currentMaskIndex == 3)
+ {
+ currentMaskIndex = 0;
+ }
+ else
+ {
+ currentMaskIndex++;
+
+ }
+
+ }
+ }
+
+ ///
+ /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader,
+ /// and an int to move the buffer forward when it reads a header. False when it can't read a header
+ ///
+ /// Bytes read from the stream
+ /// Starting place in the stream to begin trying to read from
+ /// Lenth in the stream to try and read from. Provided for cases where the
+ /// buffer's length is larger then the data in it
+ /// Outputs the read WebSocket frame header
+ /// Informs the calling stream to move the buffer forward
+ /// True if it got a header, False if it didn't get a header
+ public static bool TryReadHeader(byte[] pBuffer, int pOffset, int length, out WebsocketFrameHeader oHeader,
+ out int moveBuffer)
+ {
+ oHeader = WebsocketFrameHeader.ZeroHeader;
+ int minumheadersize = 2;
+ if (length > pBuffer.Length - pOffset)
+ throw new ArgumentOutOfRangeException("The Length specified was larger the byte array supplied");
+ if (length < minumheadersize)
+ {
+ moveBuffer = 0;
+ return false;
+ }
+
+ byte nibble1 = (byte)(pBuffer[pOffset] & 0xF0); //FIN/RSV1/RSV2/RSV3
+ byte nibble2 = (byte)(pBuffer[pOffset] & 0x0F); // Opcode block
+
+ oHeader = new WebsocketFrameHeader();
+ oHeader.SetDefault();
+
+ if ((nibble1 & WebSocketReader.EndBit) == WebSocketReader.EndBit)
+ {
+ oHeader.IsEnd = true;
+ }
+ else
+ {
+ oHeader.IsEnd = false;
+ }
+ //Opcode
+ oHeader.Opcode = (WebSocketReader.OpCode)nibble2;
+ //Mask
+ oHeader.IsMasked = Convert.ToBoolean((pBuffer[pOffset + 1] & 0x80) >> 7);
+
+ // Payload length
+ oHeader.PayloadLen = (byte)(pBuffer[pOffset + 1] & 0x7F);
+
+ int index = 2; // LargerPayload length starts at byte 3
+
+ switch (oHeader.PayloadLen)
+ {
+ case 126:
+ minumheadersize += 2;
+ if (length < minumheadersize)
+ {
+ moveBuffer = 0;
+ return false;
+ }
+ Array.Reverse(pBuffer, pOffset + index, 2); // two bytes
+ oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index);
+ index += 2;
+ break;
+ case 127: // we got more this is a bigger frame
+ // 8 bytes - uint64 - most significant bit 0 network byte order
+ minumheadersize += 8;
+ if (length < minumheadersize)
+ {
+ moveBuffer = 0;
+ return false;
+ }
+ Array.Reverse(pBuffer, pOffset + index, 8);
+ oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index);
+ index += 8;
+ break;
+
+ }
+ //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network. This is different then frame fragmentation
+ if (oHeader.IsMasked)
+ {
+ minumheadersize += 4;
+ if (length < minumheadersize)
+ {
+ moveBuffer = 0;
+ return false;
+ }
+ oHeader.Mask = BitConverter.ToInt32(pBuffer, pOffset + index);
+ index += 4;
+ }
+ moveBuffer = index;
+ return true;
+
+ }
+ }
+
+ ///
+ /// RFC6455 Websocket Frame
+ ///
+ public class WebSocketFrame
+ {
+ /*
+ * RFC6455
+nib 0 1 2 3 4 5 6 7
+byt 0 1 2 3
+dec 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +-+-+-+-+-------+-+-------------+-------------------------------+
+ |F|R|R|R| opcode|M| Payload len | Extended payload length |
+ |I|S|S|S| (4) |A| (7) | (16/64) +
+ |N|V|V|V| |S| | (if payload len==126/127) |
+ | |1|2|3| |K| | +
+ +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
+ | Extended payload length continued, if payload len == 127 |
+ + - - - - - - - - - - - - - - - +-------------------------------+
+ | |Masking-key, if MASK set to 1 |
+ +-------------------------------+-------------------------------+
+ | Masking-key (continued) | Payload Data |
+ +-------------------------------- - - - - - - - - - - - - - - - +
+ : Payload Data continued ... :
+ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
+ | Payload Data continued ... |
+ +---------------------------------------------------------------+
+
+ * When reading these, the frames are possibly fragmented and interleaved with control frames
+ * the fragmented frames are not interleaved with data frames. Just control frames
+ */
+ public static readonly WebSocketFrame DefaultFrame = new WebSocketFrame(){Header = new WebsocketFrameHeader(),WebSocketPayload = new byte[0]};
+ public WebsocketFrameHeader Header;
+ public byte[] WebSocketPayload;
+
+ public byte[] ToBytes()
+ {
+ Header.PayloadLen = (ulong)WebSocketPayload.Length;
+ return Header.ToBytes(WebSocketPayload);
+ }
+
+ }
+
+ public struct WebsocketFrameHeader
+ {
+ //public byte CurrentMaskIndex;
+ ///
+ /// The last frame in a sequence of fragmented frames or the one and only frame for this message.
+ ///
+ public bool IsEnd;
+
+ ///
+ /// Returns whether the payload data is masked or not. Data from Clients MUST be masked, Data from Servers MUST NOT be masked
+ ///
+ public bool IsMasked;
+
+ ///
+ /// A set of cryptologically sound random bytes XoR-ed against the payload octally. Looped
+ ///
+ public int Mask;
+ /*
+byt 0 1 2 3
+ 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ +---------------+---------------+---------------+---------------+
+ | Octal 1 | Octal 2 | Octal 3 | Octal 4 |
+ +---------------+---------------+---------------+---------------+
+*/
+
+
+ public WebSocketReader.OpCode Opcode;
+
+ public UInt64 PayloadLen;
+ //public UInt64 PayloadLeft;
+ // Payload is X + Y
+ //public UInt64 ExtensionDataLength;
+ //public UInt64 ApplicationDataLength;
+ public static readonly WebsocketFrameHeader ZeroHeader = WebsocketFrameHeader.HeaderDefault();
+
+ public void SetDefault()
+ {
+
+ //CurrentMaskIndex = 0;
+ IsEnd = true;
+ IsMasked = true;
+ Mask = 0;
+ Opcode = WebSocketReader.OpCode.Close;
+ // PayloadLeft = 0;
+ PayloadLen = 0;
+ // ExtensionDataLength = 0;
+ // ApplicationDataLength = 0;
+
+ }
+
+ ///
+ /// Returns a byte array representing the Frame header
+ ///
+ /// This is the frame data payload. The header describes the size of the payload.
+ /// If payload is null, a Zero sized payload is assumed
+ /// Returns a byte array representing the frame header
+ public byte[] ToBytes(byte[] payload)
+ {
+ List result = new List();
+
+ // Squeeze in our opcode and our ending bit.
+ result.Add((byte)((byte)Opcode | (IsEnd?0x80:0x00) ));
+
+ // Again with the three different byte interpretations of size..
+
+ //bytesize
+ if (PayloadLen <= 125)
+ {
+ result.Add((byte) PayloadLen);
+ } //Uint16
+ else if (PayloadLen <= ushort.MaxValue)
+ {
+ result.Add(126);
+ byte[] payloadLengthByte = BitConverter.GetBytes(Convert.ToUInt16(PayloadLen));
+ Array.Reverse(payloadLengthByte);
+ result.AddRange(payloadLengthByte);
+ } //UInt64
+ else
+ {
+ result.Add(127);
+ byte[] payloadLengthByte = BitConverter.GetBytes(PayloadLen);
+ Array.Reverse(payloadLengthByte);
+ result.AddRange(payloadLengthByte);
+ }
+
+ // Only add a payload if it's not null
+ if (payload != null)
+ {
+ result.AddRange(payload);
+ }
+ return result.ToArray();
+ }
+
+ ///
+ /// A Helper method to define the defaults
+ ///
+ ///
+
+ public static WebsocketFrameHeader HeaderDefault()
+ {
+ return new WebsocketFrameHeader
+ {
+ //CurrentMaskIndex = 0,
+ IsEnd = false,
+ IsMasked = true,
+ Mask = 0,
+ Opcode = WebSocketReader.OpCode.Close,
+ //PayloadLeft = 0,
+ PayloadLen = 0,
+ // ExtensionDataLength = 0,
+ // ApplicationDataLength = 0
+ };
+ }
+ }
+
+ public delegate void DataDelegate(object sender, WebsocketDataEventArgs data);
+
+ public delegate void TextDelegate(object sender, WebsocketTextEventArgs text);
+
+ public delegate void PingDelegate(object sender, PingEventArgs pingdata);
+
+ public delegate void PongDelegate(object sender, PongEventArgs pongdata);
+
+ public delegate void RegularHttpRequestDelegate(object sender, RegularHttpRequestEvnetArgs request);
+
+ public delegate void UpgradeCompletedDelegate(object sender, UpgradeCompletedEventArgs completeddata);
+
+ public delegate void UpgradeFailedDelegate(object sender, UpgradeFailedEventArgs faileddata);
+
+ public delegate void CloseDelegate(object sender, CloseEventArgs closedata);
+
+ public delegate bool ValidateHandshake(string pWebOrigin, string pWebSocketKey, string pHost);
+
+
+ public class WebsocketDataEventArgs : EventArgs
+ {
+ public byte[] Data;
+ }
+
+ public class WebsocketTextEventArgs : EventArgs
+ {
+ public string Data;
+ }
+
+ public class PingEventArgs : EventArgs
+ {
+ ///
+ /// The ping event can arbitrarily contain data
+ ///
+ public byte[] Data;
+ }
+
+ public class PongEventArgs : EventArgs
+ {
+ ///
+ /// The pong event can arbitrarily contain data
+ ///
+ public byte[] Data;
+
+ public int PingResponseMS;
+
+ }
+
+ public class RegularHttpRequestEvnetArgs : EventArgs
+ {
+
+ }
+
+ public class UpgradeCompletedEventArgs : EventArgs
+ {
+
+ }
+
+ public class UpgradeFailedEventArgs : EventArgs
+ {
+
+ }
+
+ public class CloseEventArgs : EventArgs
+ {
+
+ }
+
+
+}
diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs
new file mode 100644
index 0000000..f212208
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs
@@ -0,0 +1,91 @@
+/*
+ * 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.Net;
+using Nwc.XmlRpc;
+using OpenSim.Framework;
+
+
+namespace OpenSim.Framework.Servers.HttpServer
+{
+ public class XmlRpcBasicDOSProtector
+ {
+ private readonly XmlRpcMethod _normalMethod;
+ private readonly XmlRpcMethod _throttledMethod;
+
+ private readonly BasicDosProtectorOptions _options;
+ private readonly BasicDOSProtector _dosProtector;
+
+ public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options)
+ {
+ _normalMethod = normalMethod;
+ _throttledMethod = throttledMethod;
+
+ _options = options;
+ _dosProtector = new BasicDOSProtector(_options);
+
+ }
+ public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client)
+ {
+
+ XmlRpcResponse resp = null;
+ string clientstring = GetClientString(request, client);
+ string endpoint = GetEndPoint(request, client);
+ if (_dosProtector.Process(clientstring, endpoint))
+ resp = _normalMethod(request, client);
+ else
+ resp = _throttledMethod(request, client);
+ if (_options.MaxConcurrentSessions > 0)
+ _dosProtector.ProcessEnd(clientstring, endpoint);
+ return resp;
+ }
+
+ private string GetClientString(XmlRpcRequest request, IPEndPoint client)
+ {
+ string clientstring;
+ if (_options.AllowXForwardedFor && request.Params.Count > 3)
+ {
+ object headerstr = request.Params[3];
+ if (headerstr != null && !string.IsNullOrEmpty(headerstr.ToString()))
+ clientstring = request.Params[3].ToString();
+ else
+ clientstring = client.Address.ToString();
+ }
+ else
+ clientstring = client.Address.ToString();
+ return clientstring;
+ }
+
+ private string GetEndPoint(XmlRpcRequest request, IPEndPoint client)
+ {
+ return client.Address.ToString();
+ }
+
+ }
+
+
+}
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs
index ae7d515..57931d4 100644
--- a/OpenSim/Framework/Servers/MainServer.cs
+++ b/OpenSim/Framework/Servers/MainServer.cs
@@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers
+ " level >= 2 then long warnings are logged when receiving bad input data.\n"
+ " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
+ " level >= 4 then the time taken to fulfill the request is logged.\n"
- + " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
- + " level >= 6 then the entire incoming data is logged.\n"
+ + " level >= 5 then a sample from the beginning of the data is logged.\n"
+ + " level >= 6 then the entire data is logged.\n"
+ " no level is specified then the current level is returned.\n\n"
+ "If out or all and\n"
+ " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
- + " level >= 4 then the time taken to fulfill the request is logged.\n",
+ + " level >= 4 then the time taken to fulfill the request is logged.\n"
+ + " level >= 5 then a sample from the beginning of the data is logged.\n"
+ + " level >= 6 then the entire data is logged.\n",
HandleDebugHttpCommand);
}
@@ -227,9 +229,16 @@ namespace OpenSim.Framework.Servers
handlers.AppendFormat("\t{0}\n", s);
handlers.AppendFormat("* HTTP:\n");
- List poll = httpServer.GetPollServiceHandlerKeys();
foreach (String s in httpServer.GetHTTPHandlerKeys())
- handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty));
+ handlers.AppendFormat("\t{0}\n", s);
+
+ handlers.AppendFormat("* HTTP (poll):\n");
+ foreach (String s in httpServer.GetPollServiceHandlerKeys())
+ handlers.AppendFormat("\t{0}\n", s);
+
+ handlers.AppendFormat("* JSONRPC:\n");
+ foreach (String s in httpServer.GetJsonRpcHandlerKeys())
+ handlers.AppendFormat("\t{0}\n", s);
// handlers.AppendFormat("* Agent:\n");
// foreach (String s in httpServer.GetAgentHandlerKeys())
@@ -276,7 +285,12 @@ namespace OpenSim.Framework.Servers
public static bool RemoveHttpServer(uint port)
{
lock (m_Servers)
+ {
+ if (instance != null && instance.Port == port)
+ instance = null;
+
return m_Servers.Remove(port);
+ }
}
///
diff --git a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
index 021f63c..792c62e 100644
--- a/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Servers/Properties/AssemblyInfo.cs
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
-[assembly: AssemblyVersion("0.7.5.*")]
+[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs
index 47baac8..07a09e6 100644
--- a/OpenSim/Framework/Servers/ServerBase.cs
+++ b/OpenSim/Framework/Servers/ServerBase.cs
@@ -29,6 +29,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
@@ -62,6 +63,8 @@ namespace OpenSim.Framework.Servers
protected string m_pidFile = String.Empty;
+ protected ServerStatsCollector m_serverStatsCollector;
+
///
/// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
///
@@ -76,6 +79,11 @@ namespace OpenSim.Framework.Servers
protected void CreatePIDFile(string path)
{
+ if (File.Exists(path))
+ m_log.ErrorFormat(
+ "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.",
+ path);
+
try
{
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
@@ -113,6 +121,26 @@ namespace OpenSim.Framework.Servers
}
}
+ ///
+ /// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details,
+ /// etc.).
+ ///
+ public void LogEnvironmentInformation()
+ {
+ // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
+ // XmlConfigurator calls first accross servers.
+ m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
+
+ m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version);
+
+ // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
+ // the clr version number doesn't match the project version number under Mono.
+ //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
+ m_log.InfoFormat(
+ "[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit",
+ Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
+ }
+
public void RegisterCommonAppenders(IConfig startupConfig)
{
ILoggerRepository repository = LogManager.GetRepository();
@@ -219,7 +247,7 @@ namespace OpenSim.Framework.Servers
"Show thread status", HandleShow);
m_console.Commands.AddCommand(
- "General", false, "threads abort",
+ "Debug", false, "threads abort",
"threads abort ",
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
@@ -229,11 +257,281 @@ namespace OpenSim.Framework.Servers
"Show thread status. Synonym for \"show threads\"",
(string module, string[] args) => Notice(GetThreadsReport()));
+ m_console.Commands.AddCommand (
+ "Debug", false, "debug comms set",
+ "debug comms set serialosdreq true|false",
+ "Set comms parameters. For debug purposes.",
+ HandleDebugCommsSet);
+
+ m_console.Commands.AddCommand (
+ "Debug", false, "debug comms status",
+ "debug comms status",
+ "Show current debug comms parameters.",
+ HandleDebugCommsStatus);
+
+ m_console.Commands.AddCommand (
+ "Debug", false, "debug threadpool set",
+ "debug threadpool set worker|iocp min|max ",
+ "Set threadpool parameters. For debug purposes.",
+ HandleDebugThreadpoolSet);
+
+ m_console.Commands.AddCommand (
+ "Debug", false, "debug threadpool status",
+ "debug threadpool status",
+ "Show current debug threadpool parameters.",
+ HandleDebugThreadpoolStatus);
+
+ m_console.Commands.AddCommand(
+ "Debug", false, "debug threadpool level",
+ "debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL,
+ "Turn on logging of activity in the main thread pool.",
+ "Log levels:\n"
+ + " 0 = no logging\n"
+ + " 1 = only first line of stack trace; don't log common threads\n"
+ + " 2 = full stack trace; don't log common threads\n"
+ + " 3 = full stack trace, including common threads\n",
+ HandleDebugThreadpoolLevel);
+
+// m_console.Commands.AddCommand(
+// "Debug", false, "show threadpool calls active",
+// "show threadpool calls active",
+// "Show details about threadpool calls that are still active (currently waiting or in progress)",
+// HandleShowThreadpoolCallsActive);
+
m_console.Commands.AddCommand(
- "General", false, "force gc",
+ "Debug", false, "show threadpool calls complete",
+ "show threadpool calls complete",
+ "Show details about threadpool calls that have been completed.",
+ HandleShowThreadpoolCallsComplete);
+
+ m_console.Commands.AddCommand(
+ "Debug", false, "force gc",
"force gc",
"Manually invoke runtime garbage collection. For debugging purposes",
HandleForceGc);
+
+ m_console.Commands.AddCommand(
+ "General", false, "quit",
+ "quit",
+ "Quit the application", (mod, args) => Shutdown());
+
+ m_console.Commands.AddCommand(
+ "General", false, "shutdown",
+ "shutdown",
+ "Quit the application", (mod, args) => Shutdown());
+
+ ChecksManager.RegisterConsoleCommands(m_console);
+ StatsManager.RegisterConsoleCommands(m_console);
+ }
+
+ public void RegisterCommonComponents(IConfigSource configSource)
+ {
+ IConfig networkConfig = configSource.Configs["Network"];
+
+ if (networkConfig != null)
+ {
+ WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false);
+ }
+
+ m_serverStatsCollector = new ServerStatsCollector();
+ m_serverStatsCollector.Initialise(configSource);
+ m_serverStatsCollector.Start();
+ }
+
+ private void HandleDebugCommsStatus(string module, string[] args)
+ {
+ Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint);
+ }
+
+ private void HandleDebugCommsSet(string module, string[] args)
+ {
+ if (args.Length != 5)
+ {
+ Notice("Usage: debug comms set serialosdreq true|false");
+ return;
+ }
+
+ if (args[3] != "serialosdreq")
+ {
+ Notice("Usage: debug comms set serialosdreq true|false");
+ return;
+ }
+
+ bool setSerializeOsdRequests;
+
+ if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests))
+ return;
+
+ WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests;
+
+ Notice("serialosdreq is now {0}", setSerializeOsdRequests);
+ }
+
+ private void HandleShowThreadpoolCallsActive(string module, string[] args)
+ {
+ List> calls = Util.GetFireAndForgetCallsInProgress().ToList();
+ calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value));
+ int namedCalls = 0;
+
+ ConsoleDisplayList cdl = new ConsoleDisplayList();
+ foreach (KeyValuePair kvp in calls)
+ {
+ if (kvp.Value > 0)
+ {
+ cdl.AddRow(kvp.Key, kvp.Value);
+ namedCalls += kvp.Value;
+ }
+ }
+
+ cdl.AddRow("TOTAL NAMED", namedCalls);
+
+ long allQueuedCalls = Util.TotalQueuedFireAndForgetCalls;
+ long allRunningCalls = Util.TotalRunningFireAndForgetCalls;
+
+ cdl.AddRow("TOTAL QUEUED", allQueuedCalls);
+ cdl.AddRow("TOTAL RUNNING", allRunningCalls);
+ cdl.AddRow("TOTAL ANONYMOUS", allQueuedCalls + allRunningCalls - namedCalls);
+ cdl.AddRow("TOTAL ALL", allQueuedCalls + allRunningCalls);
+
+ MainConsole.Instance.Output(cdl.ToString());
+ }
+
+ private void HandleShowThreadpoolCallsComplete(string module, string[] args)
+ {
+ List> calls = Util.GetFireAndForgetCallsMade().ToList();
+ calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value));
+ int namedCallsMade = 0;
+
+ ConsoleDisplayList cdl = new ConsoleDisplayList();
+ foreach (KeyValuePair kvp in calls)
+ {
+ cdl.AddRow(kvp.Key, kvp.Value);
+ namedCallsMade += kvp.Value;
+ }
+
+ cdl.AddRow("TOTAL NAMED", namedCallsMade);
+
+ long allCallsMade = Util.TotalFireAndForgetCallsMade;
+ cdl.AddRow("TOTAL ANONYMOUS", allCallsMade - namedCallsMade);
+ cdl.AddRow("TOTAL ALL", allCallsMade);
+
+ MainConsole.Instance.Output(cdl.ToString());
+ }
+
+ private void HandleDebugThreadpoolStatus(string module, string[] args)
+ {
+ int workerThreads, iocpThreads;
+
+ ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
+ Notice("Min worker threads: {0}", workerThreads);
+ Notice("Min IOCP threads: {0}", iocpThreads);
+
+ ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
+ Notice("Max worker threads: {0}", workerThreads);
+ Notice("Max IOCP threads: {0}", iocpThreads);
+
+ ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
+ Notice("Available worker threads: {0}", workerThreads);
+ Notice("Available IOCP threads: {0}", iocpThreads);
+ }
+
+ private void HandleDebugThreadpoolSet(string module, string[] args)
+ {
+ if (args.Length != 6)
+ {
+ Notice("Usage: debug threadpool set worker|iocp min|max ");
+ return;
+ }
+
+ int newThreads;
+
+ if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads))
+ return;
+
+ string poolType = args[3];
+ string bound = args[4];
+
+ bool fail = false;
+ int workerThreads, iocpThreads;
+
+ if (poolType == "worker")
+ {
+ if (bound == "min")
+ {
+ ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
+
+ if (!ThreadPool.SetMinThreads(newThreads, iocpThreads))
+ fail = true;
+ }
+ else
+ {
+ ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
+
+ if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads))
+ fail = true;
+ }
+ }
+ else
+ {
+ if (bound == "min")
+ {
+ ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
+
+ if (!ThreadPool.SetMinThreads(workerThreads, newThreads))
+ fail = true;
+ }
+ else
+ {
+ ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
+
+ if (!ThreadPool.SetMaxThreads(workerThreads, newThreads))
+ fail = true;
+ }
+ }
+
+ if (fail)
+ {
+ Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads);
+ }
+ else
+ {
+ int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads;
+
+ ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads);
+ ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads);
+
+ Notice("Min worker threads now {0}", minWorkerThreads);
+ Notice("Min IOCP threads now {0}", minIocpThreads);
+ Notice("Max worker threads now {0}", maxWorkerThreads);
+ Notice("Max IOCP threads now {0}", maxIocpThreads);
+ }
+ }
+
+ private static void HandleDebugThreadpoolLevel(string module, string[] cmdparams)
+ {
+ if (cmdparams.Length < 4)
+ {
+ MainConsole.Instance.Output("Usage: debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL);
+ return;
+ }
+
+ string rawLevel = cmdparams[3];
+ int newLevel;
+
+ if (!int.TryParse(rawLevel, out newLevel))
+ {
+ MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawLevel);
+ return;
+ }
+
+ if (newLevel < 0 || newLevel > Util.MAX_THREADPOOL_LEVEL)
+ {
+ MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0.." + Util.MAX_THREADPOOL_LEVEL, newLevel);
+ return;
+ }
+
+ Util.LogThreadPool = newLevel;
+ MainConsole.Instance.OutputFormat("LogThreadPool set to {0}", newLevel);
}
private void HandleForceGc(string module, string[] args)
@@ -575,7 +873,8 @@ namespace OpenSim.Framework.Servers
protected string GetVersionText()
{
- return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion);
+ return String.Format("Version: {0} (SIMULATION/{1} - SIMULATION/{2})",
+ m_version, VersionInfo.SimulationServiceVersionSupportedMin, VersionInfo.SimulationServiceVersionSupportedMax);
}
///
@@ -621,7 +920,68 @@ namespace OpenSim.Framework.Servers
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
sb.Append("Main threadpool (excluding script engine pools)\n");
- sb.Append(Util.GetThreadPoolReport());
+ sb.Append(GetThreadPoolReport());
+
+ return sb.ToString();
+ }
+
+ ///
+ /// Get a thread pool report.
+ ///
+ ///
+ public static string GetThreadPoolReport()
+ {
+ string threadPoolUsed = null;
+ int maxThreads = 0;
+ int minThreads = 0;
+ int allocatedThreads = 0;
+ int inUseThreads = 0;
+ int waitingCallbacks = 0;
+ int completionPortThreads = 0;
+
+ StringBuilder sb = new StringBuilder();
+ if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
+ {
+ STPInfo stpi = Util.GetSmartThreadPoolInfo();
+
+ // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
+ if (stpi != null)
+ {
+ threadPoolUsed = "SmartThreadPool";
+ maxThreads = stpi.MaxThreads;
+ minThreads = stpi.MinThreads;
+ inUseThreads = stpi.InUseThreads;
+ allocatedThreads = stpi.ActiveThreads;
+ waitingCallbacks = stpi.WaitingCallbacks;
+ }
+ }
+ else if (
+ Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem
+ || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem)
+ {
+ threadPoolUsed = "BuiltInThreadPool";
+ ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);
+ ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
+ int availableThreads;
+ ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
+ inUseThreads = maxThreads - availableThreads;
+ allocatedThreads = -1;
+ waitingCallbacks = -1;
+ }
+
+ if (threadPoolUsed != null)
+ {
+ sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed);
+ sb.AppendFormat("Max threads : {0}\n", maxThreads);
+ sb.AppendFormat("Min threads : {0}\n", minThreads);
+ sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString());
+ sb.AppendFormat("In use threads : {0}\n", inUseThreads);
+ sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString());
+ }
+ else
+ {
+ sb.AppendFormat("Thread pool not used\n");
+ }
return sb.ToString();
}
@@ -673,5 +1033,16 @@ namespace OpenSim.Framework.Servers
if (m_console != null)
m_console.OutputFormat(format, components);
}
+
+ public virtual void Shutdown()
+ {
+ m_serverStatsCollector.Close();
+ ShutdownSpecific();
+ }
+
+ ///
+ /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
+ ///
+ protected virtual void ShutdownSpecific() {}
}
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
index 3412e0f..5c0e0df 100644
--- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
+++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs
@@ -41,318 +41,7 @@ namespace OpenSim.Framework.Servers.Tests
{
[TestFixture]
public class OSHttpTests : OpenSimTestCase
- {
- // we need an IHttpClientContext for our tests
- public class TestHttpClientContext: IHttpClientContext
- {
- private bool _secured;
- public bool IsSecured
- {
- get { return _secured; }
- }
- public bool Secured
- {
- get { return _secured; }
- }
-
- public TestHttpClientContext(bool secured)
- {
- _secured = secured;
- }
-
- public void Disconnect(SocketError error) {}
- public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {}
- public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {}
- public void Respond(string body) {}
- public void Send(byte[] buffer) {}
- public void Send(byte[] buffer, int offset, int size) {}
- public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {}
- public void Close() { }
- public bool EndWhenDone { get { return false;} set { return;}}
-
- public event EventHandler Disconnected = delegate { };
- ///
- /// A request have been received in the context.
- ///
- public event EventHandler RequestReceived = delegate { };
-
- }
-
- public class TestHttpRequest: IHttpRequest
- {
- private string _uriPath;
- public bool BodyIsComplete
- {
- get { return true; }
- }
- public string[] AcceptTypes
- {
- get {return _acceptTypes; }
- }
- private string[] _acceptTypes;
- public Stream Body
- {
- get { return _body; }
- set { _body = value;}
- }
- private Stream _body;
- public ConnectionType Connection
- {
- get { return _connection; }
- set { _connection = value; }
- }
- private ConnectionType _connection;
- public int ContentLength
- {
- get { return _contentLength; }
- set { _contentLength = value; }
- }
- private int _contentLength;
- public NameValueCollection Headers
- {
- get { return _headers; }
- }
- private NameValueCollection _headers = new NameValueCollection();
- public string HttpVersion
- {
- get { return _httpVersion; }
- set { _httpVersion = value; }
- }
- private string _httpVersion = null;
- public string Method
- {
- get { return _method; }
- set { _method = value; }
- }
- private string _method = null;
- public HttpInput QueryString
- {
- get { return _queryString; }
- }
- private HttpInput _queryString = null;
- public Uri Uri
- {
- get { return _uri; }
- set { _uri = value; }
- }
- private Uri _uri = null;
- public string[] UriParts
- {
- get { return _uri.Segments; }
- }
- public HttpParam Param
- {
- get { return null; }
- }
- public HttpForm Form
- {
- get { return null; }
- }
- public bool IsAjax
- {
- get { return false; }
- }
- public RequestCookies Cookies
- {
- get { return null; }
- }
-
- public TestHttpRequest() {}
-
- public TestHttpRequest(string contentEncoding, string contentType, string userAgent,
- string remoteAddr, string remotePort, string[] acceptTypes,
- ConnectionType connectionType, int contentLength, Uri uri)
- {
- _headers["content-encoding"] = contentEncoding;
- _headers["content-type"] = contentType;
- _headers["user-agent"] = userAgent;
- _headers["remote_addr"] = remoteAddr;
- _headers["remote_port"] = remotePort;
-
- _acceptTypes = acceptTypes;
- _connection = connectionType;
- _contentLength = contentLength;
- _uri = uri;
- }
-
- public void DecodeBody(FormDecoderProvider providers) {}
- public void SetCookies(RequestCookies cookies) {}
- public void AddHeader(string name, string value)
- {
- _headers.Add(name, value);
- }
- public int AddToBody(byte[] bytes, int offset, int length)
- {
- return 0;
- }
- public void Clear() {}
-
- public object Clone()
- {
- TestHttpRequest clone = new TestHttpRequest();
- clone._acceptTypes = _acceptTypes;
- clone._connection = _connection;
- clone._contentLength = _contentLength;
- clone._uri = _uri;
- clone._headers = new NameValueCollection(_headers);
-
- return clone;
- }
- public IHttpResponse CreateResponse(IHttpClientContext context)
- {
- return new HttpResponse(context, this);
- }
- ///
- /// Path and query (will be merged with the host header) and put in Uri
- ///
- ///
- public string UriPath
- {
- get { return _uriPath; }
- set
- {
- _uriPath = value;
-
- }
- }
-
- }
-
- public class TestHttpResponse: IHttpResponse
- {
- public Stream Body
- {
- get { return _body; }
-
- set { _body = value; }
- }
- private Stream _body;
-
- public string ProtocolVersion
- {
- get { return _protocolVersion; }
- set { _protocolVersion = value; }
- }
- private string _protocolVersion;
-
- public bool Chunked
- {
- get { return _chunked; }
-
- set { _chunked = value; }
- }
- private bool _chunked;
-
- public ConnectionType Connection
- {
- get { return _connection; }
-
- set { _connection = value; }
- }
- private ConnectionType _connection;
-
- public Encoding Encoding
- {
- get { return _encoding; }
-
- set { _encoding = value; }
- }
- private Encoding _encoding;
-
- public int KeepAlive
- {
- get { return _keepAlive; }
-
- set { _keepAlive = value; }
- }
- private int _keepAlive;
-
- public HttpStatusCode Status
- {
- get { return _status; }
-
- set { _status = value; }
- }
- private HttpStatusCode _status;
-
- public string Reason
- {
- get { return _reason; }
-
- set { _reason = value; }
- }
- private string _reason;
-
- public long ContentLength
- {
- get { return _contentLength; }
-
- set { _contentLength = value; }
- }
- private long _contentLength;
-
- public string ContentType
- {
- get { return _contentType; }
-
- set { _contentType = value; }
- }
- private string _contentType;
-
- public bool HeadersSent
- {
- get { return _headersSent; }
- }
- private bool _headersSent;
-
- public bool Sent
- {
- get { return _sent; }
- }
- private bool _sent;
-
- public ResponseCookies Cookies
- {
- get { return _cookies; }
- }
- private ResponseCookies _cookies = null;
-
- public TestHttpResponse()
- {
- _headersSent = false;
- _sent = false;
- }
-
- public void AddHeader(string name, string value) {}
- public void Send()
- {
- if (!_headersSent) SendHeaders();
- if (_sent) throw new InvalidOperationException("stuff already sent");
- _sent = true;
- }
-
- public void SendBody(byte[] buffer, int offset, int count)
- {
- if (!_headersSent) SendHeaders();
- _sent = true;
- }
- public void SendBody(byte[] buffer)
- {
- if (!_headersSent) SendHeaders();
- _sent = true;
- }
-
- public void SendHeaders()
- {
- if (_headersSent) throw new InvalidOperationException("headers already sent");
- _headersSent = true;
- }
-
- public void Redirect(Uri uri) {}
- public void Redirect(string url) {}
- }
-
-
+ {
public OSHttpRequest req0;
public OSHttpRequest req1;
@@ -424,4 +113,4 @@ namespace OpenSim.Framework.Servers.Tests
Assert.That(rsp0.ContentType, Is.EqualTo("text/xml"));
}
}
-}
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
index 2d72cb8..480f2bb 100644
--- a/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
+++ b/OpenSim/Framework/Servers/Tests/VersionInfoTests.cs
@@ -47,7 +47,7 @@ namespace OpenSim.Framework.Servers.Tests
{
foreach (VersionInfo.Flavour flavour in Enum.GetValues(typeof(VersionInfo.Flavour)))
{
- Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.GetVersionString("0.0.0", "0", flavour).Length, "0.0.0/" + flavour + " failed");
+ Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.GetVersionString("0.0.0", flavour).Length, "0.0.0/" + flavour + " failed");
}
}
}
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
deleted file mode 100644
index 54af95e..0000000
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.
- */
-
-namespace OpenSim
-{
- public class VersionInfo
- {
- private const string VERSION_NUMBER = "0.7.5";
- private const string IG_BUILD_NUMBER = "4";
- private const Flavour VERSION_FLAVOUR = Flavour.IG;
-
- public enum Flavour
- {
- Unknown,
- Dev,
- RC1,
- RC2,
- Release,
- Post_Fixes,
- Extended,
- IG
- }
-
- public static string Version
- {
- get { return GetVersionString(VERSION_NUMBER, IG_BUILD_NUMBER, VERSION_FLAVOUR); }
- }
-
- public static string GetVersionString(string versionNumber, string buildNumber, Flavour flavour)
- {
- string versionString = "OpenSim " + versionNumber + " " + flavour + " build " + buildNumber;
- return versionString.PadRight(VERSIONINFO_VERSION_LENGTH);
- }
-
- public const int VERSIONINFO_VERSION_LENGTH = 39;
-
- ///
- /// This is the external interface version. It is separate from the OpenSimulator project version.
- ///
- /// This version number should be
- /// increased by 1 every time a code change makes the previous OpenSimulator revision incompatible
- /// with the new revision. This will usually be due to interregion or grid facing interface changes.
- ///
- /// Changes which are compatible with an older revision (e.g. older revisions experience degraded functionality
- /// but not outright failure) do not need a version number increment.
- ///
- /// Having this version number allows the grid service to reject connections from regions running a version
- /// of the code that is too old.
- ///
- ///
- public readonly static int MajorInterfaceVersion = 7;
- }
-}
diff --git a/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs
new file mode 100644
index 0000000..512ac4f
--- /dev/null
+++ b/OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs
@@ -0,0 +1,113 @@
+/*
+ * 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.Collections.Specialized;
+using System.Net;
+using System.Reflection;
+
+using Nini.Config;
+using log4net;
+
+namespace OpenSim.Framework.ServiceAuth
+{
+ public class BasicHttpAuthentication : IServiceAuth
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public string Name { get { return "BasicHttp"; } }
+
+ private string m_Username, m_Password;
+ private string m_CredentialsB64;
+
+// private string remove_me;
+
+ public string Credentials
+ {
+ get { return m_CredentialsB64; }
+ }
+
+ public BasicHttpAuthentication(IConfigSource config, string section)
+ {
+// remove_me = section;
+ m_Username = Util.GetConfigVarFromSections(config, "HttpAuthUsername", new string[] { "Network", section }, string.Empty);
+ m_Password = Util.GetConfigVarFromSections(config, "HttpAuthPassword", new string[] { "Network", section }, string.Empty);
+ string str = m_Username + ":" + m_Password;
+ byte[] encData_byte = Util.UTF8.GetBytes(str);
+
+ m_CredentialsB64 = Convert.ToBase64String(encData_byte);
+// m_log.DebugFormat("[HTTP BASIC AUTH]: {0} {1} [{2}]", m_Username, m_Password, section);
+ }
+
+ public void AddAuthorization(NameValueCollection headers)
+ {
+ //m_log.DebugFormat("[HTTP BASIC AUTH]: Adding authorization for {0}", remove_me);
+ headers["Authorization"] = "Basic " + m_CredentialsB64;
+ }
+
+ public bool Authenticate(string data)
+ {
+ string recovered = Util.Base64ToString(data);
+ if (!String.IsNullOrEmpty(recovered))
+ {
+ string[] parts = recovered.Split(new char[] { ':' });
+ if (parts.Length >= 2)
+ {
+ return m_Username.Equals(parts[0]) && m_Password.Equals(parts[1]);
+ }
+ }
+
+ return false;
+ }
+
+ public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
+ {
+// m_log.DebugFormat("[HTTP BASIC AUTH]: Authenticate in {0}", "BasicHttpAuthentication");
+
+ string value = requestHeaders.Get("Authorization");
+ if (value != null)
+ {
+ value = value.Trim();
+ if (value.StartsWith("Basic "))
+ {
+ value = value.Replace("Basic ", string.Empty);
+ if (Authenticate(value))
+ {
+ statusCode = HttpStatusCode.OK;
+ return true;
+ }
+ }
+ }
+
+ d("WWW-Authenticate", "Basic realm = \"Asset Server\"");
+
+ statusCode = HttpStatusCode.Unauthorized;
+ return false;
+ }
+ }
+}
diff --git a/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
new file mode 100644
index 0000000..a49952c
--- /dev/null
+++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
@@ -0,0 +1,82 @@
+/*
+ * 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.Collections.Specialized;
+using System.Linq;
+using System.Net;
+
+namespace OpenSim.Framework.ServiceAuth
+{
+ public class CompoundAuthentication : IServiceAuth
+ {
+ public string Name { get { return "Compound"; } }
+
+ private List m_authentications = new List();
+
+ public int Count { get { return m_authentications.Count; } }
+
+ public List GetAuthentors()
+ {
+ return new List(m_authentications);
+ }
+
+ public void AddAuthenticator(IServiceAuth auth)
+ {
+ m_authentications.Add(auth);
+ }
+
+ public void RemoveAuthenticator(IServiceAuth auth)
+ {
+ m_authentications.Remove(auth);
+ }
+
+ public void AddAuthorization(NameValueCollection headers)
+ {
+ foreach (IServiceAuth auth in m_authentications)
+ auth.AddAuthorization(headers);
+ }
+
+ public bool Authenticate(string data)
+ {
+ return m_authentications.TrueForAll(a => a.Authenticate(data));
+ }
+
+ public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
+ {
+ foreach (IServiceAuth auth in m_authentications)
+ {
+ if (!auth.Authenticate(requestHeaders, d, out statusCode))
+ return false;
+ }
+
+ statusCode = HttpStatusCode.OK;
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs
new file mode 100644
index 0000000..e0c413b
--- /dev/null
+++ b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs
@@ -0,0 +1,59 @@
+/*
+ * 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.Specialized;
+using System.Net;
+
+namespace OpenSim.Framework.ServiceAuth
+{
+ public class DisallowLlHttpRequest : IServiceAuth
+ {
+ public string Name { get { return "DisallowllHTTPRequest"; } }
+
+ public void AddAuthorization(NameValueCollection headers) {}
+
+ public bool Authenticate(string data)
+ {
+ return false;
+ }
+
+ public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
+ {
+// Console.WriteLine("DisallowLlHttpRequest");
+
+ if (requestHeaders["X-SecondLife-Shard"] != null)
+ {
+ statusCode = HttpStatusCode.Forbidden;
+ return false;
+ }
+
+ statusCode = HttpStatusCode.OK;
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/ServiceAuth/IServiceAuth.cs b/OpenSim/Framework/ServiceAuth/IServiceAuth.cs
new file mode 100644
index 0000000..5f744cb
--- /dev/null
+++ b/OpenSim/Framework/ServiceAuth/IServiceAuth.cs
@@ -0,0 +1,48 @@
+/*
+ * 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.Net;
+using System.Collections.Generic;
+using System.Collections.Specialized;
+
+namespace OpenSim.Framework.ServiceAuth
+{
+ public delegate void AddHeaderDelegate(string key, string value);
+
+ public interface IServiceAuth
+ {
+ ///
+ /// Name of this authenticator.
+ ///
+ string Name { get; }
+
+ bool Authenticate(string data);
+ bool Authenticate(NameValueCollection headers, AddHeaderDelegate d, out HttpStatusCode statusCode);
+ void AddAuthorization(NameValueCollection headers);
+ }
+}
diff --git a/OpenSim/Framework/ServiceAuth/ServiceAuth.cs b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs
new file mode 100644
index 0000000..51012e3
--- /dev/null
+++ b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs
@@ -0,0 +1,68 @@
+/*
+ * 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 log4net;
+using Nini.Config;
+
+namespace OpenSim.Framework.ServiceAuth
+{
+ public class ServiceAuth
+ {
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ public static IServiceAuth Create(IConfigSource config, string section)
+ {
+ CompoundAuthentication compoundAuth = new CompoundAuthentication();
+
+ bool allowLlHttpRequestIn
+ = Util.GetConfigVarFromSections(config, "AllowllHTTPRequestIn", new string[] { "Network", section }, false);
+
+ if (!allowLlHttpRequestIn)
+ compoundAuth.AddAuthenticator(new DisallowLlHttpRequest());
+
+ string authType = Util.GetConfigVarFromSections(config, "AuthType", new string[] { "Network", section }, "None");
+
+ switch (authType)
+ {
+ case "BasicHttpAuthentication":
+ compoundAuth.AddAuthenticator(new BasicHttpAuthentication(config, section));
+ break;
+ }
+
+// foreach (IServiceAuth auth in compoundAuth.GetAuthentors())
+// m_log.DebugFormat("[SERVICE AUTH]: Configured authenticator {0}", auth.Name);
+
+ if (compoundAuth.Count > 0)
+ return compoundAuth;
+ else
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs
index a06f8e7..307cb75 100644
--- a/OpenSim/Framework/TaskInventoryItem.cs
+++ b/OpenSim/Framework/TaskInventoryItem.cs
@@ -124,7 +124,7 @@ namespace OpenSim.Framework
{
get
{
- if (_creatorData != null && _creatorData != string.Empty)
+ if (!string.IsNullOrEmpty(_creatorData))
return _creatorID.ToString() + ';' + _creatorData;
else
return _creatorID.ToString();
diff --git a/OpenSim/Framework/TerrainData.cs b/OpenSim/Framework/TerrainData.cs
new file mode 100644
index 0000000..6b1be4e
--- /dev/null
+++ b/OpenSim/Framework/TerrainData.cs
@@ -0,0 +1,464 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+
+using OpenMetaverse;
+
+using log4net;
+
+namespace OpenSim.Framework
+{
+ public abstract class TerrainData
+ {
+ // Terrain always is a square
+ public int SizeX { get; protected set; }
+ public int SizeY { get; protected set; }
+ public int SizeZ { get; protected set; }
+
+ // A height used when the user doesn't specify anything
+ public const float DefaultTerrainHeight = 21f;
+
+ public abstract float this[int x, int y] { get; set; }
+ // Someday terrain will have caves
+ public abstract float this[int x, int y, int z] { get; set; }
+
+ public abstract bool IsTaintedAt(int xx, int yy);
+ public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest);
+ public abstract void TaintAllTerrain();
+ public abstract void ClearTaint();
+
+ public abstract void ClearLand();
+ public abstract void ClearLand(float height);
+
+ // Return a representation of this terrain for storing as a blob in the database.
+ // Returns 'true' to say blob was stored in the 'out' locations.
+ public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
+
+ // Given a revision code and a blob from the database, create and return the right type of TerrainData.
+ // The sizes passed are the expected size of the region. The database info will be used to
+ // initialize the heightmap of that sized region with as much data is in the blob.
+ // Return created TerrainData or 'null' if unsuccessful.
+ public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
+ {
+ // For the moment, there is only one implementation class
+ return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob);
+ }
+
+ // return a special compressed representation of the heightmap in ints
+ public abstract int[] GetCompressedMap();
+ public abstract float CompressionFactor { get; }
+
+ public abstract float[] GetFloatsSerialized();
+ public abstract double[,] GetDoubles();
+ public abstract TerrainData Clone();
+ }
+
+ // The terrain is stored in the database as a blob with a 'revision' field.
+ // Some implementations of terrain storage would fill the revision field with
+ // the time the terrain was stored. When real revisions were added and this
+ // feature removed, that left some old entries with the time in the revision
+ // field.
+ // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
+ // left over and it is presumed to be 'Legacy256'.
+ // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
+ // If a revision does not match any of these, it is assumed to be Legacy256.
+ public enum DBTerrainRevision
+ {
+ // Terrain is 'double[256,256]'
+ Legacy256 = 11,
+ // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions
+ // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
+ Variable2D = 22,
+ // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions
+ // and third int is the 'compression factor'. The heights are compressed as
+ // "int compressedHeight = (int)(height * compressionFactor);"
+ // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
+ Compressed2D = 27,
+ // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
+ RevisionHigh = 1234
+ }
+
+ // Version of terrain that is a heightmap.
+ // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
+ // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
+ // The heighmap is kept as an array of integers. The integer values are converted to
+ // and from floats by TerrainCompressionFactor.
+ public class HeightmapTerrainData : TerrainData
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]";
+
+ // TerrainData.this[x, y]
+ public override float this[int x, int y]
+ {
+ get { return FromCompressedHeight(m_heightmap[x, y]); }
+ set {
+ int newVal = ToCompressedHeight(value);
+ if (m_heightmap[x, y] != newVal)
+ {
+ m_heightmap[x, y] = newVal;
+ m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
+ }
+ }
+ }
+
+ // TerrainData.this[x, y, z]
+ public override float this[int x, int y, int z]
+ {
+ get { return this[x, y]; }
+ set { this[x, y] = value; }
+ }
+
+ // TerrainData.ClearTaint
+ public override void ClearTaint()
+ {
+ SetAllTaint(false);
+ }
+
+ // TerrainData.TaintAllTerrain
+ public override void TaintAllTerrain()
+ {
+ SetAllTaint(true);
+ }
+
+ private void SetAllTaint(bool setting)
+ {
+ for (int ii = 0; ii < m_taint.GetLength(0); ii++)
+ for (int jj = 0; jj < m_taint.GetLength(1); jj++)
+ m_taint[ii, jj] = setting;
+ }
+
+ // TerrainData.ClearLand
+ public override void ClearLand()
+ {
+ ClearLand(DefaultTerrainHeight);
+ }
+ // TerrainData.ClearLand(float)
+ public override void ClearLand(float pHeight)
+ {
+ int flatHeight = ToCompressedHeight(pHeight);
+ for (int xx = 0; xx < SizeX; xx++)
+ for (int yy = 0; yy < SizeY; yy++)
+ m_heightmap[xx, yy] = flatHeight;
+ }
+
+ // Return 'true' of the patch that contains these region coordinates has been modified.
+ // Note that checking the taint clears it.
+ // There is existing code that relies on this feature.
+ public override bool IsTaintedAt(int xx, int yy, bool clearOnTest)
+ {
+ int tx = xx / Constants.TerrainPatchSize;
+ int ty = yy / Constants.TerrainPatchSize;
+ bool ret = m_taint[tx, ty];
+ if (ret && clearOnTest)
+ m_taint[tx, ty] = false;
+ return ret;
+ }
+
+ // Old form that clears the taint flag when we check it.
+ public override bool IsTaintedAt(int xx, int yy)
+ {
+ return IsTaintedAt(xx, yy, true /* clearOnTest */);
+ }
+
+ // TerrainData.GetDatabaseBlob
+ // The user wants something to store in the database.
+ public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
+ {
+ bool ret = false;
+ if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize)
+ {
+ DBRevisionCode = (int)DBTerrainRevision.Legacy256;
+ blob = ToLegacyTerrainSerialization();
+ ret = true;
+ }
+ else
+ {
+ DBRevisionCode = (int)DBTerrainRevision.Compressed2D;
+ blob = ToCompressedTerrainSerialization();
+ ret = true;
+ }
+ return ret;
+ }
+
+ // TerrainData.CompressionFactor
+ private float m_compressionFactor = 100.0f;
+ public override float CompressionFactor { get { return m_compressionFactor; } }
+
+ // TerrainData.GetCompressedMap
+ public override int[] GetCompressedMap()
+ {
+ int[] newMap = new int[SizeX * SizeY];
+
+ int ind = 0;
+ for (int xx = 0; xx < SizeX; xx++)
+ for (int yy = 0; yy < SizeY; yy++)
+ newMap[ind++] = m_heightmap[xx, yy];
+
+ return newMap;
+
+ }
+ // TerrainData.Clone
+ public override TerrainData Clone()
+ {
+ HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
+ ret.m_heightmap = (int[,])this.m_heightmap.Clone();
+ return ret;
+ }
+
+ // TerrainData.GetFloatsSerialized
+ // This one dimensional version is ordered so height = map[y*sizeX+x];
+ // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
+ // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
+ public override float[] GetFloatsSerialized()
+ {
+ int points = SizeX * SizeY;
+ float[] heights = new float[points];
+
+ int idx = 0;
+ for (int jj = 0; jj < SizeY; jj++)
+ for (int ii = 0; ii < SizeX; ii++)
+ {
+ heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]);
+ }
+
+ return heights;
+ }
+
+ // TerrainData.GetDoubles
+ public override double[,] GetDoubles()
+ {
+ double[,] ret = new double[SizeX, SizeY];
+ for (int xx = 0; xx < SizeX; xx++)
+ for (int yy = 0; yy < SizeY; yy++)
+ ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]);
+
+ return ret;
+ }
+
+
+ // =============================================================
+
+ private int[,] m_heightmap;
+ // Remember subregions of the heightmap that has changed.
+ private bool[,] m_taint;
+
+ // To save space (especially for large regions), keep the height as a short integer
+ // that is coded as the float height times the compression factor (usually '100'
+ // to make for two decimal points).
+ public int ToCompressedHeight(double pHeight)
+ {
+ return (int)(pHeight * CompressionFactor);
+ }
+
+ public float FromCompressedHeight(int pHeight)
+ {
+ return ((float)pHeight) / CompressionFactor;
+ }
+
+ // To keep with the legacy theme, create an instance of this class based on the
+ // way terrain used to be passed around.
+ public HeightmapTerrainData(double[,] pTerrain)
+ {
+ SizeX = pTerrain.GetLength(0);
+ SizeY = pTerrain.GetLength(1);
+ SizeZ = (int)Constants.RegionHeight;
+ m_compressionFactor = 100.0f;
+
+ m_heightmap = new int[SizeX, SizeY];
+ for (int ii = 0; ii < SizeX; ii++)
+ {
+ for (int jj = 0; jj < SizeY; jj++)
+ {
+ m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]);
+
+ }
+ }
+ // m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
+
+ m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
+ ClearTaint();
+ }
+
+ // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
+ public HeightmapTerrainData(int pX, int pY, int pZ)
+ {
+ SizeX = pX;
+ SizeY = pY;
+ SizeZ = pZ;
+ m_compressionFactor = 100.0f;
+ m_heightmap = new int[SizeX, SizeY];
+ m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
+ // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
+ ClearTaint();
+ ClearLand(0f);
+ }
+
+ public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ)
+ {
+ m_compressionFactor = pCompressionFactor;
+ int ind = 0;
+ for (int xx = 0; xx < SizeX; xx++)
+ for (int yy = 0; yy < SizeY; yy++)
+ m_heightmap[xx, yy] = cmap[ind++];
+ // m_log.DebugFormat("{0} new by compressed map. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
+ }
+
+ // Create a heighmap from a database blob
+ public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ)
+ {
+ switch ((DBTerrainRevision)pFormatCode)
+ {
+ case DBTerrainRevision.Compressed2D:
+ FromCompressedTerrainSerialization(pBlob);
+ m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
+ break;
+ default:
+ FromLegacyTerrainSerialization(pBlob);
+ m_log.DebugFormat("{0} HeightmapTerrainData create from legacy serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
+ break;
+ }
+ }
+
+ // Just create an array of doubles. Presumes the caller implicitly knows the size.
+ public Array ToLegacyTerrainSerialization()
+ {
+ Array ret = null;
+
+ using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
+ {
+ using (BinaryWriter bw = new BinaryWriter(str))
+ {
+ for (int xx = 0; xx < Constants.RegionSize; xx++)
+ {
+ for (int yy = 0; yy < Constants.RegionSize; yy++)
+ {
+ double height = this[xx, yy];
+ if (height == 0.0)
+ height = double.Epsilon;
+ bw.Write(height);
+ }
+ }
+ }
+ ret = str.ToArray();
+ }
+ return ret;
+ }
+
+ // Just create an array of doubles. Presumes the caller implicitly knows the size.
+ public void FromLegacyTerrainSerialization(byte[] pBlob)
+ {
+ // In case database info doesn't match real terrain size, initialize the whole terrain.
+ ClearLand();
+
+ using (MemoryStream mstr = new MemoryStream(pBlob))
+ {
+ using (BinaryReader br = new BinaryReader(mstr))
+ {
+ for (int xx = 0; xx < (int)Constants.RegionSize; xx++)
+ {
+ for (int yy = 0; yy < (int)Constants.RegionSize; yy++)
+ {
+ float val = (float)br.ReadDouble();
+ if (xx < SizeX && yy < SizeY)
+ m_heightmap[xx, yy] = ToCompressedHeight(val);
+ }
+ }
+ }
+ ClearTaint();
+ }
+ }
+
+ // See the reader below.
+ public Array ToCompressedTerrainSerialization()
+ {
+ Array ret = null;
+ using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16))))
+ {
+ using (BinaryWriter bw = new BinaryWriter(str))
+ {
+ bw.Write((Int32)DBTerrainRevision.Compressed2D);
+ bw.Write((Int32)SizeX);
+ bw.Write((Int32)SizeY);
+ bw.Write((Int32)CompressionFactor);
+ for (int yy = 0; yy < SizeY; yy++)
+ for (int xx = 0; xx < SizeX; xx++)
+ {
+ bw.Write((Int16)m_heightmap[xx, yy]);
+ }
+ }
+ ret = str.ToArray();
+ }
+ return ret;
+ }
+
+ // Initialize heightmap from blob consisting of:
+ // int32, int32, int32, int32, int16[]
+ // where the first int32 is format code, next two int32s are the X and y of heightmap data and
+ // the forth int is the compression factor for the following int16s
+ // This is just sets heightmap info. The actual size of the region was set on this instance's
+ // creation and any heights not initialized by theis blob are set to the default height.
+ public void FromCompressedTerrainSerialization(byte[] pBlob)
+ {
+ Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor;
+
+ using (MemoryStream mstr = new MemoryStream(pBlob))
+ {
+ using (BinaryReader br = new BinaryReader(mstr))
+ {
+ hmFormatCode = br.ReadInt32();
+ hmSizeX = br.ReadInt32();
+ hmSizeY = br.ReadInt32();
+ hmCompressionFactor = br.ReadInt32();
+
+ m_compressionFactor = hmCompressionFactor;
+
+ // In case database info doesn't match real terrain size, initialize the whole terrain.
+ ClearLand();
+
+ for (int yy = 0; yy < hmSizeY; yy++)
+ {
+ for (int xx = 0; xx < hmSizeX; xx++)
+ {
+ Int16 val = br.ReadInt16();
+ if (xx < SizeX && yy < SizeY)
+ m_heightmap[xx, yy] = val;
+ }
+ }
+ }
+ ClearTaint();
+
+ m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}",
+ LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor);
+ }
+ }
+ }
+}
diff --git a/OpenSim/Framework/Tests/AnimationTests.cs b/OpenSim/Framework/Tests/AnimationTests.cs
index f3be81b..d8f17d0 100644
--- a/OpenSim/Framework/Tests/AnimationTests.cs
+++ b/OpenSim/Framework/Tests/AnimationTests.cs
@@ -32,7 +32,6 @@ using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Tests.Common;
-using OpenSim.Tests.Common.Mock;
using Animation = OpenSim.Framework.Animation;
namespace OpenSim.Framework.Tests
diff --git a/OpenSim/Framework/Tests/AssetBaseTest.cs b/OpenSim/Framework/Tests/AssetBaseTest.cs
index 25d2393..1975a4d 100644
--- a/OpenSim/Framework/Tests/AssetBaseTest.cs
+++ b/OpenSim/Framework/Tests/AssetBaseTest.cs
@@ -50,19 +50,15 @@ namespace OpenSim.Framework.Tests
CheckContainsReferences(AssetType.ImageJPEG , false);
CheckContainsReferences(AssetType.ImageTGA , false);
CheckContainsReferences(AssetType.Landmark , false);
- CheckContainsReferences(AssetType.LostAndFoundFolder, false);
CheckContainsReferences(AssetType.LSLBytecode, false);
CheckContainsReferences(AssetType.LSLText, false);
CheckContainsReferences(AssetType.Notecard, false);
CheckContainsReferences(AssetType.Object, false);
- CheckContainsReferences(AssetType.RootFolder, false);
CheckContainsReferences(AssetType.Simstate, false);
- CheckContainsReferences(AssetType.SnapshotFolder, false);
CheckContainsReferences(AssetType.Sound, false);
CheckContainsReferences(AssetType.SoundWAV, false);
CheckContainsReferences(AssetType.Texture, false);
CheckContainsReferences(AssetType.TextureTGA, false);
- CheckContainsReferences(AssetType.TrashFolder, false);
CheckContainsReferences(AssetType.Unknown, false);
}
diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs
index a56ecb4..3d5d1d2 100644
--- a/OpenSim/Framework/Tests/LocationTest.cs
+++ b/OpenSim/Framework/Tests/LocationTest.cs
@@ -51,21 +51,28 @@ namespace OpenSim.Framework.Tests
[Test]
public void locationXYRegionHandle()
{
- Location TestLocation1 = new Location(256000,256000);
- Location TestLocation2 = new Location(1099511628032000);
+ Location TestLocation1 = new Location(255000,256000);
+ Location TestLocation2 = new Location(1095216660736000);
Assert.That(TestLocation1 == TestLocation2);
- Assert.That(TestLocation2.X == 256000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided");
+ Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor");
+ Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided");
- Assert.That(TestLocation2.RegionHandle == 1099511628032000,
+ Assert.That(TestLocation2.RegionHandle == 1095216660736000,
"Location RegionHandle Property didn't match regionhandle provided in constructor");
+ ulong RegionHandle = TestLocation1.RegionHandle;
+ Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor");
- TestLocation1 = new Location(256001, 256001);
- TestLocation2 = new Location(1099511628032000);
+ TestLocation2 = new Location(RegionHandle);
+ Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor");
+
+
+ TestLocation1 = new Location(255001, 256001);
+ TestLocation2 = new Location(1095216660736000);
Assert.That(TestLocation1 != TestLocation2);
- Assert.That(TestLocation1.Equals(256001, 256001), "Equals(x,y) failed to match the position in the constructor");
+ Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor");
Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode");
diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
index 1dc8053..3f0a031 100644
--- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
+++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Framework.Tests
cadu.AVHeight = Size1.Z;
AgentPosition position2 = new AgentPosition();
- position2.CopyFrom(cadu);
+ position2.CopyFrom(cadu, position1.SessionID);
Assert.IsTrue(
position2.AgentID == position1.AgentID
diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs
index 11ca068..cfe3139 100644
--- a/OpenSim/Framework/Tests/UtilTest.cs
+++ b/OpenSim/Framework/Tests/UtilTest.cs
@@ -173,8 +173,8 @@ namespace OpenSim.Framework.Tests
[Test]
public void SLUtilTypeConvertTests()
{
- int[] assettypes = new int[]{-1,0,1,2,3,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22
- ,23,24,25,46,47,48};
+ int[] assettypes = new int[]{-1,0,1,2,3,5,6,7,8,10,11,12,13,17,18,19,20,21,22
+ ,24,25};
string[] contenttypes = new string[]
{
"application/octet-stream",
@@ -186,26 +186,18 @@ namespace OpenSim.Framework.Tests
"application/vnd.ll.primitive",
"application/vnd.ll.notecard",
"application/vnd.ll.folder",
- "application/vnd.ll.rootfolder",
"application/vnd.ll.lsltext",
"application/vnd.ll.lslbyte",
"image/tga",
"application/vnd.ll.bodypart",
- "application/vnd.ll.trashfolder",
- "application/vnd.ll.snapshotfolder",
- "application/vnd.ll.lostandfoundfolder",
"audio/x-wav",
"image/tga",
"image/jpeg",
"application/vnd.ll.animation",
"application/vnd.ll.gesture",
"application/x-metaverse-simstate",
- "application/vnd.ll.favoritefolder",
"application/vnd.ll.link",
"application/vnd.ll.linkfolder",
- "application/vnd.ll.currentoutfitfolder",
- "application/vnd.ll.outfitfolder",
- "application/vnd.ll.myoutfitsfolder"
};
for (int i=0;i
+ /// A thread-safe Random since the .NET version is not.
+ /// See http://msdn.microsoft.com/en-us/library/system.random%28v=vs.100%29.aspx
+ ///
+ public class ThreadSafeRandom : Random
+ {
+ public ThreadSafeRandom() : base() {}
+
+ public ThreadSafeRandom(int seed): base (seed) {}
+
+ public override int Next()
+ {
+ lock (this)
+ return base.Next();
+ }
+
+ public override int Next(int maxValue)
+ {
+ lock (this)
+ return base.Next(maxValue);
+ }
+
+ public override int Next(int minValue, int maxValue)
+ {
+ lock (this)
+ return base.Next(minValue, maxValue);
+ }
+
+ public override void NextBytes(byte[] buffer)
+ {
+ lock (this)
+ base.NextBytes(buffer);
+ }
+
+ public override double NextDouble()
+ {
+ lock (this)
+ return base.NextDouble();
+ }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/ThrottleOutPacketType.cs b/OpenSim/Framework/ThrottleOutPacketType.cs
index d56231a..ca4b126 100644
--- a/OpenSim/Framework/ThrottleOutPacketType.cs
+++ b/OpenSim/Framework/ThrottleOutPacketType.cs
@@ -47,9 +47,6 @@ namespace OpenSim.Framework
Texture = 5,
/// Non-texture assets
Asset = 6,
- /// Avatar and primitive data
- /// This is a sub-category of Task
- State = 7,
}
[Flags]
@@ -61,6 +58,5 @@ namespace OpenSim.Framework
Task = 1 << 3,
Texture = 1 << 4,
Asset = 1 << 5,
- State = 1 << 6,
}
}
diff --git a/OpenSim/Framework/UntrustedWebRequest.cs b/OpenSim/Framework/UntrustedWebRequest.cs
deleted file mode 100644
index e6411cc..0000000
--- a/OpenSim/Framework/UntrustedWebRequest.cs
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright (c) Contributors, http://opensimulator.org/
- * See CONTRIBUTORS.TXT for a full list of copyright holders.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of the OpenSimulator Project nor the
- * names of its contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Net;
-using System.Net.Security;
-using System.Text;
-using log4net;
-
-namespace OpenSim.Framework
-{
- ///
- /// Used for requests to untrusted endpoints that may potentially be
- /// malicious
- ///
- public static class UntrustedHttpWebRequest
- {
- /// Setting this to true will allow HTTP connections to localhost
- private const bool DEBUG = true;
-
- private static readonly ILog m_log =
- LogManager.GetLogger(
- System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
-
- private static readonly ICollection allowableSchemes = new List { "http", "https" };
-
- ///
- /// Creates an HttpWebRequest that is hardened against malicious
- /// endpoints after ensuring the given Uri is safe to retrieve
- ///
- /// Web location to request
- /// A hardened HttpWebRequest if the uri was determined to be safe
- /// If uri is null
- /// If uri is unsafe
- public static HttpWebRequest Create(Uri uri)
- {
- return Create(uri, DEBUG, 1000 * 5, 1000 * 20, 10);
- }
-
- ///
- /// Creates an HttpWebRequest that is hardened against malicious
- /// endpoints after ensuring the given Uri is safe to retrieve
- ///
- /// Web location to request
- /// True to allow connections to localhost, otherwise false
- /// Read write timeout, in milliseconds
- /// Connection timeout, in milliseconds
- /// Maximum number of allowed redirects
- /// A hardened HttpWebRequest if the uri was determined to be safe
- /// If uri is null
- /// If uri is unsafe
- public static HttpWebRequest Create(Uri uri, bool allowLoopback, int readWriteTimeoutMS, int timeoutMS, int maximumRedirects)
- {
- if (uri == null)
- throw new ArgumentNullException("uri");
-
- if (!IsUriAllowable(uri, allowLoopback))
- throw new ArgumentException("Uri " + uri + " was rejected");
-
- HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
- httpWebRequest.MaximumAutomaticRedirections = maximumRedirects;
- httpWebRequest.ReadWriteTimeout = readWriteTimeoutMS;
- httpWebRequest.Timeout = timeoutMS;
- httpWebRequest.KeepAlive = false;
-
- return httpWebRequest;
- }
-
- public static string PostToUntrustedUrl(Uri url, string data)
- {
- try
- {
- byte[] requestData = System.Text.Encoding.UTF8.GetBytes(data);
-
- HttpWebRequest request = Create(url);
- request.Method = "POST";
- request.ContentLength = requestData.Length;
- request.ContentType = "application/x-www-form-urlencoded";
-
- using (Stream requestStream = request.GetRequestStream())
- requestStream.Write(requestData, 0, requestData.Length);
-
- using (WebResponse response = request.GetResponse())
- {
- using (Stream responseStream = response.GetResponseStream())
- return responseStream.GetStreamString();
- }
- }
- catch (Exception ex)
- {
- m_log.Warn("POST to untrusted URL " + url + " failed: " + ex.Message);
- return null;
- }
- }
-
- public static string GetUntrustedUrl(Uri url)
- {
- try
- {
- HttpWebRequest request = Create(url);
-
- using (WebResponse response = request.GetResponse())
- {
- using (Stream responseStream = response.GetResponseStream())
- return responseStream.GetStreamString();
- }
- }
- catch (Exception ex)
- {
- m_log.Warn("GET from untrusted URL " + url + " failed: " + ex.Message);
- return null;
- }
- }
-
- ///
- /// Determines whether a URI is allowed based on scheme and host name.
- /// No requireSSL check is done here
- ///
- /// True to allow loopback addresses to be used
- /// The URI to test for whether it should be allowed.
- ///
- /// true if [is URI allowable] [the specified URI]; otherwise, false.
- ///
- private static bool IsUriAllowable(Uri uri, bool allowLoopback)
- {
- if (!allowableSchemes.Contains(uri.Scheme))
- {
- m_log.WarnFormat("Rejecting URL {0} because it uses a disallowed scheme.", uri);
- return false;
- }
-
- // Try to interpret the hostname as an IP address so we can test for internal
- // IP address ranges. Note that IP addresses can appear in many forms
- // (e.g. http://127.0.0.1, http://2130706433, http://0x0100007f, http://::1
- // So we convert them to a canonical IPAddress instance, and test for all
- // non-routable IP ranges: 10.*.*.*, 127.*.*.*, ::1
- // Note that Uri.IsLoopback is very unreliable, not catching many of these variants.
- IPAddress hostIPAddress;
- if (IPAddress.TryParse(uri.DnsSafeHost, out hostIPAddress))
- {
- byte[] addressBytes = hostIPAddress.GetAddressBytes();
-
- // The host is actually an IP address.
- switch (hostIPAddress.AddressFamily)
- {
- case System.Net.Sockets.AddressFamily.InterNetwork:
- if (!allowLoopback && (addressBytes[0] == 127 || addressBytes[0] == 10))
- {
- m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri);
- return false;
- }
- break;
- case System.Net.Sockets.AddressFamily.InterNetworkV6:
- if (!allowLoopback && IsIPv6Loopback(hostIPAddress))
- {
- m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri);
- return false;
- }
- break;
- default:
- m_log.WarnFormat("Rejecting URL {0} because it does not use an IPv4 or IPv6 address.", uri);
- return false;
- }
- }
- else
- {
- // The host is given by name. We require names to contain periods to
- // help make sure it's not an internal address.
- if (!allowLoopback && !uri.Host.Contains("."))
- {
- m_log.WarnFormat("Rejecting URL {0} because it does not contain a period in the host name.", uri);
- return false;
- }
- }
-
- return true;
- }
-
- ///
- /// Determines whether an IP address is the IPv6 equivalent of "localhost/127.0.0.1".
- ///
- /// The ip address to check.
- ///
- /// true if this is a loopback IP address; false otherwise.
- ///
- private static bool IsIPv6Loopback(IPAddress ip)
- {
- if (ip == null)
- throw new ArgumentNullException("ip");
-
- byte[] addressBytes = ip.GetAddressBytes();
- for (int i = 0; i < addressBytes.Length - 1; i++)
- {
- if (addressBytes[i] != 0)
- return false;
- }
-
- if (addressBytes[addressBytes.Length - 1] != 1)
- return false;
-
- return true;
- }
- }
-}
diff --git a/OpenSim/Framework/UserProfileData.cs b/OpenSim/Framework/UserProfileData.cs
index 9bac739..266ccf0 100644
--- a/OpenSim/Framework/UserProfileData.cs
+++ b/OpenSim/Framework/UserProfileData.cs
@@ -160,15 +160,19 @@ namespace OpenSim.Framework
public virtual ulong HomeRegion
{
get
- {
- return Utils.UIntsToLong(
- m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
+ {
+ return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY));
+ // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
}
set
{
- m_homeRegionX = (uint) (value >> 40);
- m_homeRegionY = (((uint) (value)) >> 8);
+ uint regionWorldLocX, regionWorldLocY;
+ Util.RegionHandleToWorldLoc(value, out regionWorldLocX, out regionWorldLocY);
+ m_homeRegionX = Util.WorldToRegionLoc(regionWorldLocX);
+ m_homeRegionY = Util.WorldToRegionLoc(regionWorldLocY);
+ // m_homeRegionX = (uint) (value >> 40);
+ // m_homeRegionY = (((uint) (value)) >> 8);
}
}
diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs
new file mode 100644
index 0000000..98ab651
--- /dev/null
+++ b/OpenSim/Framework/UserProfiles.cs
@@ -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 OpenMetaverse;
+
+namespace OpenSim.Framework
+{
+ public class UserClassifiedAdd
+ {
+ public UUID ClassifiedId = UUID.Zero;
+ public UUID CreatorId = UUID.Zero;
+ public int CreationDate = 0;
+ public int ExpirationDate = 0;
+ public int Category = 0;
+ public string Name = string.Empty;
+ public string Description = string.Empty;
+ public UUID ParcelId = UUID.Zero;
+ public int ParentEstate = 0;
+ public UUID SnapshotId = UUID.Zero;
+ public string SimName = string.Empty;
+ public string GlobalPos = "<0,0,0>";
+ public string ParcelName = string.Empty;
+ public byte Flags = 0;
+ public int Price = 0;
+ }
+
+ public class UserProfileProperties
+ {
+ public UUID UserId = UUID.Zero;
+ public UUID PartnerId = UUID.Zero;
+ public bool PublishProfile = false;
+ public bool PublishMature = false;
+ public string WebUrl = string.Empty;
+ public int WantToMask = 0;
+ public string WantToText = string.Empty;
+ public int SkillsMask = 0;
+ public string SkillsText = string.Empty;
+ public string Language = string.Empty;
+ public UUID ImageId = UUID.Zero;
+ public string AboutText = string.Empty;
+ public UUID FirstLifeImageId = UUID.Zero;
+ public string FirstLifeText = string.Empty;
+ }
+
+ public class UserProfilePick
+ {
+ public UUID PickId = UUID.Zero;
+ public UUID CreatorId = UUID.Zero;
+ public bool TopPick = false;
+ public string Name = string.Empty;
+ public string OriginalName = string.Empty;
+ public string Desc = string.Empty;
+ public UUID ParcelId = UUID.Zero;
+ public UUID SnapshotId = UUID.Zero;
+ public string ParcelName = string.Empty;
+ public string SimName = string.Empty;
+ public string GlobalPos = "<0,0,0>";
+ public string Gatekeeper = string.Empty;
+ public int SortOrder = 0;
+ public bool Enabled = false;
+ }
+
+ public class UserProfileNotes
+ {
+ public UUID UserId;
+ public UUID TargetId;
+ public string Notes;
+ }
+
+ public class UserPreferences
+ {
+ public UUID UserId;
+ public bool IMViaEmail = false;
+ public bool Visible = false;
+ public string EMail = string.Empty;
+ }
+
+ public class UserAccountProperties
+ {
+ public string EmailAddress = string.Empty;
+ public string Firstname = string.Empty;
+ public string LastName = string.Empty;
+ public string Password = string.Empty;
+ public string UserId = string.Empty;
+ }
+
+ public class UserAccountAuth
+ {
+ public string UserId = UUID.Zero.ToString();
+ public string Password = string.Empty;
+ }
+
+ public class UserAppData
+ {
+ public string TagId = string.Empty;
+ public string DataKey = string.Empty;
+ public string UserId = UUID.Zero.ToString();
+ public string DataVal = string.Empty;
+ }
+}
+
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 0bd2977..1f74168 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -45,14 +45,33 @@ using System.Text.RegularExpressions;
using System.Xml;
using System.Threading;
using log4net;
+using log4net.Appender;
using Nini.Config;
using Nwc.XmlRpc;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using Amib.Threading;
+using System.Collections.Concurrent;
+using System.Collections.Specialized;
+using System.Web;
namespace OpenSim.Framework
{
+ [Flags]
+ public enum PermissionMask : uint
+ {
+ None = 0,
+ Transfer = 1 << 13,
+ Modify = 1 << 14,
+ Copy = 1 << 15,
+ Export = 1 << 16,
+ Move = 1 << 19,
+ Damage = 1 << 20,
+ // All does not contain Export, which is special and must be
+ // explicitly given
+ All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19)
+ }
+
///
/// The method used by Util.FireAndForget for asynchronously firing events
///
@@ -73,14 +92,53 @@ namespace OpenSim.Framework
}
///
+ /// Class for delivering SmartThreadPool statistical information
+ ///
+ ///
+ /// We do it this way so that we do not directly expose STP.
+ ///
+ public class STPInfo
+ {
+ public string Name { get; set; }
+ public STPStartInfo STPStartInfo { get; set; }
+ public WIGStartInfo WIGStartInfo { get; set; }
+ public bool IsIdle { get; set; }
+ public bool IsShuttingDown { get; set; }
+ public int MaxThreads { get; set; }
+ public int MinThreads { get; set; }
+ public int InUseThreads { get; set; }
+ public int ActiveThreads { get; set; }
+ public int WaitingCallbacks { get; set; }
+ public int MaxConcurrentWorkItems { get; set; }
+ }
+
+ ///
/// Miscellaneous utility functions
///
- public class Util
+ public static class Util
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+ ///
+ /// Log-level for the thread pool:
+ /// 0 = no logging
+ /// 1 = only first line of stack trace; don't log common threads
+ /// 2 = full stack trace; don't log common threads
+ /// 3 = full stack trace, including common threads
+ ///
+ public static int LogThreadPool { get; set; }
+ public static bool LogOverloads { get; set; }
+
+ public static readonly int MAX_THREADPOOL_LEVEL = 3;
+
+ static Util()
+ {
+ LogThreadPool = 0;
+ LogOverloads = true;
+ }
+
private static uint nextXferID = 5000;
- private static Random randomClass = new Random();
+ private static Random randomClass = new ThreadSafeRandom();
// Get a list of invalid file characters (OS dependent)
private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
@@ -92,8 +150,11 @@ namespace OpenSim.Framework
///
private static SmartThreadPool m_ThreadPool;
+ // Watchdog timer that aborts threads that have timed-out
+ private static Timer m_threadPoolWatchdog;
+
// Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.
- private static readonly DateTime unixEpoch =
+ public static readonly DateTime UnixEpoch =
DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
private static readonly string rawUUIDPattern
@@ -104,6 +165,11 @@ namespace OpenSim.Framework
public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
+ public static bool IsPlatformMono
+ {
+ get { return Type.GetType("Mono.Runtime") != null; }
+ }
+
///
/// Gets the name of the directory where the current running executable
/// is located
@@ -291,6 +357,49 @@ namespace OpenSim.Framework
return Utils.UIntsToLong(X, Y);
}
+ // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong.
+ // Several places rely on the ability to extract a region's location from its handle.
+ // Note the location is in 'world coordinates' (see below).
+ // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0.
+ public static ulong RegionWorldLocToHandle(uint X, uint Y)
+ {
+ return Utils.UIntsToLong(X, Y);
+ }
+
+ public static ulong RegionLocToHandle(uint X, uint Y)
+ {
+ return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y));
+ }
+
+ public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y)
+ {
+ X = (uint)(handle >> 32);
+ Y = (uint)(handle & (ulong)uint.MaxValue);
+ }
+
+ public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y)
+ {
+ uint worldX, worldY;
+ RegionHandleToWorldLoc(handle, out worldX, out worldY);
+ X = WorldToRegionLoc(worldX);
+ Y = WorldToRegionLoc(worldY);
+ }
+
+ // A region location can be 'world coordinates' (meters from zero) or 'region coordinates'
+ // (number of regions from zero). This measurement of regions relies on the legacy 256 region size.
+ // These routines exist to make what is being converted explicit so the next person knows what was meant.
+ // Convert a region's 'world coordinate' to its 'region coordinate'.
+ public static uint WorldToRegionLoc(uint worldCoord)
+ {
+ return worldCoord / Constants.RegionSize;
+ }
+
+ // Convert a region's 'region coordinate' to its 'world coordinate'.
+ public static uint RegionToWorldLoc(uint regionCoord)
+ {
+ return regionCoord * Constants.RegionSize;
+ }
+
public static T Clamp(T x, T min, T max)
where T : IComparable
{
@@ -302,15 +411,31 @@ namespace OpenSim.Framework
// Clamp the maximum magnitude of a vector
public static Vector3 ClampV(Vector3 x, float max)
{
- Vector3 ret = x;
float lenSq = x.LengthSquared();
if (lenSq > (max * max))
{
x = x / x.Length() * max;
}
+
return x;
}
+ ///
+ /// Check if any of the values in a Vector3 are NaN or Infinity
+ ///
+ /// Vector3 to check
+ ///
+ public static bool IsNanOrInfinity(Vector3 v)
+ {
+ if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z))
+ return true;
+
+ if (float.IsInfinity(v.X) || float.IsInfinity(v.Y) || float.IsNaN(v.Z))
+ return true;
+
+ return false;
+ }
+
// Inclusive, within range test (true if equal to the endpoints)
public static bool InRange(T x, T min, T max)
where T : IComparable
@@ -400,6 +525,19 @@ namespace OpenSim.Framework
return sb.ToString();
}
+ public static byte[] DocToBytes(XmlDocument doc)
+ {
+ using (MemoryStream ms = new MemoryStream())
+ using (XmlTextWriter xw = new XmlTextWriter(ms, null))
+ {
+ xw.Formatting = Formatting.Indented;
+ doc.WriteTo(xw);
+ xw.Flush();
+
+ return ms.ToArray();
+ }
+ }
+
///
/// Is the platform Windows?
///
@@ -416,6 +554,11 @@ namespace OpenSim.Framework
public static bool LoadArchSpecificWindowsDll(string libraryName)
{
+ return LoadArchSpecificWindowsDll(libraryName, string.Empty);
+ }
+
+ public static bool LoadArchSpecificWindowsDll(string libraryName, string path)
+ {
// We do this so that OpenSimulator on Windows loads the correct native library depending on whether
// it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
// will find it already loaded later on.
@@ -425,9 +568,9 @@ namespace OpenSim.Framework
string nativeLibraryPath;
if (Util.Is64BitProcess())
- nativeLibraryPath = "lib64/" + libraryName;
+ nativeLibraryPath = Path.Combine(Path.Combine(path, "lib64"), libraryName);
else
- nativeLibraryPath = "lib32/" + libraryName;
+ nativeLibraryPath = Path.Combine(Path.Combine(path, "lib32"), libraryName);
m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath);
@@ -479,20 +622,18 @@ namespace OpenSim.Framework
public static int ToUnixTime(DateTime stamp)
{
- TimeSpan t = stamp.ToUniversalTime() - unixEpoch;
- return (int) t.TotalSeconds;
+ TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
+ return (int)t.TotalSeconds;
}
public static DateTime ToDateTime(ulong seconds)
{
- DateTime epoch = unixEpoch;
- return epoch.AddSeconds(seconds);
+ return UnixEpoch.AddSeconds(seconds);
}
public static DateTime ToDateTime(int seconds)
{
- DateTime epoch = unixEpoch;
- return epoch.AddSeconds(seconds);
+ return UnixEpoch.AddSeconds(seconds);
}
///
@@ -664,16 +805,6 @@ namespace OpenSim.Framework
}
///
- /// Converts a URL to a IPAddress
- ///
- /// URL Standard Format
- /// A resolved IP Address
- public static IPAddress GetHostFromURL(string url)
- {
- return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]);
- }
-
- ///
/// Returns a IP address from a specified DNS, favouring IPv4 addresses.
///
/// DNS Hostname
@@ -763,6 +894,54 @@ namespace OpenSim.Framework
}
///
+ /// Parses a foreign asset ID.
+ ///
+ /// A possibly-foreign asset ID: http://grid.example.com:8002/00000000-0000-0000-0000-000000000000
+ /// The URL: http://grid.example.com:8002
+ /// The asset ID: 00000000-0000-0000-0000-000000000000. Returned even if 'id' isn't foreign.
+ /// True: this is a foreign asset ID; False: it isn't
+ public static bool ParseForeignAssetID(string id, out string url, out string assetID)
+ {
+ url = String.Empty;
+ assetID = String.Empty;
+
+ UUID uuid;
+ if (UUID.TryParse(id, out uuid))
+ {
+ assetID = uuid.ToString();
+ return false;
+ }
+
+ if ((id.Length == 0) || (id[0] != 'h' && id[0] != 'H'))
+ return false;
+
+ Uri assetUri;
+ if (!Uri.TryCreate(id, UriKind.Absolute, out assetUri) || assetUri.Scheme != Uri.UriSchemeHttp)
+ return false;
+
+ // Simian
+ if (assetUri.Query != string.Empty)
+ {
+ NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query);
+ assetID = qscoll["id"];
+ if (assetID != null)
+ url = id.Replace(assetID, ""); // Malformed again, as simian expects
+ else
+ url = id; // !!! best effort
+ }
+ else // robust
+ {
+ url = "http://" + assetUri.Authority;
+ assetID = assetUri.LocalPath.Trim(new char[] { '/' });
+ }
+
+ if (!UUID.TryParse(assetID, out uuid))
+ return false;
+
+ return true;
+ }
+
+ ///
/// Removes all invalid path chars (OS dependent)
///
/// path
@@ -816,9 +995,22 @@ namespace OpenSim.Framework
return ".";
}
+ public static string logFile()
+ {
+ foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
+ {
+ if (appender is FileAppender)
+ {
+ return ((FileAppender)appender).File;
+ }
+ }
+
+ return "./OpenSim.log";
+ }
+
public static string logDir()
{
- return ".";
+ return Path.GetDirectoryName(logFile());
}
// From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
@@ -849,12 +1041,13 @@ namespace OpenSim.Framework
return FileName;
}
- // Nini (config) related Methods
+ #region Nini (config) related Methods
+
public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName)
{
if (!File.Exists(fileName))
{
- //create new file
+ // create new file
}
XmlConfigSource config = new XmlConfigSource(fileName);
AddDataRowToConfig(config, row);
@@ -872,6 +1065,202 @@ namespace OpenSim.Framework
}
}
+ ///
+ /// Gets the value of a configuration variable by looking into
+ /// multiple sections in order. The latter sections overwrite
+ /// any values previously found.
+ ///
+ /// Type of the variable
+ /// The configuration object
+ /// The configuration variable
+ /// Ordered sequence of sections to look at
+ ///
+ public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections)
+ {
+ return GetConfigVarFromSections(config, varname, sections, default(T));
+ }
+
+ ///
+ /// Gets the value of a configuration variable by looking into
+ /// multiple sections in order. The latter sections overwrite
+ /// any values previously found.
+ ///
+ ///
+ /// If no value is found then the given default value is returned
+ ///
+ /// Type of the variable
+ /// The configuration object
+ /// The configuration variable
+ /// Ordered sequence of sections to look at
+ /// Default value
+ ///
+ public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections, object val)
+ {
+ foreach (string section in sections)
+ {
+ IConfig cnf = config.Configs[section];
+ if (cnf == null)
+ continue;
+
+ if (typeof(T) == typeof(String))
+ val = cnf.GetString(varname, (string)val);
+ else if (typeof(T) == typeof(Boolean))
+ val = cnf.GetBoolean(varname, (bool)val);
+ else if (typeof(T) == typeof(Int32))
+ val = cnf.GetInt(varname, (int)val);
+ else if (typeof(T) == typeof(float))
+ val = cnf.GetFloat(varname, (float)val);
+ else
+ m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T));
+ }
+
+ return (T)val;
+ }
+
+ public static void MergeEnvironmentToConfig(IConfigSource ConfigSource)
+ {
+ IConfig enVars = ConfigSource.Configs["Environment"];
+ // if section does not exist then user isn't expecting them, so don't bother.
+ if( enVars != null )
+ {
+ // load the values from the environment
+ EnvConfigSource envConfigSource = new EnvConfigSource();
+ // add the requested keys
+ string[] env_keys = enVars.GetKeys();
+ foreach ( string key in env_keys )
+ {
+ envConfigSource.AddEnv(key, string.Empty);
+ }
+ // load the values from environment
+ envConfigSource.LoadEnv();
+ // add them in to the master
+ ConfigSource.Merge(envConfigSource);
+ ConfigSource.ExpandKeyValues();
+ }
+ }
+
+ public static T ReadSettingsFromIniFile(IConfig config, T settingsClass)
+ {
+ Type settingsType = settingsClass.GetType();
+
+ FieldInfo[] fieldInfos = settingsType.GetFields();
+ foreach (FieldInfo fieldInfo in fieldInfos)
+ {
+ if (!fieldInfo.IsStatic)
+ {
+ if (fieldInfo.FieldType == typeof(System.String))
+ {
+ fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
+ }
+ else if (fieldInfo.FieldType == typeof(System.Boolean))
+ {
+ fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
+ }
+ else if (fieldInfo.FieldType == typeof(System.Int32))
+ {
+ fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
+ }
+ else if (fieldInfo.FieldType == typeof(System.Single))
+ {
+ fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
+ }
+ else if (fieldInfo.FieldType == typeof(System.UInt32))
+ {
+ fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
+ }
+ }
+ }
+
+ PropertyInfo[] propertyInfos = settingsType.GetProperties();
+ foreach (PropertyInfo propInfo in propertyInfos)
+ {
+ if ((propInfo.CanRead) && (propInfo.CanWrite))
+ {
+ if (propInfo.PropertyType == typeof(System.String))
+ {
+ propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
+ }
+ else if (propInfo.PropertyType == typeof(System.Boolean))
+ {
+ propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
+ }
+ else if (propInfo.PropertyType == typeof(System.Int32))
+ {
+ propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
+ }
+ else if (propInfo.PropertyType == typeof(System.Single))
+ {
+ propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
+ }
+ if (propInfo.PropertyType == typeof(System.UInt32))
+ {
+ propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
+ }
+ }
+ }
+
+ return settingsClass;
+ }
+
+ ///
+ /// Reads a configuration file, configFile, merging it with the main configuration, config.
+ /// If the file doesn't exist, it copies a given exampleConfigFile onto configFile, and then
+ /// merges it.
+ ///
+ /// The main configuration data
+ /// The name of a configuration file in ConfigDirectory variable, no path
+ /// Full path to an example configuration file
+ /// Full path ConfigDirectory/configFileName
+ /// True if the file was created in ConfigDirectory, false if it existed
+ /// True if success
+ public static bool MergeConfigurationFile(IConfigSource config, string configFileName, string exampleConfigFile, out string configFilePath, out bool created)
+ {
+ created = false;
+ configFilePath = string.Empty;
+
+ IConfig cnf = config.Configs["Startup"];
+ if (cnf == null)
+ {
+ m_log.WarnFormat("[UTILS]: Startup section doesn't exist");
+ return false;
+ }
+
+ string configDirectory = cnf.GetString("ConfigDirectory", ".");
+ string configFile = Path.Combine(configDirectory, configFileName);
+
+ if (!File.Exists(configFile) && !string.IsNullOrEmpty(exampleConfigFile))
+ {
+ // We need to copy the example onto it
+
+ if (!Directory.Exists(configDirectory))
+ Directory.CreateDirectory(configDirectory);
+
+ try
+ {
+ File.Copy(exampleConfigFile, configFile);
+ created = true;
+ }
+ catch (Exception e)
+ {
+ m_log.WarnFormat("[UTILS]: Exception copying configuration file {0} to {1}: {2}", configFile, exampleConfigFile, e.Message);
+ return false;
+ }
+ }
+
+ if (File.Exists(configFile))
+ {
+ // Merge
+ config.Merge(new IniConfigSource(configFile));
+ config.ExpandKeyValues();
+ configFilePath = configFile;
+ return true;
+ }
+ else
+ return false;
+ }
+
+ #endregion
+
public static float Clip(float x, float min, float max)
{
return Math.Min(Math.Max(x, min), max);
@@ -999,46 +1388,6 @@ namespace OpenSim.Framework
return ret;
}
- public static string Compress(string text)
- {
- byte[] buffer = Util.UTF8.GetBytes(text);
- MemoryStream memory = new MemoryStream();
- using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true))
- {
- compressor.Write(buffer, 0, buffer.Length);
- }
-
- memory.Position = 0;
-
- byte[] compressed = new byte[memory.Length];
- memory.Read(compressed, 0, compressed.Length);
-
- byte[] compressedBuffer = new byte[compressed.Length + 4];
- Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length);
- Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4);
- return Convert.ToBase64String(compressedBuffer);
- }
-
- public static string Decompress(string compressedText)
- {
- byte[] compressedBuffer = Convert.FromBase64String(compressedText);
- using (MemoryStream memory = new MemoryStream())
- {
- int msgLength = BitConverter.ToInt32(compressedBuffer, 0);
- memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4);
-
- byte[] buffer = new byte[msgLength];
-
- memory.Position = 0;
- using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress))
- {
- decompressor.Read(buffer, 0, buffer.Length);
- }
-
- return Util.UTF8.GetString(buffer);
- }
- }
-
///
/// Copy data from one stream to another, leaving the read position of both streams at the beginning.
///
@@ -1119,7 +1468,7 @@ namespace OpenSim.Framework
byte[] bytes =
{
(byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
- (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56),
+ (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
(byte)x, (byte)(x >> 8), 0, 0,
(byte)y, (byte)(y >> 8), 0, 0 };
return new UUID(bytes, 0);
@@ -1130,7 +1479,7 @@ namespace OpenSim.Framework
byte[] bytes =
{
(byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
- (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56),
+ (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
(byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
(byte)y, (byte)(y >> 8), 0, 0 };
return new UUID(bytes, 0);
@@ -1203,7 +1552,7 @@ namespace OpenSim.Framework
ru = "OSX/Mono";
else
{
- if (Type.GetType("Mono.Runtime") != null)
+ if (IsPlatformMono)
ru = "Win/Mono";
else
ru = "Win/.NET";
@@ -1242,79 +1591,56 @@ namespace OpenSim.Framework
return displayConnectionString;
}
- public static T ReadSettingsFromIniFile(IConfig config, T settingsClass)
+ public static string Base64ToString(string str)
{
- Type settingsType = settingsClass.GetType();
+ Decoder utf8Decode = Encoding.UTF8.GetDecoder();
- FieldInfo[] fieldInfos = settingsType.GetFields();
- foreach (FieldInfo fieldInfo in fieldInfos)
+ byte[] todecode_byte = Convert.FromBase64String(str);
+ int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
+ char[] decoded_char = new char[charCount];
+ utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
+ string result = new String(decoded_char);
+ return result;
+ }
+
+ public static void BinaryToASCII(char[] chars)
+ {
+ for (int i = 0; i < chars.Length; i++)
{
- if (!fieldInfo.IsStatic)
- {
- if (fieldInfo.FieldType == typeof(System.String))
- {
- fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
- }
- else if (fieldInfo.FieldType == typeof(System.Boolean))
- {
- fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
- }
- else if (fieldInfo.FieldType == typeof(System.Int32))
- {
- fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
- }
- else if (fieldInfo.FieldType == typeof(System.Single))
- {
- fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
- }
- else if (fieldInfo.FieldType == typeof(System.UInt32))
- {
- fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
- }
- }
- }
-
- PropertyInfo[] propertyInfos = settingsType.GetProperties();
- foreach (PropertyInfo propInfo in propertyInfos)
- {
- if ((propInfo.CanRead) && (propInfo.CanWrite))
- {
- if (propInfo.PropertyType == typeof(System.String))
- {
- propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
- }
- else if (propInfo.PropertyType == typeof(System.Boolean))
- {
- propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
- }
- else if (propInfo.PropertyType == typeof(System.Int32))
- {
- propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
- }
- else if (propInfo.PropertyType == typeof(System.Single))
- {
- propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
- }
- if (propInfo.PropertyType == typeof(System.UInt32))
- {
- propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
- }
- }
+ char ch = chars[i];
+ if (ch < 32 || ch > 127)
+ chars[i] = '.';
}
+ }
- return settingsClass;
+ public static string BinaryToASCII(string src)
+ {
+ char[] chars = src.ToCharArray();
+ BinaryToASCII(chars);
+ return new String(chars);
}
- public static string Base64ToString(string str)
+ ///
+ /// Reads a known number of bytes from a stream.
+ /// Throws EndOfStreamException if the stream doesn't contain enough data.
+ ///
+ /// The stream to read data from
+ /// The array to write bytes into. The array
+ /// will be completely filled from the stream, so an appropriate
+ /// size must be given.
+ public static void ReadStream(Stream stream, byte[] data)
{
- Decoder utf8Decode = Encoding.UTF8.GetDecoder();
+ int offset = 0;
+ int remaining = data.Length;
- byte[] todecode_byte = Convert.FromBase64String(str);
- int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
- char[] decoded_char = new char[charCount];
- utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
- string result = new String(decoded_char);
- return result;
+ while (remaining > 0)
+ {
+ int read = stream.Read(data, offset, remaining);
+ if (read <= 0)
+ throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining));
+ remaining -= read;
+ offset += read;
+ }
}
public static Guid GetHashGuid(string data, string salt)
@@ -1466,32 +1792,6 @@ namespace OpenSim.Framework
return found.ToArray();
}
- public static string ServerURI(string uri)
- {
- if (uri == string.Empty)
- return string.Empty;
-
- // Get rid of eventual slashes at the end
- uri = uri.TrimEnd('/');
-
- IPAddress ipaddr1 = null;
- string port1 = "";
- try
- {
- ipaddr1 = Util.GetHostFromURL(uri);
- }
- catch { }
-
- try
- {
- port1 = uri.Split(new char[] { ':' })[2];
- }
- catch { }
-
- // We tried our best to convert the domain names to IP addresses
- return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
- }
-
///
/// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
///
@@ -1518,17 +1818,26 @@ namespace OpenSim.Framework
///
public static byte[] StringToBytes256(string str)
{
- if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
- if (str.Length > 254) str = str.Remove(254);
- if (!str.EndsWith("\0")) { str += "\0"; }
+ if (String.IsNullOrEmpty(str))
+ return Utils.EmptyBytes;
+
+ if (!str.EndsWith("\0"))
+ str += "\0";
// Because this is UTF-8 encoding and not ASCII, it's possible we
// might have gotten an oversized array even after the string trim
byte[] data = UTF8.GetBytes(str);
+
if (data.Length > 256)
{
- Array.Resize(ref data, 256);
- data[255] = 0;
+ int cut = 255;
+ if((data[cut] & 0x80 ) != 0 )
+ {
+ while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
+ cut--;
+ }
+ Array.Resize(ref data, cut + 1);
+ data[cut] = 0;
}
return data;
@@ -1560,23 +1869,56 @@ namespace OpenSim.Framework
///
public static byte[] StringToBytes1024(string str)
{
- if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
- if (str.Length > 1023) str = str.Remove(1023);
- if (!str.EndsWith("\0")) { str += "\0"; }
+ if (String.IsNullOrEmpty(str))
+ return Utils.EmptyBytes;
+
+ if (!str.EndsWith("\0"))
+ str += "\0";
// Because this is UTF-8 encoding and not ASCII, it's possible we
// might have gotten an oversized array even after the string trim
byte[] data = UTF8.GetBytes(str);
+
if (data.Length > 1024)
{
- Array.Resize(ref data, 1024);
- data[1023] = 0;
+ int cut = 1023;
+ if((data[cut] & 0x80 ) != 0 )
+ {
+ while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
+ cut--;
+ }
+ Array.Resize(ref data, cut + 1);
+ data[cut] = 0;
}
return data;
}
///
+ /// Pretty format the hashtable contents to a single line.
+ ///
+ ///
+ /// Used for debugging output.
+ ///
+ ///
+ public static string PrettyFormatToSingleLine(Hashtable ht)
+ {
+ StringBuilder sb = new StringBuilder();
+
+ int i = 0;
+
+ foreach (string key in ht.Keys)
+ {
+ sb.AppendFormat("{0}:{1}", key, ht[key]);
+
+ if (++i < ht.Count)
+ sb.AppendFormat(", ");
+ }
+
+ return sb.ToString();
+ }
+
+ ///
/// Used to trigger an early library load on Windows systems.
///
///
@@ -1646,25 +1988,28 @@ namespace OpenSim.Framework
}
}
- public static void FireAndForget(System.Threading.WaitCallback callback)
- {
- FireAndForget(callback, null);
- }
-
- public static void InitThreadPool(int maxThreads)
+ public static void InitThreadPool(int minThreads, int maxThreads)
{
if (maxThreads < 2)
throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
+
+ if (minThreads > maxThreads || minThreads < 2)
+ throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads");
+
if (m_ThreadPool != null)
- throw new InvalidOperationException("SmartThreadPool is already initialized");
+ {
+ m_log.Warn("SmartThreadPool is already initialized. Ignoring request.");
+ return;
+ }
STPStartInfo startInfo = new STPStartInfo();
startInfo.ThreadPoolName = "Util";
startInfo.IdleTimeout = 2000;
startInfo.MaxWorkerThreads = maxThreads;
- startInfo.MinWorkerThreads = 2;
+ startInfo.MinWorkerThreads = minThreads;
m_ThreadPool = new SmartThreadPool(startInfo);
+ m_threadPoolWatchdog = new Timer(ThreadPoolWatchdog, null, 0, 1000);
}
public static int FireAndForgetCount()
@@ -1687,15 +2032,179 @@ namespace OpenSim.Framework
throw new NotImplementedException();
}
}
+
+ ///
+ /// Additional information about threads in the main thread pool. Used to time how long the
+ /// thread has been running, and abort it if it has timed-out.
+ ///
+ private class ThreadInfo
+ {
+ public long ThreadFuncNum { get; set; }
+ public string StackTrace { get; set; }
+ private string context;
+ public bool LogThread { get; set; }
+
+ public IWorkItemResult WorkItem { get; set; }
+ public Thread Thread { get; set; }
+ public bool Running { get; set; }
+ public bool Aborted { get; set; }
+ private int started;
+
+ public ThreadInfo(long threadFuncNum, string context)
+ {
+ ThreadFuncNum = threadFuncNum;
+ this.context = context;
+ LogThread = false;
+ Thread = null;
+ Running = false;
+ Aborted = false;
+ }
+
+ public void Started()
+ {
+ Thread = Thread.CurrentThread;
+ started = EnvironmentTickCount();
+ Running = true;
+ }
+
+ public void Ended()
+ {
+ Running = false;
+ }
+
+ public int Elapsed()
+ {
+ return EnvironmentTickCountSubtract(started);
+ }
+
+ public void Abort()
+ {
+ Aborted = true;
+ WorkItem.Cancel(true);
+ }
+
+ ///
+ /// Returns the thread's stack trace.
+ ///
+ ///
+ /// May return one of two stack traces. First, tries to get the thread's active stack
+ /// trace. But this can fail, so as a fallback this method will return the stack
+ /// trace that was active when the task was queued.
+ ///
+ public string GetStackTrace()
+ {
+ string ret = (context == null) ? "" : ("(" + context + ") ");
+
+ StackTrace activeStackTrace = Util.GetStackTrace(Thread);
+ if (activeStackTrace != null)
+ ret += activeStackTrace.ToString();
+ else if (StackTrace != null)
+ ret += "(Stack trace when queued) " + StackTrace;
+ // else, no stack trace available
+
+ return ret;
+ }
+ }
+
+ private static long nextThreadFuncNum = 0;
+ private static long numQueuedThreadFuncs = 0;
+ private static long numRunningThreadFuncs = 0;
+ private static long numTotalThreadFuncsCalled = 0;
+ private static Int32 threadFuncOverloadMode = 0;
+
+ public static long TotalQueuedFireAndForgetCalls { get { return numQueuedThreadFuncs; } }
+ public static long TotalRunningFireAndForgetCalls { get { return numRunningThreadFuncs; } }
+
+ // Maps (ThreadFunc number -> Thread)
+ private static ConcurrentDictionary activeThreads = new ConcurrentDictionary();
+
+ private static readonly int THREAD_TIMEOUT = 10 * 60 * 1000; // 10 minutes
+
+ ///
+ /// Finds threads in the main thread pool that have timed-out, and aborts them.
+ ///
+ private static void ThreadPoolWatchdog(object state)
+ {
+ foreach (KeyValuePair entry in activeThreads)
+ {
+ ThreadInfo t = entry.Value;
+ if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT))
+ {
+ m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace());
+ t.Abort();
+
+ ThreadInfo dummy;
+ activeThreads.TryRemove(entry.Key, out dummy);
+
+ // It's possible that the thread won't abort. To make sure the thread pool isn't
+ // depleted, increase the pool size.
+ m_ThreadPool.MaxThreads++;
+ }
+ }
+ }
+
+ public static long TotalFireAndForgetCallsMade { get { return numTotalThreadFuncsCalled; } }
+
+ public static Dictionary GetFireAndForgetCallsMade()
+ {
+ return new Dictionary(m_fireAndForgetCallsMade);
+ }
+
+ private static Dictionary m_fireAndForgetCallsMade = new Dictionary();
+
+ public static Dictionary