aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework
diff options
context:
space:
mode:
authorDavid Walter Seikel2016-11-03 21:44:39 +1000
committerDavid Walter Seikel2016-11-03 21:44:39 +1000
commit134f86e8d5c414409631b25b8c6f0ee45fbd8631 (patch)
tree216b89d3fb89acfb81be1e440c25c41ab09fa96d /OpenSim/Framework
parentMore changing to production grid. Double oops. (diff)
downloadopensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.zip
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.gz
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.bz2
opensim-SC_OLD-134f86e8d5c414409631b25b8c6f0ee45fbd8631.tar.xz
Initial update to OpenSim 0.8.2.1 source code.
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r--OpenSim/Framework/AgentCircuitData.cs28
-rw-r--r--OpenSim/Framework/Animation.cs24
-rw-r--r--OpenSim/Framework/AssemblyInfo.cs3
-rw-r--r--OpenSim/Framework/AssetBase.cs13
-rw-r--r--OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/AvatarAppearance.cs335
-rw-r--r--OpenSim/Framework/AvatarWearable.cs4
-rw-r--r--OpenSim/Framework/BasicDOSProtector.cs275
-rw-r--r--OpenSim/Framework/BlockingQueue.cs32
-rw-r--r--OpenSim/Framework/CachedTextureEventArg.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppError.cs)21
-rw-r--r--OpenSim/Framework/ChildAgentDataUpdate.cs60
-rw-r--r--OpenSim/Framework/CircularBuffer.cs312
-rw-r--r--OpenSim/Framework/ClientInfo.cs16
-rw-r--r--OpenSim/Framework/Communications/GenericAsyncResult.cs185
-rw-r--r--OpenSim/Framework/Communications/IUserService.cs157
-rw-r--r--OpenSim/Framework/Communications/Limit/IRequestLimitStrategy.cs66
-rw-r--r--OpenSim/Framework/Communications/Limit/RepeatLimitStrategy.cs109
-rw-r--r--OpenSim/Framework/Communications/Limit/TimeLimitStrategy.cs140
-rw-r--r--OpenSim/Framework/Communications/Properties/AssemblyInfo.cs65
-rw-r--r--OpenSim/Framework/Communications/XMPP/XmppSerializer.cs79
-rw-r--r--OpenSim/Framework/ConfigSettings.cs1
-rw-r--r--OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs119
-rw-r--r--OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Framework/Configuration/XML/XmlConfiguration.cs141
-rw-r--r--OpenSim/Framework/ConfigurationMember.cs530
-rw-r--r--OpenSim/Framework/Console/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Console/CommandConsole.cs46
-rw-r--r--OpenSim/Framework/Console/ConsoleDisplayUtil.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppWriter.cs)39
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs175
-rw-r--r--OpenSim/Framework/Console/LocalConsole.cs85
-rw-r--r--OpenSim/Framework/Console/MockConsole.cs3
-rw-r--r--OpenSim/Framework/Console/RemoteConsole.cs4
-rw-r--r--OpenSim/Framework/Constants.cs11
-rw-r--r--OpenSim/Framework/DAMap.cs328
-rw-r--r--OpenSim/Framework/DOMap.cs (renamed from OpenSim/Framework/ForeignUserProfileData.cs)85
-rw-r--r--OpenSim/Framework/EstateBan.cs49
-rw-r--r--OpenSim/Framework/EstateSettings.cs147
-rw-r--r--OpenSim/Framework/ExtraPhysicsData.cs (renamed from OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs)28
-rw-r--r--OpenSim/Framework/GridInstantMessage.cs18
-rw-r--r--OpenSim/Framework/IClientAPI.cs29
-rw-r--r--OpenSim/Framework/ICommandConsole.cs11
-rw-r--r--OpenSim/Framework/IImprovedAssetCache.cs27
-rw-r--r--OpenSim/Framework/ILandChannel.cs7
-rw-r--r--OpenSim/Framework/ILandObject.cs2
-rw-r--r--OpenSim/Framework/IMoneyModule.cs3
-rw-r--r--OpenSim/Framework/IPeople.cs49
-rw-r--r--OpenSim/Framework/IScene.cs21
-rw-r--r--OpenSim/Framework/ISceneAgent.cs7
-rw-r--r--OpenSim/Framework/ISceneObject.cs2
-rw-r--r--OpenSim/Framework/InventoryCollection.cs4
-rw-r--r--OpenSim/Framework/InventoryFolderBase.cs3
-rw-r--r--OpenSim/Framework/InventoryItemBase.cs9
-rw-r--r--OpenSim/Framework/Location.cs16
-rwxr-xr-xOpenSim/Framework/LogWriter.cs181
-rw-r--r--OpenSim/Framework/MapBlockData.cs18
-rw-r--r--OpenSim/Framework/MapItemReplyStruct.cs33
-rw-r--r--OpenSim/Framework/MetricsCollector.cs223
-rw-r--r--OpenSim/Framework/Monitoring/AssetStatsCollector.cs26
-rw-r--r--OpenSim/Framework/Monitoring/BaseStatsCollector.cs19
-rw-r--r--OpenSim/Framework/Monitoring/Checks/Check.cs118
-rw-r--r--OpenSim/Framework/Monitoring/ChecksManager.cs262
-rw-r--r--OpenSim/Framework/Monitoring/Interfaces/IStatsCollector.cs9
-rw-r--r--OpenSim/Framework/Monitoring/JobEngine.cs341
-rw-r--r--OpenSim/Framework/Monitoring/MemoryWatchdog.cs8
-rw-r--r--OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Monitoring/ServerStatsCollector.cs346
-rwxr-xr-x[-rw-r--r--]OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs106
-rwxr-xr-xOpenSim/Framework/Monitoring/Stats/CounterStat.cs119
-rwxr-xr-xOpenSim/Framework/Monitoring/Stats/EventHistogram.cs173
-rw-r--r--OpenSim/Framework/Monitoring/Stats/PercentageStat.cs16
-rw-r--r--OpenSim/Framework/Monitoring/Stats/Stat.cs102
-rw-r--r--OpenSim/Framework/Monitoring/StatsLogger.cs151
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs403
-rw-r--r--OpenSim/Framework/Monitoring/UserStatsCollector.cs18
-rw-r--r--OpenSim/Framework/Monitoring/Watchdog.cs106
-rw-r--r--OpenSim/Framework/Monitoring/WorkManager.cs290
-rw-r--r--OpenSim/Framework/OutboundUrlFilter.cs256
-rw-r--r--OpenSim/Framework/PermissionsUtil.cs87
-rw-r--r--OpenSim/Framework/PluginLoader.cs17
-rw-r--r--OpenSim/Framework/PluginManager.cs4
-rw-r--r--OpenSim/Framework/PrimitiveBaseShape.cs22
-rw-r--r--OpenSim/Framework/RegionFlags.cs3
-rw-r--r--OpenSim/Framework/RegionInfo.cs463
-rw-r--r--OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs116
-rw-r--r--OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs33
-rw-r--r--OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs130
-rw-r--r--OpenSim/Framework/RegionSettings.cs23
-rw-r--r--OpenSim/Framework/RestClient.cs (renamed from OpenSim/Framework/Communications/RestClient.cs)314
-rw-r--r--OpenSim/Framework/SLUtil.cs430
-rw-r--r--OpenSim/Framework/Serialization/ArchiveConstants.cs11
-rw-r--r--OpenSim/Framework/Serialization/External/ExternalRepresentationUtils.cs267
-rw-r--r--OpenSim/Framework/Serialization/External/LandDataSerializer.cs28
-rw-r--r--OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs49
-rw-r--r--OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Serialization/Tests/LandDataSerializerTests.cs3
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs82
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs383
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppStanza.cs)52
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs23
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs49
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs107
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs119
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IHttpServer.cs14
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs15
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs (renamed from OpenSim/Framework/IRegionLoader.cs)13
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRpcRequestManager.cs190
-rw-r--r--OpenSim/Framework/Servers/HttpServer/JsonRpcResponse.cs150
-rw-r--r--OpenSim/Framework/Servers/HttpServer/OSHttpRequest.cs13
-rw-r--r--OpenSim/Framework/Servers/HttpServer/OSHttpRequestPump.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/OSHttpServer.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs31
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs45
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs318
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceWorkerThread.cs165
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestObjectPoster.cs28
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestObjectPosterResponse.cs29
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestSessionService.cs89
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs1159
-rw-r--r--OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs91
-rw-r--r--OpenSim/Framework/Servers/MainServer.cs24
-rw-r--r--OpenSim/Framework/Servers/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Servers/ServerBase.cs381
-rw-r--r--OpenSim/Framework/Servers/Tests/OSHttpTests.cs315
-rw-r--r--OpenSim/Framework/Servers/Tests/VersionInfoTests.cs2
-rw-r--r--OpenSim/Framework/ServiceAuth/BasicHttpAuthentication.cs113
-rw-r--r--OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs)79
-rw-r--r--OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs)49
-rw-r--r--OpenSim/Framework/ServiceAuth/IServiceAuth.cs48
-rw-r--r--OpenSim/Framework/ServiceAuth/ServiceAuth.cs (renamed from OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs)55
-rw-r--r--OpenSim/Framework/TaskInventoryItem.cs2
-rw-r--r--OpenSim/Framework/TerrainData.cs464
-rw-r--r--OpenSim/Framework/Tests/AnimationTests.cs1
-rw-r--r--OpenSim/Framework/Tests/AssetBaseTest.cs4
-rw-r--r--OpenSim/Framework/Tests/LocationTest.cs21
-rw-r--r--OpenSim/Framework/Tests/MundaneFrameworkTests.cs2
-rw-r--r--OpenSim/Framework/Tests/UtilTest.cs101
-rw-r--r--OpenSim/Framework/ThreadSafeRandom.cs (renamed from OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs)57
-rw-r--r--OpenSim/Framework/ThrottleOutPacketType.cs4
-rw-r--r--OpenSim/Framework/UntrustedWebRequest.cs230
-rw-r--r--OpenSim/Framework/UserProfileData.cs14
-rw-r--r--OpenSim/Framework/UserProfiles.cs126
-rw-r--r--OpenSim/Framework/Util.cs1510
-rw-r--r--OpenSim/Framework/VersionInfo.cs (renamed from OpenSim/Framework/Servers/VersionInfo.cs)41
-rw-r--r--OpenSim/Framework/WearableCacheItem.cs157
-rw-r--r--OpenSim/Framework/WebUtil.cs928
151 files changed, 12566 insertions, 4707 deletions
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
128 /// <summary> 128 /// <summary>
129 /// Viewer's version string as reported by the viewer at login 129 /// Viewer's version string as reported by the viewer at login
130 /// </summary> 130 /// </summary>
131 public string Viewer; 131 private string m_viewerInternal;
132
133 /// <summary>
134 /// Viewer's version string
135 /// </summary>
136 public string Viewer
137 {
138 set { m_viewerInternal = value; }
139
140 // Try to return consistent viewer string taking into account
141 // that viewers have chaagned how version is reported
142 // See http://opensimulator.org/mantis/view.php?id=6851
143 get
144 {
145 // Old style version string contains viewer name followed by a space followed by a version number
146 if (m_viewerInternal == null || m_viewerInternal.Contains(" "))
147 {
148 return m_viewerInternal;
149 }
150 else // New style version contains no spaces, just version number
151 {
152 return Channel + " " + m_viewerInternal;
153 }
154 }
155 }
132 156
133 /// <summary> 157 /// <summary>
134 /// The channel strinf sent by the viewer at login 158 /// The channel strinf sent by the viewer at login
@@ -297,6 +321,8 @@ namespace OpenSim.Framework
297 Mac = args["mac"].AsString(); 321 Mac = args["mac"].AsString();
298 if (args["id0"] != null) 322 if (args["id0"] != null)
299 Id0 = args["id0"].AsString(); 323 Id0 = args["id0"].AsString();
324 if (args["teleport_flags"] != null)
325 teleportFlags = args["teleport_flags"].AsUInteger();
300 326
301 if (args["start_pos"] != null) 327 if (args["start_pos"] != null)
302 Vector3.TryParse(args["start_pos"].AsString(), out startpos); 328 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
120 sequenceNum = args["seq_num"].AsInteger(); 120 sequenceNum = args["seq_num"].AsInteger();
121 } 121 }
122 122
123 public override bool Equals(object obj)
124 {
125 Animation other = obj as Animation;
126 if (other != null)
127 {
128 return (other.AnimID.Equals(this.AnimID)
129 && other.SequenceNum == this.SequenceNum
130 && other.ObjectID.Equals(this.ObjectID) );
131 }
132 return base.Equals(obj);
133 }
134
135 public override int GetHashCode()
136 {
137 return base.GetHashCode();
138 }
139
140 public override string ToString()
141 {
142 return "AnimID=" + AnimID.ToString()
143 + "/seq=" + SequenceNum.ToString()
144 + "/objID=" + ObjectID.ToString();
145 }
146
123 } 147 }
124} 148}
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;
59// Revision 59// Revision
60// 60//
61 61
62[assembly : AssemblyVersion("0.7.5.*")] 62[assembly : AssemblyVersion("0.8.2.*")]
63[assembly : AssemblyFileVersion("0.6.5.0")] \ No newline at end of file
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
50 { 50 {
51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 51 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 52
53 public static readonly int MAX_ASSET_NAME = 64;
54 public static readonly int MAX_ASSET_DESC = 64;
55
53 /// <summary> 56 /// <summary>
54 /// Data of the Asset 57 /// Data of the Asset
55 /// </summary> 58 /// </summary>
@@ -133,7 +136,7 @@ namespace OpenSim.Framework
133 get 136 get
134 { 137 {
135 return 138 return
136 (Type == (sbyte) AssetType.Animation || 139 (Type == (sbyte)AssetType.Animation ||
137 Type == (sbyte)AssetType.Gesture || 140 Type == (sbyte)AssetType.Gesture ||
138 Type == (sbyte)AssetType.Simstate || 141 Type == (sbyte)AssetType.Simstate ||
139 Type == (sbyte)AssetType.Unknown || 142 Type == (sbyte)AssetType.Unknown ||
@@ -143,13 +146,9 @@ namespace OpenSim.Framework
143 Type == (sbyte)AssetType.Texture || 146 Type == (sbyte)AssetType.Texture ||
144 Type == (sbyte)AssetType.TextureTGA || 147 Type == (sbyte)AssetType.TextureTGA ||
145 Type == (sbyte)AssetType.Folder || 148 Type == (sbyte)AssetType.Folder ||
146 Type == (sbyte)AssetType.RootFolder ||
147 Type == (sbyte)AssetType.LostAndFoundFolder ||
148 Type == (sbyte)AssetType.SnapshotFolder ||
149 Type == (sbyte)AssetType.TrashFolder ||
150 Type == (sbyte)AssetType.ImageJPEG || 149 Type == (sbyte)AssetType.ImageJPEG ||
151 Type == (sbyte) AssetType.ImageTGA || 150 Type == (sbyte)AssetType.ImageTGA ||
152 Type == (sbyte) AssetType.LSLBytecode); 151 Type == (sbyte)AssetType.LSLBytecode);
153 } 152 }
154 } 153 }
155 154
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;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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
40 /// </summary> 40 /// </summary>
41 public class AvatarAppearance 41 public class AvatarAppearance
42 { 42 {
43 // SL box diferent to size
44 const float AVBOXAJUST = 0.2f;
45 // constrains for ubitode physics
46 const float AVBOXMINX = 0.2f;
47 const float AVBOXMINY = 0.3f;
48 const float AVBOXMINZ = 1.2f;
49
43 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44 51
52 // this is viewer capabilities and weared things dependent
53 // should be only used as initial default value ( V1 viewers )
45 public readonly static int VISUALPARAM_COUNT = 218; 54 public readonly static int VISUALPARAM_COUNT = 218;
46 55
47 public readonly static int TEXTURE_COUNT = 21; 56 public readonly static int TEXTURE_COUNT = 21;
@@ -53,7 +62,15 @@ namespace OpenSim.Framework
53 protected AvatarWearable[] m_wearables; 62 protected AvatarWearable[] m_wearables;
54 protected Dictionary<int, List<AvatarAttachment>> m_attachments; 63 protected Dictionary<int, List<AvatarAttachment>> m_attachments;
55 protected float m_avatarHeight = 0; 64 protected float m_avatarHeight = 0;
65 protected Vector3 m_avatarSize = new Vector3(0.45f, 0.6f, 1.9f); // sl Z cloud value
66 protected Vector3 m_avatarBoxSize = new Vector3(0.45f, 0.6f, 1.9f);
67 protected float m_avatarFeetOffset = 0;
68 protected float m_avatarAnimOffset = 0;
69 protected WearableCacheItem[] m_cacheitems;
70 protected bool m_cacheItemsDirty = true;
71
56 72
73 public bool PackLegacyWearables {get; set; }
57 public virtual int Serial 74 public virtual int Serial
58 { 75 {
59 get { return m_serial; } 76 get { return m_serial; }
@@ -66,6 +83,21 @@ namespace OpenSim.Framework
66 set { m_visualparams = value; } 83 set { m_visualparams = value; }
67 } 84 }
68 85
86 public virtual Vector3 AvatarSize
87 {
88 get { return m_avatarSize; }
89 }
90
91 public virtual Vector3 AvatarBoxSize
92 {
93 get { return m_avatarBoxSize; }
94 }
95
96 public virtual float AvatarFeetOffset
97 {
98 get { return m_avatarFeetOffset + m_avatarAnimOffset; }
99 }
100
69 public virtual Primitive.TextureEntry Texture 101 public virtual Primitive.TextureEntry Texture
70 { 102 {
71 get { return m_texture; } 103 get { return m_texture; }
@@ -87,16 +119,29 @@ namespace OpenSim.Framework
87 get { return m_avatarHeight; } 119 get { return m_avatarHeight; }
88 set { m_avatarHeight = value; } 120 set { m_avatarHeight = value; }
89 } 121 }
122
123 public virtual WearableCacheItem[] WearableCacheItems
124 {
125 get { return m_cacheitems; }
126 set { m_cacheitems = value; }
127 }
128
129 public virtual bool WearableCacheItemsDirty
130 {
131 get { return m_cacheItemsDirty; }
132 set { m_cacheItemsDirty = value; }
133 }
90 134
91 public AvatarAppearance() 135 public AvatarAppearance()
92 { 136 {
93// m_log.WarnFormat("[AVATAR APPEARANCE]: create empty appearance"); 137// m_log.WarnFormat("[AVATAR APPEARANCE]: create empty appearance");
94 138 PackLegacyWearables = false;
95 m_serial = 0; 139 m_serial = 0;
96 SetDefaultWearables(); 140 SetDefaultWearables();
97 SetDefaultTexture(); 141 SetDefaultTexture();
98 SetDefaultParams(); 142 SetDefaultParams();
99 SetHeight(); 143// SetHeight();
144 SetSize(new Vector3(0.45f,0.6f,1.9f));
100 m_attachments = new Dictionary<int, List<AvatarAttachment>>(); 145 m_attachments = new Dictionary<int, List<AvatarAttachment>>();
101 } 146 }
102 147
@@ -105,7 +150,7 @@ namespace OpenSim.Framework
105// m_log.WarnFormat("[AVATAR APPEARANCE]: create appearance from OSDMap"); 150// m_log.WarnFormat("[AVATAR APPEARANCE]: create appearance from OSDMap");
106 151
107 Unpack(map); 152 Unpack(map);
108 SetHeight(); 153// SetHeight(); done in Unpack
109 } 154 }
110 155
111 public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams) 156 public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams)
@@ -129,7 +174,9 @@ namespace OpenSim.Framework
129 else 174 else
130 SetDefaultParams(); 175 SetDefaultParams();
131 176
132 SetHeight(); 177// SetHeight();
178 if(m_avatarHeight == 0)
179 SetSize(new Vector3(0.45f,0.6f,1.9f));
133 180
134 m_attachments = new Dictionary<int, List<AvatarAttachment>>(); 181 m_attachments = new Dictionary<int, List<AvatarAttachment>>();
135 } 182 }
@@ -148,7 +195,8 @@ namespace OpenSim.Framework
148 SetDefaultWearables(); 195 SetDefaultWearables();
149 SetDefaultTexture(); 196 SetDefaultTexture();
150 SetDefaultParams(); 197 SetDefaultParams();
151 SetHeight(); 198// SetHeight();
199 SetSize(new Vector3(0.45f, 0.6f, 1.9f));
152 m_attachments = new Dictionary<int, List<AvatarAttachment>>(); 200 m_attachments = new Dictionary<int, List<AvatarAttachment>>();
153 201
154 return; 202 return;
@@ -162,7 +210,10 @@ namespace OpenSim.Framework
162 210
163 if (copyWearables && (appearance.Wearables != null)) 211 if (copyWearables && (appearance.Wearables != null))
164 { 212 {
165 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) 213 int len = appearance.Wearables.Length;
214 if(len > AvatarWearable.MAX_WEARABLES)
215 len = AvatarWearable.MAX_WEARABLES;
216 for (int i = 0; i < len; i++)
166 SetWearable(i,appearance.Wearables[i]); 217 SetWearable(i,appearance.Wearables[i]);
167 } 218 }
168 219
@@ -177,7 +228,8 @@ namespace OpenSim.Framework
177 if (appearance.VisualParams != null) 228 if (appearance.VisualParams != null)
178 m_visualparams = (byte[])appearance.VisualParams.Clone(); 229 m_visualparams = (byte[])appearance.VisualParams.Clone();
179 230
180 m_avatarHeight = appearance.m_avatarHeight; 231// m_avatarHeight = appearance.m_avatarHeight;
232 SetSize(appearance.AvatarSize);
181 233
182 // Copy the attachment, force append mode since that ensures consistency 234 // Copy the attachment, force append mode since that ensures consistency
183 m_attachments = new Dictionary<int, List<AvatarAttachment>>(); 235 m_attachments = new Dictionary<int, List<AvatarAttachment>>();
@@ -240,6 +292,21 @@ namespace OpenSim.Framework
240// } 292// }
241 } 293 }
242 294
295 /// <summary>
296 /// Invalidate all of the baked textures in the appearance, useful
297 /// if you know that none are valid
298 /// </summary>
299 public virtual void ResetBakedTextures()
300 {
301 SetDefaultTexture();
302
303 //for (int i = 0; i < BAKE_INDICES.Length; i++)
304 // {
305 // int idx = BAKE_INDICES[i];
306 // m_texture.FaceTextures[idx].TextureID = UUID.Zero;
307 // }
308 }
309
243 protected virtual void SetDefaultTexture() 310 protected virtual void SetDefaultTexture()
244 { 311 {
245 m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE)); 312 m_texture = new Primitive.TextureEntry(new UUID(AppearanceManager.DEFAULT_AVATAR_TEXTURE));
@@ -304,22 +371,33 @@ namespace OpenSim.Framework
304 // made. We determine if any of the visual parameters actually 371 // made. We determine if any of the visual parameters actually
305 // changed to know if the appearance should be saved later 372 // changed to know if the appearance should be saved later
306 bool changed = false; 373 bool changed = false;
307 for (int i = 0; i < AvatarAppearance.VISUALPARAM_COUNT; i++) 374
375 int newsize = visualParams.Length;
376
377 if (newsize != m_visualparams.Length)
308 { 378 {
309 if (visualParams[i] != m_visualparams[i]) 379 changed = true;
380 m_visualparams = (byte[])visualParams.Clone();
381 }
382 else
383 {
384
385 for (int i = 0; i < newsize; i++)
310 { 386 {
311// DEBUG ON 387 if (visualParams[i] != m_visualparams[i])
312// m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}", 388 {
313// i,m_visualparams[i],visualParams[i]); 389 // DEBUG ON
314// DEBUG OFF 390 // m_log.WarnFormat("[AVATARAPPEARANCE] vparams changed [{0}] {1} ==> {2}",
315 m_visualparams[i] = visualParams[i]; 391 // i,m_visualparams[i],visualParams[i]);
316 changed = true; 392 // DEBUG OFF
393 m_visualparams[i] = visualParams[i];
394 changed = true;
395 }
317 } 396 }
318 } 397 }
319
320 // Reset the height if the visual parameters actually changed 398 // Reset the height if the visual parameters actually changed
321 if (changed) 399// if (changed)
322 SetHeight(); 400// SetHeight();
323 401
324 return changed; 402 return changed;
325 } 403 }
@@ -335,6 +413,7 @@ namespace OpenSim.Framework
335 /// </summary> 413 /// </summary>
336 public virtual void SetHeight() 414 public virtual void SetHeight()
337 { 415 {
416/*
338 // Start with shortest possible female avatar height 417 // Start with shortest possible female avatar height
339 m_avatarHeight = 1.14597f; 418 m_avatarHeight = 1.14597f;
340 // Add offset for male avatars 419 // Add offset for male avatars
@@ -347,6 +426,35 @@ namespace OpenSim.Framework
347 + 0.07f * (float)m_visualparams[(int)VPElement.SHOES_PLATFORM_HEIGHT] / 255.0f 426 + 0.07f * (float)m_visualparams[(int)VPElement.SHOES_PLATFORM_HEIGHT] / 255.0f
348 + 0.08f * (float)m_visualparams[(int)VPElement.SHOES_HEEL_HEIGHT] / 255.0f 427 + 0.08f * (float)m_visualparams[(int)VPElement.SHOES_HEEL_HEIGHT] / 255.0f
349 + 0.076f * (float)m_visualparams[(int)VPElement.SHAPE_NECK_LENGTH] / 255.0f; 428 + 0.076f * (float)m_visualparams[(int)VPElement.SHAPE_NECK_LENGTH] / 255.0f;
429*/
430 }
431
432 public void SetSize(Vector3 avSize)
433 {
434 if (avSize.X > 32f)
435 avSize.X = 32f;
436 else if (avSize.X < 0.1f)
437 avSize.X = 0.1f;
438
439 if (avSize.Y > 32f)
440 avSize.Y = 32f;
441 else if (avSize.Y < 0.1f)
442 avSize.Y = 0.1f;
443 if (avSize.Z > 32f)
444 avSize.Z = 32f;
445 else if (avSize.Z < 0.1f)
446 avSize.Z = 0.1f;
447
448 m_avatarSize = avSize;
449 m_avatarBoxSize = avSize;
450 m_avatarBoxSize.Z += AVBOXAJUST;
451 if (m_avatarBoxSize.X < AVBOXMINX)
452 m_avatarBoxSize.X = AVBOXMINX;
453 if (m_avatarBoxSize.Y < AVBOXMINY)
454 m_avatarBoxSize.Y = AVBOXMINY;
455 if (m_avatarBoxSize.Z < AVBOXMINZ)
456 m_avatarBoxSize.Z = AVBOXMINZ;
457 m_avatarHeight = m_avatarSize.Z;
350 } 458 }
351 459
352 public virtual void SetWearable(int wearableId, AvatarWearable wearable) 460 public virtual void SetWearable(int wearableId, AvatarWearable wearable)
@@ -355,8 +463,11 @@ namespace OpenSim.Framework
355// m_log.WarnFormat("[AVATARAPPEARANCE] set wearable {0} --> {1}:{2}",wearableId,wearable.ItemID,wearable.AssetID); 463// m_log.WarnFormat("[AVATARAPPEARANCE] set wearable {0} --> {1}:{2}",wearableId,wearable.ItemID,wearable.AssetID);
356// DEBUG OFF 464// DEBUG OFF
357 m_wearables[wearableId].Clear(); 465 m_wearables[wearableId].Clear();
358 for (int i = 0; i < wearable.Count; i++) 466 int count = wearable.Count;
359 m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID); 467 if (count > AvatarWearable.MAX_WEARABLES)
468 count = AvatarWearable.MAX_WEARABLES;
469 for (int i = 0; i < count; i++)
470 m_wearables[wearableId].Add(wearable[i].ItemID, wearable[i].AssetID);
360 } 471 }
361 472
362// DEBUG ON 473// DEBUG ON
@@ -377,7 +488,8 @@ namespace OpenSim.Framework
377 } 488 }
378 489
379 s += "Visual Params: "; 490 s += "Visual Params: ";
380 for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++) 491 // for (uint j = 0; j < AvatarAppearance.VISUALPARAM_COUNT; j++)
492 for (uint j = 0; j < m_visualparams.Length; j++)
381 s += String.Format("{0},",m_visualparams[j]); 493 s += String.Format("{0},",m_visualparams[j]);
382 s += "\n"; 494 s += "\n";
383 495
@@ -393,18 +505,16 @@ namespace OpenSim.Framework
393 /// </remarks> 505 /// </remarks>
394 public List<AvatarAttachment> GetAttachments() 506 public List<AvatarAttachment> GetAttachments()
395 { 507 {
396 List<AvatarAttachment> alist = new List<AvatarAttachment>();
397
398 lock (m_attachments) 508 lock (m_attachments)
399 { 509 {
510 List<AvatarAttachment> alist = new List<AvatarAttachment>();
400 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments) 511 foreach (KeyValuePair<int, List<AvatarAttachment>> kvp in m_attachments)
401 { 512 {
402 foreach (AvatarAttachment attach in kvp.Value) 513 foreach (AvatarAttachment attach in kvp.Value)
403 alist.Add(new AvatarAttachment(attach)); 514 alist.Add(new AvatarAttachment(attach));
404 } 515 }
405 } 516 return alist;
406 517 }
407 return alist;
408 } 518 }
409 519
410 internal void AppendAttachment(AvatarAttachment attach) 520 internal void AppendAttachment(AvatarAttachment attach)
@@ -418,6 +528,12 @@ namespace OpenSim.Framework
418 if (!m_attachments.ContainsKey(attach.AttachPoint)) 528 if (!m_attachments.ContainsKey(attach.AttachPoint))
419 m_attachments[attach.AttachPoint] = new List<AvatarAttachment>(); 529 m_attachments[attach.AttachPoint] = new List<AvatarAttachment>();
420 530
531 foreach (AvatarAttachment prev in m_attachments[attach.AttachPoint])
532 {
533 if (prev.ItemID == attach.ItemID)
534 return;
535 }
536
421 m_attachments[attach.AttachPoint].Add(attach); 537 m_attachments[attach.AttachPoint].Add(attach);
422 } 538 }
423 } 539 }
@@ -459,45 +575,59 @@ namespace OpenSim.Framework
459 if (attachpoint == 0) 575 if (attachpoint == 0)
460 return false; 576 return false;
461 577
462 if (item == UUID.Zero) 578 lock (m_attachments)
463 { 579 {
464 lock (m_attachments) 580 if (item == UUID.Zero)
465 { 581 {
466 if (m_attachments.ContainsKey(attachpoint)) 582 if (m_attachments.ContainsKey(attachpoint))
467 { 583 {
468 m_attachments.Remove(attachpoint); 584 m_attachments.Remove(attachpoint);
469 return true; 585 return true;
470 } 586 }
587
588 return false;
471 } 589 }
472
473 return false;
474 }
475 590
476 // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However, 591 // When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
477 // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If 592 // the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
478 // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments 593 // we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
479 // later fail unless the attachment is detached and reattached. 594 // later fail unless the attachment is detached and reattached.
480 // 595 //
481 // Therefore, we will carry on with the set if the existing attachment has no asset id. 596 // Therefore, we will carry on with the set if the existing attachment has no asset id.
482 AvatarAttachment existingAttachment = GetAttachmentForItem(item); 597 AvatarAttachment existingAttachment = GetAttachmentForItem(item);
483 if (existingAttachment != null 598 if (existingAttachment != null)
484 && existingAttachment.AssetID != UUID.Zero 599 {
485 && existingAttachment.AttachPoint == (attachpoint & 0x7F)) 600// m_log.DebugFormat(
486 { 601// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}",
487 // m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item); 602// existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint);
488 return false; 603
489 } 604 if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F))
490 605 {
491 // check if this is an append or a replace, 0x80 marks it as an append 606 m_log.DebugFormat(
492 if ((attachpoint & 0x80) > 0) 607 "[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}",
493 { 608 item, attachpoint);
494 // strip the append bit 609
495 int point = attachpoint & 0x7F; 610 return false;
496 AppendAttachment(new AvatarAttachment(point, item, asset)); 611 }
497 } 612 else
498 else 613 {
499 { 614 // Remove it here so that the later append does not add a second attachment but we still update
500 ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset)); 615 // the assetID
616 DetachAttachment(existingAttachment.ItemID);
617 }
618 }
619
620 // check if this is an append or a replace, 0x80 marks it as an append
621 if ((attachpoint & 0x80) > 0)
622 {
623 // strip the append bit
624 int point = attachpoint & 0x7F;
625 AppendAttachment(new AvatarAttachment(point, item, asset));
626 }
627 else
628 {
629 ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
630 }
501 } 631 }
502 632
503 return true; 633 return true;
@@ -534,7 +664,6 @@ namespace OpenSim.Framework
534 return kvp.Key; 664 return kvp.Key;
535 } 665 }
536 } 666 }
537
538 return 0; 667 return 0;
539 } 668 }
540 669
@@ -547,6 +676,10 @@ namespace OpenSim.Framework
547 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; }); 676 int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
548 if (index >= 0) 677 if (index >= 0)
549 { 678 {
679// m_log.DebugFormat(
680// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}",
681// m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint);
682
550 // Remove it from the list of attachments at that attach point 683 // Remove it from the list of attachments at that attach point
551 m_attachments[kvp.Key].RemoveAt(index); 684 m_attachments[kvp.Key].RemoveAt(index);
552 685
@@ -581,8 +714,15 @@ namespace OpenSim.Framework
581 data["height"] = OSD.FromReal(m_avatarHeight); 714 data["height"] = OSD.FromReal(m_avatarHeight);
582 715
583 // Wearables 716 // Wearables
584 OSDArray wears = new OSDArray(AvatarWearable.MAX_WEARABLES); 717
585 for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++) 718 int wearsCount;
719 if(PackLegacyWearables)
720 wearsCount = AvatarWearable.LEGACY_VERSION_MAX_WEARABLES;
721 else
722 wearsCount = AvatarWearable.MAX_WEARABLES;
723
724 OSDArray wears = new OSDArray(wearsCount);
725 for (int i = 0; i < wearsCount; i++)
586 wears.Add(m_wearables[i].Pack()); 726 wears.Add(m_wearables[i].Pack());
587 data["wearables"] = wears; 727 data["wearables"] = wears;
588 728
@@ -601,12 +741,14 @@ namespace OpenSim.Framework
601 OSDBinary visualparams = new OSDBinary(m_visualparams); 741 OSDBinary visualparams = new OSDBinary(m_visualparams);
602 data["visualparams"] = visualparams; 742 data["visualparams"] = visualparams;
603 743
604 // Attachments 744 lock (m_attachments)
605 List<AvatarAttachment> attachments = GetAttachments(); 745 {
606 OSDArray attachs = new OSDArray(attachments.Count); 746 // Attachments
607 foreach (AvatarAttachment attach in GetAttachments()) 747 OSDArray attachs = new OSDArray(m_attachments.Count);
608 attachs.Add(attach.Pack()); 748 foreach (AvatarAttachment attach in GetAttachments())
609 data["attachments"] = attachs; 749 attachs.Add(attach.Pack());
750 data["attachments"] = attachs;
751 }
610 752
611 return data; 753 return data;
612 } 754 }
@@ -620,7 +762,8 @@ namespace OpenSim.Framework
620 if ((data != null) && (data["serial"] != null)) 762 if ((data != null) && (data["serial"] != null))
621 m_serial = data["serial"].AsInteger(); 763 m_serial = data["serial"].AsInteger();
622 if ((data != null) && (data["height"] != null)) 764 if ((data != null) && (data["height"] != null))
623 m_avatarHeight = (float)data["height"].AsReal(); 765// m_avatarHeight = (float)data["height"].AsReal();
766 SetSize(new Vector3(0.45f,0.6f, (float)data["height"].AsReal()));
624 767
625 try 768 try
626 { 769 {
@@ -629,7 +772,12 @@ namespace OpenSim.Framework
629 if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array) 772 if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array)
630 { 773 {
631 OSDArray wears = (OSDArray)(data["wearables"]); 774 OSDArray wears = (OSDArray)(data["wearables"]);
632 for (int i = 0; i < wears.Count; i++) 775
776 int count = wears.Count;
777 if (count > AvatarWearable.MAX_WEARABLES)
778 count = AvatarWearable.MAX_WEARABLES;
779
780 for (int i = 0; i < count; i++)
633 m_wearables[i] = new AvatarWearable((OSDArray)wears[i]); 781 m_wearables[i] = new AvatarWearable((OSDArray)wears[i]);
634 } 782 }
635 else 783 else
@@ -1453,7 +1601,58 @@ namespace OpenSim.Framework
1453 SHAPE_EYELID_INNER_CORNER_UP = 214, 1601 SHAPE_EYELID_INNER_CORNER_UP = 214,
1454 SKIRT_SKIRT_RED = 215, 1602 SKIRT_SKIRT_RED = 215,
1455 SKIRT_SKIRT_GREEN = 216, 1603 SKIRT_SKIRT_GREEN = 216,
1456 SKIRT_SKIRT_BLUE = 217 1604 SKIRT_SKIRT_BLUE = 217,
1605
1606 /// <summary>
1607 /// Avatar Physics section. These are 0 type visual params which get transmitted.
1608 /// </summary>
1609
1610 /// <summary>
1611 /// Breast Part 1
1612 /// </summary>
1613 BREAST_PHYSICS_MASS = 218,
1614 BREAST_PHYSICS_GRAVITY = 219,
1615 BREAST_PHYSICS_DRAG = 220,
1616 BREAST_PHYSICS_UPDOWN_MAX_EFFECT = 221,
1617 BREAST_PHYSICS_UPDOWN_SPRING = 222,
1618 BREAST_PHYSICS_UPDOWN_GAIN = 223,
1619 BREAST_PHYSICS_UPDOWN_DAMPING = 224,
1620 BREAST_PHYSICS_INOUT_MAX_EFFECT = 225,
1621 BREAST_PHYSICS_INOUT_SPRING = 226,
1622 BREAST_PHYSICS_INOUT_GAIN = 227,
1623 BREAST_PHYSICS_INOUT_DAMPING = 228,
1624 /// <summary>
1625 /// Belly
1626 /// </summary>
1627 BELLY_PHYISCS_MASS = 229,
1628 BELLY_PHYSICS_GRAVITY = 230,
1629 BELLY_PHYSICS_DRAG = 231,
1630 BELLY_PHYISCS_UPDOWN_MAX_EFFECT = 232,
1631 BELLY_PHYSICS_UPDOWN_SPRING = 233,
1632 BELLY_PHYSICS_UPDOWN_GAIN = 234,
1633 BELLY_PHYSICS_UPDOWN_DAMPING = 235,
1634
1635 /// <summary>
1636 /// Butt
1637 /// </summary>
1638 BUTT_PHYSICS_MASS = 236,
1639 BUTT_PHYSICS_GRAVITY = 237,
1640 BUTT_PHYSICS_DRAG = 238,
1641 BUTT_PHYSICS_UPDOWN_MAX_EFFECT = 239,
1642 BUTT_PHYSICS_UPDOWN_SPRING = 240,
1643 BUTT_PHYSICS_UPDOWN_GAIN = 241,
1644 BUTT_PHYSICS_UPDOWN_DAMPING = 242,
1645 BUTT_PHYSICS_LEFTRIGHT_MAX_EFFECT = 243,
1646 BUTT_PHYSICS_LEFTRIGHT_SPRING = 244,
1647 BUTT_PHYSICS_LEFTRIGHT_GAIN = 245,
1648 BUTT_PHYSICS_LEFTRIGHT_DAMPING = 246,
1649 /// <summary>
1650 /// Breast Part 2
1651 /// </summary>
1652 BREAST_PHYSICS_LEFTRIGHT_MAX_EFFECT = 247,
1653 BREAST_PHYSICS_LEFTRIGHT_SPRING= 248,
1654 BREAST_PHYSICS_LEFTRIGHT_GAIN = 249,
1655 BREAST_PHYSICS_LEFTRIGHT_DAMPING = 250
1457 } 1656 }
1458 #endregion 1657 #endregion
1459 } 1658 }
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
65 public static readonly int ALPHA = 13; 65 public static readonly int ALPHA = 13;
66 public static readonly int TATTOO = 14; 66 public static readonly int TATTOO = 14;
67 67
68 public static readonly int MAX_WEARABLES = 15; 68 public static readonly int LEGACY_VERSION_MAX_WEARABLES = 15;
69 public static readonly int PHYSICS = 15;
70 public static readonly int MAX_WEARABLES = 16;
69 71
70 public static readonly UUID DEFAULT_BODY_ITEM = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9"); 72 public static readonly UUID DEFAULT_BODY_ITEM = new UUID("66c41e39-38f9-f75a-024e-585989bfaba9");
71 public static readonly UUID DEFAULT_BODY_ASSET = new UUID("66c41e39-38f9-f75a-024e-585989bfab73"); 73 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Collections.Generic;
29using System.Reflection;
30using log4net;
31
32namespace OpenSim.Framework
33{
34
35 public class BasicDOSProtector
36 {
37 public enum ThrottleAction
38 {
39 DoThrottledMethod,
40 DoThrow
41 }
42 private readonly CircularBuffer<int> _generalRequestTimes; // General request checker
43 private readonly BasicDosProtectorOptions _options;
44 private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker
45 private readonly Dictionary<string, int> _tempBlocked; // blocked list
46 private readonly Dictionary<string, int> _sessions;
47 private readonly System.Timers.Timer _forgetTimer; // Cleanup timer
48 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
49 private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim();
50 private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim();
51 public BasicDOSProtector(BasicDosProtectorOptions options)
52 {
53 _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true);
54 _generalRequestTimes.Put(0);
55 _options = options;
56 _deeperInspection = new Dictionary<string, CircularBuffer<int>>();
57 _tempBlocked = new Dictionary<string, int>();
58 _sessions = new Dictionary<string, int>();
59 _forgetTimer = new System.Timers.Timer();
60 _forgetTimer.Elapsed += delegate
61 {
62 _forgetTimer.Enabled = false;
63
64 List<string> removes = new List<string>();
65 _blockLockSlim.EnterReadLock();
66 foreach (string str in _tempBlocked.Keys)
67 {
68 if (
69 Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),
70 _tempBlocked[str]) > 0)
71 removes.Add(str);
72 }
73 _blockLockSlim.ExitReadLock();
74 lock (_deeperInspection)
75 {
76 _blockLockSlim.EnterWriteLock();
77 for (int i = 0; i < removes.Count; i++)
78 {
79 _tempBlocked.Remove(removes[i]);
80 _deeperInspection.Remove(removes[i]);
81 _sessions.Remove(removes[i]);
82 }
83 _blockLockSlim.ExitWriteLock();
84 }
85 foreach (string str in removes)
86 {
87 m_log.InfoFormat("[{0}] client: {1} is no longer blocked.",
88 _options.ReportingName, str);
89 }
90 _blockLockSlim.EnterReadLock();
91 if (_tempBlocked.Count > 0)
92 _forgetTimer.Enabled = true;
93 _blockLockSlim.ExitReadLock();
94 };
95
96 _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds;
97 }
98
99 /// <summary>
100 /// Given a string Key, Returns if that context is blocked
101 /// </summary>
102 /// <param name="key">A Key identifying the context</param>
103 /// <returns>bool Yes or No, True or False for blocked</returns>
104 public bool IsBlocked(string key)
105 {
106 bool ret = false;
107 _blockLockSlim.EnterReadLock();
108 ret = _tempBlocked.ContainsKey(key);
109 _blockLockSlim.ExitReadLock();
110 return ret;
111 }
112
113 /// <summary>
114 /// Process the velocity of this context
115 /// </summary>
116 /// <param name="key"></param>
117 /// <param name="endpoint"></param>
118 /// <returns></returns>
119 public bool Process(string key, string endpoint)
120 {
121 if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1)
122 return true;
123
124 string clientstring = key;
125
126 _blockLockSlim.EnterReadLock();
127 if (_tempBlocked.ContainsKey(clientstring))
128 {
129 _blockLockSlim.ExitReadLock();
130
131 if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
132 return false;
133 else
134 throw new System.Security.SecurityException("Throttled");
135 }
136
137 _blockLockSlim.ExitReadLock();
138
139 lock (_generalRequestTimes)
140 _generalRequestTimes.Put(Util.EnvironmentTickCount());
141
142 if (_options.MaxConcurrentSessions > 0)
143 {
144 int sessionscount = 0;
145
146 _sessionLockSlim.EnterReadLock();
147 if (_sessions.ContainsKey(key))
148 sessionscount = _sessions[key];
149 _sessionLockSlim.ExitReadLock();
150
151 if (sessionscount > _options.MaxConcurrentSessions)
152 {
153 // Add to blocking and cleanup methods
154 lock (_deeperInspection)
155 {
156 _blockLockSlim.EnterWriteLock();
157 if (!_tempBlocked.ContainsKey(clientstring))
158 {
159 _tempBlocked.Add(clientstring,
160 Util.EnvironmentTickCount() +
161 (int) _options.ForgetTimeSpan.TotalMilliseconds);
162 _forgetTimer.Enabled = true;
163 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);
164
165 }
166 else
167 _tempBlocked[clientstring] = Util.EnvironmentTickCount() +
168 (int) _options.ForgetTimeSpan.TotalMilliseconds;
169 _blockLockSlim.ExitWriteLock();
170
171 }
172
173
174 }
175 else
176 ProcessConcurrency(key, endpoint);
177 }
178 if (_generalRequestTimes.Size == _generalRequestTimes.Capacity &&
179 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) <
180 _options.RequestTimeSpan.TotalMilliseconds))
181 {
182 //Trigger deeper inspection
183 if (DeeperInspection(key, endpoint))
184 return true;
185 if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
186 return false;
187 else
188 throw new System.Security.SecurityException("Throttled");
189 }
190 return true;
191 }
192 private void ProcessConcurrency(string key, string endpoint)
193 {
194 _sessionLockSlim.EnterWriteLock();
195 if (_sessions.ContainsKey(key))
196 _sessions[key] = _sessions[key] + 1;
197 else
198 _sessions.Add(key,1);
199 _sessionLockSlim.ExitWriteLock();
200 }
201 public void ProcessEnd(string key, string endpoint)
202 {
203 _sessionLockSlim.EnterWriteLock();
204 if (_sessions.ContainsKey(key))
205 {
206 _sessions[key]--;
207 if (_sessions[key] <= 0)
208 _sessions.Remove(key);
209 }
210 else
211 _sessions.Add(key, 1);
212
213 _sessionLockSlim.ExitWriteLock();
214 }
215
216 /// <summary>
217 /// At this point, the rate limiting code needs to track 'per user' velocity.
218 /// </summary>
219 /// <param name="key">Context Key, string representing a rate limiting context</param>
220 /// <param name="endpoint"></param>
221 /// <returns></returns>
222 private bool DeeperInspection(string key, string endpoint)
223 {
224 lock (_deeperInspection)
225 {
226 string clientstring = key;
227
228
229 if (_deeperInspection.ContainsKey(clientstring))
230 {
231 _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
232 if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity &&
233 (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) <
234 _options.RequestTimeSpan.TotalMilliseconds))
235 {
236 //Looks like we're over the limit
237 _blockLockSlim.EnterWriteLock();
238 if (!_tempBlocked.ContainsKey(clientstring))
239 _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds);
240 else
241 _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds;
242 _blockLockSlim.ExitWriteLock();
243
244 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);
245
246 return false;
247 }
248 //else
249 // return true;
250 }
251 else
252 {
253 _deeperInspection.Add(clientstring, new CircularBuffer<int>(_options.MaxRequestsInTimeframe + 1, true));
254 _deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
255 _forgetTimer.Enabled = true;
256 }
257
258 }
259 return true;
260 }
261
262 }
263
264
265 public class BasicDosProtectorOptions
266 {
267 public int MaxRequestsInTimeframe;
268 public TimeSpan RequestTimeSpan;
269 public TimeSpan ForgetTimeSpan;
270 public bool AllowXForwardedFor;
271 public string ReportingName = "BASICDOSPROTECTOR";
272 public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod;
273 public int MaxConcurrentSessions;
274 }
275}
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
58 { 58 {
59 lock (m_queueSync) 59 lock (m_queueSync)
60 { 60 {
61 if (m_queue.Count < 1 && m_pqueue.Count < 1) 61 while (m_queue.Count < 1 && m_pqueue.Count < 1)
62 { 62 {
63 Monitor.Wait(m_queueSync); 63 Monitor.Wait(m_queueSync);
64 } 64 }
@@ -76,9 +76,10 @@ namespace OpenSim.Framework
76 { 76 {
77 lock (m_queueSync) 77 lock (m_queueSync)
78 { 78 {
79 if (m_queue.Count < 1 && m_pqueue.Count < 1) 79 bool success = true;
80 while (m_queue.Count < 1 && m_pqueue.Count < 1 && success)
80 { 81 {
81 Monitor.Wait(m_queueSync, msTimeout); 82 success = Monitor.Wait(m_queueSync, msTimeout);
82 } 83 }
83 84
84 if (m_pqueue.Count > 0) 85 if (m_pqueue.Count > 0)
@@ -89,28 +90,47 @@ namespace OpenSim.Framework
89 } 90 }
90 } 91 }
91 92
93 /// <summary>
94 /// Indicate whether this queue contains the given item.
95 /// </summary>
96 /// <remarks>
97 /// This method is not thread-safe. Do not rely on the result without consistent external locking.
98 /// </remarks>
92 public bool Contains(T item) 99 public bool Contains(T item)
93 { 100 {
94 lock (m_queueSync) 101 lock (m_queueSync)
95 { 102 {
103 if (m_queue.Count < 1 && m_pqueue.Count < 1)
104 return false;
105
96 if (m_pqueue.Contains(item)) 106 if (m_pqueue.Contains(item))
97 return true; 107 return true;
98 return m_queue.Contains(item); 108 return m_queue.Contains(item);
99 } 109 }
100 } 110 }
101 111
112 /// <summary>
113 /// Return a count of the number of requests on this queue.
114 /// </summary>
102 public int Count() 115 public int Count()
103 { 116 {
104 lock (m_queueSync) 117 lock (m_queueSync)
105 { 118 return m_queue.Count + m_pqueue.Count;
106 return m_queue.Count+m_pqueue.Count;
107 }
108 } 119 }
109 120
121 /// <summary>
122 /// Return the array of items on this queue.
123 /// </summary>
124 /// <remarks>
125 /// This method is not thread-safe. Do not rely on the result without consistent external locking.
126 /// </remarks>
110 public T[] GetQueueArray() 127 public T[] GetQueueArray()
111 { 128 {
112 lock (m_queueSync) 129 lock (m_queueSync)
113 { 130 {
131 if (m_queue.Count < 1 && m_pqueue.Count < 1)
132 return new T[0];
133
114 return m_queue.ToArray(); 134 return m_queue.ToArray();
115 } 135 }
116 } 136 }
diff --git a/OpenSim/Framework/Communications/XMPP/XmppError.cs b/OpenSim/Framework/CachedTextureEventArg.cs
index 3d36e9c..239fc56 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppError.cs
+++ b/OpenSim/Framework/CachedTextureEventArg.cs
@@ -25,15 +25,22 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Xml.Serialization; 28using System;
29using System.Text;
30using OpenMetaverse;
29 31
30namespace OpenSim.Framework.Communications.XMPP 32namespace OpenSim.Framework
31{ 33{
32 [XmlRoot("error")] 34 public class CachedTextureRequestArg
33 public class XmppErrorStanza
34 { 35 {
35 public XmppErrorStanza() 36 public int BakedTextureIndex;
36 { 37 public UUID WearableHashID;
37 } 38 }
39
40 public class CachedTextureResponseArg
41 {
42 public int BakedTextureIndex;
43 public UUID BakedTextureID;
44 public String HostName;
38 } 45 }
39} 46}
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
171 /// Soon to be decommissioned 171 /// Soon to be decommissioned
172 /// </summary> 172 /// </summary>
173 /// <param name="cAgent"></param> 173 /// <param name="cAgent"></param>
174 public void CopyFrom(ChildAgentDataUpdate cAgent) 174 public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid)
175 { 175 {
176 AgentID = new UUID(cAgent.AgentID); 176 AgentID = new UUID(cAgent.AgentID);
177 SessionID = sid;
177 178
178 // next: ??? 179 // next: ???
179 Size = new Vector3(); 180 Size = new Vector3();
@@ -229,12 +230,14 @@ namespace OpenSim.Framework
229 230
230 public class ControllerData 231 public class ControllerData
231 { 232 {
233 public UUID ObjectID;
232 public UUID ItemID; 234 public UUID ItemID;
233 public uint IgnoreControls; 235 public uint IgnoreControls;
234 public uint EventControls; 236 public uint EventControls;
235 237
236 public ControllerData(UUID item, uint ignore, uint ev) 238 public ControllerData(UUID obj, UUID item, uint ignore, uint ev)
237 { 239 {
240 ObjectID = obj;
238 ItemID = item; 241 ItemID = item;
239 IgnoreControls = ignore; 242 IgnoreControls = ignore;
240 EventControls = ev; 243 EventControls = ev;
@@ -248,6 +251,7 @@ namespace OpenSim.Framework
248 public OSDMap PackUpdateMessage() 251 public OSDMap PackUpdateMessage()
249 { 252 {
250 OSDMap controldata = new OSDMap(); 253 OSDMap controldata = new OSDMap();
254 controldata["object"] = OSD.FromUUID(ObjectID);
251 controldata["item"] = OSD.FromUUID(ItemID); 255 controldata["item"] = OSD.FromUUID(ItemID);
252 controldata["ignore"] = OSD.FromInteger(IgnoreControls); 256 controldata["ignore"] = OSD.FromInteger(IgnoreControls);
253 controldata["event"] = OSD.FromInteger(EventControls); 257 controldata["event"] = OSD.FromInteger(EventControls);
@@ -258,6 +262,8 @@ namespace OpenSim.Framework
258 262
259 public void UnpackUpdateMessage(OSDMap args) 263 public void UnpackUpdateMessage(OSDMap args)
260 { 264 {
265 if (args["object"] != null)
266 ObjectID = args["object"].AsUUID();
261 if (args["item"] != null) 267 if (args["item"] != null)
262 ItemID = args["item"].AsUUID(); 268 ItemID = args["item"].AsUUID();
263 if (args["ignore"] != null) 269 if (args["ignore"] != null)
@@ -286,7 +292,13 @@ namespace OpenSim.Framework
286 public Vector3 AtAxis; 292 public Vector3 AtAxis;
287 public Vector3 LeftAxis; 293 public Vector3 LeftAxis;
288 public Vector3 UpAxis; 294 public Vector3 UpAxis;
289 public bool ChangedGrid; 295
296 /// <summary>
297 /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the
298 /// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after
299 /// establishing the connection triggered by it's receipt of a TeleportFinish EQ message).
300 /// </summary>
301 public bool SenderWantsToWaitForRoot;
290 302
291 public float Far; 303 public float Far;
292 public float Aspect; 304 public float Aspect;
@@ -310,6 +322,8 @@ namespace OpenSim.Framework
310 public Animation AnimState = null; 322 public Animation AnimState = null;
311 323
312 public UUID GranterID; 324 public UUID GranterID;
325 public UUID ParentPart;
326 public Vector3 SitOffset;
313 327
314 // Appearance 328 // Appearance
315 public AvatarAppearance Appearance; 329 public AvatarAppearance Appearance;
@@ -355,8 +369,9 @@ namespace OpenSim.Framework
355 args["left_axis"] = OSD.FromString(LeftAxis.ToString()); 369 args["left_axis"] = OSD.FromString(LeftAxis.ToString());
356 args["up_axis"] = OSD.FromString(UpAxis.ToString()); 370 args["up_axis"] = OSD.FromString(UpAxis.ToString());
357 371
358 372 //backwards compatibility
359 args["changed_grid"] = OSD.FromBoolean(ChangedGrid); 373 args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
374 args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
360 args["far"] = OSD.FromReal(Far); 375 args["far"] = OSD.FromReal(Far);
361 args["aspect"] = OSD.FromReal(Aspect); 376 args["aspect"] = OSD.FromReal(Aspect);
362 377
@@ -428,9 +443,18 @@ namespace OpenSim.Framework
428 // We might not pass this in all cases... 443 // We might not pass this in all cases...
429 if ((Appearance.Wearables != null) && (Appearance.Wearables.Length > 0)) 444 if ((Appearance.Wearables != null) && (Appearance.Wearables.Length > 0))
430 { 445 {
431 OSDArray wears = new OSDArray(Appearance.Wearables.Length); 446 int wearsCount;
432 foreach (AvatarWearable awear in Appearance.Wearables) 447 if(Appearance.PackLegacyWearables)
433 wears.Add(awear.Pack()); 448 wearsCount = AvatarWearable.LEGACY_VERSION_MAX_WEARABLES;
449 else
450 wearsCount = AvatarWearable.MAX_WEARABLES;
451
452 if(wearsCount > Appearance.Wearables.Length)
453 wearsCount = Appearance.Wearables.Length;
454
455 OSDArray wears = new OSDArray(wearsCount);
456 for(int i = 0; i < wearsCount ; i++)
457 wears.Add(Appearance.Wearables[i].Pack());
434 458
435 args["wearables"] = wears; 459 args["wearables"] = wears;
436 } 460 }
@@ -480,6 +504,10 @@ namespace OpenSim.Framework
480 } 504 }
481 args["attach_objects"] = attObjs; 505 args["attach_objects"] = attObjs;
482 } 506 }
507
508 args["parent_part"] = OSD.FromUUID(ParentPart);
509 args["sit_offset"] = OSD.FromString(SitOffset.ToString());
510
483 return args; 511 return args;
484 } 512 }
485 513
@@ -525,8 +553,8 @@ namespace OpenSim.Framework
525 if (args["up_axis"] != null) 553 if (args["up_axis"] != null)
526 Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); 554 Vector3.TryParse(args["up_axis"].AsString(), out AtAxis);
527 555
528 if (args["changed_grid"] != null) 556 if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null)
529 ChangedGrid = args["changed_grid"].AsBoolean(); 557 SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean();
530 558
531 if (args["far"] != null) 559 if (args["far"] != null)
532 Far = (float)(args["far"].AsReal()); 560 Far = (float)(args["far"].AsReal());
@@ -646,7 +674,12 @@ namespace OpenSim.Framework
646 if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array) 674 if ((args["wearables"] != null) && (args["wearables"]).Type == OSDType.Array)
647 { 675 {
648 OSDArray wears = (OSDArray)(args["wearables"]); 676 OSDArray wears = (OSDArray)(args["wearables"]);
649 for (int i = 0; i < wears.Count / 2; i++) 677
678 int count = wears.Count;
679 if (count > AvatarWearable.MAX_WEARABLES)
680 count = AvatarWearable.MAX_WEARABLES;
681
682 for (int i = 0; i < count / 2; i++)
650 { 683 {
651 AvatarWearable awear = new AvatarWearable((OSDArray)wears[i]); 684 AvatarWearable awear = new AvatarWearable((OSDArray)wears[i]);
652 Appearance.SetWearable(i,awear); 685 Appearance.SetWearable(i,awear);
@@ -711,6 +744,11 @@ namespace OpenSim.Framework
711 } 744 }
712 } 745 }
713 } 746 }
747
748 if (args["parent_part"] != null)
749 ParentPart = args["parent_part"].AsUUID();
750 if (args["sit_offset"] != null)
751 Vector3.TryParse(args["sit_offset"].AsString(), out SitOffset);
714 } 752 }
715 753
716 public AgentData() 754 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 @@
1/*
2Copyright (c) 2012, Alex Regueiro
3All rights reserved.
4Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
5following conditions are met:
6
7Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
8Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
9in the documentation and/or other materials provided with the distribution.
10
11THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
12BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
13IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
14OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
15OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
16OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
17POSSIBILITY OF SUCH DAMAGE.
18*/
19using System;
20using System.Collections;
21using System.Collections.Generic;
22using System.Threading;
23
24namespace OpenSim.Framework
25{
26 public class CircularBuffer<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
27 {
28 private int capacity;
29 private int size;
30 private int head;
31 private int tail;
32 private T[] buffer;
33
34 [NonSerialized()]
35 private object syncRoot;
36
37 public CircularBuffer(int capacity)
38 : this(capacity, false)
39 {
40 }
41
42 public CircularBuffer(int capacity, bool allowOverflow)
43 {
44 if (capacity < 0)
45 throw new ArgumentException("Needs to have at least 1","capacity");
46
47 this.capacity = capacity;
48 size = 0;
49 head = 0;
50 tail = 0;
51 buffer = new T[capacity];
52 AllowOverflow = allowOverflow;
53 }
54
55 public bool AllowOverflow
56 {
57 get;
58 set;
59 }
60
61 public int Capacity
62 {
63 get { return capacity; }
64 set
65 {
66 if (value == capacity)
67 return;
68
69 if (value < size)
70 throw new ArgumentOutOfRangeException("value","Capacity is too small.");
71
72 var dst = new T[value];
73 if (size > 0)
74 CopyTo(dst);
75 buffer = dst;
76
77 capacity = value;
78 }
79 }
80
81 public int Size
82 {
83 get { return size; }
84 }
85
86 public bool Contains(T item)
87 {
88 int bufferIndex = head;
89 var comparer = EqualityComparer<T>.Default;
90 for (int i = 0; i < size; i++, bufferIndex++)
91 {
92 if (bufferIndex == capacity)
93 bufferIndex = 0;
94
95 if (item == null && buffer[bufferIndex] == null)
96 return true;
97 else if ((buffer[bufferIndex] != null) &&
98 comparer.Equals(buffer[bufferIndex], item))
99 return true;
100 }
101
102 return false;
103 }
104
105 public void Clear()
106 {
107 size = 0;
108 head = 0;
109 tail = 0;
110 }
111
112 public int Put(T[] src)
113 {
114 return Put(src, 0, src.Length);
115 }
116
117 public int Put(T[] src, int offset, int count)
118 {
119 if (!AllowOverflow && count > capacity - size)
120 throw new InvalidOperationException("Buffer Overflow");
121
122 int srcIndex = offset;
123 for (int i = 0; i < count; i++, tail++, srcIndex++)
124 {
125 if (tail == capacity)
126 tail = 0;
127 buffer[tail] = src[srcIndex];
128 }
129 size = Math.Min(size + count, capacity);
130 return count;
131 }
132
133 public void Put(T item)
134 {
135 if (!AllowOverflow && size == capacity)
136 throw new InvalidOperationException("Buffer Overflow");
137
138 buffer[tail] = item;
139 if (++tail == capacity)
140 tail = 0;
141 size++;
142 }
143
144 public void Skip(int count)
145 {
146 head += count;
147 if (head >= capacity)
148 head -= capacity;
149 }
150
151 public T[] Get(int count)
152 {
153 var dst = new T[count];
154 Get(dst);
155 return dst;
156 }
157
158 public int Get(T[] dst)
159 {
160 return Get(dst, 0, dst.Length);
161 }
162
163 public int Get(T[] dst, int offset, int count)
164 {
165 int realCount = Math.Min(count, size);
166 int dstIndex = offset;
167 for (int i = 0; i < realCount; i++, head++, dstIndex++)
168 {
169 if (head == capacity)
170 head = 0;
171 dst[dstIndex] = buffer[head];
172 }
173 size -= realCount;
174 return realCount;
175 }
176
177 public T Get()
178 {
179 if (size == 0)
180 throw new InvalidOperationException("Buffer Empty");
181
182 var item = buffer[head];
183 if (++head == capacity)
184 head = 0;
185 size--;
186 return item;
187 }
188
189 public void CopyTo(T[] array)
190 {
191 CopyTo(array, 0);
192 }
193
194 public void CopyTo(T[] array, int arrayIndex)
195 {
196 CopyTo(0, array, arrayIndex, size);
197 }
198
199 public void CopyTo(int index, T[] array, int arrayIndex, int count)
200 {
201 if (count > size)
202 throw new ArgumentOutOfRangeException("count", "Count Too Large");
203
204 int bufferIndex = head;
205 for (int i = 0; i < count; i++, bufferIndex++, arrayIndex++)
206 {
207 if (bufferIndex == capacity)
208 bufferIndex = 0;
209 array[arrayIndex] = buffer[bufferIndex];
210 }
211 }
212
213 public IEnumerator<T> GetEnumerator()
214 {
215 int bufferIndex = head;
216 for (int i = 0; i < size; i++, bufferIndex++)
217 {
218 if (bufferIndex == capacity)
219 bufferIndex = 0;
220
221 yield return buffer[bufferIndex];
222 }
223 }
224
225 public T[] GetBuffer()
226 {
227 return buffer;
228 }
229
230 public T[] ToArray()
231 {
232 var dst = new T[size];
233 CopyTo(dst);
234 return dst;
235 }
236
237 #region ICollection<T> Members
238
239 int ICollection<T>.Count
240 {
241 get { return Size; }
242 }
243
244 bool ICollection<T>.IsReadOnly
245 {
246 get { return false; }
247 }
248
249 void ICollection<T>.Add(T item)
250 {
251 Put(item);
252 }
253
254 bool ICollection<T>.Remove(T item)
255 {
256 if (size == 0)
257 return false;
258
259 Get();
260 return true;
261 }
262
263 #endregion
264
265 #region IEnumerable<T> Members
266
267 IEnumerator<T> IEnumerable<T>.GetEnumerator()
268 {
269 return GetEnumerator();
270 }
271
272 #endregion
273
274 #region ICollection Members
275
276 int ICollection.Count
277 {
278 get { return Size; }
279 }
280
281 bool ICollection.IsSynchronized
282 {
283 get { return false; }
284 }
285
286 object ICollection.SyncRoot
287 {
288 get
289 {
290 if (syncRoot == null)
291 Interlocked.CompareExchange(ref syncRoot, new object(), null);
292 return syncRoot;
293 }
294 }
295
296 void ICollection.CopyTo(Array array, int arrayIndex)
297 {
298 CopyTo((T[])array, arrayIndex);
299 }
300
301 #endregion
302
303 #region IEnumerable Members
304
305 IEnumerator IEnumerable.GetEnumerator()
306 {
307 return (IEnumerator)GetEnumerator();
308 }
309
310 #endregion
311 }
312}
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
33{ 33{
34 public class ClientInfo 34 public class ClientInfo
35 { 35 {
36 public AgentCircuitData agentcircuit; 36 public readonly DateTime StartedTime = DateTime.Now;
37 public AgentCircuitData agentcircuit = null;
37 38
38 public Dictionary<uint, byte[]> needAck; 39 public Dictionary<uint, byte[]> needAck;
39 40
40 public List<byte[]> out_packets; 41 public List<byte[]> out_packets = new List<byte[]>();
41 public Dictionary<uint, uint> pendingAcks; 42 public Dictionary<uint, uint> pendingAcks = new Dictionary<uint,uint>();
42 public EndPoint proxyEP; 43 public EndPoint proxyEP;
43 44
44 public uint sequence; 45 public uint sequence;
@@ -53,5 +54,14 @@ namespace OpenSim.Framework
53 public int assetThrottle; 54 public int assetThrottle;
54 public int textureThrottle; 55 public int textureThrottle;
55 public int totalThrottle; 56 public int totalThrottle;
57
58 // Used by adaptive only
59 public int targetThrottle;
60
61 public int maxThrottle;
62
63 public Dictionary<string, int> SyncRequests = new Dictionary<string,int>();
64 public Dictionary<string, int> AsyncRequests = new Dictionary<string,int>();
65 public Dictionary<string, int> GenericRequests = new Dictionary<string,int>();
56 } 66 }
57} 67}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Threading;
30
31namespace OpenSim.Framework.Communications
32{
33 internal class SimpleAsyncResult : IAsyncResult
34 {
35 private readonly AsyncCallback m_callback;
36
37 /// <summary>
38 /// Is process completed?
39 /// </summary>
40 /// <remarks>Should really be boolean, but VolatileRead has no boolean method</remarks>
41 private byte m_completed;
42
43 /// <summary>
44 /// Did process complete synchronously?
45 /// </summary>
46 /// <remarks>I have a hard time imagining a scenario where this is the case, again, same issue about
47 /// booleans and VolatileRead as m_completed
48 /// </remarks>
49 private byte m_completedSynchronously;
50
51 private readonly object m_asyncState;
52 private ManualResetEvent m_waitHandle;
53 private Exception m_exception;
54
55 internal SimpleAsyncResult(AsyncCallback cb, object state)
56 {
57 m_callback = cb;
58 m_asyncState = state;
59 m_completed = 0;
60 m_completedSynchronously = 1;
61 }
62
63 #region IAsyncResult Members
64
65 public object AsyncState
66 {
67 get { return m_asyncState; }
68 }
69
70 public WaitHandle AsyncWaitHandle
71 {
72 get
73 {
74 if (m_waitHandle == null)
75 {
76 bool done = IsCompleted;
77 ManualResetEvent mre = new ManualResetEvent(done);
78 if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null)
79 {
80 mre.Close();
81 }
82 else
83 {
84 if (!done && IsCompleted)
85 {
86 m_waitHandle.Set();
87 }
88 }
89 }
90
91 return m_waitHandle;
92 }
93 }
94
95
96 public bool CompletedSynchronously
97 {
98 get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; }
99 }
100
101
102 public bool IsCompleted
103 {
104 get { return Thread.VolatileRead(ref m_completed) == 1; }
105 }
106
107 #endregion
108
109 #region class Methods
110
111 internal void SetAsCompleted(bool completedSynchronously)
112 {
113 m_completed = 1;
114 if (completedSynchronously)
115 m_completedSynchronously = 1;
116 else
117 m_completedSynchronously = 0;
118
119 SignalCompletion();
120 }
121
122 internal void HandleException(Exception e, bool completedSynchronously)
123 {
124 m_completed = 1;
125 if (completedSynchronously)
126 m_completedSynchronously = 1;
127 else
128 m_completedSynchronously = 0;
129 m_exception = e;
130
131 SignalCompletion();
132 }
133
134 private void SignalCompletion()
135 {
136 if (m_waitHandle != null) m_waitHandle.Set();
137
138 if (m_callback != null) m_callback(this);
139 }
140
141 public void EndInvoke()
142 {
143 // This method assumes that only 1 thread calls EndInvoke
144 if (!IsCompleted)
145 {
146 // If the operation isn't done, wait for it
147 AsyncWaitHandle.WaitOne();
148 AsyncWaitHandle.Close();
149 m_waitHandle.Close();
150 m_waitHandle = null; // Allow early GC
151 }
152
153 // Operation is done: if an exception occured, throw it
154 if (m_exception != null) throw m_exception;
155 }
156
157 #endregion
158 }
159
160 internal class AsyncResult<T> : SimpleAsyncResult
161 {
162 private T m_result = default(T);
163
164 public AsyncResult(AsyncCallback asyncCallback, Object state) :
165 base(asyncCallback, state)
166 {
167 }
168
169 public void SetAsCompleted(T result, bool completedSynchronously)
170 {
171 // Save the asynchronous operation's result
172 m_result = result;
173
174 // Tell the base class that the operation completed
175 // sucessfully (no exception)
176 base.SetAsCompleted(completedSynchronously);
177 }
178
179 public new T EndInvoke()
180 {
181 base.EndInvoke();
182 return m_result;
183 }
184 }
185} \ 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenSim.Services.Interfaces;
32
33namespace OpenSim.Framework.Communications
34{
35 public interface IUserService
36 {
37 /// <summary>
38 /// Add a temporary user profile.
39 /// </summary>
40 /// A temporary user profile is one that should exist only for the lifetime of the process.
41 /// <param name="userProfile"></param>
42 void AddTemporaryUserProfile(UserProfileData userProfile);
43
44 /// <summary>
45 /// Loads a user profile by name
46 /// </summary>
47 /// <param name="firstName">First name</param>
48 /// <param name="lastName">Last name</param>
49 /// <returns>A user profile. Returns null if no profile is found</returns>
50 UserProfileData GetUserProfile(string firstName, string lastName);
51
52 /// <summary>
53 /// Loads a user profile from a database by UUID
54 /// </summary>
55 /// <param name="userId">The target UUID</param>
56 /// <returns>A user profile. Returns null if no user profile is found.</returns>
57 UserProfileData GetUserProfile(UUID userId);
58
59 UserProfileData GetUserProfile(Uri uri);
60
61 Uri GetUserUri(UserProfileData userProfile);
62
63 UserAgentData GetAgentByUUID(UUID userId);
64
65 void ClearUserAgent(UUID avatarID);
66 List<AvatarPickerAvatar> GenerateAgentPickerRequestResponse(UUID QueryID, string Query);
67
68 UserProfileData SetupMasterUser(string firstName, string lastName);
69 UserProfileData SetupMasterUser(string firstName, string lastName, string password);
70 UserProfileData SetupMasterUser(UUID userId);
71
72 /// <summary>
73 /// Update the user's profile.
74 /// </summary>
75 /// <param name="data">UserProfileData object with updated data. Should be obtained
76 /// via a call to GetUserProfile().</param>
77 /// <returns>true if the update could be applied, false if it could not be applied.</returns>
78 bool UpdateUserProfile(UserProfileData data);
79
80 /// <summary>
81 /// Adds a new friend to the database for XUser
82 /// </summary>
83 /// <param name="friendlistowner">The agent that who's friends list is being added to</param>
84 /// <param name="friend">The agent that being added to the friends list of the friends list owner</param>
85 /// <param name="perms">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 </param>
86 void AddNewUserFriend(UUID friendlistowner, UUID friend, uint perms);
87
88 /// <summary>
89 /// Delete friend on friendlistowner's friendlist.
90 /// </summary>
91 /// <param name="friendlistowner">The agent that who's friends list is being updated</param>
92 /// <param name="friend">The Ex-friend agent</param>
93 void RemoveUserFriend(UUID friendlistowner, UUID friend);
94
95 /// <summary>
96 /// Update permissions for friend on friendlistowner's friendlist.
97 /// </summary>
98 /// <param name="friendlistowner">The agent that who's friends list is being updated</param>
99 /// <param name="friend">The agent that is getting or loosing permissions</param>
100 /// <param name="perms">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 </param>
101 void UpdateUserFriendPerms(UUID friendlistowner, UUID friend, uint perms);
102
103 /// <summary>
104 /// Logs off a user on the user server
105 /// </summary>
106 /// <param name="userid">UUID of the user</param>
107 /// <param name="regionid">UUID of the Region</param>
108 /// <param name="regionhandle">regionhandle</param>
109 /// <param name="position">final position</param>
110 /// <param name="lookat">final lookat</param>
111 void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, Vector3 position, Vector3 lookat);
112
113 /// <summary>
114 /// Logs off a user on the user server (deprecated as of 2008-08-27)
115 /// </summary>
116 /// <param name="userid">UUID of the user</param>
117 /// <param name="regionid">UUID of the Region</param>
118 /// <param name="regionhandle">regionhandle</param>
119 /// <param name="posx">final position x</param>
120 /// <param name="posy">final position y</param>
121 /// <param name="posz">final position z</param>
122 void LogOffUser(UUID userid, UUID regionid, ulong regionhandle, float posx, float posy, float posz);
123
124 /// <summary>
125 /// Returns a list of FriendsListItems that describe the friends and permissions in the friend relationship
126 /// for UUID friendslistowner
127 /// </summary>
128 ///
129 /// <param name="friendlistowner">The agent for whom we're retreiving the friends Data.</param>
130 /// <returns>
131 /// A List of FriendListItems that contains info about the user's friends.
132 /// Always returns a list even if the user has no friends
133 /// </returns>
134 List<FriendListItem> GetUserFriendList(UUID friendlistowner);
135
136 // This probably shouldn't be here, it belongs to IAuthentication
137 // But since Scenes only have IUserService references, I'm placing it here for now.
138 bool VerifySession(UUID userID, UUID sessionID);
139
140 /// <summary>
141 /// Authenticate a user by their password.
142 /// </summary>
143 ///
144 /// This is used by callers outside the login process that want to
145 /// verify a user who has given their password.
146 ///
147 /// This should probably also be in IAuthentication but is here for the same reasons as VerifySession() is
148 ///
149 /// <param name="userID"></param>
150 /// <param name="password"></param>
151 /// <returns></returns>
152 bool AuthenticateUserByPassword(UUID userID, string password);
153
154 // Temporary Hack until we move everything to the new service model
155 void SetInventoryService(IInventoryService invService);
156 }
157}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28namespace OpenSim.Framework.Communications.Limit
29{
30 /// <summary>
31 /// Interface for strategies that can limit requests from the client. Currently only used in the
32 /// texture modules to deal with repeated requests for certain textures. However, limiting strategies
33 /// could be used with other requests.
34 /// </summary>
35 public interface IRequestLimitStrategy<TId>
36 {
37 /// <summary>
38 /// Should the request be allowed? If the id is not monitored, then the request is always allowed.
39 /// Otherwise, the strategy criteria will be applied.
40 /// </summary>
41 /// <param name="id"></param>
42 /// <returns></returns>
43 bool AllowRequest(TId id);
44
45 /// <summary>
46 /// Has the request been refused just once?
47 /// </summary>
48 /// <returns>False if the request has not yet been refused, or if the request has been refused more
49 /// than once.</returns>
50 bool IsFirstRefusal(TId id);
51
52 /// <summary>
53 /// Start monitoring for future AllowRequest calls. If the id is already monitored, then monitoring
54 /// continues.
55 /// </summary>
56 /// <param name="id"></param>
57 void MonitorRequests(TId id);
58
59 /// <summary>
60 /// Is the id being monitored?
61 /// </summary>
62 /// <param name="uuid"> </param>
63 /// <returns></returns>
64 bool IsMonitoringRequests(TId id);
65 }
66}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections.Generic;
29
30namespace OpenSim.Framework.Communications.Limit
31{
32 /// <summary>
33 /// Limit requests by discarding them after they've been repeated a certain number of times.
34 /// </summary>
35 public class RepeatLimitStrategy<TId> : IRequestLimitStrategy<TId>
36 {
37 /// <summary>
38 /// Record each asset request that we're notified about.
39 /// </summary>
40 private readonly Dictionary<TId, int> requestCounts = new Dictionary<TId, int>();
41
42 /// <summary>
43 /// The maximum number of requests that can be made before we drop subsequent requests.
44 /// </summary>
45 private readonly int m_maxRequests;
46 public int MaxRequests
47 {
48 get { return m_maxRequests; }
49 }
50
51 /// <summary></summary>
52 /// <param name="maxRequests">The maximum number of requests that may be served before all further
53 /// requests are dropped.</param>
54 public RepeatLimitStrategy(int maxRequests)
55 {
56 m_maxRequests = maxRequests;
57 }
58
59 /// <summary>
60 /// <see cref="IRequestLimitStrategy"/>
61 /// </summary>
62 public bool AllowRequest(TId id)
63 {
64 if (requestCounts.ContainsKey(id))
65 {
66 requestCounts[id] += 1;
67
68 if (requestCounts[id] > m_maxRequests)
69 {
70 return false;
71 }
72 }
73
74 return true;
75 }
76
77 /// <summary>
78 /// <see cref="IRequestLimitStrategy"/>
79 /// </summary>
80 public bool IsFirstRefusal(TId id)
81 {
82 if (requestCounts.ContainsKey(id) && m_maxRequests + 1 == requestCounts[id])
83 {
84 return true;
85 }
86
87 return false;
88 }
89
90 /// <summary>
91 /// <see cref="IRequestLimitStrategy"/>
92 /// </summary>
93 public void MonitorRequests(TId id)
94 {
95 if (!IsMonitoringRequests(id))
96 {
97 requestCounts.Add(id, 1);
98 }
99 }
100
101 /// <summary>
102 /// <see cref="IRequestLimitStrategy"/>
103 /// </summary>
104 public bool IsMonitoringRequests(TId id)
105 {
106 return requestCounts.ContainsKey(id);
107 }
108 }
109}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30
31namespace OpenSim.Framework.Communications.Limit
32{
33 /// <summary>
34 /// Limit requests by discarding repeat attempts that occur within a given time period
35 ///
36 /// XXX Don't use this for limiting texture downloading, at least not until we better handle multiple requests
37 /// for the same texture at different resolutions.
38 /// </summary>
39 public class TimeLimitStrategy<TId> : IRequestLimitStrategy<TId>
40 {
41 /// <summary>
42 /// Record the time at which an asset request occurs.
43 /// </summary>
44 private readonly Dictionary<TId, Request> requests = new Dictionary<TId, Request>();
45
46 /// <summary>
47 /// The minimum time period between which requests for the same data will be serviced.
48 /// </summary>
49 private readonly TimeSpan m_repeatPeriod;
50 public TimeSpan RepeatPeriod
51 {
52 get { return m_repeatPeriod; }
53 }
54
55 /// <summary></summary>
56 /// <param name="repeatPeriod"></param>
57 public TimeLimitStrategy(TimeSpan repeatPeriod)
58 {
59 m_repeatPeriod = repeatPeriod;
60 }
61
62 /// <summary>
63 /// <see cref="IRequestLimitStrategy"/>
64 /// </summary>
65 public bool AllowRequest(TId id)
66 {
67 if (IsMonitoringRequests(id))
68 {
69 DateTime now = DateTime.Now;
70 TimeSpan elapsed = now - requests[id].Time;
71
72 if (elapsed < RepeatPeriod)
73 {
74 requests[id].Refusals += 1;
75 return false;
76 }
77
78 requests[id].Time = now;
79 }
80
81 return true;
82 }
83
84 /// <summary>
85 /// <see cref="IRequestLimitStrategy"/>
86 /// </summary>
87 public bool IsFirstRefusal(TId id)
88 {
89 if (IsMonitoringRequests(id))
90 {
91 if (1 == requests[id].Refusals)
92 {
93 return true;
94 }
95 }
96
97 return false;
98 }
99
100 /// <summary>
101 /// <see cref="IRequestLimitStrategy"/>
102 /// </summary>
103 public void MonitorRequests(TId id)
104 {
105 if (!IsMonitoringRequests(id))
106 {
107 requests.Add(id, new Request(DateTime.Now));
108 }
109 }
110
111 /// <summary>
112 /// <see cref="IRequestLimitStrategy"/>
113 /// </summary>
114 public bool IsMonitoringRequests(TId id)
115 {
116 return requests.ContainsKey(id);
117 }
118 }
119
120 /// <summary>
121 /// Private request details.
122 /// </summary>
123 class Request
124 {
125 /// <summary>
126 /// Time of last request
127 /// </summary>
128 public DateTime Time;
129
130 /// <summary>
131 /// Number of refusals associated with this request
132 /// </summary>
133 public int Refusals;
134
135 public Request(DateTime time)
136 {
137 Time = time;
138 }
139 }
140}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Reflection;
29using System.Runtime.InteropServices;
30
31// General information about an assembly is controlled through the following
32// set of attributes. Change these attribute values to modify the information
33// associated with an assembly.
34
35[assembly : AssemblyTitle("OpenSim.Framework.Communications")]
36[assembly : AssemblyDescription("")]
37[assembly : AssemblyConfiguration("")]
38[assembly : AssemblyCompany("http://opensimulator.org")]
39[assembly : AssemblyProduct("OpenSim")]
40[assembly : AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
41[assembly : AssemblyTrademark("")]
42[assembly : AssemblyCulture("")]
43
44// Setting ComVisible to false makes the types in this assembly not visible
45// to COM components. If you need to access a type in this assembly from
46// COM, set the ComVisible attribute to true on that type.
47
48[assembly : ComVisible(false)]
49
50// The following GUID is for the ID of the typelib if this project is exposed to COM
51
52[assembly : Guid("13e7c396-78a9-4a5c-baf2-6f980ea75d95")]
53
54// Version information for an assembly consists of the following four values:
55//
56// Major Version
57// Minor Version
58// Build Number
59// Revision
60//
61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below:
63
64[assembly : AssemblyVersion("0.7.5.*")]
65[assembly : AssemblyFileVersion("0.6.5.0")]
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Xml;
31using System.Xml.Serialization;
32
33namespace OpenSim.Framework.Communications.XMPP
34{
35 public class XmppSerializer
36 {
37 // private static readonly ILog _log =
38 // LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 // need to do it this way, as XmlSerializer(type, extratypes)
41 // does not work on mono (at least).
42 private Dictionary<Type, XmlSerializer> _serializerForType = new Dictionary<Type, XmlSerializer>();
43 private Dictionary<string, XmlSerializer> _serializerForName = new Dictionary<string, XmlSerializer>();
44 private XmlSerializerNamespaces _xmlNs;
45 private string _defaultNS;
46
47 public XmppSerializer(bool server)
48 {
49 _xmlNs = new XmlSerializerNamespaces();
50 _xmlNs.Add(String.Empty, String.Empty);
51 if (server)
52 _defaultNS = "jabber:server";
53 else
54 _defaultNS = "jabber:client";
55
56 // TODO: do this via reflection
57 _serializerForType[typeof(XmppMessageStanza)] = _serializerForName["message"] =
58 new XmlSerializer(typeof(XmppMessageStanza), _defaultNS);
59 }
60
61 public void Serialize(XmlWriter xw, object o)
62 {
63 if (!_serializerForType.ContainsKey(o.GetType()))
64 throw new ArgumentException(String.Format("no serializer available for type {0}", o.GetType()));
65
66 _serializerForType[o.GetType()].Serialize(xw, o, _xmlNs);
67 }
68
69 public object Deserialize(XmlReader xr)
70 {
71 // position on next element
72 xr.Read();
73 if (!_serializerForName.ContainsKey(xr.LocalName))
74 throw new ArgumentException(String.Format("no serializer available for name {0}", xr.LocalName));
75
76 return _serializerForName[xr.LocalName].Deserialize(xr);
77 }
78 }
79}
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
31 { 31 {
32 public string PhysicsEngine { get; set; } 32 public string PhysicsEngine { get; set; }
33 public string MeshEngineName { get; set; } 33 public string MeshEngineName { get; set; }
34 public string StorageDll { get; set; }
35 public string ClientstackDll { get; set; } 34 public string ClientstackDll { get; set; }
36 public string LibrariesXMLFile { get; set; } 35 public string LibrariesXMLFile { get; set; }
37 36
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Net;
31using System.Reflection;
32using System.Text;
33using log4net;
34using OpenSim.Framework.Configuration.XML;
35
36namespace OpenSim.Framework.Configuration.HTTP
37{
38 public class HTTPConfiguration : IGenericConfig
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private RemoteConfigSettings remoteConfigSettings;
43
44 private XmlConfiguration xmlConfig;
45
46 private string configFileName = String.Empty;
47
48 public HTTPConfiguration()
49 {
50 remoteConfigSettings = new RemoteConfigSettings("remoteconfig.xml");
51 xmlConfig = new XmlConfiguration();
52 }
53
54 public void SetFileName(string fileName)
55 {
56 configFileName = fileName;
57 }
58
59 public void LoadData()
60 {
61 try
62 {
63 StringBuilder sb = new StringBuilder();
64
65 byte[] buf = new byte[8192];
66 HttpWebRequest request =
67 (HttpWebRequest) WebRequest.Create(remoteConfigSettings.baseConfigURL + configFileName);
68 HttpWebResponse response = (HttpWebResponse) request.GetResponse();
69
70 Stream resStream = response.GetResponseStream();
71
72 string tempString = null;
73 int count = 0;
74
75 do
76 {
77 count = resStream.Read(buf, 0, buf.Length);
78 if (count != 0)
79 {
80 tempString = Util.UTF8.GetString(buf, 0, count);
81 sb.Append(tempString);
82 }
83 } while (count > 0);
84 LoadDataFromString(sb.ToString());
85 }
86 catch (WebException)
87 {
88 m_log.Warn("Unable to connect to remote configuration file (" +
89 remoteConfigSettings.baseConfigURL + configFileName +
90 "). Creating local file instead.");
91 xmlConfig.SetFileName(configFileName);
92 xmlConfig.LoadData();
93 }
94 }
95
96 public void LoadDataFromString(string data)
97 {
98 xmlConfig.LoadDataFromString(data);
99 }
100
101 public string GetAttribute(string attributeName)
102 {
103 return xmlConfig.GetAttribute(attributeName);
104 }
105
106 public bool SetAttribute(string attributeName, string attributeValue)
107 {
108 return true;
109 }
110
111 public void Commit()
112 {
113 }
114
115 public void Close()
116 {
117 }
118 }
119}
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 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Framework.Configuration.HTTP")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator develoeprs")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("cb78b672-d000-4f93-88f9-dae151cc0061")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")]
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 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Framework.Configuration.XML")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("eeb880df-0112-4c3d-87ed-b2108d614c55")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Xml;
31
32namespace OpenSim.Framework.Configuration.XML
33{
34 public class XmlConfiguration : IGenericConfig
35 {
36 private XmlDocument doc;
37 private XmlNode rootNode;
38 private XmlNode configNode;
39 private string fileName;
40 private bool createdFile = false;
41
42 public void SetFileName(string file)
43 {
44 fileName = file;
45 }
46
47 private void LoadDataToClass()
48 {
49 rootNode = doc.SelectSingleNode("Root");
50 if (null == rootNode)
51 throw new Exception("Error: Invalid .xml File. Missing <Root>");
52
53 configNode = rootNode.SelectSingleNode("Config");
54 if (null == configNode)
55 throw new Exception("Error: Invalid .xml File. <Root> should contain a <Config>");
56 }
57
58 public void LoadData()
59 {
60 lock (this)
61 {
62 doc = new XmlDocument();
63 if (File.Exists(fileName))
64 {
65 XmlTextReader reader = new XmlTextReader(fileName);
66 reader.WhitespaceHandling = WhitespaceHandling.None;
67 doc.Load(reader);
68 reader.Close();
69 }
70 else
71 {
72 createdFile = true;
73 rootNode = doc.CreateNode(XmlNodeType.Element, "Root", String.Empty);
74 doc.AppendChild(rootNode);
75 configNode = doc.CreateNode(XmlNodeType.Element, "Config", String.Empty);
76 rootNode.AppendChild(configNode);
77 }
78
79 LoadDataToClass();
80
81 if (createdFile)
82 {
83 Commit();
84 }
85 }
86 }
87
88 public void LoadDataFromString(string data)
89 {
90 doc = new XmlDocument();
91 doc.LoadXml(data);
92
93 LoadDataToClass();
94 }
95
96 public string GetAttribute(string attributeName)
97 {
98 string result = null;
99 if (configNode.Attributes[attributeName] != null)
100 {
101 result = ((XmlAttribute) configNode.Attributes.GetNamedItem(attributeName)).Value;
102 }
103 return result;
104 }
105
106 public bool SetAttribute(string attributeName, string attributeValue)
107 {
108 if (configNode.Attributes[attributeName] != null)
109 {
110 ((XmlAttribute) configNode.Attributes.GetNamedItem(attributeName)).Value = attributeValue;
111 }
112 else
113 {
114 XmlAttribute attri;
115 attri = doc.CreateAttribute(attributeName);
116 attri.Value = attributeValue;
117 configNode.Attributes.Append(attri);
118 }
119 return true;
120 }
121
122 public void Commit()
123 {
124 if (fileName == null || fileName == String.Empty)
125 return;
126
127 if (!Directory.Exists(Util.configDir()))
128 {
129 Directory.CreateDirectory(Util.configDir());
130 }
131 doc.Save(fileName);
132 }
133
134 public void Close()
135 {
136 configNode = null;
137 rootNode = null;
138 doc = null;
139 }
140 }
141}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Globalization;
31using System.Net;
32using System.Reflection;
33using System.Xml;
34using log4net;
35using OpenMetaverse;
36//using OpenSim.Framework.Console;
37
38namespace OpenSim.Framework
39{
40 public class ConfigurationMember
41 {
42 #region Delegates
43
44 public delegate bool ConfigurationOptionResult(string configuration_key, object configuration_result);
45
46 public delegate void ConfigurationOptionsLoad();
47
48 #endregion
49
50 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 private int cE = 0;
52
53 private string configurationDescription = String.Empty;
54 private string configurationFilename = String.Empty;
55 private XmlNode configurationFromXMLNode = null;
56 private List<ConfigurationOption> configurationOptions = new List<ConfigurationOption>();
57 private IGenericConfig configurationPlugin = null;
58
59 /// <summary>
60 /// This is the default configuration DLL loaded
61 /// </summary>
62 private string configurationPluginFilename = "OpenSim.Framework.Configuration.XML.dll";
63
64 private ConfigurationOptionsLoad loadFunction;
65 private ConfigurationOptionResult resultFunction;
66
67 private bool useConsoleToPromptOnError = true;
68
69 public ConfigurationMember(string configuration_filename, string configuration_description,
70 ConfigurationOptionsLoad load_function, ConfigurationOptionResult result_function, bool use_console_to_prompt_on_error)
71 {
72 configurationFilename = configuration_filename;
73 configurationDescription = configuration_description;
74 loadFunction = load_function;
75 resultFunction = result_function;
76 useConsoleToPromptOnError = use_console_to_prompt_on_error;
77 }
78
79 public ConfigurationMember(XmlNode configuration_xml, string configuration_description,
80 ConfigurationOptionsLoad load_function, ConfigurationOptionResult result_function, bool use_console_to_prompt_on_error)
81 {
82 configurationFilename = String.Empty;
83 configurationFromXMLNode = configuration_xml;
84 configurationDescription = configuration_description;
85 loadFunction = load_function;
86 resultFunction = result_function;
87 useConsoleToPromptOnError = use_console_to_prompt_on_error;
88 }
89
90 public void setConfigurationFilename(string filename)
91 {
92 configurationFilename = filename;
93 }
94
95 public void setConfigurationDescription(string desc)
96 {
97 configurationDescription = desc;
98 }
99
100 public void setConfigurationResultFunction(ConfigurationOptionResult result)
101 {
102 resultFunction = result;
103 }
104
105 public void forceConfigurationPluginLibrary(string dll_filename)
106 {
107 configurationPluginFilename = dll_filename;
108 }
109
110 private void checkAndAddConfigOption(ConfigurationOption option)
111 {
112 if ((option.configurationKey != String.Empty && option.configurationQuestion != String.Empty) ||
113 (option.configurationKey != String.Empty && option.configurationUseDefaultNoPrompt))
114 {
115 if (!configurationOptions.Contains(option))
116 {
117 configurationOptions.Add(option);
118 }
119 }
120 else
121 {
122 m_log.Info(
123 "Required fields for adding a configuration option is invalid. Will not add this option (" +
124 option.configurationKey + ")");
125 }
126 }
127
128 public void addConfigurationOption(string configuration_key,
129 ConfigurationOption.ConfigurationTypes configuration_type,
130 string configuration_question, string configuration_default,
131 bool use_default_no_prompt)
132 {
133 ConfigurationOption configOption = new ConfigurationOption();
134 configOption.configurationKey = configuration_key;
135 configOption.configurationQuestion = configuration_question;
136 configOption.configurationDefault = configuration_default;
137 configOption.configurationType = configuration_type;
138 configOption.configurationUseDefaultNoPrompt = use_default_no_prompt;
139 configOption.shouldIBeAsked = null; //Assumes true, I can ask whenever
140 checkAndAddConfigOption(configOption);
141 }
142
143 public void addConfigurationOption(string configuration_key,
144 ConfigurationOption.ConfigurationTypes configuration_type,
145 string configuration_question, string configuration_default,
146 bool use_default_no_prompt,
147 ConfigurationOption.ConfigurationOptionShouldBeAsked shouldIBeAskedDelegate)
148 {
149 ConfigurationOption configOption = new ConfigurationOption();
150 configOption.configurationKey = configuration_key;
151 configOption.configurationQuestion = configuration_question;
152 configOption.configurationDefault = configuration_default;
153 configOption.configurationType = configuration_type;
154 configOption.configurationUseDefaultNoPrompt = use_default_no_prompt;
155 configOption.shouldIBeAsked = shouldIBeAskedDelegate;
156 checkAndAddConfigOption(configOption);
157 }
158
159 // TEMP - REMOVE
160 public void performConfigurationRetrieve()
161 {
162 if (cE > 1)
163 m_log.Error("READING CONFIGURATION COUT: " + cE.ToString());
164
165
166 configurationPlugin = LoadConfigDll(configurationPluginFilename);
167 configurationOptions.Clear();
168 if (loadFunction == null)
169 {
170 m_log.Error("Load Function for '" + configurationDescription +
171 "' is null. Refusing to run configuration.");
172 return;
173 }
174
175 if (resultFunction == null)
176 {
177 m_log.Error("Result Function for '" + configurationDescription +
178 "' is null. Refusing to run configuration.");
179 return;
180 }
181
182 //m_log.Debug("[CONFIG]: Calling Configuration Load Function...");
183 loadFunction();
184
185 if (configurationOptions.Count <= 0)
186 {
187 m_log.Error("[CONFIG]: No configuration options were specified for '" + configurationOptions +
188 "'. Refusing to continue configuration.");
189 return;
190 }
191
192 bool useFile = true;
193 if (configurationPlugin == null)
194 {
195 m_log.Error("[CONFIG]: Configuration Plugin NOT LOADED!");
196 return;
197 }
198
199 if (configurationFilename.Trim() != String.Empty)
200 {
201 configurationPlugin.SetFileName(configurationFilename);
202 try
203 {
204 configurationPlugin.LoadData();
205 useFile = true;
206 }
207 catch (XmlException e)
208 {
209 m_log.WarnFormat("[CONFIG] Not using {0}: {1}",
210 configurationFilename,
211 e.Message.ToString());
212 //m_log.Error("Error loading " + configurationFilename + ": " + e.ToString());
213 useFile = false;
214 }
215 }
216 else
217 {
218 if (configurationFromXMLNode != null)
219 {
220 m_log.Info("Loading from XML Node, will not save to the file");
221 configurationPlugin.LoadDataFromString(configurationFromXMLNode.OuterXml);
222 }
223
224 m_log.Info("XML Configuration Filename is not valid; will not save to the file.");
225 useFile = false;
226 }
227
228 foreach (ConfigurationOption configOption in configurationOptions)
229 {
230 bool convertSuccess = false;
231 object return_result = null;
232 string errorMessage = String.Empty;
233 bool ignoreNextFromConfig = false;
234 while (convertSuccess == false)
235 {
236 string console_result = String.Empty;
237 string attribute = null;
238 if (useFile || configurationFromXMLNode != null)
239 {
240 if (!ignoreNextFromConfig)
241 {
242 attribute = configurationPlugin.GetAttribute(configOption.configurationKey);
243 }
244 else
245 {
246 ignoreNextFromConfig = false;
247 }
248 }
249
250 if (attribute == null)
251 {
252 if (configOption.configurationUseDefaultNoPrompt || useConsoleToPromptOnError == false)
253 {
254 console_result = configOption.configurationDefault;
255 }
256 else
257 {
258 if ((configOption.shouldIBeAsked != null &&
259 configOption.shouldIBeAsked(configOption.configurationKey)) ||
260 configOption.shouldIBeAsked == null)
261 {
262 if (configurationDescription.Trim() != String.Empty)
263 {
264 console_result =
265 MainConsole.Instance.CmdPrompt(
266 configurationDescription + ": " + configOption.configurationQuestion,
267 configOption.configurationDefault);
268 }
269 else
270 {
271 console_result =
272 MainConsole.Instance.CmdPrompt(configOption.configurationQuestion,
273 configOption.configurationDefault);
274 }
275 }
276 else
277 {
278 //Dont Ask! Just use default
279 console_result = configOption.configurationDefault;
280 }
281 }
282 }
283 else
284 {
285 console_result = attribute;
286 }
287
288 // if the first character is a "$", assume it's the name
289 // of an environment variable and substitute with the value of that variable
290 if (console_result.StartsWith("$"))
291 console_result = Environment.GetEnvironmentVariable(console_result.Substring(1));
292
293 switch (configOption.configurationType)
294 {
295 case ConfigurationOption.ConfigurationTypes.TYPE_STRING:
296 return_result = console_result;
297 convertSuccess = true;
298 break;
299 case ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY:
300 if (console_result.Length > 0)
301 {
302 return_result = console_result;
303 convertSuccess = true;
304 }
305 errorMessage = "a string that is not empty";
306 break;
307 case ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN:
308 bool boolResult;
309 if (Boolean.TryParse(console_result, out boolResult))
310 {
311 convertSuccess = true;
312 return_result = boolResult;
313 }
314 errorMessage = "'true' or 'false' (Boolean)";
315 break;
316 case ConfigurationOption.ConfigurationTypes.TYPE_BYTE:
317 byte byteResult;
318 if (Byte.TryParse(console_result, out byteResult))
319 {
320 convertSuccess = true;
321 return_result = byteResult;
322 }
323 errorMessage = "a byte (Byte)";
324 break;
325 case ConfigurationOption.ConfigurationTypes.TYPE_CHARACTER:
326 char charResult;
327 if (Char.TryParse(console_result, out charResult))
328 {
329 convertSuccess = true;
330 return_result = charResult;
331 }
332 errorMessage = "a character (Char)";
333 break;
334 case ConfigurationOption.ConfigurationTypes.TYPE_INT16:
335 short shortResult;
336 if (Int16.TryParse(console_result, out shortResult))
337 {
338 convertSuccess = true;
339 return_result = shortResult;
340 }
341 errorMessage = "a signed 32 bit integer (short)";
342 break;
343 case ConfigurationOption.ConfigurationTypes.TYPE_INT32:
344 int intResult;
345 if (Int32.TryParse(console_result, out intResult))
346 {
347 convertSuccess = true;
348 return_result = intResult;
349 }
350 errorMessage = "a signed 32 bit integer (int)";
351 break;
352 case ConfigurationOption.ConfigurationTypes.TYPE_INT64:
353 long longResult;
354 if (Int64.TryParse(console_result, out longResult))
355 {
356 convertSuccess = true;
357 return_result = longResult;
358 }
359 errorMessage = "a signed 32 bit integer (long)";
360 break;
361 case ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS:
362 IPAddress ipAddressResult;
363 if (IPAddress.TryParse(console_result, out ipAddressResult))
364 {
365 convertSuccess = true;
366 return_result = ipAddressResult;
367 }
368 errorMessage = "an IP Address (IPAddress)";
369 break;
370 case ConfigurationOption.ConfigurationTypes.TYPE_UUID:
371 UUID uuidResult;
372 if (UUID.TryParse(console_result, out uuidResult))
373 {
374 convertSuccess = true;
375 return_result = uuidResult;
376 }
377 errorMessage = "a UUID (UUID)";
378 break;
379 case ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE:
380 UUID uuidResult2;
381 if (UUID.TryParse(console_result, out uuidResult2))
382 {
383 convertSuccess = true;
384
385 if (uuidResult2 == UUID.Zero)
386 uuidResult2 = UUID.Random();
387
388 return_result = uuidResult2;
389 }
390 errorMessage = "a non-null UUID (UUID)";
391 break;
392 case ConfigurationOption.ConfigurationTypes.TYPE_Vector3:
393 Vector3 vectorResult;
394 if (Vector3.TryParse(console_result, out vectorResult))
395 {
396 convertSuccess = true;
397 return_result = vectorResult;
398 }
399 errorMessage = "a vector (Vector3)";
400 break;
401 case ConfigurationOption.ConfigurationTypes.TYPE_UINT16:
402 ushort ushortResult;
403 if (UInt16.TryParse(console_result, out ushortResult))
404 {
405 convertSuccess = true;
406 return_result = ushortResult;
407 }
408 errorMessage = "an unsigned 16 bit integer (ushort)";
409 break;
410 case ConfigurationOption.ConfigurationTypes.TYPE_UINT32:
411 uint uintResult;
412 if (UInt32.TryParse(console_result, out uintResult))
413 {
414 convertSuccess = true;
415 return_result = uintResult;
416 }
417 errorMessage = "an unsigned 32 bit integer (uint)";
418 break;
419 case ConfigurationOption.ConfigurationTypes.TYPE_UINT64:
420 ulong ulongResult;
421 if (UInt64.TryParse(console_result, out ulongResult))
422 {
423 convertSuccess = true;
424 return_result = ulongResult;
425 }
426 errorMessage = "an unsigned 64 bit integer (ulong)";
427 break;
428 case ConfigurationOption.ConfigurationTypes.TYPE_FLOAT:
429 float floatResult;
430 if (
431 float.TryParse(console_result, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, Culture.NumberFormatInfo,
432 out floatResult))
433 {
434 convertSuccess = true;
435 return_result = floatResult;
436 }
437 errorMessage = "a single-precision floating point number (float)";
438 break;
439 case ConfigurationOption.ConfigurationTypes.TYPE_DOUBLE:
440 double doubleResult;
441 if (
442 Double.TryParse(console_result, NumberStyles.AllowDecimalPoint | NumberStyles.AllowLeadingSign, Culture.NumberFormatInfo,
443 out doubleResult))
444 {
445 convertSuccess = true;
446 return_result = doubleResult;
447 }
448 errorMessage = "an double-precision floating point number (double)";
449 break;
450 }
451
452 if (convertSuccess)
453 {
454 if (useFile)
455 {
456 configurationPlugin.SetAttribute(configOption.configurationKey, console_result);
457 }
458
459 if (!resultFunction(configOption.configurationKey, return_result))
460 {
461 m_log.Info(
462 "The handler for the last configuration option denied that input, please try again.");
463 convertSuccess = false;
464 ignoreNextFromConfig = true;
465 }
466 }
467 else
468 {
469 if (configOption.configurationUseDefaultNoPrompt)
470 {
471 m_log.Error(string.Format(
472 "[CONFIG]: [{3}]:[{1}] is not valid default for parameter [{0}].\nThe configuration result must be parsable to {2}.\n",
473 configOption.configurationKey, console_result, errorMessage,
474 configurationFilename));
475 convertSuccess = true;
476 }
477 else
478 {
479 m_log.Warn(string.Format(
480 "[CONFIG]: [{3}]:[{1}] is not a valid value [{0}].\nThe configuration result must be parsable to {2}.\n",
481 configOption.configurationKey, console_result, errorMessage,
482 configurationFilename));
483 ignoreNextFromConfig = true;
484 }
485 }
486 }
487 }
488
489 if (useFile)
490 {
491 configurationPlugin.Commit();
492 configurationPlugin.Close();
493 }
494 }
495
496 private static IGenericConfig LoadConfigDll(string dllName)
497 {
498 Assembly pluginAssembly = Assembly.LoadFrom(dllName);
499 IGenericConfig plug = null;
500
501 foreach (Type pluginType in pluginAssembly.GetTypes())
502 {
503 if (pluginType.IsPublic)
504 {
505 if (!pluginType.IsAbstract)
506 {
507 Type typeInterface = pluginType.GetInterface("IGenericConfig", true);
508
509 if (typeInterface != null)
510 {
511 plug =
512 (IGenericConfig) Activator.CreateInstance(pluginAssembly.GetType(pluginType.ToString()));
513 }
514 }
515 }
516 }
517
518 pluginAssembly = null;
519 return plug;
520 }
521
522 public void forceSetConfigurationOption(string configuration_key, string configuration_value)
523 {
524 configurationPlugin.LoadData();
525 configurationPlugin.SetAttribute(configuration_key, configuration_value);
526 configurationPlugin.Commit();
527 configurationPlugin.Close();
528 }
529 }
530}
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;
55// You can specify all values by your own or you can build default build and revision 55// You can specify all values by your own or you can build default build and revision
56// numbers with the '*' character (the default): 56// numbers with the '*' character (the default):
57 57
58[assembly : AssemblyVersion("0.7.5.*")] 58[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
424 return new string[] { new List<string>(current.Keys)[0] }; 424 return new string[] { new List<string>(current.Keys)[0] };
425 } 425 }
426 426
427 public string[] Resolve(string[] cmd) 427 private CommandInfo ResolveCommand(string[] cmd, out string[] result)
428 { 428 {
429 string[] result = cmd; 429 result = cmd;
430 int index = -1; 430 int index = -1;
431 431
432 Dictionary<string, object> current = tree; 432 Dictionary<string, object> current = tree;
@@ -458,7 +458,7 @@ namespace OpenSim.Framework.Console
458 } 458 }
459 else if (found.Count > 0) 459 else if (found.Count > 0)
460 { 460 {
461 return new string[0]; 461 return null;
462 } 462 }
463 else 463 else
464 { 464 {
@@ -467,21 +467,37 @@ namespace OpenSim.Framework.Console
467 } 467 }
468 468
469 if (current.ContainsKey(String.Empty)) 469 if (current.ContainsKey(String.Empty))
470 return (CommandInfo)current[String.Empty];
471
472 return null;
473 }
474
475 public bool HasCommand(string command)
476 {
477 string[] result;
478 return ResolveCommand(Parser.Parse(command), out result) != null;
479 }
480
481 public string[] Resolve(string[] cmd)
482 {
483 string[] result;
484 CommandInfo ci = ResolveCommand(cmd, out result);
485
486 if (ci == null)
487 return new string[0];
488
489 if (ci.fn.Count == 0)
490 return new string[0];
491
492 foreach (CommandDelegate fn in ci.fn)
470 { 493 {
471 CommandInfo ci = (CommandInfo)current[String.Empty]; 494 if (fn != null)
472 if (ci.fn.Count == 0) 495 fn(ci.module, result);
496 else
473 return new string[0]; 497 return new string[0];
474 foreach (CommandDelegate fn in ci.fn)
475 {
476 if (fn != null)
477 fn(ci.module, result);
478 else
479 return new string[0];
480 }
481 return result;
482 } 498 }
483 499
484 return new string[0]; 500 return result;
485 } 501 }
486 502
487 public XmlElement GetXml(XmlDocument doc) 503 public XmlElement GetXml(XmlDocument doc)
diff --git a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs
index 415d808..6417663 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs
+++ b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs
@@ -25,33 +25,24 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.IO; 28using System;
29using System.Text;
30using System.Xml;
31using IOStream = System.IO.Stream;
32 29
33namespace OpenSim.Framework.Communications.XMPP 30namespace OpenSim.Framework.Console
34{ 31{
35 public class XMPPWriter: XmlTextWriter 32 /// <summary>
33 /// This will be a set of typical column sizes to allow greater consistency between console commands.
34 /// </summary>
35 public static class ConsoleDisplayUtil
36 { 36 {
37 public XMPPWriter(TextWriter textWriter) : base(textWriter) 37 public const int CoordTupleSize = 11;
38 { 38 public const int PortSize = 5;
39 }
40 39
41 public XMPPWriter(IOStream stream) : this(stream, Util.UTF8) 40 public const int EstateNameSize = 20;
42 { 41 public const int ParcelNameSize = 40;
43 } 42 public const int RegionNameSize = 20;
43 public const int UserNameSize = 35;
44 44
45 public XMPPWriter(IOStream stream, Encoding enc) : base(stream, enc) 45 public const int UuidSize = 36;
46 { 46 public const int VectorSize = 15;
47 }
48
49 public override void WriteStartDocument()
50 {
51 }
52
53 public override void WriteStartDocument(bool standalone)
54 {
55 }
56 } 47 }
57} 48} \ 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
49 = @"Each component of the coord is comma separated. There must be no spaces between the commas. 49 = @"Each component of the coord is comma separated. There must be no spaces between the commas.
50 If you don't care about the z component you can simply omit it. 50 If you don't care about the z component you can simply omit it.
51 If you don't care about the x or y components then you can leave them blank (though a comma is still required) 51 If you don't care about the x or y components then you can leave them blank (though a comma is still required)
52 If you want to specify the maxmimum value of a component then you can use ~ instead of a number 52 If you want to specify the maximum value of a component then you can use ~ instead of a number
53 If you want to specify the minimum value of a component then you can use -~ instead of a number 53 If you want to specify the minimum value of a component then you can use -~ instead of a number
54 e.g. 54 e.g.
55 delete object pos 20,20,20 to 40,40,40 55 show object pos 20,20,20 to 40,40,40
56 delete object pos 20,20 to 40,40 56 delete object pos 20,20 to 40,40
57 delete object pos ,20,20 to ,40,40 57 show object pos ,20,20 to ,40,40
58 delete object pos ,,30 to ,,~ 58 delete object pos ,,30 to ,,~
59 delete object pos ,,-~ to ,,30"; 59 show object pos ,,-~ to ,,30";
60 60
61 public const string MinRawConsoleVectorValue = "-~"; 61 public const string MinRawConsoleVectorValue = "-~";
62 public const string MaxRawConsoleVectorValue = "~"; 62 public const string MaxRawConsoleVectorValue = "~";
@@ -156,12 +156,32 @@ namespace OpenSim.Framework.Console
156 } 156 }
157 157
158 /// <summary> 158 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 159 /// Convert a console input to a bool, automatically complaining if a console is given.
160 /// </summary> 160 /// </summary>
161 /// <param name='console'>Can be null if no console is available.</param> 161 /// <param name='console'>Can be null if no console is available.</param>
162 /// <param name='rawConsoleVector'>/param> 162 /// <param name='rawConsoleVector'>/param>
163 /// <param name='vector'></param> 163 /// <param name='vector'></param>
164 /// <returns></returns> 164 /// <returns></returns>
165 public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
166 {
167 if (!bool.TryParse(rawConsoleString, out b))
168 {
169 if (console != null)
170 console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString);
171
172 return false;
173 }
174
175 return true;
176 }
177
178 /// <summary>
179 /// Convert a console input to an int, automatically complaining if a console is given.
180 /// </summary>
181 /// <param name='console'>Can be null if no console is available.</param>
182 /// <param name='rawConsoleInt'>/param>
183 /// <param name='i'></param>
184 /// <returns></returns>
165 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i) 185 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
166 { 186 {
167 if (!int.TryParse(rawConsoleInt, out i)) 187 if (!int.TryParse(rawConsoleInt, out i))
@@ -174,6 +194,71 @@ namespace OpenSim.Framework.Console
174 194
175 return true; 195 return true;
176 } 196 }
197
198 /// <summary>
199 /// Convert a console input to a float, automatically complaining if a console is given.
200 /// </summary>
201 /// <param name='console'>Can be null if no console is available.</param>
202 /// <param name='rawConsoleInput'>/param>
203 /// <param name='i'></param>
204 /// <returns></returns>
205 public static bool TryParseConsoleFloat(ICommandConsole console, string rawConsoleInput, out float i)
206 {
207 if (!float.TryParse(rawConsoleInput, out i))
208 {
209 if (console != null)
210 console.OutputFormat("ERROR: {0} is not a valid float", rawConsoleInput);
211
212 return false;
213 }
214
215 return true;
216 }
217
218 /// <summary>
219 /// Convert a console input to a double, automatically complaining if a console is given.
220 /// </summary>
221 /// <param name='console'>Can be null if no console is available.</param>
222 /// <param name='rawConsoleInput'>/param>
223 /// <param name='i'></param>
224 /// <returns></returns>
225 public static bool TryParseConsoleDouble(ICommandConsole console, string rawConsoleInput, out double i)
226 {
227 if (!double.TryParse(rawConsoleInput, out i))
228 {
229 if (console != null)
230 console.OutputFormat("ERROR: {0} is not a valid double", rawConsoleInput);
231
232 return false;
233 }
234
235 return true;
236 }
237
238 /// <summary>
239 /// Convert a console integer to a natural int, automatically complaining if a console is given.
240 /// </summary>
241 /// <param name='console'>Can be null if no console is available.</param>
242 /// <param name='rawConsoleInt'>/param>
243 /// <param name='i'></param>
244 /// <returns></returns>
245 public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i)
246 {
247 if (TryParseConsoleInt(console, rawConsoleInt, out i))
248 {
249 if (i < 0)
250 {
251 if (console != null)
252 console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt);
253
254 return false;
255 }
256
257 return true;
258 }
259
260 return false;
261 }
177 262
178 /// <summary> 263 /// <summary>
179 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 264 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
@@ -207,24 +292,82 @@ namespace OpenSim.Framework.Console
207 /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue 292 /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
208 /// Other than that, component values must be numeric. 293 /// Other than that, component values must be numeric.
209 /// </param> 294 /// </param>
210 /// <param name='blankComponentFunc'></param> 295 /// <param name='blankComponentFunc'>
296 /// Behaviour if component is blank. If null then conversion fails on a blank component.
297 /// </param>
211 /// <param name='vector'></param> 298 /// <param name='vector'></param>
212 /// <returns></returns> 299 /// <returns></returns>
213 public static bool TryParseConsoleVector( 300 public static bool TryParseConsoleVector(
214 string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector) 301 string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector)
215 { 302 {
216 List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList(); 303 return Vector3.TryParse(CookVector(rawConsoleVector, 3, blankComponentFunc), out vector);
217 304 }
218 if (components.Count < 1 || components.Count > 3) 305
306 /// <summary>
307 /// Convert a vector input from the console to an OpenMetaverse.Vector2
308 /// </summary>
309 /// <param name='rawConsoleVector'>
310 /// A string in the form <x>,<y> where there is no space between values.
311 /// Any component can be missing (e.g. ,40). blankComponentFunc is invoked to replace the blank with a suitable value
312 /// Also, if the blank component is at the end, then the comma can be missed off entirely (e.g. 40)
313 /// The strings "~" and "-~" are valid in components. The first substitutes float.MaxValue whilst the second is float.MinValue
314 /// Other than that, component values must be numeric.
315 /// </param>
316 /// <param name='blankComponentFunc'>
317 /// Behaviour if component is blank. If null then conversion fails on a blank component.
318 /// </param>
319 /// <param name='vector'></param>
320 /// <returns></returns>
321 public static bool TryParseConsole2DVector(
322 string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector2 vector)
323 {
324 // We don't use Vector2.TryParse() for now because for some reason it expects an input with 3 components
325 // rather than 2.
326 string cookedVector = CookVector(rawConsoleVector, 2, blankComponentFunc);
327
328 if (cookedVector == null)
219 { 329 {
220 vector = Vector3.Zero; 330 vector = Vector2.Zero;
331
221 return false; 332 return false;
222 } 333 }
334 else
335 {
336 string[] cookedComponents = cookedVector.Split(VectorSeparatorChars);
337
338 vector = new Vector2(float.Parse(cookedComponents[0]), float.Parse(cookedComponents[1]));
339
340 return true;
341 }
342
343 //return Vector2.TryParse(CookVector(rawConsoleVector, 2, blankComponentFunc), out vector);
344 }
345
346 /// <summary>
347 /// Convert a raw console vector into a vector that can be be parsed by the relevant OpenMetaverse.TryParse()
348 /// </summary>
349 /// <param name='rawConsoleVector'></param>
350 /// <param name='dimensions'></param>
351 /// <param name='blankComponentFunc'></param>
352 /// <returns>null if conversion was not possible</returns>
353 private static string CookVector(
354 string rawConsoleVector, int dimensions, Func<string, string> blankComponentFunc)
355 {
356 List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList();
223 357
224 for (int i = components.Count; i < 3; i++) 358 if (components.Count < 1 || components.Count > dimensions)
225 components.Add(""); 359 return null;
226 360
227 List<string> semiDigestedComponents 361 if (components.Count < dimensions)
362 {
363 if (blankComponentFunc == null)
364 return null;
365 else
366 for (int i = components.Count; i < dimensions; i++)
367 components.Add("");
368 }
369
370 List<string> cookedComponents
228 = components.ConvertAll<string>( 371 = components.ConvertAll<string>(
229 c => 372 c =>
230 { 373 {
@@ -238,11 +381,7 @@ namespace OpenSim.Framework.Console
238 return c; 381 return c;
239 }); 382 });
240 383
241 string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray()); 384 return string.Join(VectorSeparator, cookedComponents.ToArray());
242
243 // m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector);
244
245 return Vector3.TryParse(semiDigestedConsoleVector, out vector);
246 } 385 }
247 } 386 }
248} \ No newline at end of file 387} \ 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;
32using System.Text; 32using System.Text;
33using System.Text.RegularExpressions; 33using System.Text.RegularExpressions;
34using System.Threading; 34using System.Threading;
35using System.IO;
36using Nini.Config;
35using log4net; 37using log4net;
36 38
37namespace OpenSim.Framework.Console 39namespace OpenSim.Framework.Console
@@ -41,11 +43,18 @@ namespace OpenSim.Framework.Console
41 /// </summary> 43 /// </summary>
42 public class LocalConsole : CommandConsole 44 public class LocalConsole : CommandConsole
43 { 45 {
44// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
47 private string m_historyPath;
48 private bool m_historyEnable;
45 49
46 // private readonly object m_syncRoot = new object(); 50 // private readonly object m_syncRoot = new object();
47 private const string LOGLEVEL_NONE = "(none)"; 51 private const string LOGLEVEL_NONE = "(none)";
48 52
53 // Used to extract categories for colourization.
54 private Regex m_categoryRegex
55 = new Regex(
56 @"^(?<Front>.*?)\[(?<Category>[^\]]+)\]:?(?<End>.*)", RegexOptions.Singleline | RegexOptions.Compiled);
57
49 private int m_cursorYPosition = -1; 58 private int m_cursorYPosition = -1;
50 private int m_cursorXPosition = 0; 59 private int m_cursorXPosition = 0;
51 private StringBuilder m_commandLine = new StringBuilder(); 60 private StringBuilder m_commandLine = new StringBuilder();
@@ -74,8 +83,54 @@ namespace OpenSim.Framework.Console
74 return Colors[(Math.Abs(input.ToUpper().GetHashCode()) % Colors.Length)]; 83 return Colors[(Math.Abs(input.ToUpper().GetHashCode()) % Colors.Length)];
75 } 84 }
76 85
77 public LocalConsole(string defaultPrompt) : base(defaultPrompt) 86 public LocalConsole(string defaultPrompt, IConfig startupConfig = null) : base(defaultPrompt)
78 { 87 {
88
89 if (startupConfig == null) return;
90
91 m_historyEnable = startupConfig.GetBoolean("ConsoleHistoryFileEnabled", false);
92 if (!m_historyEnable)
93 {
94 m_log.Info("[LOCAL CONSOLE]: Persistent command line history from file is Disabled");
95 return;
96 }
97
98 string m_historyFile = startupConfig.GetString("ConsoleHistoryFile", "OpenSimConsoleHistory.txt");
99 int m_historySize = startupConfig.GetInt("ConsoleHistoryFileLines", 100);
100 m_historyPath = Path.GetFullPath(Path.Combine(Util.configDir(), m_historyFile));
101 m_log.InfoFormat("[LOCAL CONSOLE]: Persistent command line history is Enabled, up to {0} lines from file {1}", m_historySize, m_historyPath);
102
103 if (File.Exists(m_historyPath))
104 {
105 using (StreamReader history_file = new StreamReader(m_historyPath))
106 {
107 string line;
108 while ((line = history_file.ReadLine()) != null)
109 {
110 m_history.Add(line);
111 }
112 }
113
114 if (m_history.Count > m_historySize)
115 {
116 while (m_history.Count > m_historySize)
117 m_history.RemoveAt(0);
118
119 using (StreamWriter history_file = new StreamWriter(m_historyPath))
120 {
121 foreach (string line in m_history)
122 {
123 history_file.WriteLine(line);
124 }
125 }
126 }
127 m_log.InfoFormat("[LOCAL CONSOLE]: Read {0} lines of command line history from file {1}", m_history.Count, m_historyPath);
128 }
129 else
130 {
131 m_log.InfoFormat("[LOCAL CONSOLE]: Creating new empty command line history file {0}", m_historyPath);
132 File.Create(m_historyPath).Dispose();
133 }
79 } 134 }
80 135
81 private void AddToHistory(string text) 136 private void AddToHistory(string text)
@@ -84,6 +139,10 @@ namespace OpenSim.Framework.Console
84 m_history.RemoveAt(0); 139 m_history.RemoveAt(0);
85 140
86 m_history.Add(text); 141 m_history.Add(text);
142 if (m_historyEnable)
143 {
144 File.AppendAllText(m_historyPath, text + Environment.NewLine);
145 }
87 } 146 }
88 147
89 /// <summary> 148 /// <summary>
@@ -280,11 +339,8 @@ namespace OpenSim.Framework.Console
280 string outText = text; 339 string outText = text;
281 340
282 if (level != LOGLEVEL_NONE) 341 if (level != LOGLEVEL_NONE)
283 { 342 {
284 string regex = @"^(?<Front>.*?)\[(?<Category>[^\]]+)\]:?(?<End>.*)"; 343 MatchCollection matches = m_categoryRegex.Matches(text);
285
286 Regex RE = new Regex(regex, RegexOptions.Multiline);
287 MatchCollection matches = RE.Matches(text);
288 344
289 if (matches.Count == 1) 345 if (matches.Count == 1)
290 { 346 {
@@ -426,6 +482,21 @@ namespace OpenSim.Framework.Console
426 System.Console.Write("{0}", prompt); 482 System.Console.Write("{0}", prompt);
427 483
428 break; 484 break;
485 case ConsoleKey.Delete:
486 if (m_cursorXPosition == m_commandLine.Length)
487 break;
488
489 m_commandLine.Remove(m_cursorXPosition, 1);
490
491 SetCursorLeft(0);
492 m_cursorYPosition = SetCursorTop(m_cursorYPosition);
493
494 if (m_echo)
495 System.Console.Write("{0}{1} ", prompt, m_commandLine);
496 else
497 System.Console.Write("{0}", prompt);
498
499 break;
429 case ConsoleKey.End: 500 case ConsoleKey.End:
430 m_cursorXPosition = m_commandLine.Length; 501 m_cursorXPosition = m_commandLine.Length;
431 break; 502 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
40 /// </summary> 40 /// </summary>
41 public class MockConsole : ICommandConsole 41 public class MockConsole : ICommandConsole
42 { 42 {
43#pragma warning disable 0067
43 public event OnOutputDelegate OnOutput; 44 public event OnOutputDelegate OnOutput;
45#pragma warning restore 0067
44 46
45 private MockCommands m_commands = new MockCommands(); 47 private MockCommands m_commands = new MockCommands();
46 48
@@ -80,6 +82,7 @@ namespace OpenSim.Framework.Console
80 public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) {} 82 public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) {}
81 public void AddCommand(string module, bool shared, string command, string help, string longhelp, string descriptivehelp, CommandDelegate fn) {} 83 public void AddCommand(string module, bool shared, string command, string help, string longhelp, string descriptivehelp, CommandDelegate fn) {}
82 public string[] FindNextOption(string[] cmd, bool term) { return null; } 84 public string[] FindNextOption(string[] cmd, bool term) { return null; }
85 public bool HasCommand(string cmd) { return false; }
83 public string[] Resolve(string[] cmd) { return null; } 86 public string[] Resolve(string[] cmd) { return null; }
84 public XmlElement GetXml(XmlDocument doc) { return null; } 87 public XmlElement GetXml(XmlDocument doc) { return null; }
85 } 88 }
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
234 string uri = "/ReadResponses/" + sessionID.ToString() + "/"; 234 string uri = "/ReadResponses/" + sessionID.ToString() + "/";
235 235
236 m_Server.AddPollServiceHTTPHandler( 236 m_Server.AddPollServiceHTTPHandler(
237 uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID)); 237 uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout
238 238
239 XmlDocument xmldoc = new XmlDocument(); 239 XmlDocument xmldoc = new XmlDocument();
240 XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, 240 XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
@@ -425,7 +425,7 @@ namespace OpenSim.Framework.Console
425 return false; 425 return false;
426 } 426 }
427 427
428 private Hashtable GetEvents(UUID RequestID, UUID sessionID, string request) 428 private Hashtable GetEvents(UUID RequestID, UUID sessionID)
429 { 429 {
430 ConsoleConnection c = null; 430 ConsoleConnection c = null;
431 431
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
30{ 30{
31 public class Constants 31 public class Constants
32 { 32 {
33 // 'RegionSize' is the legacy region size.
34 // DO NOT USE THIS FOR ANY NEW CODE. Use Scene.RegionInfo.RegionSize[XYZ] as a region might not
35 // be the legacy region size.
33 public const uint RegionSize = 256; 36 public const uint RegionSize = 256;
34 public const uint RegionHeight = 4096; 37 public const uint RegionHeight = 4096;
35 public const byte TerrainPatchSize = 16; 38 // This could be a parameters but, really, a region of greater than this is pretty unmanageable
39 public const uint MaximumRegionSize = 8192;
40
41 // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum
42 public const int MinRegionSize = 16;
43 public const int TerrainPatchSize = 16;
44
36 public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; 45 public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f";
37 46
38 public enum EstateAccessCodex : uint 47 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using System.Text;
34using System.Xml;
35using System.Xml.Schema;
36using System.Xml.Serialization;
37using log4net;
38using OpenMetaverse;
39using OpenMetaverse.StructuredData;
40
41namespace OpenSim.Framework
42{
43 /// <summary>
44 /// This class stores and retrieves dynamic attributes.
45 /// </summary>
46 /// <remarks>
47 /// Modules that want to use dynamic attributes need to do so in a private data store
48 /// which is accessed using a unique name. DAMap provides access to the data stores,
49 /// each of which is an OSDMap. Modules are free to store any type of data they want
50 /// within their data store. However, avoid storing large amounts of data because that
51 /// would slow down database access.
52 /// </remarks>
53 public class DAMap : IXmlSerializable
54 {
55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
56
57 private static readonly int MIN_NAMESPACE_LENGTH = 4;
58
59 private OSDMap m_map = new OSDMap();
60
61 // WARNING: this is temporary for experimentation only, it will be removed!!!!
62 public OSDMap TopLevelMap
63 {
64 get { return m_map; }
65 set { m_map = value; }
66 }
67
68 public XmlSchema GetSchema() { return null; }
69
70 public static DAMap FromXml(string rawXml)
71 {
72 DAMap map = new DAMap();
73 map.ReadXml(rawXml);
74 return map;
75 }
76
77 public void ReadXml(XmlReader reader)
78 {
79 ReadXml(reader.ReadInnerXml());
80 }
81
82 public void ReadXml(string rawXml)
83 {
84 // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
85
86 lock (this)
87 {
88 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
89 SanitiseMap(this);
90 }
91 }
92
93 public void WriteXml(XmlWriter writer)
94 {
95 writer.WriteRaw(ToXml());
96 }
97
98 public string ToXml()
99 {
100 lock (this)
101 return OSDParser.SerializeLLSDXmlString(m_map);
102 }
103
104 public void CopyFrom(DAMap other)
105 {
106 // Deep copy
107
108 string data = null;
109 lock (other)
110 {
111 if (other.CountNamespaces > 0)
112 {
113 data = OSDParser.SerializeLLSDXmlString(other.m_map);
114 }
115 }
116
117 lock (this)
118 {
119 if (data == null)
120 Clear();
121 else
122 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(data);
123 }
124 }
125
126 /// <summary>
127 /// Sanitise the map to remove any namespaces or stores that are not OSDMap.
128 /// </summary>
129 /// <param name='map'>
130 /// </param>
131 public static void SanitiseMap(DAMap daMap)
132 {
133 List<string> keysToRemove = null;
134
135 OSDMap namespacesMap = daMap.m_map;
136
137 foreach (string key in namespacesMap.Keys)
138 {
139// Console.WriteLine("Processing ns {0}", key);
140 if (!(namespacesMap[key] is OSDMap))
141 {
142 if (keysToRemove == null)
143 keysToRemove = new List<string>();
144
145 keysToRemove.Add(key);
146 }
147 }
148
149 if (keysToRemove != null)
150 {
151 foreach (string key in keysToRemove)
152 {
153// Console.WriteLine ("Removing bad ns {0}", key);
154 namespacesMap.Remove(key);
155 }
156 }
157
158 foreach (OSD nsOsd in namespacesMap.Values)
159 {
160 OSDMap nsOsdMap = (OSDMap)nsOsd;
161 keysToRemove = null;
162
163 foreach (string key in nsOsdMap.Keys)
164 {
165 if (!(nsOsdMap[key] is OSDMap))
166 {
167 if (keysToRemove == null)
168 keysToRemove = new List<string>();
169
170 keysToRemove.Add(key);
171 }
172 }
173
174 if (keysToRemove != null)
175 foreach (string key in keysToRemove)
176 nsOsdMap.Remove(key);
177 }
178 }
179
180 /// <summary>
181 /// Get the number of namespaces
182 /// </summary>
183 public int CountNamespaces { get { lock (this) { return m_map.Count; } } }
184
185 /// <summary>
186 /// Get the number of stores.
187 /// </summary>
188 public int CountStores
189 {
190 get
191 {
192 int count = 0;
193
194 lock (this)
195 {
196 foreach (OSD osdNamespace in m_map)
197 {
198 count += ((OSDMap)osdNamespace).Count;
199 }
200 }
201
202 return count;
203 }
204 }
205
206 /// <summary>
207 /// Retrieve a Dynamic Attribute store
208 /// </summary>
209 /// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param>
210 /// <param name="storeName">name of the store within the namespace</param>
211 /// <returns>an OSDMap representing the stored data, or null if not found</returns>
212 public OSDMap GetStore(string ns, string storeName)
213 {
214 OSD namespaceOsd;
215
216 lock (this)
217 {
218 if (m_map.TryGetValue(ns, out namespaceOsd))
219 {
220 OSD store;
221
222 if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store))
223 return (OSDMap)store;
224 }
225 }
226
227 return null;
228 }
229
230 /// <summary>
231 /// Saves a Dynamic attribute store
232 /// </summary>
233 /// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param>
234 /// <param name="storeName">name of the store within the namespace</param>
235 /// <param name="store">an OSDMap representing the data to store</param>
236 public void SetStore(string ns, string storeName, OSDMap store)
237 {
238 ValidateNamespace(ns);
239 OSDMap nsMap;
240
241 lock (this)
242 {
243 if (!m_map.ContainsKey(ns))
244 {
245 nsMap = new OSDMap();
246 m_map[ns] = nsMap;
247 }
248
249 nsMap = (OSDMap)m_map[ns];
250
251// m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName);
252 nsMap[storeName] = store;
253 }
254 }
255
256 /// <summary>
257 /// Validate the key used for storing separate data stores.
258 /// </summary>
259 /// <param name='key'></param>
260 public static void ValidateNamespace(string ns)
261 {
262 if (ns.Length < MIN_NAMESPACE_LENGTH)
263 throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH);
264 }
265
266 public bool ContainsStore(string ns, string storeName)
267 {
268 OSD namespaceOsd;
269
270 lock (this)
271 {
272 if (m_map.TryGetValue(ns, out namespaceOsd))
273 {
274 return ((OSDMap)namespaceOsd).ContainsKey(storeName);
275 }
276 }
277
278 return false;
279 }
280
281 public bool TryGetStore(string ns, string storeName, out OSDMap store)
282 {
283 OSD namespaceOsd;
284
285 lock (this)
286 {
287 if (m_map.TryGetValue(ns, out namespaceOsd))
288 {
289 OSD storeOsd;
290
291 bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd);
292 store = (OSDMap)storeOsd;
293
294 return result;
295 }
296 }
297
298 store = null;
299 return false;
300 }
301
302 public void Clear()
303 {
304 lock (this)
305 m_map.Clear();
306 }
307
308 public bool RemoveStore(string ns, string storeName)
309 {
310 OSD namespaceOsd;
311
312 lock (this)
313 {
314 if (m_map.TryGetValue(ns, out namespaceOsd))
315 {
316 OSDMap namespaceOsdMap = (OSDMap)namespaceOsd;
317 namespaceOsdMap.Remove(storeName);
318
319 // Don't keep empty namespaces around
320 if (namespaceOsdMap.Count <= 0)
321 m_map.Remove(ns);
322 }
323 }
324
325 return false;
326 }
327 }
328} \ No newline at end of file
diff --git a/OpenSim/Framework/ForeignUserProfileData.cs b/OpenSim/Framework/DOMap.cs
index 2beaf80..f5b650b 100644
--- a/OpenSim/Framework/ForeignUserProfileData.cs
+++ b/OpenSim/Framework/DOMap.cs
@@ -26,52 +26,73 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Text;
33using System.Xml;
34using System.Xml.Schema;
35using System.Xml.Serialization;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
29 38
30namespace OpenSim.Framework 39namespace OpenSim.Framework
31{ 40{
32 public class ForeignUserProfileData : UserProfileData 41 /// <summary>
42 /// This class stores and retrieves dynamic objects.
43 /// </summary>
44 /// <remarks>
45 /// Experimental - DO NOT USE. Does not yet have namespace support.
46 /// </remarks>
47 public class DOMap
33 { 48 {
34 /// <summary> 49 private IDictionary<string, object> m_map;
35 /// The address of the users home sim, used for foreigners. 50
36 /// </summary> 51 public void Add(string ns, string objName, object dynObj)
37 private string _userUserServerURI = String.Empty; 52 {
53 DAMap.ValidateNamespace(ns);
38 54
39 /// <summary> 55 lock (this)
40 /// The address of the users home sim, used for foreigners. 56 {
41 /// </summary> 57 if (m_map == null)
42 private string _userHomeAddress = String.Empty; 58 m_map = new Dictionary<string, object>();
43 59
44 /// <summary> 60 m_map.Add(objName, dynObj);
45 /// The port of the users home sim, used for foreigners. 61 }
46 /// </summary>
47 private string _userHomePort = String.Empty;
48 /// <summary>
49 /// The remoting port of the users home sim, used for foreigners.
50 /// </summary>
51 private string _userHomeRemotingPort = String.Empty;
52
53 public string UserServerURI
54 {
55 get { return _userUserServerURI; }
56 set { _userUserServerURI = value; }
57 } 62 }
58 63
59 public string UserHomeAddress 64 public bool ContainsKey(string key)
60 { 65 {
61 get { return _userHomeAddress; } 66 return Get(key) != null;
62 set { _userHomeAddress = value; }
63 } 67 }
64 68
65 public string UserHomePort 69 /// <summary>
70 /// Get a dynamic object
71 /// </summary>
72 /// <remarks>
73 /// Not providing an index method so that users can't casually overwrite each other's objects.
74 /// </remarks>
75 /// <param name='key'></param>
76 public object Get(string key)
66 { 77 {
67 get { return _userHomePort; } 78 lock (this)
68 set { _userHomePort = value; } 79 {
80 if (m_map == null)
81 return null;
82 else
83 return m_map[key];
84 }
69 } 85 }
70 86
71 public string UserHomeRemotingPort 87 public bool Remove(string key)
72 { 88 {
73 get { return _userHomeRemotingPort; } 89 lock (this)
74 set { _userHomeRemotingPort = value; } 90 {
91 if (m_map == null)
92 return false;
93 else
94 return m_map.Remove(key);
95 }
75 } 96 }
76 } 97 }
77} 98} \ 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 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31
28using OpenMetaverse; 32using OpenMetaverse;
29 33
30namespace OpenSim.Framework 34namespace OpenSim.Framework
@@ -111,5 +115,50 @@ namespace OpenSim.Framework
111 } 115 }
112 } 116 }
113 117
118 public EstateBan() { }
119
120 public Dictionary<string, object> ToMap()
121 {
122 Dictionary<string, object> map = new Dictionary<string, object>();
123 PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
124 foreach (PropertyInfo p in properties)
125 map[p.Name] = p.GetValue(this, null);
126
127 return map;
128 }
129
130 public EstateBan(Dictionary<string, object> map)
131 {
132 foreach (KeyValuePair<string, object> kvp in map)
133 {
134 PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance);
135 if (p == null)
136 continue;
137 object value = p.GetValue(this, null);
138 if (value is String)
139 p.SetValue(this, map[p.Name], null);
140 else if (value is UInt32)
141 p.SetValue(this, UInt32.Parse((string)map[p.Name]), null);
142 else if (value is Boolean)
143 p.SetValue(this, Boolean.Parse((string)map[p.Name]), null);
144 else if (value is UUID)
145 p.SetValue(this, UUID.Parse((string)map[p.Name]), null);
146 }
147 }
148
149
150 /// <summary>
151 /// For debugging
152 /// </summary>
153 /// <returns></returns>
154 public override string ToString()
155 {
156 Dictionary<string, object> map = ToMap();
157 string result = string.Empty;
158 foreach (KeyValuePair<string, object> kvp in map)
159 result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value, Environment.NewLine);
160
161 return result;
162 }
114 } 163 }
115} 164}
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 @@
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.IO; 30using System.IO;
31using System.Reflection;
31using OpenMetaverse; 32using OpenMetaverse;
32 33
33namespace OpenSim.Framework 34namespace OpenSim.Framework
@@ -58,6 +59,30 @@ namespace OpenSim.Framework
58 set { m_EstateName = value; } 59 set { m_EstateName = value; }
59 } 60 }
60 61
62 private bool m_AllowLandmark = true;
63
64 public bool AllowLandmark
65 {
66 get { return m_AllowLandmark; }
67 set { m_AllowLandmark = value; }
68 }
69
70 private bool m_AllowParcelChanges = true;
71
72 public bool AllowParcelChanges
73 {
74 get { return m_AllowParcelChanges; }
75 set { m_AllowParcelChanges = value; }
76 }
77
78 private bool m_AllowSetHome = true;
79
80 public bool AllowSetHome
81 {
82 get { return m_AllowSetHome; }
83 set { m_AllowSetHome = value; }
84 }
85
61 private uint m_ParentEstateID = 1; 86 private uint m_ParentEstateID = 1;
62 87
63 public uint ParentEstateID 88 public uint ParentEstateID
@@ -374,10 +399,132 @@ namespace OpenSim.Framework
374 return l_EstateAccess.Contains(user); 399 return l_EstateAccess.Contains(user);
375 } 400 }
376 401
402 public void SetFromFlags(ulong regionFlags)
403 {
404 ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport);
405 BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell);
406 AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark);
407 AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges);
408 AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome);
409 }
410
377 public bool GroupAccess(UUID groupID) 411 public bool GroupAccess(UUID groupID)
378 { 412 {
379 return l_EstateGroups.Contains(groupID); 413 return l_EstateGroups.Contains(groupID);
380 } 414 }
381 415
416 public Dictionary<string, object> ToMap()
417 {
418 Dictionary<string, object> map = new Dictionary<string, object>();
419 PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
420 foreach (PropertyInfo p in properties)
421 {
422 // EstateBans is a complex type, let's treat it as special
423 if (p.Name == "EstateBans")
424 continue;
425
426 object value = p.GetValue(this, null);
427 if (value != null)
428 {
429 if (p.PropertyType.IsArray) // of UUIDs
430 {
431 if (((Array)value).Length > 0)
432 {
433 string[] args = new string[((Array)value).Length];
434 int index = 0;
435 foreach (object o in (Array)value)
436 args[index++] = o.ToString();
437 map[p.Name] = String.Join(",", args);
438 }
439 }
440 else // simple types
441 map[p.Name] = value;
442 }
443 }
444
445 // EstateBans are special
446 if (EstateBans.Length > 0)
447 {
448 Dictionary<string, object> bans = new Dictionary<string, object>();
449 int i = 0;
450 foreach (EstateBan ban in EstateBans)
451 bans["ban" + i++] = ban.ToMap();
452 map["EstateBans"] = bans;
453 }
454
455 return map;
456 }
457
458 /// <summary>
459 /// For debugging
460 /// </summary>
461 /// <returns></returns>
462 public override string ToString()
463 {
464 Dictionary<string, object> map = ToMap();
465 String result = String.Empty;
466
467 foreach (KeyValuePair<string, object> kvp in map)
468 {
469 if (kvp.Key == "EstateBans")
470 {
471 result += "EstateBans:" + Environment.NewLine;
472 foreach (KeyValuePair<string, object> ban in (Dictionary<string, object>)kvp.Value)
473 result += ban.Value.ToString();
474 }
475 else
476 result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value.ToString(), Environment.NewLine);
477 }
478
479 return result;
480 }
481
482 public EstateSettings(Dictionary<string, object> map)
483 {
484 foreach (KeyValuePair<string, object> kvp in map)
485 {
486 PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance);
487 if (p == null)
488 continue;
489
490 // EstateBans is a complex type, let's treat it as special
491 if (p.Name == "EstateBans")
492 continue;
493
494 if (p.PropertyType.IsArray)
495 {
496 string[] elements = ((string)map[p.Name]).Split(new char[] { ',' });
497 UUID[] uuids = new UUID[elements.Length];
498 int i = 0;
499 foreach (string e in elements)
500 uuids[i++] = new UUID(e);
501 p.SetValue(this, uuids, null);
502 }
503 else
504 {
505 object value = p.GetValue(this, null);
506 if (value is String)
507 p.SetValue(this, map[p.Name], null);
508 else if (value is UInt32)
509 p.SetValue(this, UInt32.Parse((string)map[p.Name]), null);
510 else if (value is Boolean)
511 p.SetValue(this, Boolean.Parse((string)map[p.Name]), null);
512 else if (value is UUID)
513 p.SetValue(this, UUID.Parse((string)map[p.Name]), null);
514 }
515 }
516
517 // EstateBans are special
518 if (map.ContainsKey("EstateBans"))
519 {
520 var banData = ((Dictionary<string, object>)map["EstateBans"]).Values;
521 EstateBan[] bans = new EstateBan[banData.Count];
522 int b = 0;
523 foreach (Dictionary<string, object> ban in banData)
524 bans[b++] = new EstateBan(ban);
525 PropertyInfo bansProperty = this.GetType().GetProperty("EstateBans", BindingFlags.Public | BindingFlags.Instance);
526 bansProperty.SetValue(this, bans, null);
527 }
528 }
382 } 529 }
383} 530}
diff --git a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs b/OpenSim/Framework/ExtraPhysicsData.cs
index 7672653..9e7334f 100644
--- a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs
+++ b/OpenSim/Framework/ExtraPhysicsData.cs
@@ -25,16 +25,26 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28namespace OpenSim.Framework.Communications.Limit 28using OpenMetaverse;
29
30namespace OpenSim.Framework
29{ 31{
30 /// <summary> 32 public enum PhysShapeType : byte
31 /// Strategy which polices no limits 33 {
32 /// </summary> 34 prim = 0,
33 public class NullLimitStrategy<TId> : IRequestLimitStrategy<TId> 35 none = 1,
36 convex = 2,
37
38 invalid = 255 // use to mark invalid data in ExtraPhysicsData
39 }
40
41 public struct ExtraPhysicsData
34 { 42 {
35 public bool AllowRequest(TId id) { return true; } 43 public float Density;
36 public bool IsFirstRefusal(TId id) { return false; } 44 public float GravitationModifier;
37 public void MonitorRequests(TId id) { /* intentionally blank */ } 45 public float Friction;
38 public bool IsMonitoringRequests(TId id) { return false; } 46 public float Bounce;
47 public PhysShapeType PhysShapeType;
48
39 } 49 }
40} 50}
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
53 binaryBucket = new byte[0]; 53 binaryBucket = new byte[0];
54 } 54 }
55 55
56 public GridInstantMessage(GridInstantMessage im, bool addTimestamp)
57 {
58 fromAgentID = im.fromAgentID;
59 fromAgentName = im.fromAgentName;
60 toAgentID = im.toAgentID;
61 dialog = im.dialog;
62 fromGroup = im.fromGroup;
63 message = im.message;
64 imSessionID = im.imSessionID;
65 offline = im.offline;
66 Position = im.Position;
67 binaryBucket = im.binaryBucket;
68 RegionID = im.RegionID;
69
70 if (addTimestamp)
71 timestamp = (uint)Util.UnixTimeSinceEpoch();
72 }
73
56 public GridInstantMessage(IScene scene, UUID _fromAgentID, 74 public GridInstantMessage(IScene scene, UUID _fromAgentID,
57 string _fromAgentName, UUID _toAgentID, 75 string _fromAgentName, UUID _toAgentID,
58 byte _dialog, bool _fromGroup, string _message, 76 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
64 64
65 public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); 65 public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes);
66 66
67 public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams); 67 public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List<CachedTextureRequestArg> cachedTextureRequest);
68
69 public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems);
68 70
69 public delegate void StartAnim(IClientAPI remoteClient, UUID animID); 71 public delegate void StartAnim(IClientAPI remoteClient, UUID animID);
70 72
@@ -124,7 +126,7 @@ namespace OpenSim.Framework
124 public delegate void ObjectDrop(uint localID, IClientAPI remoteClient); 126 public delegate void ObjectDrop(uint localID, IClientAPI remoteClient);
125 127
126 public delegate void UpdatePrimFlags( 128 public delegate void UpdatePrimFlags(
127 uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, IClientAPI remoteClient); 129 uint localID, bool UsePhysics, bool IsTemporary, bool IsPhantom, ExtraPhysicsData PhysData, IClientAPI remoteClient);
128 130
129 public delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient); 131 public delegate void UpdatePrimTexture(uint localID, byte[] texture, IClientAPI remoteClient);
130 132
@@ -313,7 +315,7 @@ namespace OpenSim.Framework
313 public delegate void ObjectPermissions( 315 public delegate void ObjectPermissions(
314 IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set); 316 IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set);
315 317
316 public delegate void EconomyDataRequest(UUID agentID); 318 public delegate void EconomyDataRequest(IClientAPI client);
317 319
318 public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID); 320 public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID);
319 321
@@ -780,6 +782,7 @@ namespace OpenSim.Framework
780 event EstateChangeInfo OnEstateChangeInfo; 782 event EstateChangeInfo OnEstateChangeInfo;
781 event EstateManageTelehub OnEstateManageTelehub; 783 event EstateManageTelehub OnEstateManageTelehub;
782 // [Obsolete("LLClientView Specific.")] 784 // [Obsolete("LLClientView Specific.")]
785 event CachedTextureRequest OnCachedTextureRequest;
783 event SetAppearance OnSetAppearance; 786 event SetAppearance OnSetAppearance;
784 // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] 787 // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")]
785 event AvatarNowWearing OnAvatarNowWearing; 788 event AvatarNowWearing OnAvatarNowWearing;
@@ -822,6 +825,8 @@ namespace OpenSim.Framework
822 /// </remarks> 825 /// </remarks>
823 event UpdateAgent OnAgentUpdate; 826 event UpdateAgent OnAgentUpdate;
824 827
828 event UpdateAgent OnAgentCameraUpdate;
829
825 event AgentRequestSit OnAgentRequestSit; 830 event AgentRequestSit OnAgentRequestSit;
826 event AgentSit OnAgentSit; 831 event AgentSit OnAgentSit;
827 event AvatarPickerRequest OnAvatarPickerRequest; 832 event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1087,14 +1092,15 @@ namespace OpenSim.Framework
1087 /// <param name="textureEntry"></param> 1092 /// <param name="textureEntry"></param>
1088 void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); 1093 void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry);
1089 1094
1095 void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures);
1096
1090 void SendStartPingCheck(byte seq); 1097 void SendStartPingCheck(byte seq);
1091 1098
1092 /// <summary> 1099 /// <summary>
1093 /// Tell the client that an object has been deleted 1100 /// Tell the client that an object has been deleted
1094 /// </summary> 1101 /// </summary>
1095 /// <param name="regionHandle"></param>
1096 /// <param name="localID"></param> 1102 /// <param name="localID"></param>
1097 void SendKillObject(ulong regionHandle, List<uint> localID); 1103 void SendKillObject(List<uint> localID);
1098 1104
1099 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); 1105 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
1100 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); 1106 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
@@ -1116,8 +1122,8 @@ namespace OpenSim.Framework
1116 1122
1117 void SendInstantMessage(GridInstantMessage im); 1123 void SendInstantMessage(GridInstantMessage im);
1118 1124
1119 void SendGenericMessage(string method, List<string> message); 1125 void SendGenericMessage(string method, UUID invoice, List<string> message);
1120 void SendGenericMessage(string method, List<byte[]> message); 1126 void SendGenericMessage(string method, UUID invoice, List<byte[]> message);
1121 1127
1122 void SendLayerData(float[] map); 1128 void SendLayerData(float[] map);
1123 void SendLayerData(int px, int py, float[] map); 1129 void SendLayerData(int px, int py, float[] map);
@@ -1155,7 +1161,8 @@ namespace OpenSim.Framework
1155 void SendTeleportStart(uint flags); 1161 void SendTeleportStart(uint flags);
1156 void SendTeleportProgress(uint flags, string message); 1162 void SendTeleportProgress(uint flags, string message);
1157 1163
1158 void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance); 1164 void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item);
1165
1159 void SendPayPrice(UUID objectID, int[] payPrice); 1166 void SendPayPrice(UUID objectID, int[] payPrice);
1160 1167
1161 void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations); 1168 void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations);
@@ -1250,8 +1257,6 @@ namespace OpenSim.Framework
1250 void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch, 1257 void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch,
1251 string[] buttonlabels); 1258 string[] buttonlabels);
1252 1259
1253 bool AddMoney(int debit);
1254
1255 /// <summary> 1260 /// <summary>
1256 /// Update the client as to where the sun is currently located. 1261 /// Update the client as to where the sun is currently located.
1257 /// </summary> 1262 /// </summary>
@@ -1356,6 +1361,8 @@ namespace OpenSim.Framework
1356 1361
1357 void SendObjectPropertiesReply(ISceneEntity Entity); 1362 void SendObjectPropertiesReply(ISceneEntity Entity);
1358 1363
1364 void SendPartPhysicsProprieties(ISceneEntity Entity);
1365
1359 void SendAgentOffline(UUID[] agentIDs); 1366 void SendAgentOffline(UUID[] agentIDs);
1360 1367
1361 void SendAgentOnline(UUID[] agentIDs); 1368 void SendAgentOnline(UUID[] agentIDs);
@@ -1469,7 +1476,7 @@ namespace OpenSim.Framework
1469 void SendChangeUserRights(UUID agentID, UUID friendID, int rights); 1476 void SendChangeUserRights(UUID agentID, UUID friendID, int rights);
1470 void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); 1477 void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId);
1471 1478
1472 void StopFlying(ISceneEntity presence); 1479 void SendAgentTerseUpdate(ISceneEntity presence);
1473 1480
1474 void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); 1481 void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
1475 } 1482 }
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
67 string help, string longhelp, string descriptivehelp, 67 string help, string longhelp, string descriptivehelp,
68 CommandDelegate fn); 68 CommandDelegate fn);
69 69
70 string[] FindNextOption(string[] cmd, bool term); 70 /// <summary>
71 /// Has the given command already been registered?
72 /// </summary>
73 /// <returns></returns>
74 /// <param name="command">Command.</param>
75 bool HasCommand(string command);
76
77 string[] FindNextOption(string[] command, bool term);
71 78
72 string[] Resolve(string[] cmd); 79 string[] Resolve(string[] command);
73 80
74 XmlElement GetXml(XmlDocument doc); 81 XmlElement GetXml(XmlDocument doc);
75 } 82 }
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
31{ 31{
32 public interface IImprovedAssetCache 32 public interface IImprovedAssetCache
33 { 33 {
34 /// <summary>
35 /// Cache the specified asset.
36 /// </summary>
37 /// <param name='asset'></param>
34 void Cache(AssetBase asset); 38 void Cache(AssetBase asset);
39
40 /// <summary>
41 /// Get an asset by its id.
42 /// </summary>
43 /// <param name='id'></param>
44 /// <returns>null if the asset does not exist.</returns>
35 AssetBase Get(string id); 45 AssetBase Get(string id);
46
47 /// <summary>
48 /// Check whether an asset with the specified id exists in the cache.
49 /// </summary>
50 /// <param name='id'></param>
51 bool Check(string id);
52
53 /// <summary>
54 /// Expire an asset from the cache.
55 /// </summary>
56 /// <param name='id'></param>
36 void Expire(string id); 57 void Expire(string id);
58
59 /// <summary>
60 /// Clear the cache.
61 /// </summary>
37 void Clear(); 62 void Clear();
38 } 63 }
39} 64} \ 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
56 ILandObject GetLandObject(float x, float y); 56 ILandObject GetLandObject(float x, float y);
57 57
58 /// <summary> 58 /// <summary>
59 /// Get the parcel at the specified point
60 /// </summary>
61 /// <param name="position">Vector where x and y components are between 0 and 256. z component is ignored.</param>
62 /// <returns>Land object at the point supplied</returns>
63 ILandObject GetLandObject(Vector3 position);
64
65 /// <summary>
59 /// Get the parcels near the specified point 66 /// Get the parcels near the specified point
60 /// </summary> 67 /// </summary>
61 /// <param name="position"></param> 68 /// <param name="position"></param>
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
38 int GetParcelMaxPrimCount(); 38 int GetParcelMaxPrimCount();
39 int GetSimulatorMaxPrimCount(); 39 int GetSimulatorMaxPrimCount();
40 int GetPrimsFree(); 40 int GetPrimsFree();
41 Dictionary<UUID, int> GetLandObjectOwners();
41 42
42 LandData LandData { get; set; } 43 LandData LandData { get; set; }
43 bool[,] LandBitmap { get; set; } 44 bool[,] LandBitmap { get; set; }
@@ -70,6 +71,7 @@ namespace OpenSim.Framework
70 void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client); 71 void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client);
71 bool IsEitherBannedOrRestricted(UUID avatar); 72 bool IsEitherBannedOrRestricted(UUID avatar);
72 bool IsBannedFromLand(UUID avatar); 73 bool IsBannedFromLand(UUID avatar);
74 bool CanBeOnThisLand(UUID avatar, float posHeight);
73 bool IsRestrictedFromLand(UUID avatar); 75 bool IsRestrictedFromLand(UUID avatar);
74 bool IsInLandAccessList(UUID avatar); 76 bool IsInLandAccessList(UUID avatar);
75 void SendLandUpdateToClient(IClientAPI remote_client); 77 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
38 int GetBalance(UUID agentID); 38 int GetBalance(UUID agentID);
39 bool UploadCovered(UUID agentID, int amount); 39 bool UploadCovered(UUID agentID, int amount);
40 bool AmountCovered(UUID agentID, int amount); 40 bool AmountCovered(UUID agentID, int amount);
41 void ApplyCharge(UUID agentID, int amount, string text); 41 void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type);
42 void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData);
42 void ApplyUploadCharge(UUID agentID, int amount, string text); 43 void ApplyUploadCharge(UUID agentID, int amount, string text);
43 44
44 int UploadCharge { get; } 45 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31
32namespace OpenSim.Framework
33{
34 public class UserData
35 {
36 public UUID Id { get; set; }
37 public string FirstName { get; set; }
38 public string LastName { get; set; }
39 public string HomeURL { get; set; }
40 public Dictionary<string, object> ServerURLs { get; set; }
41 public bool IsUnknownUser { get; set; }
42 public bool HasGridUserTried { get; set; }
43 }
44
45 public interface IPeople
46 {
47 List<UserData> GetUserData(string query, int page_size, int page_number);
48 }
49} \ 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
86 event restart OnRestart; 86 event restart OnRestart;
87 87
88 /// <summary> 88 /// <summary>
89 /// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent 89 /// Add a new agent with an attached client. All agents except initial login clients will starts off as a child agent
90 /// - the later agent crossing will promote it to a root agent. 90 /// - the later agent crossing will promote it to a root agent.
91 /// </summary> 91 /// </summary>
92 /// <param name="client"></param> 92 /// <param name="client"></param>
93 /// <param name="type">The type of agent to add.</param> 93 /// <param name="type">The type of agent to add.</param>
94 /// <returns> 94 /// <returns>
95 /// The scene agent if the new client was added or if an agent that already existed.</returns> 95 /// The scene agent if the new client was added or if an agent that already existed.</returns>
96 ISceneAgent AddNewClient(IClientAPI client, PresenceType type); 96 ISceneAgent AddNewAgent(IClientAPI client, PresenceType type);
97 97
98 /// <summary> 98 /// <summary>
99 /// Remove the given client from the scene. 99 /// Tell a single agent to disconnect from the region.
100 /// </summary> 100 /// </summary>
101 /// <param name="agentID"></param> 101 /// <param name="agentID"></param>
102 /// <param name="closeChildAgents">Close the neighbour child agents associated with this client.</param> 102 /// <param name="force">
103 void RemoveClient(UUID agentID, bool closeChildAgents); 103 /// Force the agent to close even if it might be in the middle of some other operation. You do not want to
104 /// force unless you are absolutely sure that the agent is dead and a normal close is not working.
105 /// </param>
106 bool CloseAgent(UUID agentID, bool force);
104 107
105 void Restart(); 108 void Restart();
106 //RegionInfo OtherRegionUp(RegionInfo thisRegion);
107 109
108 string GetSimulatorVersion(); 110 string GetSimulatorVersion();
109 111
@@ -136,5 +138,10 @@ namespace OpenSim.Framework
136 ISceneObject DeserializeObject(string representation); 138 ISceneObject DeserializeObject(string representation);
137 139
138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); 140 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep);
141
142 /// <summary>
143 /// Start the scene and associated scripts within it.
144 /// </summary>
145 void Start();
139 } 146 }
140} 147} \ 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
66 AvatarAppearance Appearance { get; set; } 66 AvatarAppearance Appearance { get; set; }
67 67
68 /// <summary> 68 /// <summary>
69 /// Set if initial data about the scene (avatars, objects) has been sent to the client.
70 /// </summary>
71 bool SentInitialDataToClient { get; }
72
73 /// <summary>
69 /// Send initial scene data to the client controlling this agent 74 /// Send initial scene data to the client controlling this agent
70 /// </summary> 75 /// </summary>
71 /// <remarks> 76 /// <remarks>
72 /// This includes scene object data and the appearance data of other avatars. 77 /// This includes scene object data and the appearance data of other avatars.
73 /// </remarks> 78 /// </remarks>
74 void SendInitialDataToMe(); 79 void SendInitialDataToClient();
75 80
76 /// <summary> 81 /// <summary>
77 /// Direction in which the scene presence is looking. 82 /// 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
32{ 32{
33 public interface ISceneObject 33 public interface ISceneObject
34 { 34 {
35 string Name { get; }
36
35 UUID UUID { get; } 37 UUID UUID { get; }
36 38
37 /// <summary> 39 /// <summary>
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
37 { 37 {
38 public List<InventoryFolderBase> Folders; 38 public List<InventoryFolderBase> Folders;
39 public List<InventoryItemBase> Items; 39 public List<InventoryItemBase> Items;
40 public UUID UserID; 40 public UUID OwnerID;
41 public UUID FolderID;
42 public int Version;
41 } 43 }
42} 44}
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
34 /// </summary> 34 /// </summary>
35 public class InventoryFolderBase : InventoryNodeBase 35 public class InventoryFolderBase : InventoryNodeBase
36 { 36 {
37 public static readonly string ROOT_FOLDER_NAME = "My Inventory";
38 public static readonly string SUITCASE_FOLDER_NAME = "My Suitcase";
39
37 /// <summary> 40 /// <summary>
38 /// The folder this folder is contained in 41 /// The folder this folder is contained in
39 /// </summary> 42 /// </summary>
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
34 /// Inventory Item - contains all the properties associated with an individual inventory piece. 34 /// Inventory Item - contains all the properties associated with an individual inventory piece.
35 /// </summary> 35 /// </summary>
36 public class InventoryItemBase : InventoryNodeBase, ICloneable 36 public class InventoryItemBase : InventoryNodeBase, ICloneable
37 { 37 {
38 /// <value> 38 /// <value>
39 /// The inventory type of the item. This is slightly different from the asset type in some situations. 39 /// The inventory type of the item. This is slightly different from the asset type in some situations.
40 /// </value> 40 /// </value>
@@ -82,12 +82,15 @@ namespace OpenSim.Framework
82 set 82 set
83 { 83 {
84 m_creatorId = value; 84 m_creatorId = value;
85
86 if ((m_creatorId == null) || !UUID.TryParse(m_creatorId, out m_creatorIdAsUuid))
87 m_creatorIdAsUuid = UUID.Zero;
85 } 88 }
86 } 89 }
87 protected string m_creatorId; 90 protected string m_creatorId;
88 91
89 /// <value> 92 /// <value>
90 /// The CreatorId expressed as a UUID.tely 93 /// The CreatorId expressed as a UUID.
91 /// </value> 94 /// </value>
92 public UUID CreatorIdAsUuid 95 public UUID CreatorIdAsUuid
93 { 96 {
@@ -122,7 +125,7 @@ namespace OpenSim.Framework
122 { 125 {
123 get 126 get
124 { 127 {
125 if (m_creatorData != null && m_creatorData != string.Empty) 128 if (!string.IsNullOrEmpty(m_creatorData))
126 return m_creatorId + ';' + m_creatorData; 129 return m_creatorId + ';' + m_creatorData;
127 else 130 else
128 return m_creatorId; 131 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
33 [Serializable] 33 [Serializable]
34 public class Location : ICloneable 34 public class Location : ICloneable
35 { 35 {
36 private readonly int m_x; 36 private readonly uint m_x;
37 private readonly int m_y; 37 private readonly uint m_y;
38 38
39 public Location(int x, int y) 39 public Location(uint x, uint y)
40 { 40 {
41 m_x = x; 41 m_x = x;
42 m_y = y; 42 m_y = y;
@@ -44,21 +44,21 @@ namespace OpenSim.Framework
44 44
45 public Location(ulong regionHandle) 45 public Location(ulong regionHandle)
46 { 46 {
47 m_x = (int) regionHandle; 47 m_x = (uint)(regionHandle >> 32);
48 m_y = (int) (regionHandle >> 32); 48 m_y = (uint)(regionHandle & (ulong)uint.MaxValue);
49 } 49 }
50 50
51 public ulong RegionHandle 51 public ulong RegionHandle
52 { 52 {
53 get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); } 53 get { return Utils.UIntsToLong(m_x, m_y); }
54 } 54 }
55 55
56 public int X 56 public uint X
57 { 57 {
58 get { return m_x; } 58 get { return m_x; }
59 } 59 }
60 60
61 public int Y 61 public uint Y
62 { 62 {
63 get { return m_y; } 63 get { return m_y; }
64 } 64 }
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Text;
31using log4net;
32
33namespace OpenSim.Framework
34{
35 /// <summary>
36 /// Class for writing a high performance, high volume log file.
37 /// Sometimes, to debug, one has a high volume logging to do and the regular
38 /// log file output is not appropriate.
39 /// Create a new instance with the parameters needed and
40 /// call Write() to output a line. Call Close() when finished.
41 /// If created with no parameters, it will not log anything.
42 /// </summary>
43 public class LogWriter : IDisposable
44 {
45 public bool Enabled { get; private set; }
46
47 private string m_logDirectory = ".";
48 private int m_logMaxFileTimeMin = 5; // 5 minutes
49 public String LogFileHeader { get; set; }
50
51 private StreamWriter m_logFile = null;
52 private TimeSpan m_logFileLife;
53 private DateTime m_logFileEndTime;
54 private Object m_logFileWriteLock = new Object();
55 private bool m_flushWrite;
56
57 // set externally when debugging. If let 'null', this does not write any error messages.
58 public ILog ErrorLogger = null;
59 private string LogHeader = "[LOG WRITER]";
60
61 /// <summary>
62 /// Create a log writer that will not write anything. Good for when not enabled
63 /// but the write statements are still in the code.
64 /// </summary>
65 public LogWriter()
66 {
67 Enabled = false;
68 m_logFile = null;
69 }
70
71 /// <summary>
72 /// Create a log writer instance.
73 /// </summary>
74 /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param>
75 /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param>
76 /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param>
77 /// <param name="flushWrite">Whether to do a flush after every log write. Best left off but
78 /// if one is looking for a crash, this is a good thing to turn on.</param>
79 public LogWriter(string dir, string headr, int maxFileTime, bool flushWrite)
80 {
81 m_logDirectory = dir == null ? "." : dir;
82
83 LogFileHeader = headr == null ? "log-" : headr;
84
85 m_logMaxFileTimeMin = maxFileTime;
86 if (m_logMaxFileTimeMin < 1)
87 m_logMaxFileTimeMin = 5;
88
89 m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0);
90 m_logFileEndTime = DateTime.Now + m_logFileLife;
91
92 m_flushWrite = flushWrite;
93
94 Enabled = true;
95 }
96 // Constructor that assumes flushWrite is off.
97 public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false)
98 {
99 }
100
101 public void Dispose()
102 {
103 this.Close();
104 }
105
106 public void Close()
107 {
108 Enabled = false;
109 if (m_logFile != null)
110 {
111 m_logFile.Close();
112 m_logFile.Dispose();
113 m_logFile = null;
114 }
115 }
116
117 public void Write(string line, params object[] args)
118 {
119 if (!Enabled) return;
120 Write(String.Format(line, args));
121 }
122
123 public void Flush()
124 {
125 if (!Enabled) return;
126 if (m_logFile != null)
127 {
128 m_logFile.Flush();
129 }
130 }
131
132 public void Write(string line)
133 {
134 if (!Enabled) return;
135 try
136 {
137 lock (m_logFileWriteLock)
138 {
139 DateTime now = DateTime.UtcNow;
140 if (m_logFile == null || now > m_logFileEndTime)
141 {
142 if (m_logFile != null)
143 {
144 m_logFile.Close();
145 m_logFile.Dispose();
146 m_logFile = null;
147 }
148
149 // First log file or time has expired, start writing to a new log file
150 m_logFileEndTime = now + m_logFileLife;
151 string path = (m_logDirectory.Length > 0 ? m_logDirectory
152 + System.IO.Path.DirectorySeparatorChar.ToString() : "")
153 + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss"));
154 m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite));
155 }
156 if (m_logFile != null)
157 {
158 StringBuilder buff = new StringBuilder(line.Length + 25);
159 buff.Append(now.ToString("yyyyMMddHHmmssfff"));
160 // buff.Append(now.ToString("yyyyMMddHHmmss"));
161 buff.Append(",");
162 buff.Append(line);
163 buff.Append("\r\n");
164 m_logFile.Write(buff.ToString());
165 if (m_flushWrite)
166 m_logFile.Flush();
167 }
168 }
169 }
170 catch (Exception e)
171 {
172 if (ErrorLogger != null)
173 {
174 ErrorLogger.ErrorFormat("{0}: FAILURE WRITING TO LOGFILE: {1}", LogHeader, e);
175 }
176 Enabled = false;
177 }
178 return;
179 }
180 }
181}
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 @@
27 27
28using System; 28using System;
29using OpenMetaverse; 29using OpenMetaverse;
30using OpenMetaverse.StructuredData;
30 31
31namespace OpenSim.Framework 32namespace OpenSim.Framework
32{ 33{
@@ -40,9 +41,26 @@ namespace OpenSim.Framework
40 public byte WaterHeight; 41 public byte WaterHeight;
41 public ushort X; 42 public ushort X;
42 public ushort Y; 43 public ushort Y;
44 public ushort SizeX;
45 public ushort SizeY;
43 46
44 public MapBlockData() 47 public MapBlockData()
45 { 48 {
46 } 49 }
50
51 public OSDMap ToOSD()
52 {
53 OSDMap map = new OSDMap();
54 map["X"] = X;
55 map["Y"] = Y;
56 map["SizeX"] = SizeX;
57 map["SizeY"] = SizeY;
58 map["Name"] = Name;
59 map["Access"] = Access;
60 map["RegionFlags"] = RegionFlags;
61 map["WaterHeight"] = WaterHeight;
62 map["MapImageID"] = MapImageId;
63 return map;
64 }
47 } 65 }
48} 66}
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 @@
26 */ 26 */
27 27
28using OpenMetaverse; 28using OpenMetaverse;
29using OpenMetaverse.StructuredData;
29 30
30namespace OpenSim.Framework 31namespace OpenSim.Framework
31{ 32{
@@ -37,5 +38,37 @@ namespace OpenSim.Framework
37 public int Extra; 38 public int Extra;
38 public int Extra2; 39 public int Extra2;
39 public string name; 40 public string name;
41
42 public mapItemReply(uint pX, uint pY, UUID pId, string pName, int pExt1, int pExt2)
43 {
44 x = pX;
45 y = pY;
46 id = pId;
47 name = pName;
48 Extra = pExt1;
49 Extra2 = pExt2;
50 }
51
52 public OSDMap ToOSD()
53 {
54 OSDMap map = new OSDMap();
55 map["X"] = OSD.FromInteger((int)x);
56 map["Y"] = OSD.FromInteger((int)y);
57 map["ID"] = OSD.FromUUID(id);
58 map["Name"] = OSD.FromString(name);
59 map["Extra"] = OSD.FromInteger(Extra);
60 map["Extra2"] = OSD.FromInteger(Extra2);
61 return map;
62 }
63
64 public void FromOSD(OSDMap map)
65 {
66 x = (uint) map["X"].AsInteger();
67 y = (uint) map["Y"].AsInteger();
68 id = map["ID"].AsUUID();
69 Extra = map["Extra"].AsInteger();
70 Extra2 = map["Extra2"].AsInteger();
71 name = map["Name"].AsString();
72 }
40 } 73 }
41} 74}
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 @@
1using System;
2using System.Diagnostics;
3
4namespace OpenSim.Framework
5{
6 /// <summary>
7 /// A MetricsCollector for 'long' values.
8 /// </summary>
9 public class MetricsCollectorLong : MetricsCollector<long>
10 {
11 public MetricsCollectorLong(int windowSize, int numBuckets)
12 : base(windowSize, numBuckets)
13 {
14 }
15
16 protected override long GetZero() { return 0; }
17
18 protected override long Add(long a, long b) { return a + b; }
19 }
20
21
22 /// <summary>
23 /// A MetricsCollector for time spans.
24 /// </summary>
25 public class MetricsCollectorTime : MetricsCollectorLong
26 {
27 public MetricsCollectorTime(int windowSize, int numBuckets)
28 : base(windowSize, numBuckets)
29 {
30 }
31
32 public void AddSample(Stopwatch timer)
33 {
34 long ticks = timer.ElapsedTicks;
35 if (ticks > 0)
36 AddSample(ticks);
37 }
38
39 public TimeSpan GetSumTime()
40 {
41 return TimeSpan.FromMilliseconds((GetSum() * 1000) / Stopwatch.Frequency);
42 }
43 }
44
45
46 struct MetricsBucket<T>
47 {
48 public T value;
49 public int count;
50 }
51
52
53 /// <summary>
54 /// Collects metrics in a sliding window.
55 /// </summary>
56 /// <remarks>
57 /// MetricsCollector provides the current Sum of the metrics that it collects. It can easily be extended
58 /// to provide the Average, too. It uses a sliding window to keep these values current.
59 ///
60 /// This class is not thread-safe.
61 ///
62 /// Subclass MetricsCollector to have it use a concrete value type. Override the abstract methods.
63 /// </remarks>
64 public abstract class MetricsCollector<T>
65 {
66 private int bucketSize; // e.g. 3,000 ms
67
68 private MetricsBucket<T>[] buckets;
69
70 private int NumBuckets { get { return buckets.Length; } }
71
72
73 // The number of the current bucket, if we had an infinite number of buckets and didn't have to wrap around
74 long curBucketGlobal;
75
76 // The total of all the buckets
77 T totalSum;
78 int totalCount;
79
80
81 /// <summary>
82 /// Returns the default (zero) value.
83 /// </summary>
84 /// <returns></returns>
85 protected abstract T GetZero();
86
87 /// <summary>
88 /// Adds two values.
89 /// </summary>
90 protected abstract T Add(T a, T b);
91
92
93 /// <summary>
94 /// Creates a MetricsCollector.
95 /// </summary>
96 /// <param name="windowSize">The period of time over which to collect the metrics, in ms. E.g.: 30,000.</param>
97 /// <param name="numBuckets">The number of buckets to divide the samples into. E.g.: 10. Using more buckets
98 /// smooths the jarring that occurs whenever we drop an old bucket, but uses more memory.</param>
99 public MetricsCollector(int windowSize, int numBuckets)
100 {
101 bucketSize = windowSize / numBuckets;
102 buckets = new MetricsBucket<T>[numBuckets];
103 Reset();
104 }
105
106 public void Reset()
107 {
108 ZeroBuckets(0, NumBuckets);
109 curBucketGlobal = GetNow() / bucketSize;
110 totalSum = GetZero();
111 totalCount = 0;
112 }
113
114 public void AddSample(T sample)
115 {
116 MoveWindow();
117
118 int curBucket = (int)(curBucketGlobal % NumBuckets);
119 buckets[curBucket].value = Add(buckets[curBucket].value, sample);
120 buckets[curBucket].count++;
121
122 totalSum = Add(totalSum, sample);
123 totalCount++;
124 }
125
126 /// <summary>
127 /// Returns the total values in the collection window.
128 /// </summary>
129 public T GetSum()
130 {
131 // It might have been a while since we last added a sample, so we may need to adjust the window
132 MoveWindow();
133
134 return totalSum;
135 }
136
137 /// <summary>
138 /// Returns the current time in ms.
139 /// </summary>
140 private long GetNow()
141 {
142 return DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
143 }
144
145 /// <summary>
146 /// Clears the values in buckets [offset, offset+num)
147 /// </summary>
148 private void ZeroBuckets(int offset, int num)
149 {
150 for (int i = 0; i < num; i++)
151 {
152 buckets[offset + i].value = GetZero();
153 buckets[offset + i].count = 0;
154 }
155 }
156
157 /// <summary>
158 /// Adjusts the buckets so that the "current bucket" corresponds to the current time.
159 /// This may require dropping old buckets.
160 /// </summary>
161 /// <remarks>
162 /// This method allows for the possibility that we don't get new samples for each bucket, so the
163 /// new bucket may be some distance away from the last used bucket.
164 /// </remarks>
165 private void MoveWindow()
166 {
167 long newBucketGlobal = GetNow() / bucketSize;
168 long bucketsDistance = newBucketGlobal - curBucketGlobal;
169
170 if (bucketsDistance == 0)
171 {
172 // We're still on the same bucket as before
173 return;
174 }
175
176 if (bucketsDistance >= NumBuckets)
177 {
178 // Discard everything
179 Reset();
180 return;
181 }
182
183 int curBucket = (int)(curBucketGlobal % NumBuckets);
184 int newBucket = (int)(newBucketGlobal % NumBuckets);
185
186
187 // Clear all the buckets in this range: (cur, new]
188 int numToClear = (int)bucketsDistance;
189
190 if (curBucket < NumBuckets - 1)
191 {
192 // Clear buckets at the end of the window
193 int num = Math.Min((int)bucketsDistance, NumBuckets - (curBucket + 1));
194 ZeroBuckets(curBucket + 1, num);
195 numToClear -= num;
196 }
197
198 if (numToClear > 0)
199 {
200 // Clear buckets at the beginning of the window
201 ZeroBuckets(0, numToClear);
202 }
203
204 // Move the "current bucket" pointer
205 curBucketGlobal = newBucketGlobal;
206
207 RecalcTotal();
208 }
209
210 private void RecalcTotal()
211 {
212 totalSum = GetZero();
213 totalCount = 0;
214
215 for (int i = 0; i < NumBuckets; i++)
216 {
217 totalSum = Add(totalSum, buckets[i].value);
218 totalCount += buckets[i].count;
219 }
220 }
221
222 }
223}
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 @@
28using System; 28using System;
29using System.Timers; 29using System.Timers;
30 30
31using OpenMetaverse.StructuredData;
32
31namespace OpenSim.Framework.Monitoring 33namespace OpenSim.Framework.Monitoring
32{ 34{
33 /// <summary> 35 /// <summary>
@@ -100,5 +102,29 @@ Asset requests yesterday : {3} ({4} per hour) of which {5} were not found",
100 AssetRequestsToday, assetRequestsTodayPerHour, AssetRequestsNotFoundToday, 102 AssetRequestsToday, assetRequestsTodayPerHour, AssetRequestsNotFoundToday,
101 AssetRequestsYesterday, assetRequestsYesterdayPerHour, AssetRequestsNotFoundYesterday); 103 AssetRequestsYesterday, assetRequestsYesterdayPerHour, AssetRequestsNotFoundYesterday);
102 } 104 }
105
106 public override string XReport(string uptime, string version)
107 {
108 return OSDParser.SerializeJsonString(OReport(uptime, version));
109 }
110
111 public override OSDMap OReport(string uptime, string version)
112 {
113 double elapsedHours = (DateTime.Now - startTime).TotalHours;
114 if (elapsedHours <= 0) { elapsedHours = 1; } // prevent divide by zero
115
116 long assetRequestsTodayPerHour = (long)Math.Round(AssetRequestsToday / elapsedHours);
117 long assetRequestsYesterdayPerHour = (long)Math.Round(AssetRequestsYesterday / 24.0);
118
119 OSDMap ret = new OSDMap();
120 ret.Add("AssetRequestsToday", OSD.FromLong(AssetRequestsToday));
121 ret.Add("AssetRequestsTodayPerHour", OSD.FromLong(assetRequestsTodayPerHour));
122 ret.Add("AssetRequestsNotFoundToday", OSD.FromLong(AssetRequestsNotFoundToday));
123 ret.Add("AssetRequestsYesterday", OSD.FromLong(AssetRequestsYesterday));
124 ret.Add("AssetRequestsYesterdayPerHour", OSD.FromLong(assetRequestsYesterdayPerHour));
125 ret.Add("AssetRequestsNotFoundYesterday", OSD.FromLong(assetRequestsNotFoundYesterday));
126
127 return ret;
128 }
103 } 129 }
104} 130}
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 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -45,16 +45,16 @@ namespace OpenSim.Framework.Monitoring
45 sb.Append(Environment.NewLine); 45 sb.Append(Environment.NewLine);
46 46
47 sb.AppendFormat( 47 sb.AppendFormat(
48 "Allocated to OpenSim objects: {0} MB\n", 48 "Heap allocated to OpenSim : {0} MB\n",
49 Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); 49 Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
50 50
51 sb.AppendFormat( 51 sb.AppendFormat(
52 "OpenSim last object memory churn : {0} MB/s\n", 52 "Last heap allocation rate : {0} MB/s\n",
53 Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3)); 53 Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
54 54
55 sb.AppendFormat( 55 sb.AppendFormat(
56 "OpenSim average object memory churn : {0} MB/s\n", 56 "Average heap allocation rate: {0} MB/s\n",
57 Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3)); 57 Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
58 58
59 sb.AppendFormat( 59 sb.AppendFormat(
60 "Process memory : {0} MB\n", 60 "Process memory : {0} MB\n",
@@ -67,5 +67,12 @@ namespace OpenSim.Framework.Monitoring
67 { 67 {
68 return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ; 68 return (string) Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0).ToString() ;
69 } 69 }
70
71 public virtual OSDMap OReport(string uptime, string version)
72 {
73 OSDMap ret = new OSDMap();
74 ret.Add("TotalMemory", new OSDReal(Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)));
75 return ret;
76 }
70 } 77 }
71} 78}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Text;
30
31namespace OpenSim.Framework.Monitoring
32{
33 public class Check
34 {
35// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
36
37 public static readonly char[] DisallowedShortNameCharacters = { '.' };
38
39 /// <summary>
40 /// Category of this stat (e.g. cache, scene, etc).
41 /// </summary>
42 public string Category { get; private set; }
43
44 /// <summary>
45 /// Containing name for this stat.
46 /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
47 /// us with a to-be-resolved problem of non-unique region names).
48 /// </summary>
49 /// <value>
50 /// The container.
51 /// </value>
52 public string Container { get; private set; }
53
54 /// <summary>
55 /// Action used to check whether alert should go off.
56 /// </summary>
57 /// <remarks>
58 /// Should return true if check passes. False otherwise.
59 /// </remarks>
60 public Func<Check, bool> CheckFunc { get; private set; }
61
62 /// <summary>
63 /// Message from the last failure, if any. If there is no message or no failure then will be null.
64 /// </summary>
65 /// <remarks>
66 /// Should be set by the CheckFunc when applicable.
67 /// </remarks>
68 public string LastFailureMessage { get; set; }
69
70 public StatVerbosity Verbosity { get; private set; }
71 public string ShortName { get; private set; }
72 public string Name { get; private set; }
73 public string Description { get; private set; }
74
75 public Check(
76 string shortName,
77 string name,
78 string description,
79 string category,
80 string container,
81 Func<Check, bool> checkFunc,
82 StatVerbosity verbosity)
83 {
84 if (ChecksManager.SubCommands.Contains(category))
85 throw new Exception(
86 string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category));
87
88 foreach (char c in DisallowedShortNameCharacters)
89 {
90 if (shortName.IndexOf(c) != -1)
91 throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c));
92 }
93
94 ShortName = shortName;
95 Name = name;
96 Description = description;
97 Category = category;
98 Container = container;
99 CheckFunc = checkFunc;
100 Verbosity = verbosity;
101 }
102
103 public bool CheckIt()
104 {
105 return CheckFunc(this);
106 }
107
108 public virtual string ToConsoleString()
109 {
110 return string.Format(
111 "{0}.{1}.{2} - {3}",
112 Category,
113 Container,
114 ShortName,
115 Description);
116 }
117 }
118} \ 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33using log4net;
34
35namespace OpenSim.Framework.Monitoring
36{
37 /// <summary>
38 /// Static class used to register/deregister checks on runtime conditions.
39 /// </summary>
40 public static class ChecksManager
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 // Subcommand used to list other stats.
45 public const string ListSubCommand = "list";
46
47 // All subcommands
48 public static HashSet<string> SubCommands = new HashSet<string> { ListSubCommand };
49
50 /// <summary>
51 /// Checks categorized by category/container/shortname
52 /// </summary>
53 /// <remarks>
54 /// Do not add or remove directly from this dictionary.
55 /// </remarks>
56 public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>> RegisteredChecks
57 = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>>();
58
59 public static void RegisterConsoleCommands(ICommandConsole console)
60 {
61 console.Commands.AddCommand(
62 "General",
63 false,
64 "show checks",
65 "show checks",
66 "Show checks configured for this server",
67 "If no argument is specified then info on all checks will be shown.\n"
68 + "'list' argument will show check categories.\n"
69 + "THIS FACILITY IS EXPERIMENTAL",
70 HandleShowchecksCommand);
71 }
72
73 public static void HandleShowchecksCommand(string module, string[] cmd)
74 {
75 ICommandConsole con = MainConsole.Instance;
76
77 if (cmd.Length > 2)
78 {
79 foreach (string name in cmd.Skip(2))
80 {
81 string[] components = name.Split('.');
82
83 string categoryName = components[0];
84// string containerName = components.Length > 1 ? components[1] : null;
85
86 if (categoryName == ListSubCommand)
87 {
88 con.Output("check categories available are:");
89
90 foreach (string category in RegisteredChecks.Keys)
91 con.OutputFormat(" {0}", category);
92 }
93// else
94// {
95// SortedDictionary<string, SortedDictionary<string, Check>> category;
96// if (!Registeredchecks.TryGetValue(categoryName, out category))
97// {
98// con.OutputFormat("No such category as {0}", categoryName);
99// }
100// else
101// {
102// if (String.IsNullOrEmpty(containerName))
103// {
104// OutputConfiguredToConsole(con, category);
105// }
106// else
107// {
108// SortedDictionary<string, Check> container;
109// if (category.TryGetValue(containerName, out container))
110// {
111// OutputContainerChecksToConsole(con, container);
112// }
113// else
114// {
115// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
116// }
117// }
118// }
119// }
120 }
121 }
122 else
123 {
124 OutputAllChecksToConsole(con);
125 }
126 }
127
128 /// <summary>
129 /// Registers a statistic.
130 /// </summary>
131 /// <param name='stat'></param>
132 /// <returns></returns>
133 public static bool RegisterCheck(Check check)
134 {
135 SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
136 SortedDictionary<string, Check> container = null, newContainer;
137
138 lock (RegisteredChecks)
139 {
140 // Check name is not unique across category/container/shortname key.
141 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
142 // in a class are run in the same instance of the VM.
143 if (TryGetCheckParents(check, out category, out container))
144 return false;
145
146 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
147 // This means that we don't need to lock or copy them on iteration, which will be a much more
148 // common operation after startup.
149 if (container != null)
150 newContainer = new SortedDictionary<string, Check>(container);
151 else
152 newContainer = new SortedDictionary<string, Check>();
153
154 if (category != null)
155 newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
156 else
157 newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>();
158
159 newContainer[check.ShortName] = check;
160 newCategory[check.Container] = newContainer;
161 RegisteredChecks[check.Category] = newCategory;
162 }
163
164 return true;
165 }
166
167 /// <summary>
168 /// Deregister an check
169 /// </summary>>
170 /// <param name='stat'></param>
171 /// <returns></returns>
172 public static bool DeregisterCheck(Check check)
173 {
174 SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
175 SortedDictionary<string, Check> container = null, newContainer;
176
177 lock (RegisteredChecks)
178 {
179 if (!TryGetCheckParents(check, out category, out container))
180 return false;
181
182 newContainer = new SortedDictionary<string, Check>(container);
183 newContainer.Remove(check.ShortName);
184
185 newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
186 newCategory.Remove(check.Container);
187
188 newCategory[check.Container] = newContainer;
189 RegisteredChecks[check.Category] = newCategory;
190
191 return true;
192 }
193 }
194
195 public static bool TryGetCheckParents(
196 Check check,
197 out SortedDictionary<string, SortedDictionary<string, Check>> category,
198 out SortedDictionary<string, Check> container)
199 {
200 category = null;
201 container = null;
202
203 lock (RegisteredChecks)
204 {
205 if (RegisteredChecks.TryGetValue(check.Category, out category))
206 {
207 if (category.TryGetValue(check.Container, out container))
208 {
209 if (container.ContainsKey(check.ShortName))
210 return true;
211 }
212 }
213 }
214
215 return false;
216 }
217
218 public static void CheckChecks()
219 {
220 lock (RegisteredChecks)
221 {
222 foreach (SortedDictionary<string, SortedDictionary<string, Check>> category in RegisteredChecks.Values)
223 {
224 foreach (SortedDictionary<string, Check> container in category.Values)
225 {
226 foreach (Check check in container.Values)
227 {
228 if (!check.CheckIt())
229 m_log.WarnFormat(
230 "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage);
231 }
232 }
233 }
234 }
235 }
236
237 private static void OutputAllChecksToConsole(ICommandConsole con)
238 {
239 foreach (var category in RegisteredChecks.Values)
240 {
241 OutputCategoryChecksToConsole(con, category);
242 }
243 }
244
245 private static void OutputCategoryChecksToConsole(
246 ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Check>> category)
247 {
248 foreach (var container in category.Values)
249 {
250 OutputContainerChecksToConsole(con, container);
251 }
252 }
253
254 private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary<string, Check> container)
255 {
256 foreach (Check check in container.Values)
257 {
258 con.Output(check.ToConsoleString());
259 }
260 }
261 }
262} \ 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 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenMetaverse.StructuredData;
29
28namespace OpenSim.Framework.Monitoring 30namespace OpenSim.Framework.Monitoring
29{ 31{
30 /// <summary> 32 /// <summary>
@@ -45,5 +47,12 @@ namespace OpenSim.Framework.Monitoring
45 /// A <see cref="System.String"/> 47 /// A <see cref="System.String"/>
46 /// </returns> 48 /// </returns>
47 string XReport(string uptime, string version); 49 string XReport(string uptime, string version);
50
51 /// <summary>
52 /// Report back collected statistical information as an OSDMap of key/values
53 /// </summary>
54 /// <returns>
55 /// </returns>
56 OSDMap OReport(string uptime, string version);
48 } 57 }
49} 58}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Concurrent;
30using System.Reflection;
31using System.Threading;
32using log4net;
33using OpenSim.Framework;
34
35namespace OpenSim.Framework.Monitoring
36{
37 public class JobEngine
38 {
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40
41 public int LogLevel { get; set; }
42
43 public string Name { get; private set; }
44
45 public string LoggingName { get; private set; }
46
47 /// <summary>
48 /// Is this engine running?
49 /// </summary>
50 public bool IsRunning { get; private set; }
51
52 /// <summary>
53 /// The current job that the engine is running.
54 /// </summary>
55 /// <remarks>
56 /// Will be null if no job is currently running.
57 /// </remarks>
58 public Job CurrentJob { get; private set; }
59
60 /// <summary>
61 /// Number of jobs waiting to be processed.
62 /// </summary>
63 public int JobsWaiting { get { return m_jobQueue.Count; } }
64
65 /// <summary>
66 /// The timeout in milliseconds to wait for at least one event to be written when the recorder is stopping.
67 /// </summary>
68 public int RequestProcessTimeoutOnStop { get; set; }
69
70 /// <summary>
71 /// Controls whether we need to warn in the log about exceeding the max queue size.
72 /// </summary>
73 /// <remarks>
74 /// This is flipped to false once queue max has been exceeded and back to true when it falls below max, in
75 /// order to avoid spamming the log with lots of warnings.
76 /// </remarks>
77 private bool m_warnOverMaxQueue = true;
78
79 private BlockingCollection<Job> m_jobQueue;
80
81 private CancellationTokenSource m_cancelSource;
82
83 /// <summary>
84 /// Used to signal that we are ready to complete stop.
85 /// </summary>
86 private ManualResetEvent m_finishedProcessingAfterStop = new ManualResetEvent(false);
87
88 public JobEngine(string name, string loggingName)
89 {
90 Name = name;
91 LoggingName = loggingName;
92
93 RequestProcessTimeoutOnStop = 5000;
94 }
95
96 public void Start()
97 {
98 lock (this)
99 {
100 if (IsRunning)
101 return;
102
103 IsRunning = true;
104
105 m_finishedProcessingAfterStop.Reset();
106
107 m_jobQueue = new BlockingCollection<Job>(new ConcurrentQueue<Job>(), 5000);
108 m_cancelSource = new CancellationTokenSource();
109
110 WorkManager.StartThread(
111 ProcessRequests,
112 Name,
113 ThreadPriority.Normal,
114 false,
115 true,
116 null,
117 int.MaxValue);
118 }
119 }
120
121 public void Stop()
122 {
123 lock (this)
124 {
125 try
126 {
127 if (!IsRunning)
128 return;
129
130 IsRunning = false;
131
132 int requestsLeft = m_jobQueue.Count;
133
134 if (requestsLeft <= 0)
135 {
136 m_cancelSource.Cancel();
137 }
138 else
139 {
140 m_log.InfoFormat("[{0}]: Waiting to write {1} events after stop.", LoggingName, requestsLeft);
141
142 while (requestsLeft > 0)
143 {
144 if (!m_finishedProcessingAfterStop.WaitOne(RequestProcessTimeoutOnStop))
145 {
146 // After timeout no events have been written
147 if (requestsLeft == m_jobQueue.Count)
148 {
149 m_log.WarnFormat(
150 "[{0}]: No requests processed after {1} ms wait. Discarding remaining {2} requests",
151 LoggingName, RequestProcessTimeoutOnStop, requestsLeft);
152
153 break;
154 }
155 }
156
157 requestsLeft = m_jobQueue.Count;
158 }
159 }
160 }
161 finally
162 {
163 m_cancelSource.Dispose();
164 }
165 }
166 }
167
168 /// <summary>
169 /// Make a job.
170 /// </summary>
171 /// <remarks>
172 /// We provide this method to replace the constructor so that we can later pool job objects if necessary to
173 /// reduce memory churn. Normally one would directly call QueueJob() with parameters anyway.
174 /// </remarks>
175 /// <returns></returns>
176 /// <param name="name">Name.</param>
177 /// <param name="action">Action.</param>
178 /// <param name="commonId">Common identifier.</param>
179 public static Job MakeJob(string name, Action action, string commonId = null)
180 {
181 return Job.MakeJob(name, action, commonId);
182 }
183
184 /// <summary>
185 /// Remove the next job queued for processing.
186 /// </summary>
187 /// <remarks>
188 /// Returns null if there is no next job.
189 /// Will not remove a job currently being performed.
190 /// </remarks>
191 public Job RemoveNextJob()
192 {
193 Job nextJob;
194 m_jobQueue.TryTake(out nextJob);
195
196 return nextJob;
197 }
198
199 /// <summary>
200 /// Queue the job for processing.
201 /// </summary>
202 /// <returns><c>true</c>, if job was queued, <c>false</c> otherwise.</returns>
203 /// <param name="name">Name of job. This appears on the console and in logging.</param>
204 /// <param name="action">Action to perform.</param>
205 /// <param name="commonId">
206 /// Common identifier for a set of jobs. This is allows a set of jobs to be removed
207 /// if required (e.g. all jobs for a given agent. Optional.
208 /// </param>
209 public bool QueueJob(string name, Action action, string commonId = null)
210 {
211 return QueueJob(MakeJob(name, action, commonId));
212 }
213
214 /// <summary>
215 /// Queue the job for processing.
216 /// </summary>
217 /// <returns><c>true</c>, if job was queued, <c>false</c> otherwise.</returns>
218 /// <param name="job">The job</param>
219 /// </param>
220 public bool QueueJob(Job job)
221 {
222 if (m_jobQueue.Count < m_jobQueue.BoundedCapacity)
223 {
224 m_jobQueue.Add(job);
225
226 if (!m_warnOverMaxQueue)
227 m_warnOverMaxQueue = true;
228
229 return true;
230 }
231 else
232 {
233 if (m_warnOverMaxQueue)
234 {
235 m_log.WarnFormat(
236 "[{0}]: Job queue at maximum capacity, not recording job from {1} in {2}",
237 LoggingName, job.Name, Name);
238
239 m_warnOverMaxQueue = false;
240 }
241
242 return false;
243 }
244 }
245
246 private void ProcessRequests()
247 {
248 try
249 {
250 while (IsRunning || m_jobQueue.Count > 0)
251 {
252 try
253 {
254 CurrentJob = m_jobQueue.Take(m_cancelSource.Token);
255 }
256 catch (ObjectDisposedException e)
257 {
258 // If we see this whilst not running then it may be due to a race where this thread checks
259 // IsRunning after the stopping thread sets it to false and disposes of the cancellation source.
260 if (IsRunning)
261 throw e;
262 else
263 break;
264 }
265
266 if (LogLevel >= 1)
267 m_log.DebugFormat("[{0}]: Processing job {1}", LoggingName, CurrentJob.Name);
268
269 try
270 {
271 CurrentJob.Action();
272 }
273 catch (Exception e)
274 {
275 m_log.Error(
276 string.Format(
277 "[{0}]: Job {1} failed, continuing. Exception ", LoggingName, CurrentJob.Name), e);
278 }
279
280 if (LogLevel >= 1)
281 m_log.DebugFormat("[{0}]: Processed job {1}", LoggingName, CurrentJob.Name);
282
283 CurrentJob = null;
284 }
285 }
286 catch (OperationCanceledException)
287 {
288 }
289
290 m_finishedProcessingAfterStop.Set();
291 }
292
293 public class Job
294 {
295 /// <summary>
296 /// Name of the job.
297 /// </summary>
298 /// <remarks>
299 /// This appears on console and debug output.
300 /// </remarks>
301 public string Name { get; private set; }
302
303 /// <summary>
304 /// Common ID for this job.
305 /// </summary>
306 /// <remarks>
307 /// This allows all jobs with a certain common ID (e.g. a client UUID) to be removed en-masse if required.
308 /// Can be null if this is not required.
309 /// </remarks>
310 public string CommonId { get; private set; }
311
312 /// <summary>
313 /// Action to perform when this job is processed.
314 /// </summary>
315 public Action Action { get; private set; }
316
317 private Job(string name, string commonId, Action action)
318 {
319 Name = name;
320 CommonId = commonId;
321 Action = action;
322 }
323
324 /// <summary>
325 /// Make a job. It needs to be separately queued.
326 /// </summary>
327 /// <remarks>
328 /// We provide this method to replace the constructor so that we can pool job objects if necessary to
329 /// to reduce memory churn. Normally one would directly call JobEngine.QueueJob() with parameters anyway.
330 /// </remarks>
331 /// <returns></returns>
332 /// <param name="name">Name.</param>
333 /// <param name="action">Action.</param>
334 /// <param name="commonId">Common identifier.</param>
335 public static Job MakeJob(string name, Action action, string commonId = null)
336 {
337 return new Job(name, commonId, action);
338 }
339 }
340 }
341} \ 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
60 private static bool m_enabled; 60 private static bool m_enabled;
61 61
62 /// <summary> 62 /// <summary>
63 /// Last memory churn in bytes per millisecond. 63 /// Average heap allocation rate in bytes per millisecond.
64 /// </summary> 64 /// </summary>
65 public static double AverageMemoryChurn 65 public static double AverageHeapAllocationRate
66 { 66 {
67 get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } 67 get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
68 } 68 }
69 69
70 /// <summary> 70 /// <summary>
71 /// Average memory churn in bytes per millisecond. 71 /// Last heap allocation in bytes
72 /// </summary> 72 /// </summary>
73 public static double LastMemoryChurn 73 public static double LastHeapAllocationRate
74 { 74 {
75 get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } 75 get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
76 } 76 }
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;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31using System.Linq;
32using System.Net.NetworkInformation;
33using System.Text;
34using System.Threading;
35using log4net;
36using Nini.Config;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework;
39
40namespace OpenSim.Framework.Monitoring
41{
42 public class ServerStatsCollector
43 {
44 private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45 private readonly string LogHeader = "[SERVER STATS]";
46
47 public bool Enabled = false;
48 private static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>();
49
50 public readonly string CategoryServer = "server";
51
52 public readonly string ContainerThreadpool = "threadpool";
53 public readonly string ContainerProcessor = "processor";
54 public readonly string ContainerMemory = "memory";
55 public readonly string ContainerNetwork = "network";
56 public readonly string ContainerProcess = "process";
57
58 public string NetworkInterfaceTypes = "Ethernet";
59
60 readonly int performanceCounterSampleInterval = 500;
61// int lastperformanceCounterSampleTime = 0;
62
63 private class PerfCounterControl
64 {
65 public PerformanceCounter perfCounter;
66 public int lastFetch;
67 public string name;
68 public PerfCounterControl(PerformanceCounter pPc)
69 : this(pPc, String.Empty)
70 {
71 }
72 public PerfCounterControl(PerformanceCounter pPc, string pName)
73 {
74 perfCounter = pPc;
75 lastFetch = 0;
76 name = pName;
77 }
78 }
79
80 PerfCounterControl processorPercentPerfCounter = null;
81
82 // IRegionModuleBase.Initialize
83 public void Initialise(IConfigSource source)
84 {
85 if (source == null)
86 return;
87
88 IConfig cfg = source.Configs["Monitoring"];
89
90 if (cfg != null)
91 Enabled = cfg.GetBoolean("ServerStatsEnabled", true);
92
93 if (Enabled)
94 {
95 NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet");
96 }
97 }
98
99 public void Start()
100 {
101 if (RegisteredStats.Count == 0)
102 RegisterServerStats();
103 }
104
105 public void Close()
106 {
107 if (RegisteredStats.Count > 0)
108 {
109 foreach (Stat stat in RegisteredStats.Values)
110 {
111 StatsManager.DeregisterStat(stat);
112 stat.Dispose();
113 }
114 RegisteredStats.Clear();
115 }
116 }
117
118 private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act)
119 {
120 MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None);
121 }
122
123 private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act, MeasuresOfInterest moi)
124 {
125 string desc = pDesc;
126 if (desc == null)
127 desc = pName;
128 Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug);
129 StatsManager.RegisterStat(stat);
130 RegisteredStats.Add(pName, stat);
131 }
132
133 public void RegisterServerStats()
134 {
135// lastperformanceCounterSampleTime = Util.EnvironmentTickCount();
136 PerformanceCounter tempPC;
137 Stat tempStat;
138 string tempName;
139
140 try
141 {
142 tempName = "CPUPercent";
143 tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total");
144 processorPercentPerfCounter = new PerfCounterControl(tempPC);
145 // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy.
146 tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor,
147 StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter); },
148 StatVerbosity.Info);
149 StatsManager.RegisterStat(tempStat);
150 RegisteredStats.Add(tempName, tempStat);
151
152 MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
153 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds, 3); });
154
155 MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
156 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().UserProcessorTime.TotalSeconds, 3); });
157
158 MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
159 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds, 3); });
160
161 MakeStat("Threads", null, "threads", ContainerProcessor,
162 (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
163 }
164 catch (Exception e)
165 {
166 m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e);
167 }
168
169 MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool,
170 s =>
171 {
172 int workerThreads, iocpThreads;
173 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
174 s.Value = workerThreads;
175 });
176
177 MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool,
178 s =>
179 {
180 int workerThreads, iocpThreads;
181 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
182 s.Value = iocpThreads;
183 });
184
185 if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null)
186 {
187 MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads);
188 MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads);
189 MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems);
190 MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads);
191 MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads);
192 MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks);
193 }
194
195 MakeStat(
196 "HTTPRequestsMade",
197 "Number of outbound HTTP requests made",
198 "requests",
199 ContainerNetwork,
200 s => s.Value = WebUtil.RequestNumber,
201 MeasuresOfInterest.AverageChangeOverTime);
202
203 try
204 {
205 List<string> okInterfaceTypes = new List<string>(NetworkInterfaceTypes.Split(','));
206
207 IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces();
208 foreach (NetworkInterface nic in nics)
209 {
210 if (nic.OperationalStatus != OperationalStatus.Up)
211 continue;
212
213 string nicInterfaceType = nic.NetworkInterfaceType.ToString();
214 if (!okInterfaceTypes.Contains(nicInterfaceType))
215 {
216 m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
217 LogHeader, nic.Name, nicInterfaceType);
218 m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
219 LogHeader, NetworkInterfaceTypes);
220 continue;
221 }
222
223 if (nic.Supports(NetworkInterfaceComponent.IPv4))
224 {
225 IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
226 if (nicStats != null)
227 {
228 MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
229 (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
230 MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
231 (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
232 MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
233 (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
234 }
235 }
236 // TODO: add IPv6 (it may actually happen someday)
237 }
238 }
239 catch (Exception e)
240 {
241 m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
242 }
243
244 MakeStat("ProcessMemory", null, "MB", ContainerMemory,
245 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); });
246 MakeStat("HeapMemory", null, "MB", ContainerMemory,
247 (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); });
248 MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory,
249 (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
250 MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory,
251 (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
252 }
253
254 // Notes on performance counters:
255 // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx
256 // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c
257 // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters
258 private delegate double PerfCounterNextValue();
259
260 private void GetNextValue(Stat stat, PerfCounterControl perfControl)
261 {
262 if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval)
263 {
264 if (perfControl != null && perfControl.perfCounter != null)
265 {
266 try
267 {
268 stat.Value = Math.Round(perfControl.perfCounter.NextValue(), 3);
269 }
270 catch (Exception e)
271 {
272 m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e);
273 }
274
275 perfControl.lastFetch = Util.EnvironmentTickCount();
276 }
277 }
278 }
279
280 // Lookup the nic that goes with this stat and set the value by using a fetch action.
281 // Not sure about closure with delegates inside delegates.
282 private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
283 private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
284 {
285 // Get the one nic that has the name of this stat
286 IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().Where(
287 (network) => network.Name == stat.Description);
288 try
289 {
290 foreach (NetworkInterface nic in nics)
291 {
292 IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
293 if (intrStats != null)
294 {
295 double newVal = Math.Round(getter(intrStats) / factor, 3);
296 stat.Value = newVal;
297 }
298 break;
299 }
300 }
301 catch
302 {
303 // There are times interfaces go away so we just won't update the stat for this
304 m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description);
305 }
306 }
307 }
308
309 public class ServerStatsAggregator : Stat
310 {
311 public ServerStatsAggregator(
312 string shortName,
313 string name,
314 string description,
315 string unitName,
316 string category,
317 string container
318 )
319 : base(
320 shortName,
321 name,
322 description,
323 unitName,
324 category,
325 container,
326 StatType.Push,
327 MeasuresOfInterest.None,
328 null,
329 StatVerbosity.Info)
330 {
331 }
332 public override string ToConsoleString()
333 {
334 StringBuilder sb = new StringBuilder();
335
336 return sb.ToString();
337 }
338
339 public override OSDMap ToOSDMap()
340 {
341 OSDMap ret = new OSDMap();
342
343 return ret;
344 }
345 }
346}
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index aa86202..e4df7ee 100644..100755
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -27,6 +27,8 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
31using System.Linq;
30using System.Text; 32using System.Text;
31using OpenMetaverse; 33using OpenMetaverse;
32using OpenMetaverse.StructuredData; 34using OpenMetaverse.StructuredData;
@@ -39,8 +41,6 @@ namespace OpenSim.Framework.Monitoring
39 /// </summary> 41 /// </summary>
40 public class SimExtraStatsCollector : BaseStatsCollector 42 public class SimExtraStatsCollector : BaseStatsCollector
41 { 43 {
42 private long abnormalClientThreadTerminations;
43
44// private long assetsInCache; 44// private long assetsInCache;
45// private long texturesInCache; 45// private long texturesInCache;
46// private long assetCacheMemoryUsage; 46// private long assetCacheMemoryUsage;
@@ -72,11 +72,11 @@ namespace OpenSim.Framework.Monitoring
72 private volatile float pendingUploads; 72 private volatile float pendingUploads;
73 private volatile float activeScripts; 73 private volatile float activeScripts;
74 private volatile float scriptLinesPerSecond; 74 private volatile float scriptLinesPerSecond;
75 75 private volatile float m_frameDilation;
76 /// <summary> 76 private volatile float m_usersLoggingIn;
77 /// Number of times that a client thread terminated because of an exception 77 private volatile float m_totalGeoPrims;
78 /// </summary> 78 private volatile float m_totalMeshes;
79 public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } } 79 private volatile float m_inUseThreads;
80 80
81// /// <summary> 81// /// <summary>
82// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the 82// /// 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
166 private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors 166 private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors
167 = new Dictionary<UUID, PacketQueueStatsCollector>(); 167 = new Dictionary<UUID, PacketQueueStatsCollector>();
168 168
169 public void AddAbnormalClientThreadTermination()
170 {
171 abnormalClientThreadTerminations++;
172 }
173
174// public void AddAsset(AssetBase asset) 169// public void AddAsset(AssetBase asset)
175// { 170// {
176// assetsInCache++; 171// assetsInCache++;
@@ -260,6 +255,10 @@ namespace OpenSim.Framework.Monitoring
260 { 255 {
261 // FIXME: SimStats shouldn't allow an arbitrary stat packing order (which is inherited from the original 256 // FIXME: SimStats shouldn't allow an arbitrary stat packing order (which is inherited from the original
262 // SimStatsPacket that was being used). 257 // SimStatsPacket that was being used).
258
259 // For an unknown reason the original designers decided not to
260 // include the spare MS statistic inside of this class, this is
261 // located inside the StatsBlock at location 21, thus it is skipped
263 timeDilation = stats.StatsBlock[0].StatValue; 262 timeDilation = stats.StatsBlock[0].StatValue;
264 simFps = stats.StatsBlock[1].StatValue; 263 simFps = stats.StatsBlock[1].StatValue;
265 physicsFps = stats.StatsBlock[2].StatValue; 264 physicsFps = stats.StatsBlock[2].StatValue;
@@ -281,6 +280,11 @@ namespace OpenSim.Framework.Monitoring
281 pendingUploads = stats.StatsBlock[18].StatValue; 280 pendingUploads = stats.StatsBlock[18].StatValue;
282 activeScripts = stats.StatsBlock[19].StatValue; 281 activeScripts = stats.StatsBlock[19].StatValue;
283 scriptLinesPerSecond = stats.StatsBlock[20].StatValue; 282 scriptLinesPerSecond = stats.StatsBlock[20].StatValue;
283 m_frameDilation = stats.StatsBlock[22].StatValue;
284 m_usersLoggingIn = stats.StatsBlock[23].StatValue;
285 m_totalGeoPrims = stats.StatsBlock[24].StatValue;
286 m_totalMeshes = stats.StatsBlock[25].StatValue;
287 m_inUseThreads = stats.StatsBlock[26].StatValue;
284 } 288 }
285 289
286 /// <summary> 290 /// <summary>
@@ -324,10 +328,12 @@ Asset service request failures: {3}" + Environment.NewLine,
324 sb.Append(Environment.NewLine); 328 sb.Append(Environment.NewLine);
325 sb.Append("CONNECTION STATISTICS"); 329 sb.Append("CONNECTION STATISTICS");
326 sb.Append(Environment.NewLine); 330 sb.Append(Environment.NewLine);
327 sb.Append( 331
328 string.Format( 332 List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
329 "Abnormal client thread terminations: {0}" + Environment.NewLine, 333
330 abnormalClientThreadTerminations)); 334 sb.AppendFormat(
335 "Client logouts due to no data receive timeout: {0}\n\n",
336 stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
331 337
332// sb.Append(Environment.NewLine); 338// sb.Append(Environment.NewLine);
333// sb.Append("INVENTORY STATISTICS"); 339// sb.Append("INVENTORY STATISTICS");
@@ -338,7 +344,7 @@ Asset service request failures: {3}" + Environment.NewLine,
338// InventoryServiceRetrievalFailures)); 344// InventoryServiceRetrievalFailures));
339 345
340 sb.Append(Environment.NewLine); 346 sb.Append(Environment.NewLine);
341 sb.Append("FRAME STATISTICS"); 347 sb.Append("SAMPLE FRAME STATISTICS");
342 sb.Append(Environment.NewLine); 348 sb.Append(Environment.NewLine);
343 sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); 349 sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
344 sb.Append(Environment.NewLine); 350 sb.Append(Environment.NewLine);
@@ -359,11 +365,12 @@ Asset service request failures: {3}" + Environment.NewLine,
359 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime, 365 inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
360 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime)); 366 netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
361 367
362 Dictionary<string, Dictionary<string, Stat>> sceneStats; 368 /* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by
363 369 * the two formatted printouts above.
370 SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats;
364 if (StatsManager.TryGetStats("scene", out sceneStats)) 371 if (StatsManager.TryGetStats("scene", out sceneStats))
365 { 372 {
366 foreach (KeyValuePair<string, Dictionary<string, Stat>> kvp in sceneStats) 373 foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats)
367 { 374 {
368 foreach (Stat stat in kvp.Value.Values) 375 foreach (Stat stat in kvp.Value.Values)
369 { 376 {
@@ -374,6 +381,7 @@ Asset service request failures: {3}" + Environment.NewLine,
374 } 381 }
375 } 382 }
376 } 383 }
384 */
377 385
378 /* 386 /*
379 sb.Append(Environment.NewLine); 387 sb.Append(Environment.NewLine);
@@ -405,6 +413,36 @@ Asset service request failures: {3}" + Environment.NewLine,
405 /// <returns></returns> 413 /// <returns></returns>
406 public override string XReport(string uptime, string version) 414 public override string XReport(string uptime, string version)
407 { 415 {
416 return OSDParser.SerializeJsonString(OReport(uptime, version));
417 }
418
419 /// <summary>
420 /// Report back collected statistical information as an OSDMap
421 /// </summary>
422 /// <returns></returns>
423 public override OSDMap OReport(string uptime, string version)
424 {
425 // Get the amount of physical memory, allocated with the instance of this program, in kilobytes;
426 // the working set is the set of memory pages currently visible to this program in physical RAM
427 // memory and includes both shared (e.g. system libraries) and private data
428 double memUsage = Process.GetCurrentProcess().WorkingSet64 / 1024.0;
429
430 // Get the number of threads from the system that are currently
431 // running
432 int numberThreadsRunning = 0;
433 foreach (ProcessThread currentThread in
434 Process.GetCurrentProcess().Threads)
435 {
436 // A known issue with the current process .Threads property is
437 // that it can return null threads, thus don't count those as
438 // running threads and prevent the program function from failing
439 if (currentThread != null &&
440 currentThread.ThreadState == ThreadState.Running)
441 {
442 numberThreadsRunning++;
443 }
444 }
445
408 OSDMap args = new OSDMap(30); 446 OSDMap args = new OSDMap(30);
409// args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache)); 447// args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache));
410// args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}", 448// args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}",
@@ -441,14 +479,28 @@ Asset service request failures: {3}" + Environment.NewLine,
441 args["Memory"] = OSD.FromString (base.XReport (uptime, version)); 479 args["Memory"] = OSD.FromString (base.XReport (uptime, version));
442 args["Uptime"] = OSD.FromString (uptime); 480 args["Uptime"] = OSD.FromString (uptime);
443 args["Version"] = OSD.FromString (version); 481 args["Version"] = OSD.FromString (version);
444
445 string strBuffer = "";
446 strBuffer = OSDParser.SerializeJsonString(args);
447 482
448 return strBuffer; 483 args["FrameDilatn"] = OSD.FromString(String.Format("{0:0.##}", m_frameDilation));
484 args["Logging in Users"] = OSD.FromString(String.Format("{0:0.##}",
485 m_usersLoggingIn));
486 args["GeoPrims"] = OSD.FromString(String.Format("{0:0.##}",
487 m_totalGeoPrims));
488 args["Mesh Objects"] = OSD.FromString(String.Format("{0:0.##}",
489 m_totalMeshes));
490 args["XEngine Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
491 m_inUseThreads));
492 args["Util Thread Count"] = OSD.FromString(String.Format("{0:0.##}",
493 Util.GetSmartThreadPoolInfo().InUseThreads));
494 args["System Thread Count"] = OSD.FromString(String.Format(
495 "{0:0.##}", numberThreadsRunning));
496 args["ProcMem"] = OSD.FromString(String.Format("{0:#,###,###.##}",
497 memUsage));
498
499 return args;
449 } 500 }
450 } 501 }
451 502
503
452 /// <summary> 504 /// <summary>
453 /// Pull packet queue stats from packet queues and report 505 /// Pull packet queue stats from packet queues and report
454 /// </summary> 506 /// </summary>
@@ -474,5 +526,11 @@ Asset service request failures: {3}" + Environment.NewLine,
474 { 526 {
475 return ""; 527 return "";
476 } 528 }
529
530 public OSDMap OReport(string uptime, string version)
531 {
532 OSDMap ret = new OSDMap();
533 return ret;
534 }
477 } 535 }
478} 536}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenMetaverse.StructuredData;
34
35namespace OpenSim.Framework.Monitoring
36{
37// A statistic that wraps a counter.
38// Built this way mostly so histograms and history can be created.
39public class CounterStat : Stat
40{
41 private SortedDictionary<string, EventHistogram> m_histograms;
42 private object counterLock = new object();
43
44 public CounterStat(
45 string shortName,
46 string name,
47 string description,
48 string unitName,
49 string category,
50 string container,
51 StatVerbosity verbosity)
52 : base(shortName, name, description, unitName, category, container, StatType.Push, null, verbosity)
53 {
54 m_histograms = new SortedDictionary<string, EventHistogram>();
55 }
56
57 // Histograms are presumably added at intialization time and the list does not change thereafter.
58 // Thus no locking of the histogram list.
59 public void AddHistogram(string histoName, EventHistogram histo)
60 {
61 m_histograms.Add(histoName, histo);
62 }
63
64 public delegate void ProcessHistogram(string name, EventHistogram histo);
65 public void ForEachHistogram(ProcessHistogram process)
66 {
67 foreach (KeyValuePair<string, EventHistogram> kvp in m_histograms)
68 {
69 process(kvp.Key, kvp.Value);
70 }
71 }
72
73 public void Event()
74 {
75 this.Event(1);
76 }
77
78 // Count the underlying counter.
79 public void Event(int cnt)
80 {
81 lock (counterLock)
82 {
83 base.Value += cnt;
84
85 foreach (EventHistogram histo in m_histograms.Values)
86 {
87 histo.Event(cnt);
88 }
89 }
90 }
91
92 // CounterStat is a basic stat plus histograms
93 public override OSDMap ToOSDMap()
94 {
95 // Get the foundational instance
96 OSDMap map = base.ToOSDMap();
97
98 map["StatType"] = "CounterStat";
99
100 // If there are any histograms, add a new field that is an array of histograms as OSDMaps
101 if (m_histograms.Count > 0)
102 {
103 lock (counterLock)
104 {
105 if (m_histograms.Count > 0)
106 {
107 OSDArray histos = new OSDArray();
108 foreach (EventHistogram histo in m_histograms.Values)
109 {
110 histos.Add(histo.GetHistogramAsOSDMap());
111 }
112 map.Add("Histograms", histos);
113 }
114 }
115 }
116 return map;
117 }
118}
119}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenMetaverse.StructuredData;
34
35namespace OpenSim.Framework.Monitoring
36{
37// Create a time histogram of events. The histogram is built in a wrap-around
38// array of equally distributed buckets.
39// For instance, a minute long histogram of second sized buckets would be:
40// new EventHistogram(60, 1000)
41public class EventHistogram
42{
43 private int m_timeBase;
44 private int m_numBuckets;
45 private int m_bucketMilliseconds;
46 private int m_lastBucket;
47 private int m_totalHistogramMilliseconds;
48 private long[] m_histogram;
49 private object histoLock = new object();
50
51 public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
52 {
53 m_numBuckets = numberOfBuckets;
54 m_bucketMilliseconds = millisecondsPerBucket;
55 m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
56
57 m_histogram = new long[m_numBuckets];
58 Zero();
59 m_lastBucket = 0;
60 m_timeBase = Util.EnvironmentTickCount();
61 }
62
63 public void Event()
64 {
65 this.Event(1);
66 }
67
68 // Record an event at time 'now' in the histogram.
69 public void Event(int cnt)
70 {
71 lock (histoLock)
72 {
73 // The time as displaced from the base of the histogram
74 int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
75
76 // If more than the total time of the histogram, we just start over
77 if (bucketTime > m_totalHistogramMilliseconds)
78 {
79 Zero();
80 m_lastBucket = 0;
81 m_timeBase = Util.EnvironmentTickCount();
82 }
83 else
84 {
85 // To which bucket should we add this event?
86 int bucket = bucketTime / m_bucketMilliseconds;
87
88 // Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
89 while (bucket != m_lastBucket)
90 {
91 // Zero from just after the last bucket to the new bucket or the end
92 for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
93 {
94 m_histogram[jj] = 0;
95 }
96 m_lastBucket = bucket;
97 // If the new bucket is off the end, wrap around to the beginning
98 if (bucket > m_numBuckets)
99 {
100 bucket -= m_numBuckets;
101 m_lastBucket = 0;
102 m_histogram[m_lastBucket] = 0;
103 m_timeBase += m_totalHistogramMilliseconds;
104 }
105 }
106 }
107 m_histogram[m_lastBucket] += cnt;
108 }
109 }
110
111 // Get a copy of the current histogram
112 public long[] GetHistogram()
113 {
114 long[] ret = new long[m_numBuckets];
115 lock (histoLock)
116 {
117 int indx = m_lastBucket + 1;
118 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
119 {
120 if (indx >= m_numBuckets)
121 indx = 0;
122 ret[ii] = m_histogram[indx];
123 }
124 }
125 return ret;
126 }
127
128 public OSDMap GetHistogramAsOSDMap()
129 {
130 OSDMap ret = new OSDMap();
131
132 ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
133 ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
134 ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
135
136 // Compute a number for the first bucket in the histogram.
137 // This will allow readers to know how this histogram relates to any previously read histogram.
138 int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
139 ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
140
141 ret.Add("Values", GetHistogramAsOSDArray());
142
143 return ret;
144 }
145 // Get a copy of the current histogram
146 public OSDArray GetHistogramAsOSDArray()
147 {
148 OSDArray ret = new OSDArray(m_numBuckets);
149 lock (histoLock)
150 {
151 int indx = m_lastBucket + 1;
152 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
153 {
154 if (indx >= m_numBuckets)
155 indx = 0;
156 ret[ii] = OSD.FromLong(m_histogram[indx]);
157 }
158 }
159 return ret;
160 }
161
162 // Zero out the histogram
163 public void Zero()
164 {
165 lock (histoLock)
166 {
167 for (int ii = 0; ii < m_numBuckets; ii++)
168 m_histogram[ii] = 0;
169 }
170 }
171}
172
173}
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;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31 31
32using OpenMetaverse.StructuredData;
33
32namespace OpenSim.Framework.Monitoring 34namespace OpenSim.Framework.Monitoring
33{ 35{
34 public class PercentageStat : Stat 36 public class PercentageStat : Stat
@@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring
84 86
85 return sb.ToString(); 87 return sb.ToString();
86 } 88 }
89
90 // PercentageStat is a basic stat plus percent calc
91 public override OSDMap ToOSDMap()
92 {
93 // Get the foundational instance
94 OSDMap map = base.ToOSDMap();
95
96 map["StatType"] = "PercentageStat";
97
98 map.Add("Antecedent", OSD.FromLong(Antecedent));
99 map.Add("Consequent", OSD.FromLong(Consequent));
100
101 return map;
102 }
87 } 103 }
88} \ No newline at end of file 104} \ 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 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
30using System.Text; 32using System.Text;
33using log4net;
34using OpenMetaverse.StructuredData;
31 35
32namespace OpenSim.Framework.Monitoring 36namespace OpenSim.Framework.Monitoring
33{ 37{
34 /// <summary> 38 /// <summary>
35 /// Holds individual statistic details 39 /// Holds individual statistic details
36 /// </summary> 40 /// </summary>
37 public class Stat 41 public class Stat : IDisposable
38 { 42 {
43// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 public static readonly char[] DisallowedShortNameCharacters = { '.' };
46
39 /// <summary> 47 /// <summary>
40 /// Category of this stat (e.g. cache, scene, etc). 48 /// Category of this stat (e.g. cache, scene, etc).
41 /// </summary> 49 /// </summary>
@@ -93,7 +101,7 @@ namespace OpenSim.Framework.Monitoring
93 /// <remarks> 101 /// <remarks>
94 /// Will be null if no measures of interest require samples. 102 /// Will be null if no measures of interest require samples.
95 /// </remarks> 103 /// </remarks>
96 private static Queue<double> m_samples; 104 private Queue<double> m_samples;
97 105
98 /// <summary> 106 /// <summary>
99 /// Maximum number of statistical samples. 107 /// Maximum number of statistical samples.
@@ -160,6 +168,13 @@ namespace OpenSim.Framework.Monitoring
160 throw new Exception( 168 throw new Exception(
161 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); 169 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
162 170
171 foreach (char c in DisallowedShortNameCharacters)
172 {
173 if (shortName.IndexOf(c) != -1)
174 shortName = shortName.Replace(c, '#');
175// throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
176 }
177
163 ShortName = shortName; 178 ShortName = shortName;
164 Name = name; 179 Name = name;
165 Description = description; 180 Description = description;
@@ -181,6 +196,12 @@ namespace OpenSim.Framework.Monitoring
181 Verbosity = verbosity; 196 Verbosity = verbosity;
182 } 197 }
183 198
199 // IDisposable.Dispose()
200 public virtual void Dispose()
201 {
202 return;
203 }
204
184 /// <summary> 205 /// <summary>
185 /// Record a value in the sample set. 206 /// Record a value in the sample set.
186 /// </summary> 207 /// </summary>
@@ -196,6 +217,8 @@ namespace OpenSim.Framework.Monitoring
196 if (m_samples.Count >= m_maxSamples) 217 if (m_samples.Count >= m_maxSamples)
197 m_samples.Dequeue(); 218 m_samples.Dequeue();
198 219
220// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name);
221
199 m_samples.Enqueue(newValue); 222 m_samples.Enqueue(newValue);
200 } 223 }
201 } 224 }
@@ -203,35 +226,100 @@ namespace OpenSim.Framework.Monitoring
203 public virtual string ToConsoleString() 226 public virtual string ToConsoleString()
204 { 227 {
205 StringBuilder sb = new StringBuilder(); 228 StringBuilder sb = new StringBuilder();
206 sb.AppendFormat("{0}.{1}.{2} : {3}{4}", Category, Container, ShortName, Value, UnitName); 229 sb.AppendFormat(
230 "{0}.{1}.{2} : {3}{4}",
231 Category,
232 Container,
233 ShortName,
234 Value,
235 string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName));
207 236
208 AppendMeasuresOfInterest(sb); 237 AppendMeasuresOfInterest(sb);
209 238
210 return sb.ToString(); 239 return sb.ToString();
211 } 240 }
212 241
213 protected void AppendMeasuresOfInterest(StringBuilder sb) 242 public virtual OSDMap ToOSDMap()
214 { 243 {
215 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) 244 OSDMap ret = new OSDMap();
216 == MeasuresOfInterest.AverageChangeOverTime) 245 ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
246
247 ret.Add("Category", OSD.FromString(Category));
248 ret.Add("Container", OSD.FromString(Container));
249 ret.Add("ShortName", OSD.FromString(ShortName));
250 ret.Add("Name", OSD.FromString(Name));
251 ret.Add("Description", OSD.FromString(Description));
252 ret.Add("UnitName", OSD.FromString(UnitName));
253 ret.Add("Value", OSD.FromReal(Value));
254
255 double lastChangeOverTime, averageChangeOverTime;
256 if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
257 {
258 ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime));
259 ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime));
260 }
261
262 return ret;
263 }
264
265 // Compute the averages over time and return same.
266 // Return 'true' if averages were actually computed. 'false' if no average info.
267 public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
268 {
269 bool ret = false;
270 lastChangeOverTime = 0;
271 averageChangeOverTime = 0;
272
273 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
217 { 274 {
218 double totalChange = 0; 275 double totalChange = 0;
276 double? penultimateSample = null;
219 double? lastSample = null; 277 double? lastSample = null;
220 278
221 lock (m_samples) 279 lock (m_samples)
222 { 280 {
281 // m_log.DebugFormat(
282 // "[STAT]: Samples for {0} are {1}",
283 // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
284
223 foreach (double s in m_samples) 285 foreach (double s in m_samples)
224 { 286 {
225 if (lastSample != null) 287 if (lastSample != null)
226 totalChange += s - (double)lastSample; 288 totalChange += s - (double)lastSample;
227 289
290 penultimateSample = lastSample;
228 lastSample = s; 291 lastSample = s;
229 } 292 }
230 } 293 }
231 294
295 if (lastSample != null && penultimateSample != null)
296 {
297 lastChangeOverTime
298 = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
299 }
300
232 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; 301 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
233 302
234 sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); 303 averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
304 ret = true;
305 }
306
307 return ret;
308 }
309
310 protected void AppendMeasuresOfInterest(StringBuilder sb)
311 {
312 double lastChangeOverTime = 0;
313 double averageChangeOverTime = 0;
314
315 if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
316 {
317 sb.AppendFormat(
318 ", {0:0.##}{1}/s, {2:0.##}{3}/s",
319 lastChangeOverTime,
320 string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName),
321 averageChangeOverTime,
322 string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName));
235 } 323 }
236 } 324 }
237 } 325 }
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Text;
33using System.Timers;
34using log4net;
35
36namespace OpenSim.Framework.Monitoring
37{
38 /// <summary>
39 /// Provides a means to continuously log stats for debugging purposes.
40 /// </summary>
41 public static class StatsLogger
42 {
43 private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger");
44
45 private static Timer m_loggingTimer;
46 private static int m_statsLogIntervalMs = 5000;
47
48 public static void RegisterConsoleCommands(ICommandConsole console)
49 {
50 console.Commands.AddCommand(
51 "General",
52 false,
53 "stats record",
54 "stats record start|stop",
55 "Control whether stats are being regularly recorded to a separate file.",
56 "For debug purposes. Experimental.",
57 HandleStatsRecordCommand);
58
59 console.Commands.AddCommand(
60 "General",
61 false,
62 "stats save",
63 "stats save <path>",
64 "Save stats snapshot to a file. If the file already exists, then the report is appended.",
65 "For debug purposes. Experimental.",
66 HandleStatsSaveCommand);
67 }
68
69 public static void HandleStatsRecordCommand(string module, string[] cmd)
70 {
71 ICommandConsole con = MainConsole.Instance;
72
73 if (cmd.Length != 3)
74 {
75 con.Output("Usage: stats record start|stop");
76 return;
77 }
78
79 if (cmd[2] == "start")
80 {
81 Start();
82 con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs);
83 }
84 else if (cmd[2] == "stop")
85 {
86 Stop();
87 con.Output("Stopped recording stats to file.");
88 }
89 }
90
91 public static void HandleStatsSaveCommand(string module, string[] cmd)
92 {
93 ICommandConsole con = MainConsole.Instance;
94
95 if (cmd.Length != 3)
96 {
97 con.Output("Usage: stats save <path>");
98 return;
99 }
100
101 string path = cmd[2];
102
103 using (StreamWriter sw = new StreamWriter(path, true))
104 {
105 foreach (string line in GetReport())
106 sw.WriteLine(line);
107 }
108
109 MainConsole.Instance.OutputFormat("Stats saved to file {0}", path);
110 }
111
112 public static void Start()
113 {
114 if (m_loggingTimer != null)
115 Stop();
116
117 m_loggingTimer = new Timer(m_statsLogIntervalMs);
118 m_loggingTimer.AutoReset = false;
119 m_loggingTimer.Elapsed += Log;
120 m_loggingTimer.Start();
121 }
122
123 public static void Stop()
124 {
125 if (m_loggingTimer != null)
126 {
127 m_loggingTimer.Stop();
128 }
129 }
130
131 private static void Log(object sender, ElapsedEventArgs e)
132 {
133 foreach (string line in GetReport())
134 m_statsLog.Info(line);
135
136 m_loggingTimer.Start();
137 }
138
139 private static List<string> GetReport()
140 {
141 List<string> lines = new List<string>();
142
143 lines.Add(string.Format("*** STATS REPORT AT {0} ***", DateTime.Now));
144
145 foreach (string report in StatsManager.GetAllStatsReports())
146 lines.Add(report);
147
148 return lines;
149 }
150 }
151} \ 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 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Linq;
30using System.Text; 32using System.Text;
31 33
34using OpenSim.Framework;
35using OpenMetaverse.StructuredData;
36
32namespace OpenSim.Framework.Monitoring 37namespace OpenSim.Framework.Monitoring
33{ 38{
34 /// <summary> 39 /// <summary>
35 /// Singleton used to provide access to statistics reporters 40 /// Static class used to register/deregister/fetch statistics
36 /// </summary> 41 /// </summary>
37 public class StatsManager 42 public static class StatsManager
38 { 43 {
39 // Subcommand used to list other stats. 44 // Subcommand used to list other stats.
40 public const string AllSubCommand = "all"; 45 public const string AllSubCommand = "all";
@@ -51,31 +56,43 @@ namespace OpenSim.Framework.Monitoring
51 /// <remarks> 56 /// <remarks>
52 /// Do not add or remove directly from this dictionary. 57 /// Do not add or remove directly from this dictionary.
53 /// </remarks> 58 /// </remarks>
54 public static Dictionary<string, Dictionary<string, Dictionary<string, Stat>>> RegisteredStats 59 public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats
55 = new Dictionary<string, Dictionary<string, Dictionary<string, Stat>>>(); 60 = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>();
56 61
57 private static AssetStatsCollector assetStats; 62// private static AssetStatsCollector assetStats;
58 private static UserStatsCollector userStats; 63// private static UserStatsCollector userStats;
59 private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); 64// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
60 65
61 public static AssetStatsCollector AssetStats { get { return assetStats; } } 66// public static AssetStatsCollector AssetStats { get { return assetStats; } }
62 public static UserStatsCollector UserStats { get { return userStats; } } 67// public static UserStatsCollector UserStats { get { return userStats; } }
63 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 68 public static SimExtraStatsCollector SimExtraStats { get; set; }
64 69
65 public static void RegisterConsoleCommands(ICommandConsole console) 70 public static void RegisterConsoleCommands(ICommandConsole console)
66 { 71 {
67 console.Commands.AddCommand( 72 console.Commands.AddCommand(
68 "General", 73 "General",
69 false, 74 false,
70 "show stats", 75 "stats show",
71 "show stats [list|all|<category>]", 76 "stats show [list|all|(<category>[.<container>])+",
72 "Show statistical information for this server", 77 "Show statistical information for this server",
73 "If no final argument is specified then legacy statistics information is currently shown.\n" 78 "If no final argument is specified then legacy statistics information is currently shown.\n"
74 + "If list is specified then statistic categories are shown.\n" 79 + "'list' argument will show statistic categories.\n"
75 + "If all is specified then all registered statistics are shown.\n" 80 + "'all' will show all statistics.\n"
76 + "If a category name is specified then only statistics from that category are shown.\n" 81 + "A <category> name will show statistics from that category.\n"
82 + "A <category>.<container> name will show statistics from that category in that container.\n"
83 + "More than one name can be given separated by spaces.\n"
77 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", 84 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
78 HandleShowStatsCommand); 85 HandleShowStatsCommand);
86
87 console.Commands.AddCommand(
88 "General",
89 false,
90 "show stats",
91 "show stats [list|all|(<category>[.<container>])+",
92 "Alias for 'stats show' command",
93 HandleShowStatsCommand);
94
95 StatsLogger.RegisterConsoleCommands(console);
79 } 96 }
80 97
81 public static void HandleShowStatsCommand(string module, string[] cmd) 98 public static void HandleShowStatsCommand(string module, string[] cmd)
@@ -84,105 +101,286 @@ namespace OpenSim.Framework.Monitoring
84 101
85 if (cmd.Length > 2) 102 if (cmd.Length > 2)
86 { 103 {
87 var categoryName = cmd[2]; 104 foreach (string name in cmd.Skip(2))
88
89 if (categoryName == AllSubCommand)
90 { 105 {
91 foreach (var category in RegisteredStats.Values) 106 string[] components = name.Split('.');
107
108 string categoryName = components[0];
109 string containerName = components.Length > 1 ? components[1] : null;
110 string statName = components.Length > 2 ? components[2] : null;
111
112 if (categoryName == AllSubCommand)
92 { 113 {
93 OutputCategoryStatsToConsole(con, category); 114 OutputAllStatsToConsole(con);
94 } 115 }
95 } 116 else if (categoryName == ListSubCommand)
96 else if (categoryName == ListSubCommand)
97 {
98 con.Output("Statistic categories available are:");
99 foreach (string category in RegisteredStats.Keys)
100 con.OutputFormat(" {0}", category);
101 }
102 else
103 {
104 Dictionary<string, Dictionary<string, Stat>> category;
105 if (!RegisteredStats.TryGetValue(categoryName, out category))
106 { 117 {
107 con.OutputFormat("No such category as {0}", categoryName); 118 con.Output("Statistic categories available are:");
119 foreach (string category in RegisteredStats.Keys)
120 con.OutputFormat(" {0}", category);
108 } 121 }
109 else 122 else
110 { 123 {
111 OutputCategoryStatsToConsole(con, category); 124 SortedDictionary<string, SortedDictionary<string, Stat>> category;
125 if (!RegisteredStats.TryGetValue(categoryName, out category))
126 {
127 con.OutputFormat("No such category as {0}", categoryName);
128 }
129 else
130 {
131 if (String.IsNullOrEmpty(containerName))
132 {
133 OutputCategoryStatsToConsole(con, category);
134 }
135 else
136 {
137 SortedDictionary<string, Stat> container;
138 if (category.TryGetValue(containerName, out container))
139 {
140 if (String.IsNullOrEmpty(statName))
141 {
142 OutputContainerStatsToConsole(con, container);
143 }
144 else
145 {
146 Stat stat;
147 if (container.TryGetValue(statName, out stat))
148 {
149 OutputStatToConsole(con, stat);
150 }
151 else
152 {
153 con.OutputFormat(
154 "No such stat {0} in {1}.{2}", statName, categoryName, containerName);
155 }
156 }
157 }
158 else
159 {
160 con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
161 }
162 }
163 }
112 } 164 }
113 } 165 }
114 } 166 }
115 else 167 else
116 { 168 {
117 // Legacy 169 // Legacy
118 con.Output(SimExtraStats.Report()); 170 if (SimExtraStats != null)
171 con.Output(SimExtraStats.Report());
172 else
173 OutputAllStatsToConsole(con);
119 } 174 }
120 } 175 }
121 176
122 private static void OutputCategoryStatsToConsole( 177 public static List<string> GetAllStatsReports()
123 ICommandConsole con, Dictionary<string, Dictionary<string, Stat>> category) 178 {
179 List<string> reports = new List<string>();
180
181 foreach (var category in RegisteredStats.Values)
182 reports.AddRange(GetCategoryStatsReports(category));
183
184 return reports;
185 }
186
187 private static void OutputAllStatsToConsole(ICommandConsole con)
124 { 188 {
189 foreach (string report in GetAllStatsReports())
190 con.Output(report);
191 }
192
193 private static List<string> GetCategoryStatsReports(
194 SortedDictionary<string, SortedDictionary<string, Stat>> category)
195 {
196 List<string> reports = new List<string>();
197
125 foreach (var container in category.Values) 198 foreach (var container in category.Values)
199 reports.AddRange(GetContainerStatsReports(container));
200
201 return reports;
202 }
203
204 private static void OutputCategoryStatsToConsole(
205 ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category)
206 {
207 foreach (string report in GetCategoryStatsReports(category))
208 con.Output(report);
209 }
210
211 private static List<string> GetContainerStatsReports(SortedDictionary<string, Stat> container)
212 {
213 List<string> reports = new List<string>();
214
215 foreach (Stat stat in container.Values)
216 reports.Add(stat.ToConsoleString());
217
218 return reports;
219 }
220
221 private static void OutputContainerStatsToConsole(
222 ICommandConsole con, SortedDictionary<string, Stat> container)
223 {
224 foreach (string report in GetContainerStatsReports(container))
225 con.Output(report);
226 }
227
228 private static void OutputStatToConsole(ICommandConsole con, Stat stat)
229 {
230 con.Output(stat.ToConsoleString());
231 }
232
233 // Creates an OSDMap of the format:
234 // { categoryName: {
235 // containerName: {
236 // statName: {
237 // "Name": name,
238 // "ShortName": shortName,
239 // ...
240 // },
241 // statName: {
242 // "Name": name,
243 // "ShortName": shortName,
244 // ...
245 // },
246 // ...
247 // },
248 // containerName: {
249 // ...
250 // },
251 // ...
252 // },
253 // categoryName: {
254 // ...
255 // },
256 // ...
257 // }
258 // The passed in parameters will filter the categories, containers and stats returned. If any of the
259 // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned.
260 // Case matters.
261 public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName)
262 {
263 OSDMap map = new OSDMap();
264
265 foreach (string catName in RegisteredStats.Keys)
126 { 266 {
127 foreach (Stat stat in container.Values) 267 // Do this category if null spec, "all" subcommand or category name matches passed parameter.
268 // Skip category if none of the above.
269 if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName))
270 continue;
271
272 OSDMap contMap = new OSDMap();
273 foreach (string contName in RegisteredStats[catName].Keys)
128 { 274 {
129 con.Output(stat.ToConsoleString()); 275 if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName))
276 continue;
277
278 OSDMap statMap = new OSDMap();
279
280 SortedDictionary<string, Stat> theStats = RegisteredStats[catName][contName];
281 foreach (string statName in theStats.Keys)
282 {
283 if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName))
284 continue;
285
286 statMap.Add(statName, theStats[statName].ToOSDMap());
287 }
288
289 contMap.Add(contName, statMap);
130 } 290 }
291 map.Add(catName, contMap);
131 } 292 }
293
294 return map;
132 } 295 }
133 296
134 /// <summary> 297 public static Hashtable HandleStatsRequest(Hashtable request)
135 /// Start collecting statistics related to assets.
136 /// Should only be called once.
137 /// </summary>
138 public static AssetStatsCollector StartCollectingAssetStats()
139 { 298 {
140 assetStats = new AssetStatsCollector(); 299 Hashtable responsedata = new Hashtable();
300// string regpath = request["uri"].ToString();
301 int response_code = 200;
302 string contenttype = "text/json";
141 303
142 return assetStats; 304 string pCategoryName = StatsManager.AllSubCommand;
143 } 305 string pContainerName = StatsManager.AllSubCommand;
306 string pStatName = StatsManager.AllSubCommand;
144 307
145 /// <summary> 308 if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString();
146 /// Start collecting statistics related to users. 309 if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString();
147 /// Should only be called once. 310 if (request.ContainsKey("stat")) pStatName = request["stat"].ToString();
148 /// </summary>
149 public static UserStatsCollector StartCollectingUserStats()
150 {
151 userStats = new UserStatsCollector();
152 311
153 return userStats; 312 string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString();
313
314 // If requestor wants it as a callback function, build response as a function rather than just the JSON string.
315 if (request.ContainsKey("callback"))
316 {
317 strOut = request["callback"].ToString() + "(" + strOut + ");";
318 }
319
320 // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}",
321 // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut);
322
323 responsedata["int_response_code"] = response_code;
324 responsedata["content_type"] = contenttype;
325 responsedata["keepalive"] = false;
326 responsedata["str_response_string"] = strOut;
327 responsedata["access_control_allow_origin"] = "*";
328
329 return responsedata;
154 } 330 }
155 331
332// /// <summary>
333// /// Start collecting statistics related to assets.
334// /// Should only be called once.
335// /// </summary>
336// public static AssetStatsCollector StartCollectingAssetStats()
337// {
338// assetStats = new AssetStatsCollector();
339//
340// return assetStats;
341// }
342//
343// /// <summary>
344// /// Start collecting statistics related to users.
345// /// Should only be called once.
346// /// </summary>
347// public static UserStatsCollector StartCollectingUserStats()
348// {
349// userStats = new UserStatsCollector();
350//
351// return userStats;
352// }
353
156 /// <summary> 354 /// <summary>
157 /// Registers a statistic. 355 /// Register a statistic.
158 /// </summary> 356 /// </summary>
159 /// <param name='stat'></param> 357 /// <param name='stat'></param>
160 /// <returns></returns> 358 /// <returns></returns>
161 public static bool RegisterStat(Stat stat) 359 public static bool RegisterStat(Stat stat)
162 { 360 {
163 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory; 361 SortedDictionary<string, SortedDictionary<string, Stat>> category = null, newCategory;
164 Dictionary<string, Stat> container = null, newContainer; 362 SortedDictionary<string, Stat> container = null, newContainer;
165 363
166 lock (RegisteredStats) 364 lock (RegisteredStats)
167 { 365 {
168 // Stat name is not unique across category/container/shortname key. 366 // Stat name is not unique across category/container/shortname key.
169 // XXX: For now just return false. This is to avoid problems in regression tests where all tests 367 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
170 // in a class are run in the same instance of the VM. 368 // in a class are run in the same instance of the VM.
171 if (TryGetStat(stat, out category, out container)) 369 if (TryGetStatParents(stat, out category, out container))
172 return false; 370 return false;
173 371
174 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. 372 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
175 // This means that we don't need to lock or copy them on iteration, which will be a much more 373 // This means that we don't need to lock or copy them on iteration, which will be a much more
176 // common operation after startup. 374 // common operation after startup.
177 if (container != null) 375 if (container != null)
178 newContainer = new Dictionary<string, Stat>(container); 376 newContainer = new SortedDictionary<string, Stat>(container);
179 else 377 else
180 newContainer = new Dictionary<string, Stat>(); 378 newContainer = new SortedDictionary<string, Stat>();
181 379
182 if (category != null) 380 if (category != null)
183 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category); 381 newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>(category);
184 else 382 else
185 newCategory = new Dictionary<string, Dictionary<string, Stat>>(); 383 newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>();
186 384
187 newContainer[stat.ShortName] = stat; 385 newContainer[stat.ShortName] = stat;
188 newCategory[stat.Container] = newContainer; 386 newCategory[stat.Container] = newContainer;
@@ -196,21 +394,21 @@ namespace OpenSim.Framework.Monitoring
196 /// Deregister a statistic 394 /// Deregister a statistic
197 /// </summary>> 395 /// </summary>>
198 /// <param name='stat'></param> 396 /// <param name='stat'></param>
199 /// <returns></returns 397 /// <returns></returns>
200 public static bool DeregisterStat(Stat stat) 398 public static bool DeregisterStat(Stat stat)
201 { 399 {
202 Dictionary<string, Dictionary<string, Stat>> category = null, newCategory; 400 SortedDictionary<string, SortedDictionary<string, Stat>> category = null, newCategory;
203 Dictionary<string, Stat> container = null, newContainer; 401 SortedDictionary<string, Stat> container = null, newContainer;
204 402
205 lock (RegisteredStats) 403 lock (RegisteredStats)
206 { 404 {
207 if (!TryGetStat(stat, out category, out container)) 405 if (!TryGetStatParents(stat, out category, out container))
208 return false; 406 return false;
209 407
210 newContainer = new Dictionary<string, Stat>(container); 408 newContainer = new SortedDictionary<string, Stat>(container);
211 newContainer.Remove(stat.ShortName); 409 newContainer.Remove(stat.ShortName);
212 410
213 newCategory = new Dictionary<string, Dictionary<string, Stat>>(category); 411 newCategory = new SortedDictionary<string, SortedDictionary<string, Stat>>(category);
214 newCategory.Remove(stat.Container); 412 newCategory.Remove(stat.Container);
215 413
216 newCategory[stat.Container] = newContainer; 414 newCategory[stat.Container] = newContainer;
@@ -220,15 +418,70 @@ namespace OpenSim.Framework.Monitoring
220 } 418 }
221 } 419 }
222 420
223 public static bool TryGetStats(string category, out Dictionary<string, Dictionary<string, Stat>> stats) 421 public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
224 { 422 {
225 return RegisteredStats.TryGetValue(category, out stats); 423 stat = null;
424 SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
425
426 lock (RegisteredStats)
427 {
428 if (!TryGetStatsForCategory(category, out categoryStats))
429 return false;
430
431 SortedDictionary<string, Stat> containerStats;
432
433 if (!categoryStats.TryGetValue(container, out containerStats))
434 return false;
435
436 return containerStats.TryGetValue(statShortName, out stat);
437 }
438 }
439
440 public static bool TryGetStatsForCategory(
441 string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
442 {
443 lock (RegisteredStats)
444 return RegisteredStats.TryGetValue(category, out stats);
445 }
446
447 /// <summary>
448 /// Get the same stat for each container in a given category.
449 /// </summary>
450 /// <returns>
451 /// The stats if there were any to fetch. Otherwise null.
452 /// </returns>
453 /// <param name='category'></param>
454 /// <param name='statShortName'></param>
455 public static List<Stat> GetStatsFromEachContainer(string category, string statShortName)
456 {
457 SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
458
459 lock (RegisteredStats)
460 {
461 if (!RegisteredStats.TryGetValue(category, out categoryStats))
462 return null;
463
464 List<Stat> stats = null;
465
466 foreach (SortedDictionary<string, Stat> containerStats in categoryStats.Values)
467 {
468 if (containerStats.ContainsKey(statShortName))
469 {
470 if (stats == null)
471 stats = new List<Stat>();
472
473 stats.Add(containerStats[statShortName]);
474 }
475 }
476
477 return stats;
478 }
226 } 479 }
227 480
228 public static bool TryGetStat( 481 public static bool TryGetStatParents(
229 Stat stat, 482 Stat stat,
230 out Dictionary<string, Dictionary<string, Stat>> category, 483 out SortedDictionary<string, SortedDictionary<string, Stat>> category,
231 out Dictionary<string, Stat> container) 484 out SortedDictionary<string, Stat> container)
232 { 485 {
233 category = null; 486 category = null;
234 container = null; 487 container = null;
@@ -252,9 +505,9 @@ namespace OpenSim.Framework.Monitoring
252 { 505 {
253 lock (RegisteredStats) 506 lock (RegisteredStats)
254 { 507 {
255 foreach (Dictionary<string, Dictionary<string, Stat>> category in RegisteredStats.Values) 508 foreach (SortedDictionary<string, SortedDictionary<string, Stat>> category in RegisteredStats.Values)
256 { 509 {
257 foreach (Dictionary<string, Stat> container in category.Values) 510 foreach (SortedDictionary<string, Stat> container in category.Values)
258 { 511 {
259 foreach (Stat stat in container.Values) 512 foreach (Stat stat in container.Values)
260 { 513 {
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 @@
27 27
28using System.Timers; 28using System.Timers;
29 29
30using OpenMetaverse.StructuredData;
31
30namespace OpenSim.Framework.Monitoring 32namespace OpenSim.Framework.Monitoring
31{ 33{
32 /// <summary> 34 /// <summary>
@@ -88,5 +90,21 @@ namespace OpenSim.Framework.Monitoring
88 Logouts total : {3}", 90 Logouts total : {3}",
89 SuccessfulLogins, SuccessfulLoginsToday, SuccessfulLoginsYesterday, Logouts); 91 SuccessfulLogins, SuccessfulLoginsToday, SuccessfulLoginsYesterday, Logouts);
90 } 92 }
93
94 public override string XReport(string uptime, string version)
95 {
96 return OSDParser.SerializeJsonString(OReport(uptime, version));
97 }
98
99 public override OSDMap OReport(string uptime, string version)
100 {
101 OSDMap ret = new OSDMap();
102 ret.Add("SuccessfulLogins", OSD.FromInteger(SuccessfulLogins));
103 ret.Add("SuccessfulLoginsToday", OSD.FromInteger(SuccessfulLoginsToday));
104 ret.Add("SuccessfulLoginsYesterday", OSD.FromInteger(SuccessfulLoginsYesterday));
105 ret.Add("Logouts", OSD.FromInteger(Logouts));
106
107 return ret;
108 }
91 } 109 }
92} 110}
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
38 /// </summary> 38 /// </summary>
39 public static class Watchdog 39 public static class Watchdog
40 { 40 {
41 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
42
41 /// <summary>Timer interval in milliseconds for the watchdog timer</summary> 43 /// <summary>Timer interval in milliseconds for the watchdog timer</summary>
42 public const double WATCHDOG_INTERVAL_MS = 2500.0d; 44 public const double WATCHDOG_INTERVAL_MS = 2500.0d;
43 45
@@ -82,12 +84,32 @@ namespace OpenSim.Framework.Monitoring
82 /// </summary> 84 /// </summary>
83 public Func<string> AlarmMethod { get; set; } 85 public Func<string> AlarmMethod { get; set; }
84 86
85 public ThreadWatchdogInfo(Thread thread, int timeout) 87 /// <summary>
88 /// Stat structure associated with this thread.
89 /// </summary>
90 public Stat Stat { get; set; }
91
92 public ThreadWatchdogInfo(Thread thread, int timeout, string name)
86 { 93 {
87 Thread = thread; 94 Thread = thread;
88 Timeout = timeout; 95 Timeout = timeout;
89 FirstTick = Environment.TickCount & Int32.MaxValue; 96 FirstTick = Environment.TickCount & Int32.MaxValue;
90 LastTick = FirstTick; 97 LastTick = FirstTick;
98
99 Stat
100 = new Stat(
101 name,
102 string.Format("Last update of thread {0}", name),
103 "",
104 "ms",
105 "server",
106 "thread",
107 StatType.Pull,
108 MeasuresOfInterest.None,
109 stat => stat.Value = Environment.TickCount & Int32.MaxValue - LastTick,
110 StatVerbosity.Debug);
111
112 StatsManager.RegisterStat(Stat);
91 } 113 }
92 114
93 public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi) 115 public ThreadWatchdogInfo(ThreadWatchdogInfo previousTwi)
@@ -100,6 +122,11 @@ namespace OpenSim.Framework.Monitoring
100 AlarmIfTimeout = previousTwi.AlarmIfTimeout; 122 AlarmIfTimeout = previousTwi.AlarmIfTimeout;
101 AlarmMethod = previousTwi.AlarmMethod; 123 AlarmMethod = previousTwi.AlarmMethod;
102 } 124 }
125
126 public void Cleanup()
127 {
128 StatsManager.DeregisterStat(Stat);
129 }
103 } 130 }
104 131
105 /// <summary> 132 /// <summary>
@@ -116,7 +143,7 @@ namespace OpenSim.Framework.Monitoring
116 get { return m_enabled; } 143 get { return m_enabled; }
117 set 144 set
118 { 145 {
119// m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value); 146 // m_log.DebugFormat("[MEMORY WATCHDOG]: Setting MemoryWatchdog.Enabled to {0}", value);
120 147
121 if (value == m_enabled) 148 if (value == m_enabled)
122 return; 149 return;
@@ -132,9 +159,8 @@ namespace OpenSim.Framework.Monitoring
132 m_watchdogTimer.Enabled = m_enabled; 159 m_watchdogTimer.Enabled = m_enabled;
133 } 160 }
134 } 161 }
135 private static bool m_enabled;
136 162
137 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); 163 private static bool m_enabled;
138 private static Dictionary<int, ThreadWatchdogInfo> m_threads; 164 private static Dictionary<int, ThreadWatchdogInfo> m_threads;
139 private static System.Timers.Timer m_watchdogTimer; 165 private static System.Timers.Timer m_watchdogTimer;
140 166
@@ -155,57 +181,19 @@ namespace OpenSim.Framework.Monitoring
155 } 181 }
156 182
157 /// <summary> 183 /// <summary>
158 /// Start a new thread that is tracked by the watchdog timer. 184 /// Add a thread to the watchdog tracker.
159 /// </summary>
160 /// <param name="start">The method that will be executed in a new thread</param>
161 /// <param name="name">A name to give to the new thread</param>
162 /// <param name="priority">Priority to run the thread at</param>
163 /// <param name="isBackground">True to run this thread as a background thread, otherwise false</param>
164 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
165 /// <returns>The newly created Thread object</returns>
166 public static Thread StartThread(
167 ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout)
168 {
169 return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS);
170 }
171
172 /// <summary>
173 /// Start a new thread that is tracked by the watchdog timer
174 /// </summary> 185 /// </summary>
175 /// <param name="start">The method that will be executed in a new thread</param> 186 /// <param name="info">Information about the thread.</info>
176 /// <param name="name">A name to give to the new thread</param> 187 /// <param name="info">Name of the thread.</info>
177 /// <param name="priority">Priority to run the thread at</param> 188 /// <param name="log">If true then creation of thread is logged.</param>
178 /// <param name="isBackground">True to run this thread as a background 189 public static void AddThread(ThreadWatchdogInfo info, string name, bool log = true)
179 /// thread, otherwise false</param>
180 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
181 /// <param name="alarmMethod">
182 /// Alarm method to call if alarmIfTimeout is true and there is a timeout.
183 /// Normally, this will just return some useful debugging information.
184 /// </param>
185 /// <param name="timeout">Number of milliseconds to wait until we issue a warning about timeout.</param>
186 /// <returns>The newly created Thread object</returns>
187 public static Thread StartThread(
188 ThreadStart start, string name, ThreadPriority priority, bool isBackground,
189 bool alarmIfTimeout, Func<string> alarmMethod, int timeout)
190 { 190 {
191 Thread thread = new Thread(start); 191 if (log)
192 thread.Name = name; 192 m_log.DebugFormat(
193 thread.Priority = priority; 193 "[WATCHDOG]: Started tracking thread {0}, ID {1}", name, info.Thread.ManagedThreadId);
194 thread.IsBackground = isBackground;
195
196 ThreadWatchdogInfo twi
197 = new ThreadWatchdogInfo(thread, timeout)
198 { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
199
200 m_log.DebugFormat(
201 "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
202 194
203 lock (m_threads) 195 lock (m_threads)
204 m_threads.Add(twi.Thread.ManagedThreadId, twi); 196 m_threads.Add(info.Thread.ManagedThreadId, info);
205
206 thread.Start();
207
208 return thread;
209 } 197 }
210 198
211 /// <summary> 199 /// <summary>
@@ -219,25 +207,28 @@ namespace OpenSim.Framework.Monitoring
219 /// <summary> 207 /// <summary>
220 /// Stops watchdog tracking on the current thread 208 /// Stops watchdog tracking on the current thread
221 /// </summary> 209 /// </summary>
210 /// <param name="log">If true then normal events in thread removal are not logged.</param>
222 /// <returns> 211 /// <returns>
223 /// True if the thread was removed from the list of tracked 212 /// True if the thread was removed from the list of tracked
224 /// threads, otherwise false 213 /// threads, otherwise false
225 /// </returns> 214 /// </returns>
226 public static bool RemoveThread() 215 public static bool RemoveThread(bool log = true)
227 { 216 {
228 return RemoveThread(Thread.CurrentThread.ManagedThreadId); 217 return RemoveThread(Thread.CurrentThread.ManagedThreadId, log);
229 } 218 }
230 219
231 private static bool RemoveThread(int threadID) 220 private static bool RemoveThread(int threadID, bool log = true)
232 { 221 {
233 lock (m_threads) 222 lock (m_threads)
234 { 223 {
235 ThreadWatchdogInfo twi; 224 ThreadWatchdogInfo twi;
236 if (m_threads.TryGetValue(threadID, out twi)) 225 if (m_threads.TryGetValue(threadID, out twi))
237 { 226 {
238 m_log.DebugFormat( 227 if (log)
239 "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId); 228 m_log.DebugFormat(
229 "[WATCHDOG]: Removing thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
240 230
231 twi.Cleanup();
241 m_threads.Remove(threadID); 232 m_threads.Remove(threadID);
242 233
243 return true; 234 return true;
@@ -293,7 +284,7 @@ namespace OpenSim.Framework.Monitoring
293 } 284 }
294 catch { } 285 catch { }
295 } 286 }
296 287
297 /// <summary> 288 /// <summary>
298 /// Get currently watched threads for diagnostic purposes 289 /// Get currently watched threads for diagnostic purposes
299 /// </summary> 290 /// </summary>
@@ -380,6 +371,7 @@ namespace OpenSim.Framework.Monitoring
380 if (MemoryWatchdog.Enabled) 371 if (MemoryWatchdog.Enabled)
381 MemoryWatchdog.Update(); 372 MemoryWatchdog.Update();
382 373
374 ChecksManager.CheckChecks();
383 StatsManager.RecordStats(); 375 StatsManager.RecordStats();
384 376
385 m_watchdogTimer.Start(); 377 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Reflection;
30using System.Threading;
31using log4net;
32
33namespace OpenSim.Framework.Monitoring
34{
35 /// <summary>
36 /// Manages various work items in the simulator.
37 /// </summary>
38 /// <remarks>
39 /// Currently, here work can be started
40 /// * As a long-running and monitored thread.
41 /// * In a thread that will never timeout but where the job is expected to eventually complete.
42 /// * In a threadpool thread that will timeout if it takes a very long time to complete (> 10 mins).
43 /// * As a job which will be run in a single-threaded job engine. Such jobs must not incorporate delays (sleeps,
44 /// network waits, etc.).
45 ///
46 /// This is an evolving approach to better manage the work that OpenSimulator is asked to do from a very diverse
47 /// range of sources (client actions, incoming network, outgoing network calls, etc.).
48 ///
49 /// Util.FireAndForget is still available to insert jobs in the threadpool, though this is equivalent to
50 /// WorkManager.RunInThreadPool().
51 /// </remarks>
52 public static class WorkManager
53 {
54 private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
55
56 public static JobEngine JobEngine { get; private set; }
57
58 static WorkManager()
59 {
60 JobEngine = new JobEngine("Non-blocking non-critical job engine", "JOB ENGINE");
61
62 StatsManager.RegisterStat(
63 new Stat(
64 "JobsWaiting",
65 "Number of jobs waiting for processing.",
66 "",
67 "",
68 "server",
69 "jobengine",
70 StatType.Pull,
71 MeasuresOfInterest.None,
72 stat => stat.Value = JobEngine.JobsWaiting,
73 StatVerbosity.Debug));
74
75 MainConsole.Instance.Commands.AddCommand(
76 "Debug",
77 false,
78 "debug jobengine",
79 "debug jobengine <start|stop|status|log>",
80 "Start, stop, get status or set logging level of the job engine.",
81 "If stopped then all outstanding jobs are processed immediately.",
82 HandleControlCommand);
83 }
84
85 /// <summary>
86 /// Start a new long-lived thread.
87 /// </summary>
88 /// <param name="start">The method that will be executed in a new thread</param>
89 /// <param name="name">A name to give to the new thread</param>
90 /// <param name="priority">Priority to run the thread at</param>
91 /// <param name="isBackground">True to run this thread as a background thread, otherwise false</param>
92 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
93 /// <param name="log">If true then creation of thread is logged.</param>
94 /// <returns>The newly created Thread object</returns>
95 public static Thread StartThread(
96 ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, bool log = true)
97 {
98 return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS, log);
99 }
100
101 /// <summary>
102 /// Start a new thread that is tracked by the watchdog
103 /// </summary>
104 /// <param name="start">The method that will be executed in a new thread</param>
105 /// <param name="name">A name to give to the new thread</param>
106 /// <param name="priority">Priority to run the thread at</param>
107 /// <param name="isBackground">True to run this thread as a background
108 /// thread, otherwise false</param>
109 /// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
110 /// <param name="alarmMethod">
111 /// Alarm method to call if alarmIfTimeout is true and there is a timeout.
112 /// Normally, this will just return some useful debugging information.
113 /// </param>
114 /// <param name="timeout">Number of milliseconds to wait until we issue a warning about timeout.</param>
115 /// <param name="log">If true then creation of thread is logged.</param>
116 /// <returns>The newly created Thread object</returns>
117 public static Thread StartThread(
118 ThreadStart start, string name, ThreadPriority priority, bool isBackground,
119 bool alarmIfTimeout, Func<string> alarmMethod, int timeout, bool log = true)
120 {
121 Thread thread = new Thread(start);
122 thread.Priority = priority;
123 thread.IsBackground = isBackground;
124
125 Watchdog.ThreadWatchdogInfo twi
126 = new Watchdog.ThreadWatchdogInfo(thread, timeout, name)
127 { AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
128
129 Watchdog.AddThread(twi, name, log:log);
130
131 thread.Start();
132 thread.Name = name;
133
134 return thread;
135 }
136
137 /// <summary>
138 /// Run the callback in a new thread immediately. If the thread exits with an exception log it but do
139 /// not propogate it.
140 /// </summary>
141 /// <param name="callback">Code for the thread to execute.</param>
142 /// <param name="obj">Object to pass to the thread.</param>
143 /// <param name="name">Name of the thread</param>
144 public static void RunInThread(WaitCallback callback, object obj, string name, bool log = false)
145 {
146 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
147 {
148 Culture.SetCurrentCulture();
149 callback(obj);
150 return;
151 }
152
153 ThreadStart ts = new ThreadStart(delegate()
154 {
155 try
156 {
157 Culture.SetCurrentCulture();
158 callback(obj);
159 Watchdog.RemoveThread(log:false);
160 }
161 catch (Exception e)
162 {
163 m_log.Error(string.Format("[WATCHDOG]: Exception in thread {0}.", name), e);
164 }
165 });
166
167 StartThread(ts, name, ThreadPriority.Normal, true, false, log:log);
168 }
169
170 /// <summary>
171 /// Run the callback via a threadpool thread.
172 /// </summary>
173 /// <remarks>
174 /// Such jobs may run after some delay but must always complete.
175 /// </remarks>
176 /// <param name="callback"></param>
177 /// <param name="obj"></param>
178 /// <param name="name">The name of the job. This is used in monitoring and debugging.</param>
179 public static void RunInThreadPool(System.Threading.WaitCallback callback, object obj, string name)
180 {
181 Util.FireAndForget(callback, obj, name);
182 }
183
184 /// <summary>
185 /// Run a job.
186 /// </summary>
187 /// <remarks>
188 /// This differs from direct scheduling (e.g. Util.FireAndForget) in that a job can be run in the job
189 /// engine if it is running, where all jobs are currently performed in sequence on a single thread. This is
190 /// to prevent observed overload and server freeze problems when there are hundreds of connections which all attempt to
191 /// perform work at once (e.g. in conference situations). With lower numbers of connections, the small
192 /// delay in performing jobs in sequence rather than concurrently has not been notiecable in testing, though a future more
193 /// sophisticated implementation could perform jobs concurrently when the server is under low load.
194 ///
195 /// However, be advised that some callers of this function rely on all jobs being performed in sequence if any
196 /// jobs are performed in sequence (i.e. if jobengine is active or not). Therefore, expanding the jobengine
197 /// beyond a single thread will require considerable thought.
198 ///
199 /// Also, any jobs submitted must be guaranteed to complete within a reasonable timeframe (e.g. they cannot
200 /// incorporate a network delay with a long timeout). At the moment, work that could suffer such issues
201 /// should still be run directly with RunInThread(), Util.FireAndForget(), etc. This is another area where
202 /// the job engine could be improved and so CPU utilization improved by better management of concurrency within
203 /// OpenSimulator.
204 /// </remarks>
205 /// <param name="jobType">General classification for the job (e.g. "RezAttachments").</param>
206 /// <param name="callback">Callback for job.</param>
207 /// <param name="obj">Object to pass to callback when run</param>
208 /// <param name="name">Specific name of job (e.g. "RezAttachments for Joe Bloggs"</param>
209 /// <param name="canRunInThisThread">If set to true then the job may be run in ths calling thread.</param>
210 /// <param name="mustNotTimeout">If the true then the job must never timeout.</param>
211 /// <param name="log">If set to true then extra logging is performed.</param>
212 public static void RunJob(
213 string jobType, WaitCallback callback, object obj, string name,
214 bool canRunInThisThread = false, bool mustNotTimeout = false,
215 bool log = false)
216 {
217 if (Util.FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
218 {
219 Culture.SetCurrentCulture();
220 callback(obj);
221 return;
222 }
223
224 if (JobEngine.IsRunning)
225 JobEngine.QueueJob(name, () => callback(obj));
226 else if (canRunInThisThread)
227 callback(obj);
228 else if (mustNotTimeout)
229 RunInThread(callback, obj, name, log);
230 else
231 Util.FireAndForget(callback, obj, name);
232 }
233
234 private static void HandleControlCommand(string module, string[] args)
235 {
236 // if (SceneManager.Instance.CurrentScene != null && SceneManager.Instance.CurrentScene != m_udpServer.Scene)
237 // return;
238
239 if (args.Length < 3)
240 {
241 MainConsole.Instance.Output("Usage: debug jobengine <stop|start|status|log>");
242 return;
243 }
244
245 string subCommand = args[2];
246
247 if (subCommand == "stop")
248 {
249 JobEngine.Stop();
250 MainConsole.Instance.OutputFormat("Stopped job engine.");
251 }
252 else if (subCommand == "start")
253 {
254 JobEngine.Start();
255 MainConsole.Instance.OutputFormat("Started job engine.");
256 }
257 else if (subCommand == "status")
258 {
259 MainConsole.Instance.OutputFormat("Job engine running: {0}", JobEngine.IsRunning);
260
261 JobEngine.Job job = JobEngine.CurrentJob;
262 MainConsole.Instance.OutputFormat("Current job {0}", job != null ? job.Name : "none");
263
264 MainConsole.Instance.OutputFormat(
265 "Jobs waiting: {0}", JobEngine.IsRunning ? JobEngine.JobsWaiting.ToString() : "n/a");
266 MainConsole.Instance.OutputFormat("Log Level: {0}", JobEngine.LogLevel);
267 }
268 else if (subCommand == "log")
269 {
270 if (args.Length < 4)
271 {
272 MainConsole.Instance.Output("Usage: debug jobengine log <level>");
273 return;
274 }
275
276 // int logLevel;
277 int logLevel = int.Parse(args[3]);
278 // if (ConsoleUtil.TryParseConsoleInt(MainConsole.Instance, args[4], out logLevel))
279 // {
280 JobEngine.LogLevel = logLevel;
281 MainConsole.Instance.OutputFormat("Set debug log level to {0}", JobEngine.LogLevel);
282 // }
283 }
284 else
285 {
286 MainConsole.Instance.OutputFormat("Unrecognized job engine subcommand {0}", subCommand);
287 }
288 }
289 }
290} \ 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Net;
32using System.Reflection;
33using log4net;
34using LukeSkywalker.IPNetwork;
35using Nini.Config;
36
37namespace OpenSim.Framework
38{
39 public class OutboundUrlFilter
40 {
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 public string Name { get; private set; }
44
45 private List<IPNetwork> m_blacklistNetworks;
46 private List<IPEndPoint> m_blacklistEndPoints;
47
48 private List<IPNetwork> m_blacklistExceptionNetworks;
49 private List<IPEndPoint> m_blacklistExceptionEndPoints;
50
51 public OutboundUrlFilter(
52 string name,
53 List<IPNetwork> blacklistNetworks, List<IPEndPoint> blacklistEndPoints,
54 List<IPNetwork> blacklistExceptionNetworks, List<IPEndPoint> blacklistExceptionEndPoints)
55 {
56 Name = name;
57
58 m_blacklistNetworks = blacklistNetworks;
59 m_blacklistEndPoints = blacklistEndPoints;
60 m_blacklistExceptionNetworks = blacklistExceptionNetworks;
61 m_blacklistExceptionEndPoints = blacklistExceptionEndPoints;
62 }
63
64 /// <summary>
65 /// Initializes a new instance of the <see cref="OpenSim.Framework.OutboundUrlFilter"/> class.
66 /// </summary>
67 /// <param name="name">Name of the filter for logging purposes.</param>
68 /// <param name="config">Filter configuration</param>
69 public OutboundUrlFilter(string name, IConfigSource config)
70 {
71 Name = name;
72
73 string configBlacklist
74 = "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";
75 string configBlacklistExceptions = "";
76
77 IConfig networkConfig = config.Configs["Network"];
78
79 if (networkConfig != null)
80 {
81 configBlacklist = networkConfig.GetString("OutboundDisallowForUserScripts", configBlacklist);
82 configBlacklistExceptions
83 = networkConfig.GetString("OutboundDisallowForUserScriptsExcept", configBlacklistExceptions);
84 }
85
86 m_log.DebugFormat(
87 "[OUTBOUND URL FILTER]: OutboundDisallowForUserScripts for {0} is [{1}]", Name, configBlacklist);
88 m_log.DebugFormat(
89 "[OUTBOUND URL FILTER]: OutboundDisallowForUserScriptsExcept for {0} is [{1}]", Name, configBlacklistExceptions);
90
91 OutboundUrlFilter.ParseConfigList(
92 configBlacklist, Name, out m_blacklistNetworks, out m_blacklistEndPoints);
93 OutboundUrlFilter.ParseConfigList(
94 configBlacklistExceptions, Name, out m_blacklistExceptionNetworks, out m_blacklistExceptionEndPoints);
95 }
96
97 private static void ParseConfigList(
98 string fullConfigEntry, string filterName, out List<IPNetwork> networks, out List<IPEndPoint> endPoints)
99 {
100 // Parse blacklist
101 string[] configBlacklistEntries
102 = fullConfigEntry.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
103
104 configBlacklistEntries = configBlacklistEntries.Select(e => e.Trim()).ToArray();
105
106 networks = new List<IPNetwork>();
107 endPoints = new List<IPEndPoint>();
108
109 foreach (string configEntry in configBlacklistEntries)
110 {
111 if (configEntry.Contains("/"))
112 {
113 IPNetwork network;
114
115 if (!IPNetwork.TryParse(configEntry, out network))
116 {
117 m_log.ErrorFormat(
118 "[OUTBOUND URL FILTER]: Entry [{0}] is invalid network for {1}", configEntry, filterName);
119
120 continue;
121 }
122
123 networks.Add(network);
124 }
125 else
126 {
127 Uri configEntryUri;
128
129 if (!Uri.TryCreate("http://" + configEntry, UriKind.Absolute, out configEntryUri))
130 {
131 m_log.ErrorFormat(
132 "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}",
133 configEntry, filterName);
134
135 continue;
136 }
137
138 IPAddress[] addresses = Dns.GetHostAddresses(configEntryUri.Host);
139
140 foreach (IPAddress addr in addresses)
141 {
142 if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
143 {
144 // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}] in config", addr);
145
146 IPEndPoint configEntryEp = new IPEndPoint(addr, configEntryUri.Port);
147 endPoints.Add(configEntryEp);
148
149 // m_log.DebugFormat("[OUTBOUND URL FILTER]: Added blacklist exception [{0}]", configEntryEp);
150 }
151 }
152 }
153 }
154 }
155
156 /// <summary>
157 /// Determines if an url is in a list of networks and endpoints.
158 /// </summary>
159 /// <returns></returns>
160 /// <param name="url">IP address</param>
161 /// <param name="port"></param>
162 /// <param name="networks">Networks.</param>
163 /// <param name="endPoints">End points.</param>
164 /// <param name="filterName">Filter name.</param>
165 private static bool IsInNetwork(
166 IPAddress addr, int port, List<IPNetwork> networks, List<IPEndPoint> endPoints, string filterName)
167 {
168 foreach (IPNetwork ipn in networks)
169 {
170// m_log.DebugFormat(
171// "[OUTBOUND URL FILTER]: Checking [{0}] against network [{1}]", addr, ipn);
172
173 if (IPNetwork.Contains(ipn, addr))
174 {
175// m_log.DebugFormat(
176// "[OUTBOUND URL FILTER]: Found [{0}] in network [{1}]", addr, ipn);
177
178 return true;
179 }
180 }
181
182 // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr);
183
184 foreach (IPEndPoint ep in endPoints)
185 {
186// m_log.DebugFormat(
187// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]",
188// addr, port, ep);
189
190 if (addr.Equals(ep.Address) && port == ep.Port)
191 {
192// m_log.DebugFormat(
193// "[OUTBOUND URL FILTER]: Found [{0}:{1}] in endpoint [{2}]", addr, port, ep);
194
195 return true;
196 }
197 }
198
199// m_log.DebugFormat("[OUTBOUND URL FILTER]: Did not find [{0}:{1}] in list", addr, port);
200
201 return false;
202 }
203
204 /// <summary>
205 /// Checks whether the given url is allowed by the filter.
206 /// </summary>
207 /// <returns></returns>
208 public bool CheckAllowed(Uri url)
209 {
210 bool allowed = true;
211
212 // Check that we are permitted to make calls to this endpoint.
213 bool foundIpv4Address = false;
214
215 IPAddress[] addresses = Dns.GetHostAddresses(url.Host);
216
217 foreach (IPAddress addr in addresses)
218 {
219 if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
220 {
221// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr);
222
223 foundIpv4Address = true;
224
225 // Check blacklist
226 if (OutboundUrlFilter.IsInNetwork(addr, url.Port, m_blacklistNetworks, m_blacklistEndPoints, Name))
227 {
228// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in blacklist for {1}", url, Name);
229
230 // Check blacklist exceptions
231 allowed
232 = OutboundUrlFilter.IsInNetwork(
233 addr, url.Port, m_blacklistExceptionNetworks, m_blacklistExceptionEndPoints, Name);
234
235// if (allowed)
236// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in whitelist for {1}", url, Name);
237 }
238 }
239
240 // Found at least one address in a blacklist and not a blacklist exception
241 if (!allowed)
242 return false;
243// else
244// m_log.DebugFormat("[OUTBOUND URL FILTER]: URL [{0}] not in blacklist for {1}", url, Name);
245 }
246
247 // We do not know how to handle IPv6 securely yet.
248 if (!foundIpv4Address)
249 return false;
250
251// m_log.DebugFormat("[OUTBOUND URL FILTER]: Allowing request [{0}]", url);
252
253 return allowed;
254 }
255 }
256} \ 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Text;
32using log4net;
33
34namespace OpenSim.Framework
35{
36 public static class PermissionsUtil
37 {
38 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
39
40 /// <summary>
41 /// Logs permissions flags. Useful when debugging permission problems.
42 /// </summary>
43 /// <param name="message"></param>
44 public static void LogPermissions(String name, String message, uint basePerm, uint curPerm, uint nextPerm)
45 {
46 m_log.DebugFormat("Permissions of \"{0}\" at \"{1}\": Base {2} ({3:X4}), Current {4} ({5:X4}), NextOwner {6} ({7:X4})",
47 name, message,
48 PermissionsToString(basePerm), basePerm, PermissionsToString(curPerm), curPerm, PermissionsToString(nextPerm), nextPerm);
49 }
50
51 /// <summary>
52 /// Converts a permissions bit-mask to a string (e.g., "MCT").
53 /// </summary>
54 private static string PermissionsToString(uint perms)
55 {
56 string str = "";
57 if ((perms & (int)PermissionMask.Modify) != 0)
58 str += "M";
59 if ((perms & (int)PermissionMask.Copy) != 0)
60 str += "C";
61 if ((perms & (int)PermissionMask.Transfer) != 0)
62 str += "T";
63 if (str == "")
64 str = ".";
65 return str;
66 }
67
68 /// <summary>
69 /// Applies an object's folded permissions to its regular permissions.
70 /// </summary>
71 /// <param name="foldedPerms">The folded permissions. Only the lowest 7 bits are examined.</param>
72 /// <param name="mainPerms">The permissions variable to modify.</param>
73 public static void ApplyFoldedPermissions(uint foldedPerms, ref uint mainPerms)
74 {
75 if ((foldedPerms & 7) == 0)
76 return; // assume that if the folded permissions are 0 then this means that they weren't actually recorded
77
78 if ((foldedPerms & ((uint)PermissionMask.Copy >> 13)) == 0)
79 mainPerms &= ~(uint)PermissionMask.Copy;
80 if ((foldedPerms & ((uint)PermissionMask.Transfer >> 13)) == 0)
81 mainPerms &= ~(uint)PermissionMask.Transfer;
82 if ((foldedPerms & ((uint)PermissionMask.Modify >> 13)) == 0)
83 mainPerms &= ~(uint)PermissionMask.Modify;
84 }
85
86 }
87}
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
215 AddinManager.AddinLoadError += on_addinloaderror_; 215 AddinManager.AddinLoadError += on_addinloaderror_;
216 AddinManager.AddinLoaded += on_addinloaded_; 216 AddinManager.AddinLoaded += on_addinloaded_;
217 217
218 clear_registry_(); 218 //clear_registry_(dir);
219 219
220 suppress_console_output_(true); 220 //suppress_console_output_(true);
221 AddinManager.Initialize(dir); 221 AddinManager.Initialize(dir);
222 AddinManager.Registry.Update(null); 222 AddinManager.Registry.Update(null);
223 suppress_console_output_(false); 223 //suppress_console_output_(false);
224 } 224 }
225 225
226 private void on_addinloaded_(object sender, AddinEventArgs args) 226 private void on_addinloaded_(object sender, AddinEventArgs args)
@@ -239,18 +239,19 @@ namespace OpenSim.Framework
239 + args.Exception.StackTrace); 239 + args.Exception.StackTrace);
240 } 240 }
241 241
242 private void clear_registry_() 242 private void clear_registry_(string dir)
243 { 243 {
244 // The Mono addin manager (in Mono.Addins.dll version 0.2.0.0) 244 // The Mono addin manager (in Mono.Addins.dll version 0.2.0.0)
245 // occasionally seems to corrupt its addin cache 245 // occasionally seems to corrupt its addin cache
246 // Hence, as a temporary solution we'll remove it before each startup 246 // Hence, as a temporary solution we'll remove it before each startup
247
247 try 248 try
248 { 249 {
249 if (Directory.Exists("addin-db-000")) 250 if (Directory.Exists(dir + "/addin-db-000"))
250 Directory.Delete("addin-db-000", true); 251 Directory.Delete(dir + "/addin-db-000", true);
251 252
252 if (Directory.Exists("addin-db-001")) 253 if (Directory.Exists(dir + "/addin-db-001"))
253 Directory.Delete("addin-db-001", true); 254 Directory.Delete(dir + "/addin-db-001", true);
254 } 255 }
255 catch (IOException) 256 catch (IOException)
256 { 257 {
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
218 Console.WriteLine ("Looking for updates..."); 218 Console.WriteLine ("Looking for updates...");
219 Repositories.UpdateAllRepositories (ps); 219 Repositories.UpdateAllRepositories (ps);
220 Console.WriteLine ("Available add-in updates:"); 220 Console.WriteLine ("Available add-in updates:");
221 bool found = false; 221
222 AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates(); 222 AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
223 223
224 foreach (AddinRepositoryEntry entry in entries) 224 foreach (AddinRepositoryEntry entry in entries)
@@ -541,7 +541,7 @@ namespace OpenSim.Framework
541 { 541 {
542 list.AddRange(PluginRegistry.GetAddins()); 542 list.AddRange(PluginRegistry.GetAddins());
543 } 543 }
544 catch(Exception e) 544 catch (Exception)
545 { 545 {
546 Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[]; 546 Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
547 return x; 547 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
105 private ushort _profileHollow; 105 private ushort _profileHollow;
106 private Vector3 _scale; 106 private Vector3 _scale;
107 private byte _state; 107 private byte _state;
108 private byte _lastattach;
108 private ProfileShape _profileShape; 109 private ProfileShape _profileShape;
109 private HollowShape _hollowShape; 110 private HollowShape _hollowShape;
110 111
@@ -207,6 +208,7 @@ namespace OpenSim.Framework
207 PCode = (byte)prim.PrimData.PCode; 208 PCode = (byte)prim.PrimData.PCode;
208 209
209 State = prim.PrimData.State; 210 State = prim.PrimData.State;
211 LastAttachPoint = prim.PrimData.State;
210 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); 212 PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
211 PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd); 213 PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd);
212 PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX); 214 PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX);
@@ -583,6 +585,15 @@ namespace OpenSim.Framework
583 } 585 }
584 } 586 }
585 587
588 public byte LastAttachPoint {
589 get {
590 return _lastattach;
591 }
592 set {
593 _lastattach = value;
594 }
595 }
596
586 public ProfileShape ProfileShape { 597 public ProfileShape ProfileShape {
587 get { 598 get {
588 return _profileShape; 599 return _profileShape;
@@ -622,6 +633,8 @@ namespace OpenSim.Framework
622 } 633 }
623 } 634 }
624 635
636 // This is only used at runtime. For sculpties this holds the texture data, and for meshes
637 // the mesh data.
625 public byte[] SculptData 638 public byte[] SculptData
626 { 639 {
627 get 640 get
@@ -1147,14 +1160,13 @@ namespace OpenSim.Framework
1147 1160
1148 public void ReadSculptData(byte[] data, int pos) 1161 public void ReadSculptData(byte[] data, int pos)
1149 { 1162 {
1150 byte[] SculptTextureUUID = new byte[16]; 1163 UUID SculptUUID;
1151 UUID SculptUUID = UUID.Zero; 1164 byte SculptTypel;
1152 byte SculptTypel = data[16+pos];
1153 1165
1154 if (data.Length+pos >= 17) 1166 if (data.Length-pos >= 17)
1155 { 1167 {
1156 _sculptEntry = true; 1168 _sculptEntry = true;
1157 SculptTextureUUID = new byte[16]; 1169 byte[] SculptTextureUUID = new byte[16];
1158 SculptTypel = data[16 + pos]; 1170 SculptTypel = data[16 + pos];
1159 Array.Copy(data, pos, SculptTextureUUID,0, 16); 1171 Array.Copy(data, pos, SculptTextureUUID,0, 16);
1160 SculptUUID = new UUID(SculptTextureUUID, 0); 1172 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
48 NoMove = 64, // Don't allow moving this region 48 NoMove = 64, // Don't allow moving this region
49 Reservation = 128, // This is an inactive reservation 49 Reservation = 128, // This is an inactive reservation
50 Authenticate = 256, // Require authentication 50 Authenticate = 256, // Require authentication
51 Hyperlink = 512 // Record represents a HG link 51 Hyperlink = 512, // Record represents a HG link
52 DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only.
52 } 53 }
53} \ No newline at end of file 54} \ 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
99 public class RegionInfo 99 public class RegionInfo
100 { 100 {
101 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 101 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
102 private static readonly string LogHeader = "[REGION INFO]";
102 103
103 public bool commFailTF = false;
104 public ConfigurationMember configMember;
105 public string RegionFile = String.Empty; 104 public string RegionFile = String.Empty;
106 public bool isSandbox = false; 105 public bool isSandbox = false;
107 public bool Persistent = true; 106 public bool Persistent = true;
@@ -126,8 +125,8 @@ namespace OpenSim.Framework
126 private int m_physPrimMax = 0; 125 private int m_physPrimMax = 0;
127 private bool m_clampPrimSize = false; 126 private bool m_clampPrimSize = false;
128 private int m_objectCapacity = 0; 127 private int m_objectCapacity = 0;
128 private int m_maxPrimsPerUser = -1;
129 private int m_linksetCapacity = 0; 129 private int m_linksetCapacity = 0;
130 private int m_agentCapacity = 0;
131 private string m_regionType = String.Empty; 130 private string m_regionType = String.Empty;
132 private RegionLightShareData m_windlight = new RegionLightShareData(); 131 private RegionLightShareData m_windlight = new RegionLightShareData();
133 protected uint m_httpPort; 132 protected uint m_httpPort;
@@ -137,15 +136,41 @@ namespace OpenSim.Framework
137 public bool m_allow_alternate_ports; 136 public bool m_allow_alternate_ports;
138 protected string m_externalHostName; 137 protected string m_externalHostName;
139 protected IPEndPoint m_internalEndPoint; 138 protected IPEndPoint m_internalEndPoint;
140 protected uint? m_regionLocX;
141 protected uint? m_regionLocY;
142 protected uint m_remotingPort; 139 protected uint m_remotingPort;
143 public UUID RegionID = UUID.Zero; 140 public UUID RegionID = UUID.Zero;
144 public string RemotingAddress; 141 public string RemotingAddress;
145 public UUID ScopeID = UUID.Zero; 142 public UUID ScopeID = UUID.Zero;
143 private UUID m_maptileStaticUUID = UUID.Zero;
146 144
147 private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); 145 public uint WorldLocX = 0;
146 public uint WorldLocY = 0;
147 public uint WorldLocZ = 0;
148 148
149 /// <summary>
150 /// X dimension of the region.
151 /// </summary>
152 /// <remarks>
153 /// If this is a varregion then the default size set here will be replaced when we load the region config.
154 /// </remarks>
155 public uint RegionSizeX = Constants.RegionSize;
156
157 /// <summary>
158 /// X dimension of the region.
159 /// </summary>
160 /// <remarks>
161 /// If this is a varregion then the default size set here will be replaced when we load the region config.
162 /// </remarks>
163 public uint RegionSizeY = Constants.RegionSize;
164
165 /// <summary>
166 /// Z dimension of the region.
167 /// </summary>
168 /// <remarks>
169 /// XXX: Unknown if this accounts for regions with negative Z.
170 /// </remarks>
171 public uint RegionSizeZ = Constants.RegionHeight;
172
173 private Dictionary<String, String> m_extraSettings = new Dictionary<string, string>();
149 174
150 // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. 175 // Apparently, we're applying the same estatesettings regardless of whether it's local or remote.
151 176
@@ -197,7 +222,6 @@ namespace OpenSim.Framework
197 try 222 try
198 { 223 {
199 // This will throw if it's not legal Nini XML format 224 // This will throw if it's not legal Nini XML format
200 // and thereby toss it to the legacy loader
201 // 225 //
202 IConfigSource xmlsource = new XmlConfigSource(filename); 226 IConfigSource xmlsource = new XmlConfigSource(filename);
203 227
@@ -210,29 +234,27 @@ namespace OpenSim.Framework
210 catch (Exception) 234 catch (Exception)
211 { 235 {
212 } 236 }
213
214 configMember =
215 new ConfigurationMember(filename, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig);
216 configMember.performConfigurationRetrieve();
217 RegionFile = filename;
218 } 237 }
219 238
220 // The web loader uses this 239 // The web loader uses this
221 // 240 //
222 public RegionInfo(string description, XmlNode xmlNode, bool skipConsoleConfig, IConfigSource configSource) 241 public RegionInfo(string description, XmlNode xmlNode, bool skipConsoleConfig, IConfigSource configSource)
223 { 242 {
224 // m_configSource = configSource; 243 XmlElement elem = (XmlElement)xmlNode;
225 configMember = 244 string name = elem.GetAttribute("Name");
226 new ConfigurationMember(xmlNode, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig); 245 string xmlstr = "<Nini>" + xmlNode.OuterXml + "</Nini>";
227 configMember.performConfigurationRetrieve(); 246 XmlConfigSource source = new XmlConfigSource(XmlReader.Create(new StringReader(xmlstr)));
247 ReadNiniConfig(source, name);
248
228 m_serverURI = string.Empty; 249 m_serverURI = string.Empty;
229 } 250 }
230 251
231 public RegionInfo(uint regionLocX, uint regionLocY, IPEndPoint internalEndPoint, string externalUri) 252 public RegionInfo(uint legacyRegionLocX, uint legacyRegionLocY, IPEndPoint internalEndPoint, string externalUri)
232 { 253 {
233 m_regionLocX = regionLocX; 254 RegionLocX = legacyRegionLocX;
234 m_regionLocY = regionLocY; 255 RegionLocY = legacyRegionLocY;
235 256 RegionSizeX = Constants.RegionSize;
257 RegionSizeY = Constants.RegionSize;
236 m_internalEndPoint = internalEndPoint; 258 m_internalEndPoint = internalEndPoint;
237 m_externalHostName = externalUri; 259 m_externalHostName = externalUri;
238 m_serverURI = string.Empty; 260 m_serverURI = string.Empty;
@@ -318,16 +340,18 @@ namespace OpenSim.Framework
318 get { return m_objectCapacity; } 340 get { return m_objectCapacity; }
319 } 341 }
320 342
321 public int LinksetCapacity 343 public int MaxPrimsPerUser
322 { 344 {
323 get { return m_linksetCapacity; } 345 get { return m_maxPrimsPerUser; }
324 } 346 }
325 347
326 public int AgentCapacity 348 public int LinksetCapacity
327 { 349 {
328 get { return m_agentCapacity; } 350 get { return m_linksetCapacity; }
329 } 351 }
330 352
353 public int AgentCapacity { get; set; }
354
331 public byte AccessLevel 355 public byte AccessLevel
332 { 356 {
333 get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); } 357 get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); }
@@ -338,6 +362,13 @@ namespace OpenSim.Framework
338 get { return m_regionType; } 362 get { return m_regionType; }
339 } 363 }
340 364
365 public UUID MaptileStaticUUID
366 {
367 get { return m_maptileStaticUUID; }
368 }
369
370 public string MaptileStaticFile { get; private set; }
371
341 /// <summary> 372 /// <summary>
342 /// The port by which http communication occurs with the region (most noticeably, CAPS communication) 373 /// The port by which http communication occurs with the region (most noticeably, CAPS communication)
343 /// </summary> 374 /// </summary>
@@ -441,25 +472,42 @@ namespace OpenSim.Framework
441 472
442 /// <summary> 473 /// <summary>
443 /// The x co-ordinate of this region in map tiles (e.g. 1000). 474 /// The x co-ordinate of this region in map tiles (e.g. 1000).
475 /// Coordinate is scaled as world coordinates divided by the legacy region size
476 /// and is thus is the number of legacy regions.
444 /// </summary> 477 /// </summary>
445 public uint RegionLocX 478 public uint RegionLocX
446 { 479 {
447 get { return m_regionLocX.Value; } 480 get { return WorldLocX / Constants.RegionSize; }
448 set { m_regionLocX = value; } 481 set { WorldLocX = value * Constants.RegionSize; }
449 } 482 }
450 483
451 /// <summary> 484 /// <summary>
452 /// The y co-ordinate of this region in map tiles (e.g. 1000). 485 /// The y co-ordinate of this region in map tiles (e.g. 1000).
486 /// Coordinate is scaled as world coordinates divided by the legacy region size
487 /// and is thus is the number of legacy regions.
453 /// </summary> 488 /// </summary>
454 public uint RegionLocY 489 public uint RegionLocY
455 { 490 {
456 get { return m_regionLocY.Value; } 491 get { return WorldLocY / Constants.RegionSize; }
457 set { m_regionLocY = value; } 492 set { WorldLocY = value * Constants.RegionSize; }
493 }
494
495 public void SetDefaultRegionSize()
496 {
497 WorldLocX = 0;
498 WorldLocY = 0;
499 WorldLocZ = 0;
500 RegionSizeX = Constants.RegionSize;
501 RegionSizeY = Constants.RegionSize;
502 RegionSizeZ = Constants.RegionHeight;
458 } 503 }
459 504
505 // A unique region handle is created from the region's world coordinates.
506 // This cannot be changed because some code expects to receive the region handle and then
507 // compute the region coordinates from it.
460 public ulong RegionHandle 508 public ulong RegionHandle
461 { 509 {
462 get { return Util.UIntsToLong((RegionLocX * (uint) Constants.RegionSize), (RegionLocY * (uint) Constants.RegionSize)); } 510 get { return Util.UIntsToLong(WorldLocX, WorldLocY); }
463 } 511 }
464 512
465 public void SetEndPoint(string ipaddr, int port) 513 public void SetEndPoint(string ipaddr, int port)
@@ -469,20 +517,20 @@ namespace OpenSim.Framework
469 m_internalEndPoint = tmpEPE; 517 m_internalEndPoint = tmpEPE;
470 } 518 }
471 519
472 public string GetOtherSetting(string key) 520 public string GetSetting(string key)
473 { 521 {
474 string val; 522 string val;
475 string keylower = key.ToLower(); 523 string keylower = key.ToLower();
476 if (m_otherSettings.TryGetValue(keylower, out val)) 524 if (m_extraSettings.TryGetValue(keylower, out val))
477 return val; 525 return val;
478 m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key); 526 m_log.DebugFormat("[RegionInfo] Could not locate value for parameter {0}", key);
479 return null; 527 return null;
480 } 528 }
481 529
482 public void SetOtherSetting(string key, string value) 530 private void SetExtraSetting(string key, string value)
483 { 531 {
484 string keylower = key.ToLower(); 532 string keylower = key.ToLower();
485 m_otherSettings[keylower] = value; 533 m_extraSettings[keylower] = value;
486 } 534 }
487 535
488 private void ReadNiniConfig(IConfigSource source, string name) 536 private void ReadNiniConfig(IConfigSource source, string name)
@@ -566,8 +614,25 @@ namespace OpenSim.Framework
566 614
567 string[] locationElements = location.Split(new char[] {','}); 615 string[] locationElements = location.Split(new char[] {','});
568 616
569 m_regionLocX = Convert.ToUInt32(locationElements[0]); 617 RegionLocX = Convert.ToUInt32(locationElements[0]);
570 m_regionLocY = Convert.ToUInt32(locationElements[1]); 618 RegionLocY = Convert.ToUInt32(locationElements[1]);
619
620 // Region size
621 // Default to legacy region size if not specified.
622 allKeys.Remove("SizeX");
623 string configSizeX = config.GetString("SizeX", Constants.RegionSize.ToString());
624 config.Set("SizeX", configSizeX);
625 RegionSizeX = Convert.ToUInt32(configSizeX);
626 allKeys.Remove("SizeY");
627 string configSizeY = config.GetString("SizeY", Constants.RegionSize.ToString());
628 config.Set("SizeY", configSizeX);
629 RegionSizeY = Convert.ToUInt32(configSizeY);
630 allKeys.Remove("SizeZ");
631 string configSizeZ = config.GetString("SizeZ", Constants.RegionHeight.ToString());
632 config.Set("SizeZ", configSizeX);
633 RegionSizeZ = Convert.ToUInt32(configSizeZ);
634
635 DoRegionSizeSanityChecks();
571 636
572 // InternalAddress 637 // InternalAddress
573 // 638 //
@@ -641,7 +706,7 @@ namespace OpenSim.Framework
641 m_regionType = config.GetString("RegionType", String.Empty); 706 m_regionType = config.GetString("RegionType", String.Empty);
642 allKeys.Remove("RegionType"); 707 allKeys.Remove("RegionType");
643 708
644 #region Prim stuff 709 #region Prim and map stuff
645 710
646 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0); 711 m_nonphysPrimMin = config.GetFloat("NonPhysicalPrimMin", 0);
647 allKeys.Remove("NonPhysicalPrimMin"); 712 allKeys.Remove("NonPhysicalPrimMin");
@@ -661,12 +726,25 @@ namespace OpenSim.Framework
661 m_objectCapacity = config.GetInt("MaxPrims", 15000); 726 m_objectCapacity = config.GetInt("MaxPrims", 15000);
662 allKeys.Remove("MaxPrims"); 727 allKeys.Remove("MaxPrims");
663 728
729 m_maxPrimsPerUser = config.GetInt("MaxPrimsPerUser", -1);
730 allKeys.Remove("MaxPrimsPerUser");
731
664 m_linksetCapacity = config.GetInt("LinksetPrims", 0); 732 m_linksetCapacity = config.GetInt("LinksetPrims", 0);
665 allKeys.Remove("LinksetPrims"); 733 allKeys.Remove("LinksetPrims");
734
735 allKeys.Remove("MaptileStaticUUID");
736 string mapTileStaticUUID = config.GetString("MaptileStaticUUID", UUID.Zero.ToString());
737 if (UUID.TryParse(mapTileStaticUUID.Trim(), out m_maptileStaticUUID))
738 {
739 config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
740 }
741
742 MaptileStaticFile = config.GetString("MaptileStaticFile", String.Empty);
743 allKeys.Remove("MaptileStaticFile");
666 744
667 #endregion 745 #endregion
668 746
669 m_agentCapacity = config.GetInt("MaxAgents", 100); 747 AgentCapacity = config.GetInt("MaxAgents", 100);
670 allKeys.Remove("MaxAgents"); 748 allKeys.Remove("MaxAgents");
671 749
672 // Multi-tenancy 750 // Multi-tenancy
@@ -676,7 +754,58 @@ namespace OpenSim.Framework
676 754
677 foreach (String s in allKeys) 755 foreach (String s in allKeys)
678 { 756 {
679 SetOtherSetting(s, config.GetString(s)); 757 SetExtraSetting(s, config.GetString(s));
758 }
759 }
760
761 // Make sure user specified region sizes are sane.
762 // Must be multiples of legacy region size (256).
763 private void DoRegionSizeSanityChecks()
764 {
765 if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize)
766 {
767 // Doing non-legacy region sizes.
768 // Enforce region size to be multiples of the legacy region size (256)
769 uint partial = RegionSizeX % Constants.RegionSize;
770 if (partial != 0)
771 {
772 RegionSizeX -= partial;
773 if (RegionSizeX == 0)
774 RegionSizeX = Constants.RegionSize;
775 m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeX={3} instead of specified {4}",
776 LogHeader, Constants.RegionSize, m_regionName, RegionSizeX, RegionSizeX + partial);
777 }
778 partial = RegionSizeY % Constants.RegionSize;
779 if (partial != 0)
780 {
781 RegionSizeY -= partial;
782 if (RegionSizeY == 0)
783 RegionSizeY = Constants.RegionSize;
784 m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeY={3} instead of specified {4}",
785 LogHeader, Constants.RegionSize, m_regionName, RegionSizeY, RegionSizeY + partial);
786 }
787
788 // Because of things in the viewer, regions MUST be square.
789 // Remove this check when viewers have been updated.
790 if (RegionSizeX != RegionSizeY)
791 {
792 uint minSize = Math.Min(RegionSizeX, RegionSizeY);
793 RegionSizeX = minSize;
794 RegionSizeY = minSize;
795 m_log.ErrorFormat("{0} Regions must be square until viewers are updated. Forcing region {1} size to <{2},{3}>",
796 LogHeader, m_regionName, RegionSizeX, RegionSizeY);
797 }
798
799 // There is a practical limit to region size.
800 if (RegionSizeX > Constants.MaximumRegionSize || RegionSizeY > Constants.MaximumRegionSize)
801 {
802 RegionSizeX = Util.Clamp<uint>(RegionSizeX, Constants.RegionSize, Constants.MaximumRegionSize);
803 RegionSizeY = Util.Clamp<uint>(RegionSizeY, Constants.RegionSize, Constants.MaximumRegionSize);
804 m_log.ErrorFormat("{0} Region dimensions must be less than {1}. Clamping {2}'s size to <{3},{4}>",
805 LogHeader, Constants.MaximumRegionSize, m_regionName, RegionSizeX, RegionSizeY);
806 }
807
808 m_log.InfoFormat("{0} Region {1} size set to <{2},{3}>", LogHeader, m_regionName, RegionSizeX, RegionSizeY);
680 } 809 }
681 } 810 }
682 811
@@ -691,9 +820,18 @@ namespace OpenSim.Framework
691 820
692 config.Set("RegionUUID", RegionID.ToString()); 821 config.Set("RegionUUID", RegionID.ToString());
693 822
694 string location = String.Format("{0},{1}", m_regionLocX, m_regionLocY); 823 string location = String.Format("{0},{1}", RegionLocX, RegionLocY);
695 config.Set("Location", location); 824 config.Set("Location", location);
696 825
826 if (RegionSizeX > 0)
827 config.Set("SizeX", RegionSizeX);
828
829 if (RegionSizeY > 0)
830 config.Set("SizeY", RegionSizeY);
831
832// if (RegionSizeZ > 0)
833// config.Set("SizeZ", RegionSizeZ);
834
697 config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); 835 config.Set("InternalAddress", m_internalEndPoint.Address.ToString());
698 config.Set("InternalPort", m_internalEndPoint.Port); 836 config.Set("InternalPort", m_internalEndPoint.Port);
699 837
@@ -718,22 +856,26 @@ namespace OpenSim.Framework
718 if (m_objectCapacity > 0) 856 if (m_objectCapacity > 0)
719 config.Set("MaxPrims", m_objectCapacity); 857 config.Set("MaxPrims", m_objectCapacity);
720 858
859 if (m_maxPrimsPerUser > -1)
860 config.Set("MaxPrimsPerUser", m_maxPrimsPerUser);
861
721 if (m_linksetCapacity > 0) 862 if (m_linksetCapacity > 0)
722 config.Set("LinksetPrims", m_linksetCapacity); 863 config.Set("LinksetPrims", m_linksetCapacity);
723 864
724 if (m_agentCapacity > 0) 865 if (AgentCapacity > 0)
725 config.Set("MaxAgents", m_agentCapacity); 866 config.Set("MaxAgents", AgentCapacity);
726 867
727 if (ScopeID != UUID.Zero) 868 if (ScopeID != UUID.Zero)
728 config.Set("ScopeID", ScopeID.ToString()); 869 config.Set("ScopeID", ScopeID.ToString());
729 870
730 if (RegionType != String.Empty) 871 if (RegionType != String.Empty)
731 config.Set("RegionType", RegionType); 872 config.Set("RegionType", RegionType);
732 }
733 873
734 public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result) 874 if (m_maptileStaticUUID != UUID.Zero)
735 { 875 config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString());
736 return true; 876
877 if (MaptileStaticFile != null && MaptileStaticFile != String.Empty)
878 config.Set("MaptileStaticFile", MaptileStaticFile);
737 } 879 }
738 880
739 public void SaveRegionToFile(string description, string filename) 881 public void SaveRegionToFile(string description, string filename)
@@ -755,215 +897,14 @@ namespace OpenSim.Framework
755 897
756 return; 898 return;
757 } 899 }
758 else if (filename.ToLower().EndsWith(".xml"))
759 {
760 configMember = new ConfigurationMember(filename, description, loadConfigurationOptionsFromMe,
761 ignoreIncomingConfiguration, false);
762 configMember.performConfigurationRetrieve();
763 RegionFile = filename;
764 }
765 else 900 else
766 throw new Exception("Invalid file type for region persistence."); 901 throw new Exception("Invalid file type for region persistence.");
767 } 902 }
768 903
769 public void loadConfigurationOptionsFromMe()
770 {
771 configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE,
772 "UUID of Region (Default is recommended, random UUID)",
773 RegionID.ToString(), true);
774 configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
775 "Region Name", RegionName, true);
776 configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
777 "Grid Location (X Axis)", m_regionLocX.ToString(), true);
778 configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
779 "Grid Location (Y Axis)", m_regionLocY.ToString(), true);
780 //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false);
781 configMember.addConfigurationOption("internal_ip_address",
782 ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS,
783 "Internal IP Address for incoming UDP client connections",
784 m_internalEndPoint.Address.ToString(),
785 true);
786 configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
787 "Internal IP Port for incoming UDP client connections",
788 m_internalEndPoint.Port.ToString(), true);
789 configMember.addConfigurationOption("allow_alternate_ports",
790 ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
791 "Allow sim to find alternate UDP ports when ports are in use?",
792 m_allow_alternate_ports.ToString(), true);
793 configMember.addConfigurationOption("external_host_name",
794 ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
795 "External Host Name", m_externalHostName, true);
796 configMember.addConfigurationOption("lastmap_uuid", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
797 "Last Map UUID", lastMapUUID.ToString(), true);
798 configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
799 "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
800
801 configMember.addConfigurationOption("nonphysical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
802 "Minimum size for nonphysical prims", m_nonphysPrimMin.ToString(), true);
803
804 configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
805 "Maximum size for nonphysical prims", m_nonphysPrimMax.ToString(), true);
806
807 configMember.addConfigurationOption("physical_prim_min", ConfigurationOption.ConfigurationTypes.TYPE_FLOAT,
808 "Minimum size for nonphysical prims", m_physPrimMin.ToString(), true);
809
810 configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
811 "Maximum size for physical prims", m_physPrimMax.ToString(), true);
812
813 configMember.addConfigurationOption("clamp_prim_size", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
814 "Clamp prims to max size", m_clampPrimSize.ToString(), true);
815
816 configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
817 "Max objects this sim will hold", m_objectCapacity.ToString(), true);
818
819 configMember.addConfigurationOption("linkset_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
820 "Max prims an object will hold", m_linksetCapacity.ToString(), true);
821
822 configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
823 "Max avatars this sim will hold", m_agentCapacity.ToString(), true);
824
825 configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
826 "Scope ID for this region", ScopeID.ToString(), true);
827
828 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
829 "Free form string describing the type of region", String.Empty, true);
830 }
831
832 public void loadConfigurationOptions()
833 {
834 configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
835 "UUID of Region (Default is recommended, random UUID)",
836 UUID.Random().ToString(), true);
837 configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
838 "Region Name", "OpenSim Test", false);
839 configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
840 "Grid Location (X Axis)", "1000", false);
841 configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32,
842 "Grid Location (Y Axis)", "1000", false);
843 //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false);
844 configMember.addConfigurationOption("internal_ip_address",
845 ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS,
846 "Internal IP Address for incoming UDP client connections", "0.0.0.0",
847 false);
848 configMember.addConfigurationOption("internal_ip_port", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
849 "Internal IP Port for incoming UDP client connections",
850 ConfigSettings.DefaultRegionHttpPort.ToString(), false);
851 configMember.addConfigurationOption("allow_alternate_ports", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
852 "Allow sim to find alternate UDP ports when ports are in use?",
853 "false", true);
854 configMember.addConfigurationOption("external_host_name",
855 ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
856 "External Host Name", "127.0.0.1", false);
857 configMember.addConfigurationOption("lastmap_uuid", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
858 "Last Map UUID", lastMapUUID.ToString(), true);
859
860 configMember.addConfigurationOption("lastmap_refresh", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
861 "Last Map Refresh", Util.UnixTimeSinceEpoch().ToString(), true);
862
863 configMember.addConfigurationOption("nonphysical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
864 "Maximum size for nonphysical prims", "0", true);
865
866 configMember.addConfigurationOption("physical_prim_max", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
867 "Maximum size for physical prims", "0", true);
868
869 configMember.addConfigurationOption("clamp_prim_size", ConfigurationOption.ConfigurationTypes.TYPE_BOOLEAN,
870 "Clamp prims to max size", "false", true);
871
872 configMember.addConfigurationOption("object_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
873 "Max objects this sim will hold", "15000", true);
874
875 configMember.addConfigurationOption("agent_capacity", ConfigurationOption.ConfigurationTypes.TYPE_INT32,
876 "Max avatars this sim will hold", "100", true);
877
878 configMember.addConfigurationOption("scope_id", ConfigurationOption.ConfigurationTypes.TYPE_UUID,
879 "Scope ID for this region", UUID.Zero.ToString(), true);
880
881 configMember.addConfigurationOption("region_type", ConfigurationOption.ConfigurationTypes.TYPE_STRING,
882 "Region Type", String.Empty, true);
883 }
884
885 public bool handleIncomingConfiguration(string configuration_key, object configuration_result)
886 {
887 switch (configuration_key)
888 {
889 case "sim_UUID":
890 RegionID = (UUID) configuration_result;
891 originRegionID = (UUID) configuration_result;
892 break;
893 case "sim_name":
894 RegionName = (string) configuration_result;
895 break;
896 case "sim_location_x":
897 m_regionLocX = (uint) configuration_result;
898 break;
899 case "sim_location_y":
900 m_regionLocY = (uint) configuration_result;
901 break;
902 case "internal_ip_address":
903 IPAddress address = (IPAddress) configuration_result;
904 m_internalEndPoint = new IPEndPoint(address, 0);
905 break;
906 case "internal_ip_port":
907 m_internalEndPoint.Port = (int) configuration_result;
908 break;
909 case "allow_alternate_ports":
910 m_allow_alternate_ports = (bool) configuration_result;
911 break;
912 case "external_host_name":
913 if ((string) configuration_result != "SYSTEMIP")
914 {
915 m_externalHostName = (string) configuration_result;
916 }
917 else
918 {
919 m_externalHostName = Util.GetLocalHost().ToString();
920 }
921 break;
922 case "lastmap_uuid":
923 lastMapUUID = (UUID)configuration_result;
924 break;
925 case "lastmap_refresh":
926 lastMapRefresh = (string)configuration_result;
927 break;
928 case "nonphysical_prim_max":
929 m_nonphysPrimMax = (int)configuration_result;
930 break;
931 case "physical_prim_max":
932 m_physPrimMax = (int)configuration_result;
933 break;
934 case "clamp_prim_size":
935 m_clampPrimSize = (bool)configuration_result;
936 break;
937 case "object_capacity":
938 m_objectCapacity = (int)configuration_result;
939 break;
940 case "linkset_capacity":
941 m_linksetCapacity = (int)configuration_result;
942 break;
943 case "agent_capacity":
944 m_agentCapacity = (int)configuration_result;
945 break;
946 case "scope_id":
947 ScopeID = (UUID)configuration_result;
948 break;
949 case "region_type":
950 m_regionType = (string)configuration_result;
951 break;
952 }
953
954 return true;
955 }
956
957 public void SaveLastMapUUID(UUID mapUUID) 904 public void SaveLastMapUUID(UUID mapUUID)
958 { 905 {
959 lastMapUUID = mapUUID; 906 lastMapUUID = mapUUID;
960 lastMapRefresh = Util.UnixTimeSinceEpoch().ToString(); 907 lastMapRefresh = Util.UnixTimeSinceEpoch().ToString();
961
962 if (configMember == null)
963 return;
964
965 configMember.forceSetConfigurationOption("lastmap_uuid", mapUUID.ToString());
966 configMember.forceSetConfigurationOption("lastmap_refresh", lastMapRefresh);
967 } 908 }
968 909
969 public OSDMap PackRegionInfoData() 910 public OSDMap PackRegionInfoData()
@@ -975,8 +916,13 @@ namespace OpenSim.Framework
975 args["external_host_name"] = OSD.FromString(ExternalHostName); 916 args["external_host_name"] = OSD.FromString(ExternalHostName);
976 args["http_port"] = OSD.FromString(HttpPort.ToString()); 917 args["http_port"] = OSD.FromString(HttpPort.ToString());
977 args["server_uri"] = OSD.FromString(ServerURI); 918 args["server_uri"] = OSD.FromString(ServerURI);
919
978 args["region_xloc"] = OSD.FromString(RegionLocX.ToString()); 920 args["region_xloc"] = OSD.FromString(RegionLocX.ToString());
979 args["region_yloc"] = OSD.FromString(RegionLocY.ToString()); 921 args["region_yloc"] = OSD.FromString(RegionLocY.ToString());
922 args["region_size_x"] = OSD.FromString(RegionSizeX.ToString());
923 args["region_size_y"] = OSD.FromString(RegionSizeY.ToString());
924 args["region_size_z"] = OSD.FromString(RegionSizeZ.ToString());
925
980 args["internal_ep_address"] = OSD.FromString(InternalEndPoint.Address.ToString()); 926 args["internal_ep_address"] = OSD.FromString(InternalEndPoint.Address.ToString());
981 args["internal_ep_port"] = OSD.FromString(InternalEndPoint.Port.ToString()); 927 args["internal_ep_port"] = OSD.FromString(InternalEndPoint.Port.ToString());
982 if ((RemotingAddress != null) && !RemotingAddress.Equals("")) 928 if ((RemotingAddress != null) && !RemotingAddress.Equals(""))
@@ -1015,6 +961,13 @@ namespace OpenSim.Framework
1015 UInt32.TryParse(args["region_yloc"].AsString(), out locy); 961 UInt32.TryParse(args["region_yloc"].AsString(), out locy);
1016 RegionLocY = locy; 962 RegionLocY = locy;
1017 } 963 }
964 if (args.ContainsKey("region_size_x"))
965 RegionSizeX = (uint)args["region_size_x"].AsInteger();
966 if (args.ContainsKey("region_size_y"))
967 RegionSizeY = (uint)args["region_size_y"].AsInteger();
968 if (args.ContainsKey("region_size_z"))
969 RegionSizeZ = (uint)args["region_size_z"].AsInteger();
970
1018 IPAddress ip_addr = null; 971 IPAddress ip_addr = null;
1019 if (args["internal_ep_address"] != null) 972 if (args["internal_ep_address"] != null)
1020 { 973 {
@@ -1051,23 +1004,5 @@ namespace OpenSim.Framework
1051 regionInfo.ServerURI = serverURI; 1004 regionInfo.ServerURI = serverURI;
1052 return regionInfo; 1005 return regionInfo;
1053 } 1006 }
1054
1055 public Dictionary<string, object> ToKeyValuePairs()
1056 {
1057 Dictionary<string, object> kvp = new Dictionary<string, object>();
1058 kvp["uuid"] = RegionID.ToString();
1059 kvp["locX"] = RegionLocX.ToString();
1060 kvp["locY"] = RegionLocY.ToString();
1061 kvp["external_ip_address"] = ExternalEndPoint.Address.ToString();
1062 kvp["external_port"] = ExternalEndPoint.Port.ToString();
1063 kvp["external_host_name"] = ExternalHostName;
1064 kvp["http_port"] = HttpPort.ToString();
1065 kvp["internal_ip_address"] = InternalEndPoint.Address.ToString();
1066 kvp["internal_port"] = InternalEndPoint.Port.ToString();
1067 kvp["alternate_ports"] = m_allow_alternate_ports.ToString();
1068 kvp["server_uri"] = ServerURI;
1069
1070 return kvp;
1071 }
1072 } 1007 }
1073} 1008}
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 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Framework.RegionLoader.Filesystem")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("4ab5c74b-e886-40a1-b67d-a04df285e706")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using log4net;
29using System;
30using System.Collections.Generic;
31using System.IO;
32using System.Reflection;
33using Nini.Config;
34
35namespace OpenSim.Framework.RegionLoader.Filesystem
36{
37 public class RegionLoaderFileSystem : IRegionLoader
38 {
39 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
40
41 private IConfigSource m_configSource;
42
43 public void SetIniConfigSource(IConfigSource configSource)
44 {
45 m_configSource = configSource;
46 }
47
48 public RegionInfo[] LoadRegions()
49 {
50 string regionConfigPath = Path.Combine(Util.configDir(), "Regions");
51 bool allowRegionless = false;
52
53 try
54 {
55 IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"];
56 regionConfigPath = startupConfig.GetString("regionload_regionsdir", regionConfigPath).Trim();
57 allowRegionless = startupConfig.GetBoolean("allow_regionless", false);
58 }
59 catch (Exception)
60 {
61 // No INI setting recorded.
62 }
63
64 if (!Directory.Exists(regionConfigPath))
65 {
66 Directory.CreateDirectory(regionConfigPath);
67 }
68
69 string[] configFiles = Directory.GetFiles(regionConfigPath, "*.xml");
70 string[] iniFiles = Directory.GetFiles(regionConfigPath, "*.ini");
71
72 // Create an empty Regions.ini if there are no existing config files.
73 if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0)
74 {
75 new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource);
76 iniFiles = Directory.GetFiles(regionConfigPath, "*.ini");
77 }
78
79 m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config files from {0}", regionConfigPath);
80
81 List<RegionInfo> regionInfos = new List<RegionInfo>();
82
83 int i = 0;
84 foreach (string file in iniFiles)
85 {
86 m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file);
87
88 IConfigSource source = new IniConfigSource(file);
89
90 foreach (IConfig config in source.Configs)
91 {
92 RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource, config.Name);
93 regionInfos.Add(regionInfo);
94
95 m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName);
96
97 i++;
98 }
99 }
100
101 foreach (string file in configFiles)
102 {
103 m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file);
104
105 RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource);
106 regionInfos.Add(regionInfo);
107
108 m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName);
109
110 i++;
111 }
112
113 return regionInfos.ToArray();
114 }
115 }
116} \ 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 @@
1using System.Reflection;
2using System.Runtime.CompilerServices;
3using System.Runtime.InteropServices;
4
5// General Information about an assembly is controlled through the following
6// set of attributes. Change these attribute values to modify the information
7// associated with an assembly.
8[assembly: AssemblyTitle("OpenSim.Framework.RegionLoader.Web")]
9[assembly: AssemblyDescription("")]
10[assembly: AssemblyConfiguration("")]
11[assembly: AssemblyCompany("http://opensimulator.org")]
12[assembly: AssemblyProduct("OpenSim")]
13[assembly: AssemblyCopyright("OpenSimulator developers")]
14[assembly: AssemblyTrademark("")]
15[assembly: AssemblyCulture("")]
16
17// Setting ComVisible to false makes the types in this assembly not visible
18// to COM components. If you need to access a type in this assembly from
19// COM, set the ComVisible attribute to true on that type.
20[assembly: ComVisible(false)]
21
22// The following GUID is for the ID of the typelib if this project is exposed to COM
23[assembly: Guid("985afff8-e7ed-4056-acce-39abf7a43d33")]
24
25// Version information for an assembly consists of the following four values:
26//
27// Major Version
28// Minor Version
29// Build Number
30// Revision
31//
32[assembly: AssemblyVersion("0.7.5.*")]
33[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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.IO;
30using System.Net;
31using System.Reflection;
32using System.Xml;
33using log4net;
34using Nini.Config;
35
36namespace OpenSim.Framework.RegionLoader.Web
37{
38 public class RegionLoaderWebServer : IRegionLoader
39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
42 private IConfigSource m_configSource;
43
44 public void SetIniConfigSource(IConfigSource configSource)
45 {
46 m_configSource = configSource;
47 }
48
49 public RegionInfo[] LoadRegions()
50 {
51 if (m_configSource == null)
52 {
53 m_log.Error("[WEBLOADER]: Unable to load configuration source!");
54 return null;
55 }
56 else
57 {
58 IConfig startupConfig = (IConfig) m_configSource.Configs["Startup"];
59 string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim();
60 bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false);
61
62 if (url == String.Empty)
63 {
64 m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty.");
65 return null;
66 }
67 else
68 {
69 RegionInfo[] regionInfos = new RegionInfo[] {};
70 int regionCount = 0;
71 HttpWebRequest webRequest = (HttpWebRequest) WebRequest.Create(url);
72 webRequest.Timeout = 30000; //30 Second Timeout
73 m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url);
74
75 try
76 {
77 HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse();
78 m_log.Debug("[WEBLOADER]: Downloading region information...");
79 StreamReader reader = new StreamReader(webResponse.GetResponseStream());
80 string xmlSource = String.Empty;
81 string tempStr = reader.ReadLine();
82 while (tempStr != null)
83 {
84 xmlSource = xmlSource + tempStr;
85 tempStr = reader.ReadLine();
86 }
87 m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " +
88 xmlSource.Length);
89 XmlDocument xmlDoc = new XmlDocument();
90 xmlDoc.LoadXml(xmlSource);
91 if (xmlDoc.FirstChild.Name == "Regions")
92 {
93 regionCount = xmlDoc.FirstChild.ChildNodes.Count;
94
95 if (regionCount > 0)
96 {
97 regionInfos = new RegionInfo[regionCount];
98 int i;
99 for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++)
100 {
101 m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml);
102 regionInfos[i] =
103 new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource);
104 }
105 }
106 }
107 }
108 catch (WebException ex)
109 {
110 if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound)
111 {
112 if (!allowRegionless)
113 throw ex;
114 }
115 else
116 throw ex;
117 }
118
119 if (regionCount > 0 | allowRegionless)
120 return regionInfos;
121 else
122 {
123 m_log.Error("[WEBLOADER]: No region configs were available.");
124 return null;
125 }
126 }
127 }
128 }
129 }
130}
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
200 set { m_ObjectBonus = value; } 200 set { m_ObjectBonus = value; }
201 } 201 }
202 202
203 private int m_Maturity = 1; 203 private int m_Maturity = 0;
204 204
205 public int Maturity 205 public int Maturity
206 { 206 {
@@ -482,21 +482,14 @@ namespace OpenSim.Framework
482 set { m_LoadedCreationID = value; } 482 set { m_LoadedCreationID = value; }
483 } 483 }
484 484
485 // Connected Telehub object 485 /// <summary>
486 private UUID m_TelehubObject = UUID.Zero; 486 /// Connected Telehub object
487 public UUID TelehubObject 487 /// </summary>
488 { 488 public UUID TelehubObject { get; set; }
489 get
490 {
491 return m_TelehubObject;
492 }
493 set
494 {
495 m_TelehubObject = value;
496 }
497 }
498 489
499 // Our Connected Telehub's SpawnPoints 490 /// <summary>
491 /// Our connected Telehub's SpawnPoints
492 /// </summary>
500 public List<SpawnPoint> l_SpawnPoints = new List<SpawnPoint>(); 493 public List<SpawnPoint> l_SpawnPoints = new List<SpawnPoint>();
501 494
502 // Add a SpawnPoint 495 // Add a SpawnPoint
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/RestClient.cs
index 97b3b60..7080ca5 100644
--- a/OpenSim/Framework/Communications/RestClient.cs
+++ b/OpenSim/Framework/RestClient.cs
@@ -35,7 +35,9 @@ using System.Threading;
35using System.Web; 35using System.Web;
36using log4net; 36using log4net;
37 37
38namespace OpenSim.Framework.Communications 38using OpenSim.Framework.ServiceAuth;
39
40namespace OpenSim.Framework
39{ 41{
40 /// <summary> 42 /// <summary>
41 /// Implementation of a generic REST client 43 /// Implementation of a generic REST client
@@ -54,7 +56,7 @@ namespace OpenSim.Framework.Communications
54 /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be 56 /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be
55 /// invoked by the caller in either synchronous mode or asynchronous modes. 57 /// invoked by the caller in either synchronous mode or asynchronous modes.
56 /// </remarks> 58 /// </remarks>
57 public class RestClient 59 public class RestClient : IDisposable
58 { 60 {
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 62
@@ -88,7 +90,7 @@ namespace OpenSim.Framework.Communications
88 private byte[] _readbuf; 90 private byte[] _readbuf;
89 91
90 /// <summary> 92 /// <summary>
91 /// MemoryStream representing the resultiong resource 93 /// MemoryStream representing the resulting resource
92 /// </summary> 94 /// </summary>
93 private Stream _resource; 95 private Stream _resource;
94 96
@@ -146,6 +148,33 @@ namespace OpenSim.Framework.Communications
146 148
147 #endregion constructors 149 #endregion constructors
148 150
151
152 #region Dispose
153
154 private bool disposed = false;
155
156 public void Dispose()
157 {
158 Dispose(true);
159 GC.SuppressFinalize(this);
160 }
161
162 protected virtual void Dispose(bool disposing)
163 {
164 if (disposed)
165 return;
166
167 if (disposing)
168 {
169 _resource.Dispose();
170 }
171
172 disposed = true;
173 }
174
175 #endregion Dispose
176
177
149 /// <summary> 178 /// <summary>
150 /// Add a path element to the query, e.g. assets 179 /// Add a path element to the query, e.g. assets
151 /// </summary> 180 /// </summary>
@@ -299,6 +328,14 @@ namespace OpenSim.Framework.Communications
299 /// </summary> 328 /// </summary>
300 public Stream Request() 329 public Stream Request()
301 { 330 {
331 return Request(null);
332 }
333
334 /// <summary>
335 /// Perform a synchronous request
336 /// </summary>
337 public Stream Request(IServiceAuth auth)
338 {
302 lock (_lock) 339 lock (_lock)
303 { 340 {
304 _request = (HttpWebRequest) WebRequest.Create(buildUri()); 341 _request = (HttpWebRequest) WebRequest.Create(buildUri());
@@ -307,44 +344,54 @@ namespace OpenSim.Framework.Communications
307 _request.Timeout = 200000; 344 _request.Timeout = 200000;
308 _request.Method = RequestMethod; 345 _request.Method = RequestMethod;
309 _asyncException = null; 346 _asyncException = null;
347 if (auth != null)
348 auth.AddAuthorization(_request.Headers);
349
350 int reqnum = WebUtil.RequestNumber++;
351 if (WebUtil.DebugLevel >= 3)
352 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
310 353
311// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); 354// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
355
312 try 356 try
313 { 357 {
314 _response = (HttpWebResponse) _request.GetResponse(); 358 using (_response = (HttpWebResponse) _request.GetResponse())
359 {
360 using (Stream src = _response.GetResponseStream())
361 {
362 int length = src.Read(_readbuf, 0, BufferSize);
363 while (length > 0)
364 {
365 _resource.Write(_readbuf, 0, length);
366 length = src.Read(_readbuf, 0, BufferSize);
367 }
368
369 // TODO! Implement timeout, without killing the server
370 // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
371 //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
372
373 // _allDone.WaitOne();
374 }
375 }
315 } 376 }
316 catch (WebException e) 377 catch (WebException e)
317 { 378 {
318 HttpWebResponse errorResponse = e.Response as HttpWebResponse; 379 using (HttpWebResponse errorResponse = e.Response as HttpWebResponse)
319 if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
320 {
321 m_log.Warn("[REST CLIENT] Resource not found (404)");
322 }
323 else
324 { 380 {
325 m_log.Error("[REST CLIENT] Error fetching resource from server " + _request.Address.ToString()); 381 if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
326 m_log.Debug(e.ToString()); 382 {
383 // This is often benign. E.g., requesting a missing asset will return 404.
384 m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString());
385 }
386 else
387 {
388 m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e);
389 }
327 } 390 }
328 391
329 return null; 392 return null;
330 } 393 }
331 394
332 Stream src = _response.GetResponseStream();
333 int length = src.Read(_readbuf, 0, BufferSize);
334 while (length > 0)
335 {
336 _resource.Write(_readbuf, 0, length);
337 length = src.Read(_readbuf, 0, BufferSize);
338 }
339
340
341 // TODO! Implement timeout, without killing the server
342 // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
343 //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
344
345// _allDone.WaitOne();
346 if (_response != null)
347 _response.Close();
348 if (_asyncException != null) 395 if (_asyncException != null)
349 throw _asyncException; 396 throw _asyncException;
350 397
@@ -354,11 +401,14 @@ namespace OpenSim.Framework.Communications
354 _resource.Seek(0, SeekOrigin.Begin); 401 _resource.Seek(0, SeekOrigin.Begin);
355 } 402 }
356 403
404 if (WebUtil.DebugLevel >= 5)
405 WebUtil.LogResponseDetail(reqnum, _resource);
406
357 return _resource; 407 return _resource;
358 } 408 }
359 } 409 }
360 410
361 public Stream Request(Stream src) 411 public Stream Request(Stream src, IServiceAuth auth)
362 { 412 {
363 _request = (HttpWebRequest) WebRequest.Create(buildUri()); 413 _request = (HttpWebRequest) WebRequest.Create(buildUri());
364 _request.KeepAlive = false; 414 _request.KeepAlive = false;
@@ -367,24 +417,58 @@ namespace OpenSim.Framework.Communications
367 _request.Method = RequestMethod; 417 _request.Method = RequestMethod;
368 _asyncException = null; 418 _asyncException = null;
369 _request.ContentLength = src.Length; 419 _request.ContentLength = src.Length;
420 if (auth != null)
421 auth.AddAuthorization(_request.Headers);
370 422
371 m_log.InfoFormat("[REST]: Request Length {0}", _request.ContentLength);
372 m_log.InfoFormat("[REST]: Sending Web Request {0}", buildUri());
373 src.Seek(0, SeekOrigin.Begin); 423 src.Seek(0, SeekOrigin.Begin);
374 m_log.Info("[REST]: Seek is ok"); 424
425 int reqnum = WebUtil.RequestNumber++;
426 if (WebUtil.DebugLevel >= 3)
427 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
428 if (WebUtil.DebugLevel >= 5)
429 WebUtil.LogOutgoingDetail(string.Format("SEND {0}: ", reqnum), src);
430
375 Stream dst = _request.GetRequestStream(); 431 Stream dst = _request.GetRequestStream();
376 m_log.Info("[REST]: GetRequestStream is ok");
377 432
378 byte[] buf = new byte[1024]; 433 byte[] buf = new byte[1024];
379 int length = src.Read(buf, 0, 1024); 434 int length = src.Read(buf, 0, 1024);
380 m_log.Info("[REST]: First Read is ok");
381 while (length > 0) 435 while (length > 0)
382 { 436 {
383 dst.Write(buf, 0, length); 437 dst.Write(buf, 0, length);
384 length = src.Read(buf, 0, 1024); 438 length = src.Read(buf, 0, 1024);
385 } 439 }
386 440
387 _response = (HttpWebResponse) _request.GetResponse(); 441 try
442 {
443 _response = (HttpWebResponse)_request.GetResponse();
444 }
445 catch (WebException e)
446 {
447 m_log.WarnFormat("[REST]: Request {0} {1} failed with status {2} and message {3}",
448 RequestMethod, _request.RequestUri, e.Status, e.Message);
449 return null;
450 }
451 catch (Exception e)
452 {
453 m_log.WarnFormat(
454 "[REST]: Request {0} {1} failed with exception {2} {3}",
455 RequestMethod, _request.RequestUri, e.Message, e.StackTrace);
456 return null;
457 }
458
459 if (WebUtil.DebugLevel >= 5)
460 {
461 using (Stream responseStream = _response.GetResponseStream())
462 {
463 using (StreamReader reader = new StreamReader(responseStream))
464 {
465 string responseStr = reader.ReadToEnd();
466 WebUtil.LogResponseDetail(reqnum, responseStr);
467 }
468 }
469 }
470
471 _response.Close();
388 472
389// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); 473// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
390 474
@@ -403,7 +487,7 @@ namespace OpenSim.Framework.Communications
403 /// In case, we are invoked asynchroneously this object will keep track of the state 487 /// In case, we are invoked asynchroneously this object will keep track of the state
404 /// </summary> 488 /// </summary>
405 AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state); 489 AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state);
406 Util.FireAndForget(RequestHelper, ar); 490 Util.FireAndForget(RequestHelper, ar, "RestClient.BeginRequest");
407 return ar; 491 return ar;
408 } 492 }
409 493
@@ -423,7 +507,7 @@ namespace OpenSim.Framework.Communications
423 try 507 try
424 { 508 {
425 // Perform the operation; if sucessful set the result 509 // Perform the operation; if sucessful set the result
426 Stream s = Request(); 510 Stream s = Request(null);
427 ar.SetAsCompleted(s, false); 511 ar.SetAsCompleted(s, false);
428 } 512 }
429 catch (Exception e) 513 catch (Exception e)
@@ -435,4 +519,158 @@ namespace OpenSim.Framework.Communications
435 519
436 #endregion Async Invocation 520 #endregion Async Invocation
437 } 521 }
438} 522
523 internal class SimpleAsyncResult : IAsyncResult
524 {
525 private readonly AsyncCallback m_callback;
526
527 /// <summary>
528 /// Is process completed?
529 /// </summary>
530 /// <remarks>Should really be boolean, but VolatileRead has no boolean method</remarks>
531 private byte m_completed;
532
533 /// <summary>
534 /// Did process complete synchronously?
535 /// </summary>
536 /// <remarks>I have a hard time imagining a scenario where this is the case, again, same issue about
537 /// booleans and VolatileRead as m_completed
538 /// </remarks>
539 private byte m_completedSynchronously;
540
541 private readonly object m_asyncState;
542 private ManualResetEvent m_waitHandle;
543 private Exception m_exception;
544
545 internal SimpleAsyncResult(AsyncCallback cb, object state)
546 {
547 m_callback = cb;
548 m_asyncState = state;
549 m_completed = 0;
550 m_completedSynchronously = 1;
551 }
552
553 #region IAsyncResult Members
554
555 public object AsyncState
556 {
557 get { return m_asyncState; }
558 }
559
560 public WaitHandle AsyncWaitHandle
561 {
562 get
563 {
564 if (m_waitHandle == null)
565 {
566 bool done = IsCompleted;
567 ManualResetEvent mre = new ManualResetEvent(done);
568 if (Interlocked.CompareExchange(ref m_waitHandle, mre, null) != null)
569 {
570 mre.Close();
571 }
572 else
573 {
574 if (!done && IsCompleted)
575 {
576 m_waitHandle.Set();
577 }
578 }
579 }
580
581 return m_waitHandle;
582 }
583 }
584
585
586 public bool CompletedSynchronously
587 {
588 get { return Thread.VolatileRead(ref m_completedSynchronously) == 1; }
589 }
590
591
592 public bool IsCompleted
593 {
594 get { return Thread.VolatileRead(ref m_completed) == 1; }
595 }
596
597 #endregion
598
599 #region class Methods
600
601 internal void SetAsCompleted(bool completedSynchronously)
602 {
603 m_completed = 1;
604 if (completedSynchronously)
605 m_completedSynchronously = 1;
606 else
607 m_completedSynchronously = 0;
608
609 SignalCompletion();
610 }
611
612 internal void HandleException(Exception e, bool completedSynchronously)
613 {
614 m_completed = 1;
615 if (completedSynchronously)
616 m_completedSynchronously = 1;
617 else
618 m_completedSynchronously = 0;
619 m_exception = e;
620
621 SignalCompletion();
622 }
623
624 private void SignalCompletion()
625 {
626 if (m_waitHandle != null) m_waitHandle.Set();
627
628 if (m_callback != null) m_callback(this);
629 }
630
631 public void EndInvoke()
632 {
633 // This method assumes that only 1 thread calls EndInvoke
634 if (!IsCompleted)
635 {
636 // If the operation isn't done, wait for it
637 AsyncWaitHandle.WaitOne();
638 AsyncWaitHandle.Close();
639 m_waitHandle.Close();
640 m_waitHandle = null; // Allow early GC
641 }
642
643 // Operation is done: if an exception occured, throw it
644 if (m_exception != null) throw m_exception;
645 }
646
647 #endregion
648 }
649
650 internal class AsyncResult<T> : SimpleAsyncResult
651 {
652 private T m_result = default(T);
653
654 public AsyncResult(AsyncCallback asyncCallback, Object state) :
655 base(asyncCallback, state)
656 {
657 }
658
659 public void SetAsCompleted(T result, bool completedSynchronously)
660 {
661 // Save the asynchronous operation's result
662 m_result = result;
663
664 // Tell the base class that the operation completed
665 // sucessfully (no exception)
666 base.SetAsCompleted(completedSynchronously);
667 }
668
669 public new T EndInvoke()
670 {
671 base.EndInvoke();
672 return m_result;
673 }
674 }
675
676} \ 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 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using OpenMetaverse;
28using System; 29using System;
29using System.Collections.Generic; 30using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32using System.Xml;
33using log4net;
34using OpenMetaverse;
35 31
36namespace OpenSim.Framework 32namespace OpenSim.Framework
37{ 33{
@@ -39,12 +35,36 @@ namespace OpenSim.Framework
39 { 35 {
40// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 36// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41 37
38 /// <summary>
39 /// Asset types used only in OpenSim.
40 /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here.
41 /// </summary>
42 public enum OpenSimAssetType : sbyte
43 {
44 Material = -2
45 }
46
47
42 #region SL / file extension / content-type conversions 48 #region SL / file extension / content-type conversions
43 49
50 /// <summary>
51 /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs
52 /// to the AssetType or OpenSimAssetType enums.
53 /// </summary>
54 public static object AssetTypeFromCode(sbyte assetType)
55 {
56 if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
57 return (OpenMetaverse.AssetType)assetType;
58 else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType))
59 return (OpenSimAssetType)assetType;
60 else
61 return OpenMetaverse.AssetType.Unknown;
62 }
63
44 private class TypeMapping 64 private class TypeMapping
45 { 65 {
46 private sbyte assetType; 66 private sbyte assetType;
47 private InventoryType inventoryType; 67 private sbyte inventoryType;
48 private string contentType; 68 private string contentType;
49 private string contentType2; 69 private string contentType2;
50 private string extension; 70 private string extension;
@@ -56,15 +76,10 @@ namespace OpenSim.Framework
56 76
57 public object AssetType 77 public object AssetType
58 { 78 {
59 get { 79 get { return AssetTypeFromCode(assetType); }
60 if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType))
61 return (OpenMetaverse.AssetType)assetType;
62 else
63 return OpenMetaverse.AssetType.Unknown;
64 }
65 } 80 }
66 81
67 public InventoryType InventoryType 82 public sbyte InventoryType
68 { 83 {
69 get { return inventoryType; } 84 get { return inventoryType; }
70 } 85 }
@@ -84,7 +99,7 @@ namespace OpenSim.Framework
84 get { return extension; } 99 get { return extension; }
85 } 100 }
86 101
87 private TypeMapping(sbyte assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) 102 private TypeMapping(sbyte assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
88 { 103 {
89 this.assetType = assetType; 104 this.assetType = assetType;
90 this.inventoryType = inventoryType; 105 this.inventoryType = inventoryType;
@@ -93,13 +108,28 @@ namespace OpenSim.Framework
93 this.extension = extension; 108 this.extension = extension;
94 } 109 }
95 110
96 public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension) 111 public TypeMapping(AssetType assetType, sbyte inventoryType, string contentType, string contentType2, string extension)
97 : this((sbyte)assetType, inventoryType, contentType, contentType2, extension) 112 : this((sbyte)assetType, inventoryType, contentType, contentType2, extension)
98 { 113 {
99 } 114 }
100 115
116 public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string contentType2, string extension)
117 : this((sbyte)assetType, (sbyte)inventoryType, contentType, contentType2, extension)
118 {
119 }
120
101 public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension) 121 public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension)
102 : this((sbyte)assetType, inventoryType, contentType, null, extension) 122 : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
123 {
124 }
125
126 public TypeMapping(AssetType assetType, FolderType inventoryType, string contentType, string extension)
127 : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
128 {
129 }
130
131 public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension)
132 : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension)
103 { 133 {
104 } 134 }
105 } 135 }
@@ -125,51 +155,65 @@ namespace OpenSim.Framework
125 new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"), 155 new TypeMapping(AssetType.Object, InventoryType.Object, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
126 new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"), 156 new TypeMapping(AssetType.Object, InventoryType.Attachment, "application/vnd.ll.primitive", "application/x-metaverse-primitive", "primitive"),
127 new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"), 157 new TypeMapping(AssetType.Notecard, InventoryType.Notecard, "application/vnd.ll.notecard", "application/x-metaverse-notecard", "notecard"),
128 new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
129 new TypeMapping(AssetType.RootFolder, InventoryType.RootCategory, "application/vnd.ll.rootfolder", "rootfolder"),
130 new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"), 158 new TypeMapping(AssetType.LSLText, InventoryType.LSL, "application/vnd.ll.lsltext", "application/x-metaverse-lsl", "lsl"),
131 new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"), 159 new TypeMapping(AssetType.LSLBytecode, InventoryType.LSL, "application/vnd.ll.lslbyte", "application/x-metaverse-lso", "lso"),
132 new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"), 160 new TypeMapping(AssetType.Bodypart, InventoryType.Wearable, "application/vnd.ll.bodypart", "application/x-metaverse-bodypart", "bodypart"),
133 new TypeMapping(AssetType.TrashFolder, InventoryType.Folder, "application/vnd.ll.trashfolder", "trashfolder"),
134 new TypeMapping(AssetType.SnapshotFolder, InventoryType.Folder, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
135 new TypeMapping(AssetType.LostAndFoundFolder, InventoryType.Folder, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
136 new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"), 161 new TypeMapping(AssetType.Animation, InventoryType.Animation, "application/vnd.ll.animation", "application/x-metaverse-animation", "animation"),
137 new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"), 162 new TypeMapping(AssetType.Gesture, InventoryType.Gesture, "application/vnd.ll.gesture", "application/x-metaverse-gesture", "gesture"),
138 new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"), 163 new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"),
139 new TypeMapping(AssetType.FavoriteFolder, InventoryType.Unknown, "application/vnd.ll.favoritefolder", "favoritefolder"),
140 new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"), 164 new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"),
141 new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"), 165 new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"),
142 new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), 166 new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"),
143 new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), 167
144 new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), 168 // The next few items are about inventory folders
145 new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm") 169 new TypeMapping(AssetType.Folder, FolderType.None, "application/vnd.ll.folder", "folder"),
170 new TypeMapping(AssetType.Folder, FolderType.Root, "application/vnd.ll.rootfolder", "rootfolder"),
171 new TypeMapping(AssetType.Folder, FolderType.Trash, "application/vnd.ll.trashfolder", "trashfolder"),
172 new TypeMapping(AssetType.Folder, FolderType.Snapshot, "application/vnd.ll.snapshotfolder", "snapshotfolder"),
173 new TypeMapping(AssetType.Folder, FolderType.LostAndFound, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"),
174 new TypeMapping(AssetType.Folder, FolderType.Favorites, "application/vnd.ll.favoritefolder", "favoritefolder"),
175 new TypeMapping(AssetType.Folder, FolderType.CurrentOutfit, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"),
176 new TypeMapping(AssetType.Folder, FolderType.Outfit, "application/vnd.ll.outfitfolder", "outfitfolder"),
177 new TypeMapping(AssetType.Folder, FolderType.MyOutfits, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"),
178
179 // This next mappping is an asset to inventory item mapping.
180 // Note: LL stores folders as assets of type Folder = 8, and it has a corresponding InventoryType = 8
181 // OpenSim doesn't store folders as assets, so this mapping should only be used when parsing things from the viewer to the server
182 new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"),
183
184 // OpenSim specific
185 new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material")
146 }; 186 };
147 187
148 private static Dictionary<sbyte, string> asset2Content; 188 private static Dictionary<sbyte, string> asset2Content;
149 private static Dictionary<sbyte, string> asset2Extension; 189 private static Dictionary<sbyte, string> asset2Extension;
150 private static Dictionary<InventoryType, string> inventory2Content; 190 private static Dictionary<sbyte, string> inventory2Content;
151 private static Dictionary<string, sbyte> content2Asset; 191 private static Dictionary<string, sbyte> content2Asset;
152 private static Dictionary<string, InventoryType> content2Inventory; 192 private static Dictionary<string, sbyte> content2Inventory;
153 193
154 static SLUtil() 194 static SLUtil()
155 { 195 {
156 asset2Content = new Dictionary<sbyte, string>(); 196 asset2Content = new Dictionary<sbyte, string>();
157 asset2Extension = new Dictionary<sbyte, string>(); 197 asset2Extension = new Dictionary<sbyte, string>();
158 inventory2Content = new Dictionary<InventoryType, string>(); 198 inventory2Content = new Dictionary<sbyte, string>();
159 content2Asset = new Dictionary<string, sbyte>(); 199 content2Asset = new Dictionary<string, sbyte>();
160 content2Inventory = new Dictionary<string, InventoryType>(); 200 content2Inventory = new Dictionary<string, sbyte>();
161 201
162 foreach (TypeMapping mapping in MAPPINGS) 202 foreach (TypeMapping mapping in MAPPINGS)
163 { 203 {
164 sbyte assetType = mapping.AssetTypeCode; 204 sbyte assetType = mapping.AssetTypeCode;
165 if (!asset2Content.ContainsKey(assetType)) 205 if (!asset2Content.ContainsKey(assetType))
166 asset2Content.Add(assetType, mapping.ContentType); 206 asset2Content.Add(assetType, mapping.ContentType);
207
167 if (!asset2Extension.ContainsKey(assetType)) 208 if (!asset2Extension.ContainsKey(assetType))
168 asset2Extension.Add(assetType, mapping.Extension); 209 asset2Extension.Add(assetType, mapping.Extension);
210
169 if (!inventory2Content.ContainsKey(mapping.InventoryType)) 211 if (!inventory2Content.ContainsKey(mapping.InventoryType))
170 inventory2Content.Add(mapping.InventoryType, mapping.ContentType); 212 inventory2Content.Add(mapping.InventoryType, mapping.ContentType);
213
171 if (!content2Asset.ContainsKey(mapping.ContentType)) 214 if (!content2Asset.ContainsKey(mapping.ContentType))
172 content2Asset.Add(mapping.ContentType, assetType); 215 content2Asset.Add(mapping.ContentType, assetType);
216
173 if (!content2Inventory.ContainsKey(mapping.ContentType)) 217 if (!content2Inventory.ContainsKey(mapping.ContentType))
174 content2Inventory.Add(mapping.ContentType, mapping.InventoryType); 218 content2Inventory.Add(mapping.ContentType, mapping.InventoryType);
175 219
@@ -194,8 +238,8 @@ namespace OpenSim.Framework
194 public static string SLInvTypeToContentType(int invType) 238 public static string SLInvTypeToContentType(int invType)
195 { 239 {
196 string contentType; 240 string contentType;
197 if (!inventory2Content.TryGetValue((InventoryType)invType, out contentType)) 241 if (!inventory2Content.TryGetValue((sbyte)invType, out contentType))
198 contentType = inventory2Content[InventoryType.Unknown]; 242 contentType = inventory2Content[(sbyte)InventoryType.Unknown];
199 return contentType; 243 return contentType;
200 } 244 }
201 245
@@ -209,9 +253,9 @@ namespace OpenSim.Framework
209 253
210 public static sbyte ContentTypeToSLInvType(string contentType) 254 public static sbyte ContentTypeToSLInvType(string contentType)
211 { 255 {
212 InventoryType invType; 256 sbyte invType;
213 if (!content2Inventory.TryGetValue(contentType, out invType)) 257 if (!content2Inventory.TryGetValue(contentType, out invType))
214 invType = InventoryType.Unknown; 258 invType = (sbyte)InventoryType.Unknown;
215 return (sbyte)invType; 259 return (sbyte)invType;
216 } 260 }
217 261
@@ -225,106 +269,270 @@ namespace OpenSim.Framework
225 269
226 #endregion SL / file extension / content-type conversions 270 #endregion SL / file extension / content-type conversions
227 271
228 /// <summary> 272 private class NotecardReader
229 /// Parse a notecard in Linden format to a string of ordinary text.
230 /// </summary>
231 /// <param name="rawInput"></param>
232 /// <returns></returns>
233 public static string ParseNotecardToString(string rawInput)
234 { 273 {
235 string[] output = ParseNotecardToList(rawInput).ToArray(); 274 private string rawInput;
275 private int lineNumber;
236 276
237// foreach (string line in output) 277 public int LineNumber
238// m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line); 278 {
239 279 get
240 return string.Join("\n", output); 280 {
281 return lineNumber;
282 }
283 }
284
285 public NotecardReader(string _rawInput)
286 {
287 rawInput = (string)_rawInput.Clone();
288 lineNumber = 0;
289 }
290
291 public string getLine()
292 {
293 if(rawInput.Length == 0)
294 {
295 throw new NotANotecardFormatException(lineNumber + 1);
296 }
297
298 int pos = rawInput.IndexOf('\n');
299 if(pos < 0)
300 {
301 pos = rawInput.Length;
302 }
303
304 /* cut line from rest */
305 ++lineNumber;
306 string line = rawInput.Substring(0, pos);
307 if (pos + 1 >= rawInput.Length)
308 {
309 rawInput = string.Empty;
310 }
311 else
312 {
313 rawInput = rawInput.Substring(pos + 1);
314 }
315 /* clean up line from double spaces and tabs */
316 line = line.Replace("\t", " ");
317 while(line.IndexOf(" ") >= 0)
318 {
319 line = line.Replace(" ", " ");
320 }
321 return line.Replace("\r", "").Trim();
322 }
323
324 public string getBlock(int length)
325 {
326 /* cut line from rest */
327 if(length > rawInput.Length)
328 {
329 throw new NotANotecardFormatException(lineNumber);
330 }
331 string line = rawInput.Substring(0, length);
332 rawInput = rawInput.Substring(length);
333 return line;
334 }
241 } 335 }
242 336
243 /// <summary> 337 public class NotANotecardFormatException : Exception
244 /// Parse a notecard in Linden format to a list of ordinary lines. 338 {
245 /// </summary> 339 public int lineNumber;
246 /// <param name="rawInput"></param> 340 public NotANotecardFormatException(int _lineNumber)
247 /// <returns></returns> 341 : base()
248 public static List<string> ParseNotecardToList(string rawInput) 342 {
343 lineNumber = _lineNumber;
344 }
345 }
346
347 private static void skipSection(NotecardReader reader)
249 { 348 {
250 string[] input = rawInput.Replace("\r", "").Split('\n'); 349 if (reader.getLine() != "{")
251 int idx = 0; 350 throw new NotANotecardFormatException(reader.LineNumber);
252 int level = 0;
253 List<string> output = new List<string>();
254 string[] words;
255 351
256 while (idx < input.Length) 352 string line;
353 while ((line = reader.getLine()) != "}")
257 { 354 {
258 if (input[idx] == "{") 355 if(line.IndexOf('{')>=0)
356 {
357 throw new NotANotecardFormatException(reader.LineNumber);
358 }
359 }
360 }
361
362 private static void skipInventoryItem(NotecardReader reader)
363 {
364 if (reader.getLine() != "{")
365 throw new NotANotecardFormatException(reader.LineNumber);
366
367 string line;
368 while((line = reader.getLine()) != "}")
369 {
370 string[] data = line.Split(' ');
371 if(data.Length == 0)
259 { 372 {
260 level++;
261 idx++;
262 continue; 373 continue;
263 } 374 }
375 if(data[0] == "permissions")
376 {
377 skipSection(reader);
378 }
379 else if(data[0] == "sale_info")
380 {
381 skipSection(reader);
382 }
383 else if (line.IndexOf('{') >= 0)
384 {
385 throw new NotANotecardFormatException(reader.LineNumber);
386 }
387 }
388 }
389
390 private static void skipInventoryItems(NotecardReader reader)
391 {
392 if(reader.getLine() != "{")
393 {
394 throw new NotANotecardFormatException(reader.LineNumber);
395 }
264 396
265 if (input[idx]== "}") 397 string line;
398 while((line = reader.getLine()) != "}")
399 {
400 string[] data = line.Split(' ');
401 if(data.Length == 0)
266 { 402 {
267 level--;
268 idx++;
269 continue; 403 continue;
270 } 404 }
271 405
272 switch (level) 406 if(data[0] == "inv_item")
407 {
408 skipInventoryItem(reader);
409 }
410 else if (line.IndexOf('{') >= 0)
411 {
412 throw new NotANotecardFormatException(reader.LineNumber);
413 }
414
415 }
416 }
417
418 private static void skipInventory(NotecardReader reader)
419 {
420 if (reader.getLine() != "{")
421 throw new NotANotecardFormatException(reader.LineNumber);
422
423 string line;
424 while((line = reader.getLine()) != "}")
425 {
426 string[] data = line.Split(' ');
427 if(data[0] == "count")
273 { 428 {
274 case 0: 429 int count = Int32.Parse(data[1]);
275 words = input[idx].Split(' '); // Linden text ver 430 for(int i = 0; i < count; ++i)
276 // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard)
277 if (words.Length < 3)
278 return output;
279
280 int version = int.Parse(words[3]);
281 if (version != 2)
282 return output;
283 break;
284 case 1:
285 words = input[idx].Split(' ');
286 if (words[0] == "LLEmbeddedItems")
287 break;
288 if (words[0] == "Text")
289 { 431 {
290 int len = int.Parse(words[2]); 432 skipInventoryItems(reader);
291 idx++; 433 }
434 }
435 else if (line.IndexOf('{') >= 0)
436 {
437 throw new NotANotecardFormatException(reader.LineNumber);
438 }
439 }
440 }
441
442 private static string readNotecardText(NotecardReader reader)
443 {
444 if (reader.getLine() != "{")
445 throw new NotANotecardFormatException(reader.LineNumber);
446
447 string notecardString = string.Empty;
448 string line;
449 while((line = reader.getLine()) != "}")
450 {
451 string[] data = line.Split(' ');
452 if (data.Length == 0)
453 {
454 continue;
455 }
292 456
293 int count = -1; 457 if (data[0] == "LLEmbeddedItems")
458 {
459 skipInventory(reader);
460 }
461 else if(data[0] == "Text" && data.Length == 3)
462 {
463 int length = Int32.Parse(data[2]);
464 notecardString = reader.getBlock(length);
465 }
466 else if (line.IndexOf('{') >= 0)
467 {
468 throw new NotANotecardFormatException(reader.LineNumber);
469 }
294 470
295 while (count < len && idx < input.Length) 471 }
296 { 472 return notecardString;
297 // int l = input[idx].Length; 473 }
298 string ln = input[idx];
299 474
300 int need = len-count-1; 475 private static string readNotecard(byte[] rawInput)
301 if (ln.Length > need) 476 {
302 ln = ln.Substring(0, need); 477 string rawIntermedInput = string.Empty;
303 478
304// m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", ln); 479 /* make up a Raw Encoding here */
305 output.Add(ln); 480 foreach(byte c in rawInput)
306 count += ln.Length + 1; 481 {
307 idx++; 482 char d = (char)c;
308 } 483 rawIntermedInput += d;
484 }
309 485
310 return output; 486 NotecardReader reader = new NotecardReader(rawIntermedInput);
311 } 487 string line;
312 break; 488 try
313 case 2: 489 {
314 words = input[idx].Split(' '); // count 490 line = reader.getLine();
315 if (words[0] == "count") 491 }
316 { 492 catch(Exception)
317 int c = int.Parse(words[1]); 493 {
318 if (c > 0) 494 return System.Text.Encoding.UTF8.GetString(rawInput);
319 return output; 495 }
320 break; 496 string[] versioninfo = line.Split(' ');
321 } 497 if(versioninfo.Length < 3)
322 break; 498 {
499 return System.Text.Encoding.UTF8.GetString(rawInput);
500 }
501 else if(versioninfo[0] != "Linden" || versioninfo[1] != "text")
502 {
503 return System.Text.Encoding.UTF8.GetString(rawInput);
504 }
505 else
506 {
507 /* now we actually decode the Encoding, before we needed it in raw */
508 string o = readNotecardText(reader);
509 byte[] a = new byte[o.Length];
510 for(int i = 0; i < o.Length; ++i)
511 {
512 a[i] = (byte)o[i];
323 } 513 }
324 idx++; 514 return System.Text.Encoding.UTF8.GetString(a);
325 } 515 }
326 516 }
327 return output; 517
518 /// <summary>
519 /// Parse a notecard in Linden format to a string of ordinary text.
520 /// </summary>
521 /// <param name="rawInput"></param>
522 /// <returns></returns>
523 public static string ParseNotecardToString(byte[] rawInput)
524 {
525 return readNotecard(rawInput);
526 }
527
528 /// <summary>
529 /// Parse a notecard in Linden format to a list of ordinary lines.
530 /// </summary>
531 /// <param name="rawInput"></param>
532 /// <returns></returns>
533 public static string[] ParseNotecardToArray(byte[] rawInput)
534 {
535 return readNotecard(rawInput).Replace("\r", "").Split('\n');
328 } 536 }
329 } 537 }
330} 538}
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;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31using OpenMetaverse; 31using OpenMetaverse;
32using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType;
32 33
33namespace OpenSim.Framework.Serialization 34namespace OpenSim.Framework.Serialization
34{ 35{
@@ -114,20 +115,17 @@ namespace OpenSim.Framework.Serialization
114 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg"; 115 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageJPEG] = ASSET_EXTENSION_SEPARATOR + "image.jpg";
115 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga"; 116 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.ImageTGA] = ASSET_EXTENSION_SEPARATOR + "image.tga";
116 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt"; 117 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Landmark] = ASSET_EXTENSION_SEPARATOR + "landmark.txt";
117 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this
118 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso"; 118 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLBytecode] = ASSET_EXTENSION_SEPARATOR + "bytecode.lso";
119 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl"; 119 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LSLText] = ASSET_EXTENSION_SEPARATOR + "script.lsl";
120 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Mesh] = ASSET_EXTENSION_SEPARATOR + "mesh.llmesh"; 120 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Mesh] = ASSET_EXTENSION_SEPARATOR + "mesh.llmesh";
121 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt"; 121 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Notecard] = ASSET_EXTENSION_SEPARATOR + "notecard.txt";
122 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml"; 122 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Object] = ASSET_EXTENSION_SEPARATOR + "object.xml";
123 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this
124 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this 123 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Simstate] = ASSET_EXTENSION_SEPARATOR + "simstate.bin"; // Not sure if we'll ever see this
125 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this
126 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg"; 124 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Sound] = ASSET_EXTENSION_SEPARATOR + "sound.ogg";
127 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav"; 125 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SoundWAV] = ASSET_EXTENSION_SEPARATOR + "sound.wav";
128 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; 126 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2";
129 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; 127 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga";
130 ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this 128 ASSET_TYPE_TO_EXTENSION[(sbyte)OpenSimAssetType.Material] = ASSET_EXTENSION_SEPARATOR + "material.xml"; // Not sure if we'll ever see this
131 129
132 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation; 130 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation;
133 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart; 131 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart;
@@ -138,20 +136,17 @@ namespace OpenSim.Framework.Serialization
138 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = (sbyte)AssetType.ImageJPEG; 136 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.jpg"] = (sbyte)AssetType.ImageJPEG;
139 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = (sbyte)AssetType.ImageTGA; 137 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "image.tga"] = (sbyte)AssetType.ImageTGA;
140 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = (sbyte)AssetType.Landmark; 138 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "landmark.txt"] = (sbyte)AssetType.Landmark;
141 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = (sbyte)AssetType.LostAndFoundFolder;
142 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = (sbyte)AssetType.LSLBytecode; 139 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bytecode.lso"] = (sbyte)AssetType.LSLBytecode;
143 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = (sbyte)AssetType.LSLText; 140 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "script.lsl"] = (sbyte)AssetType.LSLText;
144 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "mesh.llmesh"] = (sbyte)AssetType.Mesh; 141 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "mesh.llmesh"] = (sbyte)AssetType.Mesh;
145 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = (sbyte)AssetType.Notecard; 142 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "notecard.txt"] = (sbyte)AssetType.Notecard;
146 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = (sbyte)AssetType.Object; 143 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "object.xml"] = (sbyte)AssetType.Object;
147 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = (sbyte)AssetType.RootFolder;
148 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = (sbyte)AssetType.Simstate; 144 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "simstate.bin"] = (sbyte)AssetType.Simstate;
149 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = (sbyte)AssetType.SnapshotFolder;
150 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = (sbyte)AssetType.Sound; 145 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.ogg"] = (sbyte)AssetType.Sound;
151 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = (sbyte)AssetType.SoundWAV; 146 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "sound.wav"] = (sbyte)AssetType.SoundWAV;
152 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture; 147 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture;
153 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA; 148 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA;
154 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; 149 EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "material.xml"] = (sbyte)OpenSimAssetType.Material;
155 } 150 }
156 151
157 public static string CreateOarLandDataPath(LandData ld) 152 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 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics;
30using System.IO; 31using System.IO;
31using System.Reflection; 32using System.Reflection;
32using System.Xml; 33using System.Xml;
@@ -47,20 +48,20 @@ namespace OpenSim.Framework.Serialization.External
47 /// Populate a node with data read from xml using a dictinoary of processors 48 /// Populate a node with data read from xml using a dictinoary of processors
48 /// </summary> 49 /// </summary>
49 /// <param name="nodeToFill"></param> 50 /// <param name="nodeToFill"></param>
50 /// <param name="processors">/param> 51 /// <param name="processors"></param>
51 /// <param name="xtr"></param> 52 /// <param name="xtr"></param>
52 /// <returns>true on successful, false if there were any processing failures</returns> 53 /// <returns>true on successful, false if there were any processing failures</returns>
53 public static bool ExecuteReadProcessors<NodeType>( 54 public static bool ExecuteReadProcessors<NodeType>(
54 NodeType nodeToFill, Dictionary<string, Action<NodeType, XmlTextReader>> processors, XmlTextReader xtr) 55 NodeType nodeToFill, Dictionary<string, Action<NodeType, XmlReader>> processors, XmlReader xtr)
55 { 56 {
56 return ExecuteReadProcessors( 57 return ExecuteReadProcessors(
57 nodeToFill, 58 nodeToFill,
58 processors, 59 processors,
59 xtr, 60 xtr,
60 (o, name, e) 61 (o, nodeName, e) => {
61 => m_log.DebugFormat( 62 m_log.Debug(string.Format("[ExternalRepresentationUtils]: Error while parsing element {0} ",
62 "[ExternalRepresentationUtils]: Exception while parsing element {0}, continuing. Exception {1}{2}", 63 nodeName), e);
63 name, e.Message, e.StackTrace)); 64 });
64 } 65 }
65 66
66 /// <summary> 67 /// <summary>
@@ -75,23 +76,27 @@ namespace OpenSim.Framework.Serialization.External
75 /// <returns>true on successful, false if there were any processing failures</returns> 76 /// <returns>true on successful, false if there were any processing failures</returns>
76 public static bool ExecuteReadProcessors<NodeType>( 77 public static bool ExecuteReadProcessors<NodeType>(
77 NodeType nodeToFill, 78 NodeType nodeToFill,
78 Dictionary<string, Action<NodeType, XmlTextReader>> processors, 79 Dictionary<string, Action<NodeType, XmlReader>> processors,
79 XmlTextReader xtr, 80 XmlReader xtr,
80 Action<NodeType, string, Exception> parseExceptionAction) 81 Action<NodeType, string, Exception> parseExceptionAction)
81 { 82 {
82 bool errors = false; 83 bool errors = false;
84 int numErrors = 0;
85
86 Stopwatch timer = new Stopwatch();
87 timer.Start();
83 88
84 string nodeName = string.Empty; 89 string nodeName = string.Empty;
85 while (xtr.NodeType != XmlNodeType.EndElement) 90 while (xtr.NodeType != XmlNodeType.EndElement)
86 { 91 {
87 nodeName = xtr.Name; 92 nodeName = xtr.Name;
88 93
89// m_log.DebugFormat("[ExternalRepresentationUtils]: Processing: {0}", nodeName); 94 // m_log.DebugFormat("[ExternalRepresentationUtils]: Processing node: {0}", nodeName);
90 95
91 Action<NodeType, XmlTextReader> p = null; 96 Action<NodeType, XmlReader> p = null;
92 if (processors.TryGetValue(xtr.Name, out p)) 97 if (processors.TryGetValue(xtr.Name, out p))
93 { 98 {
94// m_log.DebugFormat("[ExternalRepresentationUtils]: Found {0} processor, nodeName); 99 // m_log.DebugFormat("[ExternalRepresentationUtils]: Found processor for {0}", nodeName);
95 100
96 try 101 try
97 { 102 {
@@ -101,6 +106,18 @@ namespace OpenSim.Framework.Serialization.External
101 { 106 {
102 errors = true; 107 errors = true;
103 parseExceptionAction(nodeToFill, nodeName, e); 108 parseExceptionAction(nodeToFill, nodeName, e);
109
110 if (xtr.EOF)
111 {
112 m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to unexpected end of XML");
113 break;
114 }
115
116 if (++numErrors == 10)
117 {
118 m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to too many parsing errors");
119 break;
120 }
104 121
105 if (xtr.NodeType == XmlNodeType.EndElement) 122 if (xtr.NodeType == XmlNodeType.EndElement)
106 xtr.Read(); 123 xtr.Read();
@@ -108,9 +125,16 @@ namespace OpenSim.Framework.Serialization.External
108 } 125 }
109 else 126 else
110 { 127 {
111 // m_log.DebugFormat("[LandDataSerializer]: caught unknown element {0}", nodeName); 128 // m_log.DebugFormat("[ExternalRepresentationUtils]: found unknown element \"{0}\"", nodeName);
112 xtr.ReadOuterXml(); // ignore 129 xtr.ReadOuterXml(); // ignore
113 } 130 }
131
132 if (timer.Elapsed.TotalSeconds >= 60)
133 {
134 m_log.Debug("[ExternalRepresentationUtils]: Aborting ExecuteReadProcessors due to timeout");
135 errors = true;
136 break;
137 }
114 } 138 }
115 139
116 return errors; 140 return errors;
@@ -125,7 +149,8 @@ namespace OpenSim.Framework.Serialization.External
125 /// <param name="userService">The service for retrieving user account information</param> 149 /// <param name="userService">The service for retrieving user account information</param>
126 /// <param name="scopeID">The scope of the user account information (Grid ID)</param> 150 /// <param name="scopeID">The scope of the user account information (Grid ID)</param>
127 /// <returns>The SceneObjectPart represented in XML2</returns> 151 /// <returns>The SceneObjectPart represented in XML2</returns>
128 public static string RewriteSOP(string xml, string homeURL, IUserAccountService userService, UUID scopeID) 152 [Obsolete("This method is deprecated. Use RewriteSOP instead.")]
153 public static string RewriteSOP_Old(string xml, string homeURL, IUserAccountService userService, UUID scopeID)
129 { 154 {
130 if (xml == string.Empty || homeURL == string.Empty || userService == null) 155 if (xml == string.Empty || homeURL == string.Empty || userService == null)
131 return xml; 156 return xml;
@@ -161,7 +186,7 @@ namespace OpenSim.Framework.Serialization.External
161 if (!hasCreatorData && creator != null) 186 if (!hasCreatorData && creator != null)
162 { 187 {
163 XmlElement creatorData = doc.CreateElement("CreatorData"); 188 XmlElement creatorData = doc.CreateElement("CreatorData");
164 creatorData.InnerText = homeURL + ";" + creator.FirstName + " " + creator.LastName; 189 creatorData.InnerText = CalcCreatorData(homeURL, creator.FirstName + " " + creator.LastName);
165 sop.AppendChild(creatorData); 190 sop.AppendChild(creatorData);
166 } 191 }
167 } 192 }
@@ -172,5 +197,215 @@ namespace OpenSim.Framework.Serialization.External
172 return wr.ToString(); 197 return wr.ToString();
173 } 198 }
174 } 199 }
200
201 /// <summary>
202 /// Takes a XML representation of a SceneObjectPart and returns another XML representation
203 /// with creator data added to it.
204 /// </summary>
205 /// <param name="xml">The SceneObjectPart represented in XML2</param>
206 /// <param name="sceneName">An identifier for the component that's calling this function</param>
207 /// <param name="homeURL">The URL of the user agents service (home) for the creator</param>
208 /// <param name="userService">The service for retrieving user account information</param>
209 /// <param name="scopeID">The scope of the user account information (Grid ID)</param>
210 /// <returns>The SceneObjectPart represented in XML2</returns>
211 public static string RewriteSOP(string xmlData, string sceneName, string homeURL, IUserAccountService userService, UUID scopeID)
212 {
213 // Console.WriteLine("Input XML [{0}]", xmlData);
214 if (xmlData == string.Empty || homeURL == string.Empty || userService == null)
215 return xmlData;
216
217 // Deal with bug
218 xmlData = ExternalRepresentationUtils.SanitizeXml(xmlData);
219
220 using (StringWriter sw = new StringWriter())
221 using (XmlTextWriter writer = new XmlTextWriter(sw))
222 using (XmlTextReader wrappedReader = new XmlTextReader(xmlData, XmlNodeType.Element, null))
223 using (XmlReader reader = XmlReader.Create(wrappedReader, new XmlReaderSettings() { IgnoreWhitespace = true, ConformanceLevel = ConformanceLevel.Fragment }))
224 {
225 TransformXml(reader, writer, sceneName, homeURL, userService, scopeID);
226
227 // Console.WriteLine("Output: [{0}]", sw.ToString());
228
229 return sw.ToString();
230 }
231 }
232
233 protected static void TransformXml(XmlReader reader, XmlWriter writer, string sceneName, string homeURI, IUserAccountService userAccountService, UUID scopeID)
234 {
235 // m_log.DebugFormat("[HG ASSET MAPPER]: Transforming XML");
236
237 int sopDepth = -1;
238 UserAccount creator = null;
239 bool hasCreatorData = false;
240
241 while (reader.Read())
242 {
243 // Console.WriteLine("Depth: {0}, name {1}", reader.Depth, reader.Name);
244
245 switch (reader.NodeType)
246 {
247 case XmlNodeType.Attribute:
248 // Console.WriteLine("FOUND ATTRIBUTE {0}", reader.Name);
249 writer.WriteAttributeString(reader.Name, reader.Value);
250 break;
251
252 case XmlNodeType.CDATA:
253 writer.WriteCData(reader.Value);
254 break;
255
256 case XmlNodeType.Comment:
257 writer.WriteComment(reader.Value);
258 break;
259
260 case XmlNodeType.DocumentType:
261 writer.WriteDocType(reader.Name, reader.Value, null, null);
262 break;
263
264 case XmlNodeType.Element:
265 // m_log.DebugFormat("Depth {0} at element {1}", reader.Depth, reader.Name);
266
267 writer.WriteStartElement(reader.Prefix, reader.LocalName, reader.NamespaceURI);
268
269 if (reader.HasAttributes)
270 {
271 while (reader.MoveToNextAttribute())
272 writer.WriteAttributeString(reader.Name, reader.Value);
273
274 reader.MoveToElement();
275 }
276
277 if (reader.LocalName == "SceneObjectPart")
278 {
279 if (sopDepth < 0)
280 {
281 sopDepth = reader.Depth;
282 // m_log.DebugFormat("[HG ASSET MAPPER]: Set sopDepth to {0}", sopDepth);
283 }
284 }
285 else
286 {
287 if (sopDepth >= 0 && reader.Depth == sopDepth + 1)
288 {
289 if (reader.Name == "CreatorID")
290 {
291 reader.Read();
292 if (reader.NodeType == XmlNodeType.Element && reader.Name == "Guid" || reader.Name == "UUID")
293 {
294 reader.Read();
295
296 if (reader.NodeType == XmlNodeType.Text)
297 {
298 UUID uuid = UUID.Zero;
299 UUID.TryParse(reader.Value, out uuid);
300 creator = userAccountService.GetUserAccount(scopeID, uuid);
301 writer.WriteElementString("UUID", reader.Value);
302 reader.Read();
303 }
304 else
305 {
306 // If we unexpected run across mixed content in this node, still carry on
307 // transforming the subtree (this replicates earlier behaviour).
308 TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
309 }
310 }
311 else
312 {
313 // If we unexpected run across mixed content in this node, still carry on
314 // transforming the subtree (this replicates earlier behaviour).
315 TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
316 }
317 }
318 else if (reader.Name == "CreatorData")
319 {
320 reader.Read();
321 if (reader.NodeType == XmlNodeType.Text)
322 {
323 hasCreatorData = true;
324 writer.WriteString(reader.Value);
325 }
326 else
327 {
328 // If we unexpected run across mixed content in this node, still carry on
329 // transforming the subtree (this replicates earlier behaviour).
330 TransformXml(reader, writer, sceneName, homeURI, userAccountService, scopeID);
331 }
332 }
333 }
334 }
335
336 if (reader.IsEmptyElement)
337 {
338 // m_log.DebugFormat("[HG ASSET MAPPER]: Writing end for empty element {0}", reader.Name);
339 writer.WriteEndElement();
340 }
341
342 break;
343
344 case XmlNodeType.EndElement:
345 // m_log.DebugFormat("Depth {0} at EndElement", reader.Depth);
346 if (sopDepth == reader.Depth)
347 {
348 if (!hasCreatorData && creator != null)
349 writer.WriteElementString(reader.Prefix, "CreatorData", reader.NamespaceURI, string.Format("{0};{1} {2}", homeURI, creator.FirstName, creator.LastName));
350
351 // m_log.DebugFormat("[HG ASSET MAPPER]: Reset sopDepth");
352 sopDepth = -1;
353 creator = null;
354 hasCreatorData = false;
355 }
356 writer.WriteEndElement();
357 break;
358
359 case XmlNodeType.EntityReference:
360 writer.WriteEntityRef(reader.Name);
361 break;
362
363 case XmlNodeType.ProcessingInstruction:
364 writer.WriteProcessingInstruction(reader.Name, reader.Value);
365 break;
366
367 case XmlNodeType.Text:
368 writer.WriteString(reader.Value);
369 break;
370
371 case XmlNodeType.XmlDeclaration:
372 // For various reasons, not all serializations have xml declarations (or consistent ones)
373 // and as it's embedded inside a byte stream we don't need it anyway, so ignore.
374 break;
375
376 default:
377 m_log.WarnFormat(
378 "[HG ASSET MAPPER]: Unrecognized node {0} in asset XML transform in {1}",
379 reader.NodeType, sceneName);
380 break;
381 }
382 }
383 }
384
385 public static string CalcCreatorData(string homeURL, string name)
386 {
387 return homeURL + ";" + name;
388 }
389
390 internal static string CalcCreatorData(string homeURL, UUID uuid, string name)
391 {
392 return homeURL + "/" + uuid + ";" + name;
393 }
394
395 /// <summary>
396 /// Sanitation for bug introduced in Oct. 20 (1eb3e6cc43e2a7b4053bc1185c7c88e22356c5e8)
397 /// </summary>
398 /// <param name="xmlData"></param>
399 /// <returns></returns>
400 public static string SanitizeXml(string xmlData)
401 {
402 string fixedData = xmlData;
403 if (fixedData != null)
404 // Loop, because it may contain multiple
405 while (fixedData.Contains("xmlns:xmlns:"))
406 fixedData = fixedData.Replace("xmlns:xmlns:", "xmlns:");
407 return fixedData;
408 }
409
175 } 410 }
176} \ No newline at end of file 411}
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
44 { 44 {
45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46 46
47 private static Dictionary<string, Action<LandData, XmlTextReader>> m_ldProcessors 47 private static Dictionary<string, Action<LandData, XmlReader>> m_ldProcessors
48 = new Dictionary<string, Action<LandData, XmlTextReader>>(); 48 = new Dictionary<string, Action<LandData, XmlReader>>();
49 49
50 private static Dictionary<string, Action<LandAccessEntry, XmlTextReader>> m_laeProcessors 50 private static Dictionary<string, Action<LandAccessEntry, XmlReader>> m_laeProcessors
51 = new Dictionary<string, Action<LandAccessEntry, XmlTextReader>>(); 51 = new Dictionary<string, Action<LandAccessEntry, XmlReader>>();
52 52
53 static LandDataSerializer() 53 static LandDataSerializer()
54 { 54 {
@@ -134,7 +134,7 @@ namespace OpenSim.Framework.Serialization.External
134 "AccessList", (lae, xtr) => lae.Flags = (AccessList)Convert.ToUInt32(xtr.ReadElementString("AccessList"))); 134 "AccessList", (lae, xtr) => lae.Flags = (AccessList)Convert.ToUInt32(xtr.ReadElementString("AccessList")));
135 } 135 }
136 136
137 public static void ProcessParcelAccessList(LandData ld, XmlTextReader xtr) 137 public static void ProcessParcelAccessList(LandData ld, XmlReader xtr)
138 { 138 {
139 if (!xtr.IsEmptyElement) 139 if (!xtr.IsEmptyElement)
140 { 140 {
@@ -213,8 +213,13 @@ namespace OpenSim.Framework.Serialization.External
213 xtw.WriteElementString("ClaimDate", Convert.ToString(landData.ClaimDate)); 213 xtw.WriteElementString("ClaimDate", Convert.ToString(landData.ClaimDate));
214 xtw.WriteElementString("ClaimPrice", Convert.ToString(landData.ClaimPrice)); 214 xtw.WriteElementString("ClaimPrice", Convert.ToString(landData.ClaimPrice));
215 xtw.WriteElementString("GlobalID", landData.GlobalID.ToString()); 215 xtw.WriteElementString("GlobalID", landData.GlobalID.ToString());
216 xtw.WriteElementString("GroupID", landData.GroupID.ToString()); 216
217 xtw.WriteElementString("IsGroupOwned", Convert.ToString(landData.IsGroupOwned)); 217 UUID groupID = options.ContainsKey("wipe-owners") ? UUID.Zero : landData.GroupID;
218 xtw.WriteElementString("GroupID", groupID.ToString());
219
220 bool isGroupOwned = options.ContainsKey("wipe-owners") ? false : landData.IsGroupOwned;
221 xtw.WriteElementString("IsGroupOwned", Convert.ToString(isGroupOwned));
222
218 xtw.WriteElementString("Bitmap", Convert.ToBase64String(landData.Bitmap)); 223 xtw.WriteElementString("Bitmap", Convert.ToBase64String(landData.Bitmap));
219 xtw.WriteElementString("Description", landData.Description); 224 xtw.WriteElementString("Description", landData.Description);
220 xtw.WriteElementString("Flags", Convert.ToString((uint)landData.Flags)); 225 xtw.WriteElementString("Flags", Convert.ToString((uint)landData.Flags));
@@ -227,13 +232,8 @@ namespace OpenSim.Framework.Serialization.External
227 xtw.WriteElementString("MediaURL", landData.MediaURL); 232 xtw.WriteElementString("MediaURL", landData.MediaURL);
228 xtw.WriteElementString("MusicURL", landData.MusicURL); 233 xtw.WriteElementString("MusicURL", landData.MusicURL);
229 234
230 UUID ownerIdToWrite; 235 UUID ownerID = options.ContainsKey("wipe-owners") ? UUID.Zero : landData.OwnerID;
231 if (options != null && options.ContainsKey("wipe-owners")) 236 xtw.WriteElementString("OwnerID", ownerID.ToString());
232 ownerIdToWrite = UUID.Zero;
233 else
234 ownerIdToWrite = landData.OwnerID;
235
236 xtw.WriteElementString("OwnerID", ownerIdToWrite.ToString());
237 237
238 xtw.WriteStartElement("ParcelAccessList"); 238 xtw.WriteStartElement("ParcelAccessList");
239 foreach (LandAccessEntry pal in landData.ParcelAccessList) 239 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
46 { 46 {
47// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 47// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
48 48
49 private static Dictionary<string, Action<InventoryItemBase, XmlTextReader>> m_InventoryItemXmlProcessors 49 private static Dictionary<string, Action<InventoryItemBase, XmlReader>> m_InventoryItemXmlProcessors
50 = new Dictionary<string, Action<InventoryItemBase, XmlTextReader>>(); 50 = new Dictionary<string, Action<InventoryItemBase, XmlReader>>();
51 51
52 #region InventoryItemBase Processor initialization 52 #region InventoryItemBase Processor initialization
53 static UserInventoryItemSerializer() 53 static UserInventoryItemSerializer()
@@ -76,103 +76,103 @@ namespace OpenSim.Framework.Serialization.External
76 #endregion 76 #endregion
77 77
78 #region InventoryItemBase Processors 78 #region InventoryItemBase Processors
79 private static void ProcessName(InventoryItemBase item, XmlTextReader reader) 79 private static void ProcessName(InventoryItemBase item, XmlReader reader)
80 { 80 {
81 item.Name = reader.ReadElementContentAsString("Name", String.Empty); 81 item.Name = reader.ReadElementContentAsString("Name", String.Empty);
82 } 82 }
83 83
84 private static void ProcessID(InventoryItemBase item, XmlTextReader reader) 84 private static void ProcessID(InventoryItemBase item, XmlReader reader)
85 { 85 {
86 item.ID = Util.ReadUUID(reader, "ID"); 86 item.ID = Util.ReadUUID(reader, "ID");
87 } 87 }
88 88
89 private static void ProcessInvType(InventoryItemBase item, XmlTextReader reader) 89 private static void ProcessInvType(InventoryItemBase item, XmlReader reader)
90 { 90 {
91 item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty); 91 item.InvType = reader.ReadElementContentAsInt("InvType", String.Empty);
92 } 92 }
93 93
94 private static void ProcessCreatorUUID(InventoryItemBase item, XmlTextReader reader) 94 private static void ProcessCreatorUUID(InventoryItemBase item, XmlReader reader)
95 { 95 {
96 item.CreatorId = reader.ReadElementContentAsString("CreatorUUID", String.Empty); 96 item.CreatorId = reader.ReadElementContentAsString("CreatorUUID", String.Empty);
97 } 97 }
98 98
99 private static void ProcessCreatorID(InventoryItemBase item, XmlTextReader reader) 99 private static void ProcessCreatorID(InventoryItemBase item, XmlReader reader)
100 { 100 {
101 // when it exists, this overrides the previous 101 // when it exists, this overrides the previous
102 item.CreatorId = reader.ReadElementContentAsString("CreatorID", String.Empty); 102 item.CreatorId = reader.ReadElementContentAsString("CreatorID", String.Empty);
103 } 103 }
104 104
105 private static void ProcessCreationDate(InventoryItemBase item, XmlTextReader reader) 105 private static void ProcessCreationDate(InventoryItemBase item, XmlReader reader)
106 { 106 {
107 item.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty); 107 item.CreationDate = reader.ReadElementContentAsInt("CreationDate", String.Empty);
108 } 108 }
109 109
110 private static void ProcessOwner(InventoryItemBase item, XmlTextReader reader) 110 private static void ProcessOwner(InventoryItemBase item, XmlReader reader)
111 { 111 {
112 item.Owner = Util.ReadUUID(reader, "Owner"); 112 item.Owner = Util.ReadUUID(reader, "Owner");
113 } 113 }
114 114
115 private static void ProcessDescription(InventoryItemBase item, XmlTextReader reader) 115 private static void ProcessDescription(InventoryItemBase item, XmlReader reader)
116 { 116 {
117 item.Description = reader.ReadElementContentAsString("Description", String.Empty); 117 item.Description = reader.ReadElementContentAsString("Description", String.Empty);
118 } 118 }
119 119
120 private static void ProcessAssetType(InventoryItemBase item, XmlTextReader reader) 120 private static void ProcessAssetType(InventoryItemBase item, XmlReader reader)
121 { 121 {
122 item.AssetType = reader.ReadElementContentAsInt("AssetType", String.Empty); 122 item.AssetType = reader.ReadElementContentAsInt("AssetType", String.Empty);
123 } 123 }
124 124
125 private static void ProcessAssetID(InventoryItemBase item, XmlTextReader reader) 125 private static void ProcessAssetID(InventoryItemBase item, XmlReader reader)
126 { 126 {
127 item.AssetID = Util.ReadUUID(reader, "AssetID"); 127 item.AssetID = Util.ReadUUID(reader, "AssetID");
128 } 128 }
129 129
130 private static void ProcessSaleType(InventoryItemBase item, XmlTextReader reader) 130 private static void ProcessSaleType(InventoryItemBase item, XmlReader reader)
131 { 131 {
132 item.SaleType = (byte)reader.ReadElementContentAsInt("SaleType", String.Empty); 132 item.SaleType = (byte)reader.ReadElementContentAsInt("SaleType", String.Empty);
133 } 133 }
134 134
135 private static void ProcessSalePrice(InventoryItemBase item, XmlTextReader reader) 135 private static void ProcessSalePrice(InventoryItemBase item, XmlReader reader)
136 { 136 {
137 item.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty); 137 item.SalePrice = reader.ReadElementContentAsInt("SalePrice", String.Empty);
138 } 138 }
139 139
140 private static void ProcessBasePermissions(InventoryItemBase item, XmlTextReader reader) 140 private static void ProcessBasePermissions(InventoryItemBase item, XmlReader reader)
141 { 141 {
142 item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty); 142 item.BasePermissions = (uint)reader.ReadElementContentAsInt("BasePermissions", String.Empty);
143 } 143 }
144 144
145 private static void ProcessCurrentPermissions(InventoryItemBase item, XmlTextReader reader) 145 private static void ProcessCurrentPermissions(InventoryItemBase item, XmlReader reader)
146 { 146 {
147 item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty); 147 item.CurrentPermissions = (uint)reader.ReadElementContentAsInt("CurrentPermissions", String.Empty);
148 } 148 }
149 149
150 private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlTextReader reader) 150 private static void ProcessEveryOnePermissions(InventoryItemBase item, XmlReader reader)
151 { 151 {
152 item.EveryOnePermissions = (uint)reader.ReadElementContentAsInt("EveryOnePermissions", String.Empty); 152 item.EveryOnePermissions = (uint)reader.ReadElementContentAsInt("EveryOnePermissions", String.Empty);
153 } 153 }
154 154
155 private static void ProcessNextPermissions(InventoryItemBase item, XmlTextReader reader) 155 private static void ProcessNextPermissions(InventoryItemBase item, XmlReader reader)
156 { 156 {
157 item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty); 157 item.NextPermissions = (uint)reader.ReadElementContentAsInt("NextPermissions", String.Empty);
158 } 158 }
159 159
160 private static void ProcessFlags(InventoryItemBase item, XmlTextReader reader) 160 private static void ProcessFlags(InventoryItemBase item, XmlReader reader)
161 { 161 {
162 item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty); 162 item.Flags = (uint)reader.ReadElementContentAsInt("Flags", String.Empty);
163 } 163 }
164 164
165 private static void ProcessGroupID(InventoryItemBase item, XmlTextReader reader) 165 private static void ProcessGroupID(InventoryItemBase item, XmlReader reader)
166 { 166 {
167 item.GroupID = Util.ReadUUID(reader, "GroupID"); 167 item.GroupID = Util.ReadUUID(reader, "GroupID");
168 } 168 }
169 169
170 private static void ProcessGroupOwned(InventoryItemBase item, XmlTextReader reader) 170 private static void ProcessGroupOwned(InventoryItemBase item, XmlReader reader)
171 { 171 {
172 item.GroupOwned = Util.ReadBoolean(reader); 172 item.GroupOwned = Util.ReadBoolean(reader);
173 } 173 }
174 174
175 private static void ProcessCreatorData(InventoryItemBase item, XmlTextReader reader) 175 private static void ProcessCreatorData(InventoryItemBase item, XmlReader reader)
176 { 176 {
177 item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty); 177 item.CreatorData = reader.ReadElementContentAsString("CreatorData", String.Empty);
178 } 178 }
@@ -277,7 +277,7 @@ namespace OpenSim.Framework.Serialization.External
277 writer.WriteStartElement("GroupOwned"); 277 writer.WriteStartElement("GroupOwned");
278 writer.WriteString(inventoryItem.GroupOwned.ToString()); 278 writer.WriteString(inventoryItem.GroupOwned.ToString());
279 writer.WriteEndElement(); 279 writer.WriteEndElement();
280 if (options.ContainsKey("creators") && inventoryItem.CreatorData != null && inventoryItem.CreatorData != string.Empty) 280 if (options.ContainsKey("creators") && !string.IsNullOrEmpty(inventoryItem.CreatorData))
281 writer.WriteElementString("CreatorData", inventoryItem.CreatorData); 281 writer.WriteElementString("CreatorData", inventoryItem.CreatorData);
282 else if (options.ContainsKey("home")) 282 else if (options.ContainsKey("home"))
283 { 283 {
@@ -286,7 +286,8 @@ namespace OpenSim.Framework.Serialization.External
286 UserAccount account = userAccountService.GetUserAccount(UUID.Zero, inventoryItem.CreatorIdAsUuid); 286 UserAccount account = userAccountService.GetUserAccount(UUID.Zero, inventoryItem.CreatorIdAsUuid);
287 if (account != null) 287 if (account != null)
288 { 288 {
289 writer.WriteElementString("CreatorData", (string)options["home"] + "/" + inventoryItem.CreatorIdAsUuid + ";" + account.FirstName + " " + account.LastName); 289 string creatorData = ExternalRepresentationUtils.CalcCreatorData((string)options["home"], inventoryItem.CreatorIdAsUuid, account.FirstName + " " + account.LastName);
290 writer.WriteElementString("CreatorData", creatorData);
290 } 291 }
291 writer.WriteElementString("CreatorID", inventoryItem.CreatorId); 292 writer.WriteElementString("CreatorID", inventoryItem.CreatorId);
292 } 293 }
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;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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
121 TestHelpers.InMethod(); 121 TestHelpers.InMethod();
122// log4net.Config.XmlConfigurator.Configure(); 122// log4net.Config.XmlConfigurator.Configure();
123 123
124 LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, null)); 124 Dictionary<string, object> options = new Dictionary<string, object>();
125 LandData ld = LandDataSerializer.Deserialize(LandDataSerializer.Serialize(this.land, options));
125 Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null"); 126 Assert.That(ld, Is.Not.Null, "Deserialize(string) returned null");
126// Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax)); 127// Assert.That(ld.AABBMax, Is.EqualTo(land.AABBMax));
127// Assert.That(ld.AABBMin, Is.EqualTo(land.AABBMin)); 128// 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;
45using OpenSim.Framework.Servers; 45using OpenSim.Framework.Servers;
46using OpenSim.Framework.Servers.HttpServer; 46using OpenSim.Framework.Servers.HttpServer;
47using Timer=System.Timers.Timer; 47using Timer=System.Timers.Timer;
48using Nini.Config;
48 49
49namespace OpenSim.Framework.Servers 50namespace OpenSim.Framework.Servers
50{ 51{
@@ -56,9 +57,15 @@ namespace OpenSim.Framework.Servers
56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 57 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
57 58
58 /// <summary> 59 /// <summary>
60 /// Used by tests to suppress Environment.Exit(0) so that post-run operations are possible.
61 /// </summary>
62 public bool SuppressExit { get; set; }
63
64 /// <summary>
59 /// This will control a periodic log printout of the current 'show stats' (if they are active) for this 65 /// This will control a periodic log printout of the current 'show stats' (if they are active) for this
60 /// server. 66 /// server.
61 /// </summary> 67 /// </summary>
68 private int m_periodDiagnosticTimerMS = 60 * 60 * 1000;
62 private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); 69 private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000);
63 70
64 /// <summary> 71 /// <summary>
@@ -77,8 +84,6 @@ namespace OpenSim.Framework.Servers
77 // Random uuid for private data 84 // Random uuid for private data
78 m_osSecret = UUID.Random().ToString(); 85 m_osSecret = UUID.Random().ToString();
79 86
80 m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
81 m_periodicDiagnosticsTimer.Enabled = true;
82 } 87 }
83 88
84 /// <summary> 89 /// <summary>
@@ -86,26 +91,34 @@ namespace OpenSim.Framework.Servers
86 /// </summary> 91 /// </summary>
87 protected virtual void StartupSpecific() 92 protected virtual void StartupSpecific()
88 { 93 {
89 if (m_console == null) 94 StatsManager.SimExtraStats = new SimExtraStatsCollector();
90 return;
91
92 RegisterCommonCommands(); 95 RegisterCommonCommands();
93 96 RegisterCommonComponents(Config);
94 m_console.Commands.AddCommand("General", false, "quit", 97
95 "quit", 98 IConfig startupConfig = Config.Configs["Startup"];
96 "Quit the application", HandleQuit); 99 int logShowStatsSeconds = startupConfig.GetInt("LogShowStatsSeconds", m_periodDiagnosticTimerMS / 1000);
100 m_periodDiagnosticTimerMS = logShowStatsSeconds * 1000;
101 m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics);
102 if (m_periodDiagnosticTimerMS != 0)
103 {
104 m_periodicDiagnosticsTimer.Interval = m_periodDiagnosticTimerMS;
105 m_periodicDiagnosticsTimer.Enabled = true;
106 }
107 }
108
109 protected override void ShutdownSpecific()
110 {
111 m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
97 112
98 m_console.Commands.AddCommand("General", false, "shutdown", 113 RemovePIDFile();
99 "shutdown", 114
100 "Quit the application", HandleQuit); 115 base.ShutdownSpecific();
116
117 if (!SuppressExit)
118 Environment.Exit(0);
101 } 119 }
102 120
103 /// <summary> 121 /// <summary>
104 /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
105 /// </summary>
106 public virtual void ShutdownSpecific() {}
107
108 /// <summary>
109 /// Provides a list of help topics that are available. Overriding classes should append their topics to the 122 /// Provides a list of help topics that are available. Overriding classes should append their topics to the
110 /// information returned when the base method is called. 123 /// information returned when the base method is called.
111 /// </summary> 124 /// </summary>
@@ -133,45 +146,18 @@ namespace OpenSim.Framework.Servers
133 /// Performs initialisation of the scene, such as loading configuration from disk. 146 /// Performs initialisation of the scene, such as loading configuration from disk.
134 /// </summary> 147 /// </summary>
135 public virtual void Startup() 148 public virtual void Startup()
136 { 149 {
137 m_log.Info("[STARTUP]: Beginning startup processing");
138
139 m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
140 // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
141 // the clr version number doesn't match the project version number under Mono.
142 //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
143 m_log.InfoFormat(
144 "[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n",
145 Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
146
147 StartupSpecific(); 150 StartupSpecific();
148 151
149 TimeSpan timeTaken = DateTime.Now - m_startuptime; 152 TimeSpan timeTaken = DateTime.Now - m_startuptime;
150 153
151 m_log.InfoFormat( 154 MainConsole.Instance.OutputFormat(
152 "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.", 155 "PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED. Non-script portion of startup took {0}m {1}s.",
153 timeTaken.Minutes, timeTaken.Seconds); 156 timeTaken.Minutes, timeTaken.Seconds);
154 } 157 }
155 158
156 /// <summary> 159 public string osSecret
157 /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
158 /// </summary>
159 public virtual void Shutdown()
160 { 160 {
161 ShutdownSpecific();
162
163 m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
164 RemovePIDFile();
165
166 Environment.Exit(0);
167 }
168
169 private void HandleQuit(string module, string[] args)
170 {
171 Shutdown();
172 }
173
174 public string osSecret {
175 // Secret uuid for the simulator 161 // Secret uuid for the simulator
176 get { return m_osSecret; } 162 get { return m_osSecret; }
177 } 163 }
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;
46using HttpListener=System.Net.HttpListener; 46using HttpListener=System.Net.HttpListener;
47using LogPrio=HttpServer.LogPrio; 47using LogPrio=HttpServer.LogPrio;
48using OpenSim.Framework.Monitoring; 48using OpenSim.Framework.Monitoring;
49using System.IO.Compression;
49 50
50namespace OpenSim.Framework.Servers.HttpServer 51namespace OpenSim.Framework.Servers.HttpServer
51{ 52{
@@ -53,6 +54,16 @@ namespace OpenSim.Framework.Servers.HttpServer
53 { 54 {
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 55 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); 56 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
57 private static Encoding UTF8NoBOM = new System.Text.UTF8Encoding(false);
58
59 /// <summary>
60 /// This is a pending websocket request before it got an sucessful upgrade response.
61 /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to
62 /// start the connection and optionally provide an origin authentication method.
63 /// </summary>
64 /// <param name="servicepath"></param>
65 /// <param name="handler"></param>
66 public delegate void WebSocketRequestDelegate(string servicepath, WebSocketHttpServerHandler handler);
56 67
57 /// <summary> 68 /// <summary>
58 /// Gets or sets the debug level. 69 /// Gets or sets the debug level.
@@ -71,12 +82,18 @@ namespace OpenSim.Framework.Servers.HttpServer
71 /// </remarks> 82 /// </remarks>
72 public int RequestNumber { get; private set; } 83 public int RequestNumber { get; private set; }
73 84
85 /// <summary>
86 /// Statistic for holding number of requests processed.
87 /// </summary>
88 private Stat m_requestsProcessedStat;
89
74 private volatile int NotSocketErrors = 0; 90 private volatile int NotSocketErrors = 0;
75 public volatile bool HTTPDRunning = false; 91 public volatile bool HTTPDRunning = false;
76 92
77 // protected HttpListener m_httpListener; 93 // protected HttpListener m_httpListener;
78 protected CoolHTTPListener m_httpListener2; 94 protected CoolHTTPListener m_httpListener2;
79 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>(); 95 protected Dictionary<string, XmlRpcMethod> m_rpcHandlers = new Dictionary<string, XmlRpcMethod>();
96 protected Dictionary<string, JsonRPCMethod> jsonRpcHandlers = new Dictionary<string, JsonRPCMethod>();
80 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>(); 97 protected Dictionary<string, bool> m_rpcHandlersKeepAlive = new Dictionary<string, bool>();
81 protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ 98 protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/
82 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>(); 99 protected Dictionary<string, LLSDMethod> m_llsdHandlers = new Dictionary<string, LLSDMethod>();
@@ -86,6 +103,9 @@ namespace OpenSim.Framework.Servers.HttpServer
86 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers = 103 protected Dictionary<string, PollServiceEventArgs> m_pollHandlers =
87 new Dictionary<string, PollServiceEventArgs>(); 104 new Dictionary<string, PollServiceEventArgs>();
88 105
106 protected Dictionary<string, WebSocketRequestDelegate> m_WebSocketHandlers =
107 new Dictionary<string, WebSocketRequestDelegate>();
108
89 protected uint m_port; 109 protected uint m_port;
90 protected uint m_sslport; 110 protected uint m_sslport;
91 protected bool m_ssl; 111 protected bool m_ssl;
@@ -95,7 +115,7 @@ namespace OpenSim.Framework.Servers.HttpServer
95 115
96 protected IPAddress m_listenIPAddress = IPAddress.Any; 116 protected IPAddress m_listenIPAddress = IPAddress.Any;
97 117
98 private PollServiceRequestManager m_PollServiceManager; 118 public PollServiceRequestManager PollServiceRequestManager { get; private set; }
99 119
100 public uint SSLPort 120 public uint SSLPort
101 { 121 {
@@ -169,6 +189,22 @@ namespace OpenSim.Framework.Servers.HttpServer
169 } 189 }
170 } 190 }
171 191
192 public void AddWebSocketHandler(string servicepath, WebSocketRequestDelegate handler)
193 {
194 lock (m_WebSocketHandlers)
195 {
196 if (!m_WebSocketHandlers.ContainsKey(servicepath))
197 m_WebSocketHandlers.Add(servicepath, handler);
198 }
199 }
200
201 public void RemoveWebSocketHandler(string servicepath)
202 {
203 lock (m_WebSocketHandlers)
204 if (m_WebSocketHandlers.ContainsKey(servicepath))
205 m_WebSocketHandlers.Remove(servicepath);
206 }
207
172 public List<string> GetStreamHandlerKeys() 208 public List<string> GetStreamHandlerKeys()
173 { 209 {
174 lock (m_streamHandlers) 210 lock (m_streamHandlers)
@@ -217,6 +253,37 @@ namespace OpenSim.Framework.Servers.HttpServer
217 return new List<string>(m_rpcHandlers.Keys); 253 return new List<string>(m_rpcHandlers.Keys);
218 } 254 }
219 255
256 // JsonRPC
257 public bool AddJsonRPCHandler(string method, JsonRPCMethod handler)
258 {
259 lock(jsonRpcHandlers)
260 {
261 jsonRpcHandlers.Add(method, handler);
262 }
263 return true;
264 }
265
266 public JsonRPCMethod GetJsonRPCHandler(string method)
267 {
268 lock (jsonRpcHandlers)
269 {
270 if (jsonRpcHandlers.ContainsKey(method))
271 {
272 return jsonRpcHandlers[method];
273 }
274 else
275 {
276 return null;
277 }
278 }
279 }
280
281 public List<string> GetJsonRpcHandlerKeys()
282 {
283 lock (jsonRpcHandlers)
284 return new List<string>(jsonRpcHandlers.Keys);
285 }
286
220 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler) 287 public bool AddHTTPHandler(string methodName, GenericHTTPMethod handler)
221 { 288 {
222 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName); 289 //m_log.DebugFormat("[BASE HTTP SERVER]: Registering {0}", methodName);
@@ -309,7 +376,7 @@ namespace OpenSim.Framework.Servers.HttpServer
309 return true; 376 return true;
310 } 377 }
311 378
312 private void OnRequest(object source, RequestEventArgs args) 379 public void OnRequest(object source, RequestEventArgs args)
313 { 380 {
314 RequestNumber++; 381 RequestNumber++;
315 382
@@ -322,6 +389,8 @@ namespace OpenSim.Framework.Servers.HttpServer
322 389
323 if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) 390 if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs))
324 { 391 {
392 psEvArgs.RequestsReceived++;
393
325 PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); 394 PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request);
326 395
327 if (psEvArgs.Request != null) 396 if (psEvArgs.Request != null)
@@ -362,7 +431,7 @@ namespace OpenSim.Framework.Servers.HttpServer
362 psEvArgs.Request(psreq.RequestID, keysvals); 431 psEvArgs.Request(psreq.RequestID, keysvals);
363 } 432 }
364 433
365 m_PollServiceManager.Enqueue(psreq); 434 PollServiceRequestManager.Enqueue(psreq);
366 } 435 }
367 else 436 else
368 { 437 {
@@ -375,11 +444,24 @@ namespace OpenSim.Framework.Servers.HttpServer
375 } 444 }
376 } 445 }
377 446
378 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) 447 private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
379 { 448 {
380 OSHttpRequest req = new OSHttpRequest(context, request); 449 OSHttpRequest req = new OSHttpRequest(context, request);
450 WebSocketRequestDelegate dWebSocketRequestDelegate = null;
451 lock (m_WebSocketHandlers)
452 {
453 if (m_WebSocketHandlers.ContainsKey(req.RawUrl))
454 dWebSocketRequestDelegate = m_WebSocketHandlers[req.RawUrl];
455 }
456 if (dWebSocketRequestDelegate != null)
457 {
458 dWebSocketRequestDelegate(req.Url.AbsolutePath, new WebSocketHttpServerHandler(req, context, 8192));
459 return;
460 }
461
381 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 462 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
382 HandleRequest(req, resp); 463 resp.ReuseContext = true;
464 HandleRequest(req, resp);
383 465
384 // !!!HACK ALERT!!! 466 // !!!HACK ALERT!!!
385 // There seems to be a bug in the underlying http code that makes subsequent requests 467 // There seems to be a bug in the underlying http code that makes subsequent requests
@@ -410,7 +492,9 @@ namespace OpenSim.Framework.Servers.HttpServer
410 { 492 {
411 try 493 try
412 { 494 {
413 SendHTML500(response); 495 byte[] buffer500 = SendHTML500(response);
496 response.OutputStream.Write(buffer500, 0, buffer500.Length);
497 response.Send();
414 } 498 }
415 catch 499 catch
416 { 500 {
@@ -468,7 +552,7 @@ namespace OpenSim.Framework.Servers.HttpServer
468 LogIncomingToStreamHandler(request, requestHandler); 552 LogIncomingToStreamHandler(request, requestHandler);
469 553
470 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type. 554 response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
471 555
472 if (requestHandler is IStreamedRequestHandler) 556 if (requestHandler is IStreamedRequestHandler)
473 { 557 {
474 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler; 558 IStreamedRequestHandler streamedRequestHandler = requestHandler as IStreamedRequestHandler;
@@ -556,10 +640,18 @@ namespace OpenSim.Framework.Servers.HttpServer
556 640
557 buffer = HandleLLSDRequests(request, response); 641 buffer = HandleLLSDRequests(request, response);
558 break; 642 break;
643
644 case "application/json-rpc":
645 if (DebugLevel >= 3)
646 LogIncomingToContentTypeHandler(request);
647
648 buffer = HandleJsonRpcRequests(request, response);
649 break;
559 650
560 case "text/xml": 651 case "text/xml":
561 case "application/xml": 652 case "application/xml":
562 case "application/json": 653 case "application/json":
654
563 default: 655 default:
564 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler"); 656 //m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
565 // Point of note.. the DoWeHaveA methods check for an EXACT path 657 // Point of note.. the DoWeHaveA methods check for an EXACT path
@@ -600,7 +692,24 @@ namespace OpenSim.Framework.Servers.HttpServer
600 692
601 if (buffer != null) 693 if (buffer != null)
602 { 694 {
603 if (!response.SendChunked) 695 if (WebUtil.DebugLevel >= 5)
696 {
697 string output = System.Text.Encoding.UTF8.GetString(buffer);
698
699 if (WebUtil.DebugLevel >= 6)
700 {
701 // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name.
702 if ((requestHandler != null && requestHandler.Name == "GetMesh"))
703 {
704 if (output.Length > WebUtil.MaxRequestDiagLength)
705 output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "...";
706 }
707 }
708
709 WebUtil.LogResponseDetail(RequestNumber, output);
710 }
711
712 if (!response.SendChunked && response.ContentLength64 <= 0)
604 response.ContentLength64 = buffer.LongLength; 713 response.ContentLength64 = buffer.LongLength;
605 714
606 response.OutputStream.Write(buffer, 0, buffer.Length); 715 response.OutputStream.Write(buffer, 0, buffer.Length);
@@ -630,12 +739,20 @@ namespace OpenSim.Framework.Servers.HttpServer
630 } 739 }
631 catch (IOException e) 740 catch (IOException e)
632 { 741 {
633 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); 742 m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
634 } 743 }
635 catch (Exception e) 744 catch (Exception e)
636 { 745 {
637 m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); 746 m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e);
638 SendHTML500(response); 747 try
748 {
749 byte[] buffer500 = SendHTML500(response);
750 response.OutputStream.Write(buffer500, 0, buffer500.Length);
751 response.Send();
752 }
753 catch
754 {
755 }
639 } 756 }
640 finally 757 finally
641 { 758 {
@@ -645,7 +762,7 @@ namespace OpenSim.Framework.Servers.HttpServer
645 if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture") 762 if (tickdiff > 3000 && requestHandler != null && requestHandler.Name != "GetTexture")
646 { 763 {
647 m_log.InfoFormat( 764 m_log.InfoFormat(
648 "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", 765 "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms",
649 RequestNumber, 766 RequestNumber,
650 requestMethod, 767 requestMethod,
651 uriString, 768 uriString,
@@ -657,7 +774,7 @@ namespace OpenSim.Framework.Servers.HttpServer
657 else if (DebugLevel >= 4) 774 else if (DebugLevel >= 4)
658 { 775 {
659 m_log.DebugFormat( 776 m_log.DebugFormat(
660 "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms", 777 "[LOGHTTP] HTTP IN {0} :{1} took {2}ms",
661 RequestNumber, 778 RequestNumber,
662 Port, 779 Port,
663 tickdiff); 780 tickdiff);
@@ -668,7 +785,7 @@ namespace OpenSim.Framework.Servers.HttpServer
668 private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) 785 private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler)
669 { 786 {
670 m_log.DebugFormat( 787 m_log.DebugFormat(
671 "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", 788 "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}",
672 RequestNumber, 789 RequestNumber,
673 Port, 790 Port,
674 request.HttpMethod, 791 request.HttpMethod,
@@ -684,10 +801,10 @@ namespace OpenSim.Framework.Servers.HttpServer
684 private void LogIncomingToContentTypeHandler(OSHttpRequest request) 801 private void LogIncomingToContentTypeHandler(OSHttpRequest request)
685 { 802 {
686 m_log.DebugFormat( 803 m_log.DebugFormat(
687 "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", 804 "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}",
688 RequestNumber, 805 RequestNumber,
689 Port, 806 Port,
690 (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType, 807 string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType,
691 request.HttpMethod, 808 request.HttpMethod,
692 request.Url.PathAndQuery, 809 request.Url.PathAndQuery,
693 request.RemoteIPEndPoint); 810 request.RemoteIPEndPoint);
@@ -699,7 +816,7 @@ namespace OpenSim.Framework.Servers.HttpServer
699 private void LogIncomingToXmlRpcHandler(OSHttpRequest request) 816 private void LogIncomingToXmlRpcHandler(OSHttpRequest request)
700 { 817 {
701 m_log.DebugFormat( 818 m_log.DebugFormat(
702 "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", 819 "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}",
703 RequestNumber, 820 RequestNumber,
704 Port, 821 Port,
705 request.HttpMethod, 822 request.HttpMethod,
@@ -712,29 +829,49 @@ namespace OpenSim.Framework.Servers.HttpServer
712 829
713 private void LogIncomingInDetail(OSHttpRequest request) 830 private void LogIncomingInDetail(OSHttpRequest request)
714 { 831 {
715 using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8)) 832 if (request.ContentType == "application/octet-stream")
716 { 833 return; // never log these; they're just binary data
717 string output;
718 834
719 if (DebugLevel == 5) 835 Stream inputStream = Util.Copy(request.InputStream);
836 Stream innerStream = null;
837 try
838 {
839 if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip"))
720 { 840 {
721 const int sampleLength = 80; 841 innerStream = inputStream;
722 char[] sampleChars = new char[sampleLength + 3]; 842 inputStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
723 reader.Read(sampleChars, 0, sampleLength);
724 sampleChars[80] = '.';
725 sampleChars[81] = '.';
726 sampleChars[82] = '.';
727 output = new string(sampleChars);
728 } 843 }
729 else 844
845 using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8))
730 { 846 {
731 output = reader.ReadToEnd(); 847 string output;
732 }
733 848
734 m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n")); 849 if (DebugLevel == 5)
850 {
851 char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed
852 int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1);
853 output = new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength));
854 if (len > WebUtil.MaxRequestDiagLength)
855 output += "...";
856 }
857 else
858 {
859 output = reader.ReadToEnd();
860 }
861
862 m_log.DebugFormat("[LOGHTTP] {0}", Util.BinaryToASCII(output));
863 }
864 }
865 finally
866 {
867 if (innerStream != null)
868 innerStream.Dispose();
869 inputStream.Dispose();
735 } 870 }
736 } 871 }
737 872
873 private readonly string HANDLER_SEPARATORS = "/?&#-";
874
738 private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) 875 private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler)
739 { 876 {
740 string bestMatch = null; 877 string bestMatch = null;
@@ -743,7 +880,8 @@ namespace OpenSim.Framework.Servers.HttpServer
743 { 880 {
744 foreach (string pattern in m_streamHandlers.Keys) 881 foreach (string pattern in m_streamHandlers.Keys)
745 { 882 {
746 if (handlerKey.StartsWith(pattern)) 883 if ((handlerKey == pattern)
884 || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
747 { 885 {
748 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) 886 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
749 { 887 {
@@ -773,7 +911,8 @@ namespace OpenSim.Framework.Servers.HttpServer
773 { 911 {
774 foreach (string pattern in m_pollHandlers.Keys) 912 foreach (string pattern in m_pollHandlers.Keys)
775 { 913 {
776 if (handlerKey.StartsWith(pattern)) 914 if ((handlerKey == pattern)
915 || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
777 { 916 {
778 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) 917 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
779 { 918 {
@@ -805,7 +944,8 @@ namespace OpenSim.Framework.Servers.HttpServer
805 { 944 {
806 foreach (string pattern in m_HTTPHandlers.Keys) 945 foreach (string pattern in m_HTTPHandlers.Keys)
807 { 946 {
808 if (handlerKey.StartsWith(pattern)) 947 if ((handlerKey == pattern)
948 || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0)))
809 { 949 {
810 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) 950 if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
811 { 951 {
@@ -854,16 +994,33 @@ namespace OpenSim.Framework.Servers.HttpServer
854 /// <param name="response"></param> 994 /// <param name="response"></param>
855 private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) 995 private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response)
856 { 996 {
997 String requestBody;
998
857 Stream requestStream = request.InputStream; 999 Stream requestStream = request.InputStream;
1000 Stream innerStream = null;
1001 try
1002 {
1003 if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip"))
1004 {
1005 innerStream = requestStream;
1006 requestStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress);
1007 }
858 1008
859 Encoding encoding = Encoding.UTF8; 1009 using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8))
860 StreamReader reader = new StreamReader(requestStream, encoding); 1010 {
1011 requestBody = reader.ReadToEnd();
1012 }
1013 }
1014 finally
1015 {
1016 if (innerStream != null)
1017 innerStream.Dispose();
1018 requestStream.Dispose();
1019 }
861 1020
862 string requestBody = reader.ReadToEnd();
863 reader.Close();
864 requestStream.Close();
865 //m_log.Debug(requestBody); 1021 //m_log.Debug(requestBody);
866 requestBody = requestBody.Replace("<base64></base64>", ""); 1022 requestBody = requestBody.Replace("<base64></base64>", "");
1023
867 string responseString = String.Empty; 1024 string responseString = String.Empty;
868 XmlRpcRequest xmlRprcRequest = null; 1025 XmlRpcRequest xmlRprcRequest = null;
869 1026
@@ -958,7 +1115,19 @@ namespace OpenSim.Framework.Servers.HttpServer
958 } 1115 }
959 1116
960 response.ContentType = "text/xml"; 1117 response.ContentType = "text/xml";
961 responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); 1118 using (MemoryStream outs = new MemoryStream())
1119 using (XmlTextWriter writer = new XmlTextWriter(outs, UTF8NoBOM))
1120 {
1121 writer.Formatting = Formatting.None;
1122 XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse);
1123 writer.Flush();
1124 outs.Flush();
1125 outs.Position = 0;
1126 using (StreamReader sr = new StreamReader(outs))
1127 {
1128 responseString = sr.ReadToEnd();
1129 }
1130 }
962 } 1131 }
963 else 1132 else
964 { 1133 {
@@ -985,6 +1154,93 @@ namespace OpenSim.Framework.Servers.HttpServer
985 return buffer; 1154 return buffer;
986 } 1155 }
987 1156
1157 // JsonRpc (v2.0 only)
1158 // Batch requests not yet supported
1159 private byte[] HandleJsonRpcRequests(OSHttpRequest request, OSHttpResponse response)
1160 {
1161 Stream requestStream = request.InputStream;
1162 JsonRpcResponse jsonRpcResponse = new JsonRpcResponse();
1163 OSDMap jsonRpcRequest = null;
1164
1165 try
1166 {
1167 jsonRpcRequest = (OSDMap)OSDParser.DeserializeJson(requestStream);
1168 }
1169 catch (LitJson.JsonException e)
1170 {
1171 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1172 jsonRpcResponse.Error.Message = e.Message;
1173 }
1174
1175 requestStream.Close();
1176
1177 if (jsonRpcRequest != null)
1178 {
1179 if (jsonRpcRequest.ContainsKey("jsonrpc") || jsonRpcRequest["jsonrpc"].AsString() == "2.0")
1180 {
1181 jsonRpcResponse.JsonRpc = "2.0";
1182
1183 // If we have no id, then it's a "notification"
1184 if (jsonRpcRequest.ContainsKey("id"))
1185 {
1186 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1187 }
1188
1189 string methodname = jsonRpcRequest["method"];
1190 JsonRPCMethod method;
1191
1192 if (jsonRpcHandlers.ContainsKey(methodname))
1193 {
1194 lock(jsonRpcHandlers)
1195 {
1196 jsonRpcHandlers.TryGetValue(methodname, out method);
1197 }
1198 bool res = false;
1199 try
1200 {
1201 res = method(jsonRpcRequest, ref jsonRpcResponse);
1202 if(!res)
1203 {
1204 // The handler sent back an unspecified error
1205 if(jsonRpcResponse.Error.Code == 0)
1206 {
1207 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1208 }
1209 }
1210 }
1211 catch (Exception e)
1212 {
1213 string ErrorMessage = string.Format("[BASE HTTP SERVER]: Json-Rpc Handler Error method {0} - {1}", methodname, e.Message);
1214 m_log.Error(ErrorMessage);
1215 jsonRpcResponse.Error.Code = ErrorCode.InternalError;
1216 jsonRpcResponse.Error.Message = ErrorMessage;
1217 }
1218 }
1219 else // Error no hanlder defined for requested method
1220 {
1221 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1222 jsonRpcResponse.Error.Message = string.Format ("No handler defined for {0}", methodname);
1223 }
1224 }
1225 else // not json-rpc 2.0 could be v1
1226 {
1227 jsonRpcResponse.Error.Code = ErrorCode.InvalidRequest;
1228 jsonRpcResponse.Error.Message = "Must be valid json-rpc 2.0 see: http://www.jsonrpc.org/specification";
1229
1230 if (jsonRpcRequest.ContainsKey("id"))
1231 jsonRpcResponse.Id = jsonRpcRequest["id"].AsString();
1232 }
1233 }
1234
1235 response.KeepAlive = true;
1236 string responseData = string.Empty;
1237
1238 responseData = jsonRpcResponse.Serialize();
1239
1240 byte[] buffer = Encoding.UTF8.GetBytes(responseData);
1241 return buffer;
1242 }
1243
988 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response) 1244 private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
989 { 1245 {
990 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request"); 1246 //m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
@@ -1575,16 +1831,24 @@ namespace OpenSim.Framework.Servers.HttpServer
1575 response.SendChunked = false; 1831 response.SendChunked = false;
1576 response.ContentLength64 = buffer.Length; 1832 response.ContentLength64 = buffer.Length;
1577 response.ContentEncoding = Encoding.UTF8; 1833 response.ContentEncoding = Encoding.UTF8;
1578 1834
1835
1579 return buffer; 1836 return buffer;
1580 } 1837 }
1581 1838
1582 public void Start() 1839 public void Start()
1583 { 1840 {
1584 StartHTTP(); 1841 Start(true);
1585 } 1842 }
1586 1843
1587 private void StartHTTP() 1844 /// <summary>
1845 /// Start the http server
1846 /// </summary>
1847 /// <param name='processPollRequestsAsync'>
1848 /// If true then poll responses are performed asynchronsly.
1849 /// Option exists to allow regression tests to perform processing synchronously.
1850 /// </param>
1851 public void Start(bool performPollResponsesAsync)
1588 { 1852 {
1589 m_log.InfoFormat( 1853 m_log.InfoFormat(
1590 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); 1854 "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
@@ -1622,8 +1886,9 @@ namespace OpenSim.Framework.Servers.HttpServer
1622 m_httpListener2.Start(64); 1886 m_httpListener2.Start(64);
1623 1887
1624 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 1888 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1625 m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); 1889 PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000);
1626 m_PollServiceManager.Start(); 1890 PollServiceRequestManager.Start();
1891
1627 HTTPDRunning = true; 1892 HTTPDRunning = true;
1628 1893
1629 //HttpListenerContext context; 1894 //HttpListenerContext context;
@@ -1642,6 +1907,21 @@ namespace OpenSim.Framework.Servers.HttpServer
1642 // useful without inbound HTTP. 1907 // useful without inbound HTTP.
1643 throw e; 1908 throw e;
1644 } 1909 }
1910
1911 m_requestsProcessedStat
1912 = new Stat(
1913 "HTTPRequestsServed",
1914 "Number of inbound HTTP requests processed",
1915 "",
1916 "requests",
1917 "httpserver",
1918 Port.ToString(),
1919 StatType.Pull,
1920 MeasuresOfInterest.AverageChangeOverTime,
1921 stat => stat.Value = RequestNumber,
1922 StatVerbosity.Debug);
1923
1924 StatsManager.RegisterStat(m_requestsProcessedStat);
1645 } 1925 }
1646 1926
1647 public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) 1927 public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
@@ -1672,9 +1952,12 @@ namespace OpenSim.Framework.Servers.HttpServer
1672 public void Stop() 1952 public void Stop()
1673 { 1953 {
1674 HTTPDRunning = false; 1954 HTTPDRunning = false;
1955
1956 StatsManager.DeregisterStat(m_requestsProcessedStat);
1957
1675 try 1958 try
1676 { 1959 {
1677 m_PollServiceManager.Stop(); 1960 PollServiceRequestManager.Stop();
1678 1961
1679 m_httpListener2.ExceptionThrown -= httpServerException; 1962 m_httpListener2.ExceptionThrown -= httpServerException;
1680 //m_httpListener2.DisconnectHandler = null; 1963 //m_httpListener2.DisconnectHandler = null;
@@ -1741,6 +2024,12 @@ namespace OpenSim.Framework.Servers.HttpServer
1741 m_rpcHandlers.Remove(method); 2024 m_rpcHandlers.Remove(method);
1742 } 2025 }
1743 2026
2027 public void RemoveJsonRPCHandler(string method)
2028 {
2029 lock(jsonRpcHandlers)
2030 jsonRpcHandlers.Remove(method);
2031 }
2032
1744 public bool RemoveLLSDHandler(string path, LLSDMethod handler) 2033 public bool RemoveLLSDHandler(string path, LLSDMethod handler)
1745 { 2034 {
1746 lock (m_llsdHandlers) 2035 lock (m_llsdHandlers)
diff --git a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
index 5312a31..72b3065 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
@@ -25,46 +25,36 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System; 28using System.IO;
29using System.Xml.Serialization;
30 29
31namespace OpenSim.Framework.Communications.XMPP 30namespace OpenSim.Framework.Servers.HttpServer
32{ 31{
33 public abstract class XmppStanza 32 /// <summary>
33 /// Base handler for writing to an output stream
34 /// </summary>
35 /// <remarks>
36 /// Inheriting classes should override ProcessRequest() rather than Handle()
37 /// </remarks>
38 public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler
34 { 39 {
35 /// <summary> 40 protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
36 /// counter used for generating ID
37 /// </summary>
38 [XmlIgnore]
39 private static ulong _ctr = 0;
40 41
41 /// <summary> 42 protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description)
42 /// recipient JID 43 : base(httpMethod, path, name, description) {}
43 /// </summary>
44 [XmlAttribute("to")]
45 public string ToJid;
46 44
47 /// <summary> 45 public virtual void Handle(
48 /// sender JID 46 string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
49 /// </summary> 47 {
50 [XmlAttribute("from")] 48 RequestsReceived++;
51 public string FromJid;
52 49
53 /// <summary> 50 ProcessRequest(path, request, response, httpRequest, httpResponse);
54 /// unique ID.
55 /// </summary>
56 [XmlAttribute("id")]
57 public string MessageId;
58 51
59 public XmppStanza() 52 RequestsHandled++;
60 {
61 } 53 }
62 54
63 public XmppStanza(string fromJid, string toJid) 55 protected virtual void ProcessRequest(
56 string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
64 { 57 {
65 ToJid = toJid;
66 FromJid = fromJid;
67 MessageId = String.Format("OpenSim_{0}{1}", DateTime.UtcNow.Ticks, _ctr++);
68 } 58 }
69 } 59 }
70} 60} \ 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 @@
26 */ 26 */
27 27
28using System; 28using System;
29using OpenSim.Framework.Monitoring;
29 30
30namespace OpenSim.Framework.Servers.HttpServer 31namespace OpenSim.Framework.Servers.HttpServer
31{ 32{
32 public abstract class BaseRequestHandler 33 public abstract class BaseRequestHandler
33 { 34 {
35 public int RequestsReceived { get; protected set; }
36
37 public int RequestsHandled { get; protected set; }
38
34 public virtual string ContentType 39 public virtual string ContentType
35 { 40 {
36 get { return "application/xml"; } 41 get { return "application/xml"; }
@@ -57,6 +62,24 @@ namespace OpenSim.Framework.Servers.HttpServer
57 Description = description; 62 Description = description;
58 m_httpMethod = httpMethod; 63 m_httpMethod = httpMethod;
59 m_path = path; 64 m_path = path;
65
66 // FIXME: A very temporary measure to stop the simulator stats being overwhelmed with user CAPS info.
67 // Needs to be fixed properly in stats display
68 if (!path.StartsWith("/CAPS/"))
69 {
70 StatsManager.RegisterStat(
71 new Stat(
72 "requests",
73 "requests",
74 "Number of requests received by this service endpoint",
75 "requests",
76 "service",
77 string.Format("{0}:{1}", httpMethod, path),
78 StatType.Pull,
79 MeasuresOfInterest.AverageChangeOverTime,
80 s => s.Value = RequestsReceived,
81 StatVerbosity.Debug));
82 }
60 } 83 }
61 84
62 public virtual string Path 85 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 @@
26 */ 26 */
27 27
28using System.IO; 28using System.IO;
29using System.Net;
30using OpenSim.Framework.ServiceAuth;
29 31
30namespace OpenSim.Framework.Servers.HttpServer 32namespace OpenSim.Framework.Servers.HttpServer
31{ 33{
34 /// <summary>
35 /// Base streamed request handler.
36 /// </summary>
37 /// <remarks>
38 /// Inheriting classes should override ProcessRequest() rather than Handle()
39 /// </remarks>
32 public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler 40 public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler
33 { 41 {
34 public abstract byte[] Handle(string path, Stream request, 42 protected IServiceAuth m_Auth;
35 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse);
36 43
37 protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} 44 protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) { }
38 45
39 protected BaseStreamHandler(string httpMethod, string path, string name, string description) 46 protected BaseStreamHandler(string httpMethod, string path, string name, string description)
40 : base(httpMethod, path, name, description) {} 47 : base(httpMethod, path, name, description) {}
48
49 protected BaseStreamHandler(string httpMethod, string path, IServiceAuth auth)
50 : base(httpMethod, path, null, null)
51 {
52 m_Auth = auth;
53 }
54
55 public virtual byte[] Handle(
56 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
57 {
58 RequestsReceived++;
59
60 if (m_Auth != null)
61 {
62 HttpStatusCode statusCode;
63
64 if (!m_Auth.Authenticate(httpRequest.Headers, httpResponse.AddHeader, out statusCode))
65 {
66 httpResponse.StatusCode = (int)statusCode;
67 httpResponse.ContentType = "text/plain";
68 return new byte[0];
69 }
70 }
71
72 byte[] result = ProcessRequest(path, request, httpRequest, httpResponse);
73
74 RequestsHandled++;
75
76 return result;
77 }
78
79 protected virtual byte[] ProcessRequest(
80 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
81 {
82 return null;
83 }
41 } 84 }
42} \ No newline at end of file 85} \ 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using OpenSim.Framework;
28using System.IO;
29
30namespace OpenSim.Framework.Servers.HttpServer
31{
32 /// <summary>
33 /// BaseStreamHandlerBasicDOSProtector Base streamed request handler.
34 /// </summary>
35 /// <remarks>
36 /// Inheriting classes should override ProcessRequest() rather than Handle()
37 /// </remarks>
38 public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler
39 {
40
41 private readonly BasicDosProtectorOptions _options;
42 private readonly BasicDOSProtector _dosProtector;
43
44 protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, BasicDosProtectorOptions options) : this(httpMethod, path, null, null, options) {}
45
46 protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, string name, string description, BasicDosProtectorOptions options)
47 : base(httpMethod, path, name, description)
48 {
49 _options = options;
50 _dosProtector = new BasicDOSProtector(_options);
51 }
52
53 public virtual byte[] Handle(
54 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
55 {
56 byte[] result;
57 RequestsReceived++;
58 string clientstring = GetClientString(httpRequest);
59 string endpoint = GetRemoteAddr(httpRequest);
60 if (_dosProtector.Process(clientstring, endpoint))
61 result = ProcessRequest(path, request, httpRequest, httpResponse);
62 else
63 result = ThrottledRequest(path, request, httpRequest, httpResponse);
64 if (_options.MaxConcurrentSessions > 0)
65 _dosProtector.ProcessEnd(clientstring, endpoint);
66
67 RequestsHandled++;
68
69 return result;
70 }
71
72 protected virtual byte[] ProcessRequest(
73 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
74 {
75 return null;
76 }
77
78 protected virtual byte[] ThrottledRequest(
79 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
80 {
81 return new byte[0];
82 }
83
84
85 private string GetRemoteAddr(IOSHttpRequest httpRequest)
86 {
87 string remoteaddr = string.Empty;
88 if (httpRequest.Headers["remote_addr"] != null)
89 remoteaddr = httpRequest.Headers["remote_addr"];
90
91 return remoteaddr;
92 }
93
94 private string GetClientString(IOSHttpRequest httpRequest)
95 {
96 string clientstring = string.Empty;
97
98 if (_options.AllowXForwardedFor && httpRequest.Headers["x-forwarded-for"] != null)
99 clientstring = httpRequest.Headers["x-forwarded-for"];
100 else
101 clientstring = GetRemoteAddr(httpRequest);
102
103 return clientstring;
104
105 }
106 }
107}
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
45 m_method = binaryMethod; 45 m_method = binaryMethod;
46 } 46 }
47 47
48 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 48 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
49 { 49 {
50 byte[] data = ReadFully(request); 50 byte[] data = ReadFully(request);
51 string param = GetParam(path); 51 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Collections;
29
30namespace OpenSim.Framework.Servers.HttpServer
31{
32 public class GenericHTTPDOSProtector
33 {
34 private readonly GenericHTTPMethod _normalMethod;
35 private readonly GenericHTTPMethod _throttledMethod;
36
37 private readonly BasicDosProtectorOptions _options;
38 private readonly BasicDOSProtector _dosProtector;
39
40 public GenericHTTPDOSProtector(GenericHTTPMethod normalMethod, GenericHTTPMethod throttledMethod, BasicDosProtectorOptions options)
41 {
42 _normalMethod = normalMethod;
43 _throttledMethod = throttledMethod;
44
45 _options = options;
46 _dosProtector = new BasicDOSProtector(_options);
47 }
48 public Hashtable Process(Hashtable request)
49 {
50 Hashtable process = null;
51 string clientstring= GetClientString(request);
52 string endpoint = GetRemoteAddr(request);
53 if (_dosProtector.Process(clientstring, endpoint))
54 process = _normalMethod(request);
55 else
56 process = _throttledMethod(request);
57
58 if (_options.MaxConcurrentSessions>0)
59 _dosProtector.ProcessEnd(clientstring, endpoint);
60
61 return process;
62 }
63
64 private string GetRemoteAddr(Hashtable request)
65 {
66 string remoteaddr = "";
67 if (!request.ContainsKey("headers"))
68 return remoteaddr;
69 Hashtable requestinfo = (Hashtable)request["headers"];
70 if (!requestinfo.ContainsKey("remote_addr"))
71 return remoteaddr;
72 object remote_addrobj = requestinfo["remote_addr"];
73 if (remote_addrobj != null)
74 {
75 if (!string.IsNullOrEmpty(remote_addrobj.ToString()))
76 {
77 remoteaddr = remote_addrobj.ToString();
78 }
79
80 }
81 return remoteaddr;
82 }
83
84 private string GetClientString(Hashtable request)
85 {
86 string clientstring = "";
87 if (!request.ContainsKey("headers"))
88 return clientstring;
89
90 Hashtable requestinfo = (Hashtable)request["headers"];
91 if (_options.AllowXForwardedFor && requestinfo.ContainsKey("x-forwarded-for"))
92 {
93 object str = requestinfo["x-forwarded-for"];
94 if (str != null)
95 {
96 if (!string.IsNullOrEmpty(str.ToString()))
97 {
98 return str.ToString();
99 }
100 }
101 }
102 if (!requestinfo.ContainsKey("remote_addr"))
103 return clientstring;
104
105 object remote_addrobj = requestinfo["remote_addr"];
106 if (remote_addrobj != null)
107 {
108 if (!string.IsNullOrEmpty(remote_addrobj.ToString()))
109 {
110 clientstring = remote_addrobj.ToString();
111 }
112 }
113
114 return clientstring;
115
116 }
117
118 }
119}
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
97 bool AddXmlRPCHandler(string method, XmlRpcMethod handler); 97 bool AddXmlRPCHandler(string method, XmlRpcMethod handler);
98 bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive); 98 bool AddXmlRPCHandler(string method, XmlRpcMethod handler, bool keepAlive);
99 99
100 bool AddJsonRPCHandler(string method, JsonRPCMethod handler);
101
102 /// <summary>
103 /// Websocket HTTP server handlers.
104 /// </summary>
105 /// <param name="servicepath"></param>
106 /// <param name="handler"></param>
107 void AddWebSocketHandler(string servicepath, BaseHttpServer.WebSocketRequestDelegate handler);
108
109
110 void RemoveWebSocketHandler(string servicepath);
111
100 /// <summary> 112 /// <summary>
101 /// Gets the XML RPC handler for given method name 113 /// Gets the XML RPC handler for given method name
102 /// </summary> 114 /// </summary>
@@ -128,6 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer
128 void RemoveStreamHandler(string httpMethod, string path); 140 void RemoveStreamHandler(string httpMethod, string path);
129 141
130 void RemoveXmlRPCHandler(string method); 142 void RemoveXmlRPCHandler(string method);
143
144 void RemoveJsonRPCHandler(string method);
131 145
132 string GetHTTP404(string host); 146 string GetHTTP404(string host);
133 147
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
32{ 32{
33 public interface IRequestHandler 33 public interface IRequestHandler
34 { 34 {
35
36 /// <summary> 35 /// <summary>
37 /// Name for this handler. 36 /// Name for this handler.
38 /// </summary> 37 /// </summary>
@@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer
59 58
60 // Return path 59 // Return path
61 string Path { get; } 60 string Path { get; }
61
62 /// <summary>
63 /// Number of requests received by this handler
64 /// </summary>
65 int RequestsReceived { get; }
66
67 /// <summary>
68 /// Number of requests handled.
69 /// </summary>
70 /// <remarks>
71 /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock.
72 /// </remarks>
73 int RequestsHandled { get; }
62 } 74 }
63 75
64 public interface IStreamedRequestHandler : IRequestHandler 76 public interface IStreamedRequestHandler : IRequestHandler
@@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer
69 81
70 public interface IStreamHandler : IRequestHandler 82 public interface IStreamHandler : IRequestHandler
71 { 83 {
72 // Handle request stream, return byte array
73 void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); 84 void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse);
74 } 85 }
75 86
diff --git a/OpenSim/Framework/IRegionLoader.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
index c566fc7..5bab508 100644
--- a/OpenSim/Framework/IRegionLoader.cs
+++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs
@@ -25,13 +25,10 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using Nini.Config; 28using System.Net;
29using OpenMetaverse.StructuredData;
29 30
30namespace OpenSim.Framework 31namespace OpenSim.Framework.Servers.HttpServer
31{ 32{
32 public interface IRegionLoader 33 public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response);
33 { 34}
34 void SetIniConfigSource(IConfigSource configSource);
35 RegionInfo[] LoadRegions();
36 }
37} \ No newline at end of file
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using System.Net.Sockets;
31using System.Reflection;
32using System.Text;
33using System.IO;
34using OpenMetaverse.StructuredData;
35using OpenMetaverse;
36using log4net;
37
38namespace OpenSim.Framework.Servers.HttpServer
39{
40 /// <summary>
41 /// Json rpc request manager.
42 /// </summary>
43 public class JsonRpcRequestManager
44 {
45 static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 public JsonRpcRequestManager()
48 {
49 }
50
51 /// <summary>
52 /// Sends json-rpc request with a serializable type.
53 /// </summary>
54 /// <returns>
55 /// OSD Map.
56 /// </returns>
57 /// <param name='parameters'>
58 /// Serializable type .
59 /// </param>
60 /// <param name='method'>
61 /// Json-rpc method to call.
62 /// </param>
63 /// <param name='uri'>
64 /// URI of json-rpc service.
65 /// </param>
66 /// <param name='jsonId'>
67 /// Id for our call.
68 /// </param>
69 public bool JsonRpcRequest(ref object parameters, string method, string uri, string jsonId)
70 {
71 if (jsonId == null)
72 throw new ArgumentNullException("jsonId");
73 if (uri == null)
74 throw new ArgumentNullException("uri");
75 if (method == null)
76 throw new ArgumentNullException("method");
77 if (parameters == null)
78 throw new ArgumentNullException("parameters");
79
80 OSDMap request = new OSDMap();
81 request.Add("jsonrpc", OSD.FromString("2.0"));
82 request.Add("id", OSD.FromString(jsonId));
83 request.Add("method", OSD.FromString(method));
84 request.Add("params", OSD.SerializeMembers(parameters));
85
86 OSDMap response;
87 try
88 {
89 response = WebUtil.PostToService(uri, request, 10000, true);
90 }
91 catch (Exception e)
92 {
93 m_log.Debug(string.Format("JsonRpc request '{0}' to {1} failed", method, uri), e);
94 return false;
95 }
96
97 if (!response.ContainsKey("_Result"))
98 {
99 m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}",
100 method, uri, OSDParser.SerializeJsonString(response));
101 return false;
102 }
103 response = (OSDMap)response["_Result"];
104
105 OSD data;
106
107 if (response.ContainsKey("error"))
108 {
109 data = response["error"];
110 m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an error: {2}",
111 method, uri, OSDParser.SerializeJsonString(data));
112 return false;
113 }
114
115 if (!response.ContainsKey("result"))
116 {
117 m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}",
118 method, uri, OSDParser.SerializeJsonString(response));
119 return false;
120 }
121
122 data = response["result"];
123 OSD.DeserializeMembers(ref parameters, (OSDMap)data);
124
125 return true;
126 }
127
128 /// <summary>
129 /// Sends json-rpc request with OSD parameter.
130 /// </summary>
131 /// <returns>
132 /// The rpc request.
133 /// </returns>
134 /// <param name='data'>
135 /// data - incoming as parameters, outgoing as result/error
136 /// </param>
137 /// <param name='method'>
138 /// Json-rpc method to call.
139 /// </param>
140 /// <param name='uri'>
141 /// URI of json-rpc service.
142 /// </param>
143 /// <param name='jsonId'>
144 /// If set to <c>true</c> json identifier.
145 /// </param>
146 public bool JsonRpcRequest(ref OSD data, string method, string uri, string jsonId)
147 {
148 if (string.IsNullOrEmpty(jsonId))
149 jsonId = UUID.Random().ToString();
150
151 OSDMap request = new OSDMap();
152 request.Add("jsonrpc", OSD.FromString("2.0"));
153 request.Add("id", OSD.FromString(jsonId));
154 request.Add("method", OSD.FromString(method));
155 request.Add("params", data);
156
157 OSDMap response;
158 try
159 {
160 response = WebUtil.PostToService(uri, request, 10000, true);
161 }
162 catch (Exception e)
163 {
164 m_log.Debug(string.Format("JsonRpc request '{0}' to {1} failed", method, uri), e);
165 return false;
166 }
167
168 if (!response.ContainsKey("_Result"))
169 {
170 m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an invalid response: {2}",
171 method, uri, OSDParser.SerializeJsonString(response));
172 return false;
173 }
174 response = (OSDMap)response["_Result"];
175
176 if (response.ContainsKey("error"))
177 {
178 data = response["error"];
179 m_log.DebugFormat("JsonRpc request '{0}' to {1} returned an error: {2}",
180 method, uri, OSDParser.SerializeJsonString(data));
181 return false;
182 }
183
184 data = response;
185
186 return true;
187 }
188
189 }
190}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27using System;
28using System.Net;
29using OpenMetaverse.StructuredData;
30
31namespace OpenSim.Framework.Servers.HttpServer
32{
33 public sealed class ErrorCode
34 {
35 private ErrorCode() {}
36
37 public const int ParseError = -32700;
38 public const int InvalidRequest = -32600;
39 public const int MethodNotFound = -32601;
40 public const int InvalidParams = -32602;
41 public const int InternalError = -32604;
42
43 }
44
45 public class JsonRpcError
46 {
47 internal OSDMap Error = new OSDMap();
48
49 public int Code
50 {
51 get
52 {
53 if (Error.ContainsKey("code"))
54 return Error["code"].AsInteger();
55 else
56 return 0;
57 }
58 set
59 {
60 Error["code"] = OSD.FromInteger(value);
61 }
62 }
63
64 public string Message
65 {
66 get
67 {
68 if (Error.ContainsKey("message"))
69 return Error["message"].AsString();
70 else
71 return null;
72 }
73 set
74 {
75 Error["message"] = OSD.FromString(value);
76 }
77 }
78
79 public OSD Data
80 {
81 get; set;
82 }
83 }
84
85 public class JsonRpcResponse
86 {
87 public string JsonRpc
88 {
89 get
90 {
91 return Reply["jsonrpc"].AsString();
92 }
93 set
94 {
95 Reply["jsonrpc"] = OSD.FromString(value);
96 }
97 }
98
99 public string Id
100 {
101 get
102 {
103 return Reply["id"].AsString();
104 }
105 set
106 {
107 Reply["id"] = OSD.FromString(value);
108 }
109 }
110
111 public OSD Result
112 {
113 get; set;
114 }
115
116 public JsonRpcError Error
117 {
118 get; set;
119 }
120
121 public OSDMap Reply = new OSDMap();
122
123 public JsonRpcResponse()
124 {
125 Error = new JsonRpcError();
126 }
127
128 public string Serialize()
129 {
130 if (Result != null)
131 Reply["result"] = Result;
132
133 if (Error.Code != 0)
134 {
135 Reply["error"] = (OSD)Error.Error;
136 }
137
138 string result = string.Empty;
139 try
140 {
141 result = OSDParser.SerializeJsonString(Reply);
142 }
143 catch
144 {
145
146 }
147 return result;
148 }
149 }
150}
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
182 _context = context; 182 _context = context;
183 183
184 if (null != req.Headers["content-encoding"]) 184 if (null != req.Headers["content-encoding"])
185 _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]); 185 {
186 try
187 {
188 _contentEncoding = Encoding.GetEncoding(_request.Headers["content-encoding"]);
189 }
190 catch (Exception)
191 {
192 // ignore
193 }
194 }
195
186 if (null != req.Headers["content-type"]) 196 if (null != req.Headers["content-type"])
187 _contentType = _request.Headers["content-type"]; 197 _contentType = _request.Headers["content-type"];
188 if (null != req.Headers["user-agent"]) 198 if (null != req.Headers["user-agent"])
189 _userAgent = req.Headers["user-agent"]; 199 _userAgent = req.Headers["user-agent"];
200
190 if (null != req.Headers["remote_addr"]) 201 if (null != req.Headers["remote_addr"])
191 { 202 {
192 try 203 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
70 _id = id; 70 _id = id;
71 71
72 _engine = new Thread(new ThreadStart(Engine)); 72 _engine = new Thread(new ThreadStart(Engine));
73 _engine.Name = EngineID;
74 _engine.IsBackground = true; 73 _engine.IsBackground = true;
75 _engine.Start(); 74 _engine.Start();
75 _engine.Name = string.Format ("Engine:{0}",EngineID);
76 76
77 ThreadTracker.Add(_engine); 77 ThreadTracker.Add(_engine);
78 } 78 }
@@ -91,9 +91,9 @@ namespace OpenSim.Framework.Servers.HttpServer
91 public void Start() 91 public void Start()
92 { 92 {
93 _engine = new Thread(new ThreadStart(Engine)); 93 _engine = new Thread(new ThreadStart(Engine));
94 _engine.Name = EngineID;
95 _engine.IsBackground = true; 94 _engine.IsBackground = true;
96 _engine.Start(); 95 _engine.Start();
96 _engine.Name = string.Format ("Engine:{0}",EngineID);
97 97
98 ThreadTracker.Add(_engine); 98 ThreadTracker.Add(_engine);
99 } 99 }
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
150 public void Start() 150 public void Start()
151 { 151 {
152 _engine = new Thread(new ThreadStart(Engine)); 152 _engine = new Thread(new ThreadStart(Engine));
153 _engine.Name = _engineId;
154 _engine.IsBackground = true; 153 _engine.IsBackground = true;
155 _engine.Start(); 154 _engine.Start();
155 _engine.Name = string.Format ("Engine:{0}",_engineId);
156 156
157 ThreadTracker.Add(_engine); 157 ThreadTracker.Add(_engine);
158 158
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
34 public delegate void RequestMethod(UUID requestID, Hashtable request); 34 public delegate void RequestMethod(UUID requestID, Hashtable request);
35 public delegate bool HasEventsMethod(UUID requestID, UUID pId); 35 public delegate bool HasEventsMethod(UUID requestID, UUID pId);
36 36
37 public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId, string request); 37 public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId);
38 38
39 public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId); 39 public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId);
40 40
@@ -45,17 +45,42 @@ namespace OpenSim.Framework.Servers.HttpServer
45 public NoEventsMethod NoEvents; 45 public NoEventsMethod NoEvents;
46 public RequestMethod Request; 46 public RequestMethod Request;
47 public UUID Id; 47 public UUID Id;
48 public int TimeOutms;
49 public EventType Type;
50
51 public enum EventType : int
52 {
53 LongPoll = 0,
54 LslHttp = 1,
55 Inventory = 2
56 }
57
58 public string Url { get; set; }
59
60 /// <summary>
61 /// Number of requests received for this poll service.
62 /// </summary>
63 public int RequestsReceived { get; set; }
64
65 /// <summary>
66 /// Number of requests handled by this poll service.
67 /// </summary>
68 public int RequestsHandled { get; set; }
48 69
49 public PollServiceEventArgs( 70 public PollServiceEventArgs(
50 RequestMethod pRequest, 71 RequestMethod pRequest,
72 string pUrl,
51 HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, 73 HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
52 UUID pId) 74 UUID pId, int pTimeOutms)
53 { 75 {
54 Request = pRequest; 76 Request = pRequest;
77 Url = pUrl;
55 HasEvents = pHasEvents; 78 HasEvents = pHasEvents;
56 GetEvents = pGetEvents; 79 GetEvents = pGetEvents;
57 NoEvents = pNoEvents; 80 NoEvents = pNoEvents;
58 Id = pId; 81 Id = pId;
82 TimeOutms = pTimeOutms;
83 Type = EventType.LongPoll;
59 } 84 }
60 } 85 }
61} \ No newline at end of file 86}
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 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Reflection;
31using System.Text;
29using HttpServer; 32using HttpServer;
33using log4net;
30using OpenMetaverse; 34using OpenMetaverse;
31 35
32namespace OpenSim.Framework.Servers.HttpServer 36namespace OpenSim.Framework.Servers.HttpServer
33{ 37{
34 public class PollServiceHttpRequest 38 public class PollServiceHttpRequest
35 { 39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
36 public readonly PollServiceEventArgs PollServiceArgs; 42 public readonly PollServiceEventArgs PollServiceArgs;
37 public readonly IHttpClientContext HttpContext; 43 public readonly IHttpClientContext HttpContext;
38 public readonly IHttpRequest Request; 44 public readonly IHttpRequest Request;
@@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer
48 RequestTime = System.Environment.TickCount; 54 RequestTime = System.Environment.TickCount;
49 RequestID = UUID.Random(); 55 RequestID = UUID.Random();
50 } 56 }
57
58 internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata)
59 {
60 OSHttpResponse response
61 = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext);
62
63 byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
64
65 response.SendChunked = false;
66 response.ContentLength64 = buffer.Length;
67 response.ContentEncoding = Encoding.UTF8;
68
69 try
70 {
71 response.OutputStream.Write(buffer, 0, buffer.Length);
72 }
73 catch (Exception ex)
74 {
75 m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex);
76 }
77 finally
78 {
79 //response.OutputStream.Close();
80 try
81 {
82 response.OutputStream.Flush();
83 response.Send();
84
85 //if (!response.KeepAlive && response.ReuseContext)
86 // response.FreeContext();
87 }
88 catch (Exception e)
89 {
90 m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", e);
91 }
92
93 PollServiceArgs.RequestsHandled++;
94 }
95 }
51 } 96 }
52} \ No newline at end of file 97} \ 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;
33using HttpServer; 33using HttpServer;
34using OpenSim.Framework; 34using OpenSim.Framework;
35using OpenSim.Framework.Monitoring; 35using OpenSim.Framework.Monitoring;
36using Amib.Threading;
37using System.IO;
38using System.Text;
39using System.Collections.Generic;
36 40
37namespace OpenSim.Framework.Servers.HttpServer 41namespace OpenSim.Framework.Servers.HttpServer
38{ 42{
39 public class PollServiceRequestManager 43 public class PollServiceRequestManager
40 { 44 {
41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 45 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
46
47 /// <summary>
48 /// Is the poll service request manager running?
49 /// </summary>
50 /// <remarks>
51 /// Can be running either synchronously or asynchronously
52 /// </remarks>
53 public bool IsRunning { get; private set; }
54
55 /// <summary>
56 /// Is the poll service performing responses asynchronously (with its own threads) or synchronously (via
57 /// external calls)?
58 /// </summary>
59 public bool PerformResponsesAsync { get; private set; }
60
61 /// <summary>
62 /// Number of responses actually processed and sent to viewer (or aborted due to error).
63 /// </summary>
64 public int ResponsesProcessed { get; private set; }
42 65
43 private readonly BaseHttpServer m_server; 66 private readonly BaseHttpServer m_server;
44 private static Queue m_requests = Queue.Synchronized(new Queue()); 67
68 private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
69 private static List<PollServiceHttpRequest> m_longPollRequests = new List<PollServiceHttpRequest>();
70
45 private uint m_WorkerThreadCount = 0; 71 private uint m_WorkerThreadCount = 0;
46 private Thread[] m_workerThreads; 72 private Thread[] m_workerThreads;
47 private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
48 private volatile bool m_running = true;
49 private int m_pollTimeout;
50 73
51 public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) 74 private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
75
76// private int m_timeout = 1000; // increase timeout 250; now use the event one
77
78 public PollServiceRequestManager(
79 BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout)
52 { 80 {
53 m_server = pSrv; 81 m_server = pSrv;
82 PerformResponsesAsync = performResponsesAsync;
54 m_WorkerThreadCount = pWorkerThreadCount; 83 m_WorkerThreadCount = pWorkerThreadCount;
55 m_pollTimeout = pTimeout; 84 m_workerThreads = new Thread[m_WorkerThreadCount];
85
86 StatsManager.RegisterStat(
87 new Stat(
88 "QueuedPollResponses",
89 "Number of poll responses queued for processing.",
90 "",
91 "",
92 "httpserver",
93 m_server.Port.ToString(),
94 StatType.Pull,
95 MeasuresOfInterest.AverageChangeOverTime,
96 stat => stat.Value = m_requests.Count(),
97 StatVerbosity.Debug));
98
99 StatsManager.RegisterStat(
100 new Stat(
101 "ProcessedPollResponses",
102 "Number of poll responses processed.",
103 "",
104 "",
105 "httpserver",
106 m_server.Port.ToString(),
107 StatType.Pull,
108 MeasuresOfInterest.AverageChangeOverTime,
109 stat => stat.Value = ResponsesProcessed,
110 StatVerbosity.Debug));
56 } 111 }
57 112
58 public void Start() 113 public void Start()
59 { 114 {
60 m_running = true; 115 IsRunning = true;
61 m_workerThreads = new Thread[m_WorkerThreadCount];
62 m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
63 116
64 //startup worker threads 117 if (PerformResponsesAsync)
65 for (uint i = 0; i < m_WorkerThreadCount; i++)
66 { 118 {
67 m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout); 119 //startup worker threads
68 m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent; 120 for (uint i = 0; i < m_WorkerThreadCount; i++)
69 121 {
70 m_workerThreads[i] 122 m_workerThreads[i]
71 = Watchdog.StartThread( 123 = WorkManager.StartThread(
72 m_PollServiceWorkerThreads[i].ThreadStart, 124 PoolWorkerJob,
73 String.Format("PollServiceWorkerThread{0}", i), 125 string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
74 ThreadPriority.Normal, 126 ThreadPriority.Normal,
75 false, 127 false,
76 true, 128 false,
77 null, 129 null,
78 int.MaxValue); 130 int.MaxValue);
79 } 131 }
80 132
81 Watchdog.StartThread( 133 WorkManager.StartThread(
82 this.ThreadStart, 134 this.CheckLongPollThreads,
83 "PollServiceWatcherThread", 135 string.Format("LongPollServiceWatcherThread:{0}", m_server.Port),
84 ThreadPriority.Normal, 136 ThreadPriority.Normal,
85 false, 137 false,
86 true, 138 true,
87 null, 139 null,
88 1000 * 60 * 10); 140 1000 * 60 * 10);
141 }
89 } 142 }
90 143
91 internal void ReQueueEvent(PollServiceHttpRequest req) 144 private void ReQueueEvent(PollServiceHttpRequest req)
92 { 145 {
93 // Do accounting stuff here 146 if (IsRunning)
94 Enqueue(req); 147 {
95 } 148 // delay the enqueueing for 100ms. There's no need to have the event
149 // actively on the queue
150 Timer t = new Timer(self => {
151 ((Timer)self).Dispose();
152 m_requests.Enqueue(req);
153 });
96 154
97 public void Enqueue(PollServiceHttpRequest req) 155 t.Change(100, Timeout.Infinite);
98 { 156
99 lock (m_requests) 157 }
100 m_requests.Enqueue(req);
101 } 158 }
102 159
103 public void ThreadStart() 160 public void Enqueue(PollServiceHttpRequest req)
104 { 161 {
105 while (m_running) 162 if (IsRunning)
106 { 163 {
107 Watchdog.UpdateThread(); 164 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll)
108 ProcessQueuedRequests(); 165 {
109 Thread.Sleep(1000); 166 lock (m_longPollRequests)
167 m_longPollRequests.Add(req);
168 }
169 else
170 m_requests.Enqueue(req);
110 } 171 }
111 } 172 }
112 173
113 private void ProcessQueuedRequests() 174 private void CheckLongPollThreads()
114 { 175 {
115 lock (m_requests) 176 // The only purpose of this thread is to check the EQs for events.
177 // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests.
178 // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests.
179 // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature,
180 // so if they aren't ready to be served by a worker thread (no events), they are placed
181 // directly back in the "ready-to-serve" queue by the worker thread.
182 while (IsRunning)
116 { 183 {
117 if (m_requests.Count == 0) 184 Thread.Sleep(500);
118 return; 185 Watchdog.UpdateThread();
119
120// m_log.DebugFormat("[POLL SERVICE REQUEST MANAGER]: Processing {0} requests", m_requests.Count);
121
122 int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1;
123 186
124 // For Each WorkerThread 187// List<PollServiceHttpRequest> not_ready = new List<PollServiceHttpRequest>();
125 for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++) 188 lock (m_longPollRequests)
126 { 189 {
127 //Loop over number of requests each thread handles. 190 if (m_longPollRequests.Count > 0 && IsRunning)
128 for (int i = 0; i < reqperthread && m_requests.Count > 0; i++)
129 { 191 {
130 try 192 List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req =>
131 { 193 (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ
132 m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue()); 194 (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout
133 } 195 );
134 catch (InvalidOperationException) 196
135 { 197 ready.ForEach(req =>
136 // The queue is empty, we did our calculations wrong! 198 {
137 return; 199 m_requests.Enqueue(req);
138 } 200 m_longPollRequests.Remove(req);
139 201 });
202
140 } 203 }
204
141 } 205 }
142 } 206 }
143
144 } 207 }
145 208
146 public void Stop() 209 public void Stop()
147 { 210 {
148 m_running = false; 211 IsRunning = false;
212// m_timeout = -10000; // cause all to expire
213 Thread.Sleep(1000); // let the world move
214
215 foreach (Thread t in m_workerThreads)
216 Watchdog.AbortThread(t.ManagedThreadId);
217
218 PollServiceHttpRequest wreq;
149 219
150 foreach (object o in m_requests) 220 lock (m_longPollRequests)
151 { 221 {
152 PollServiceHttpRequest req = (PollServiceHttpRequest) o; 222 if (m_longPollRequests.Count > 0 && IsRunning)
153 PollServiceWorkerThread.DoHTTPGruntWork( 223 m_longPollRequests.ForEach(req => m_requests.Enqueue(req));
154 m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
155 } 224 }
156 225
226 while (m_requests.Count() > 0)
227 {
228 try
229 {
230 wreq = m_requests.Dequeue(0);
231 ResponsesProcessed++;
232 wreq.DoHTTPGruntWork(
233 m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id));
234 }
235 catch
236 {
237 }
238 }
239
240 m_longPollRequests.Clear();
157 m_requests.Clear(); 241 m_requests.Clear();
242 }
158 243
159 foreach (Thread t in m_workerThreads) 244 // work threads
245
246 private void PoolWorkerJob()
247 {
248 while (IsRunning)
160 { 249 {
161 t.Abort(); 250 Watchdog.UpdateThread();
251 WaitPerformResponse();
252 }
253 }
254
255 public void WaitPerformResponse()
256 {
257 PollServiceHttpRequest req = m_requests.Dequeue(5000);
258// m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString()));
259
260 if (req != null)
261 {
262 try
263 {
264 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
265 {
266 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
267
268 if (responsedata == null)
269 return;
270
271 // This is the event queue.
272 // Even if we're not running we can still perform responses by explicit request.
273 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll
274 || !PerformResponsesAsync)
275 {
276 try
277 {
278 ResponsesProcessed++;
279 req.DoHTTPGruntWork(m_server, responsedata);
280 }
281 catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
282 {
283 // Ignore it, no need to reply
284 m_log.Error(e);
285 }
286 }
287 else
288 {
289 m_threadPool.QueueWorkItem(x =>
290 {
291 try
292 {
293 ResponsesProcessed++;
294 req.DoHTTPGruntWork(m_server, responsedata);
295 }
296 catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream
297 {
298 // Ignore it, no need to reply
299 m_log.Error(e);
300 }
301 catch (Exception e)
302 {
303 m_log.Error(e);
304 }
305
306 return null;
307 }, null);
308 }
309 }
310 else
311 {
312 if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
313 {
314 ResponsesProcessed++;
315 req.DoHTTPGruntWork(
316 m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
317 }
318 else
319 {
320 ReQueueEvent(req);
321 }
322 }
323 }
324 catch (Exception e)
325 {
326 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
327 }
162 } 328 }
163 } 329 }
164 } 330 }
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Text;
33using HttpServer;
34using OpenMetaverse;
35using System.Reflection;
36using log4net;
37using OpenSim.Framework.Monitoring;
38
39namespace OpenSim.Framework.Servers.HttpServer
40{
41 public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req);
42
43 public class PollServiceWorkerThread
44 {
45 private static readonly ILog m_log =
46 LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType);
48
49 public event ReQueuePollServiceItem ReQueue;
50
51 private readonly BaseHttpServer m_server;
52 private BlockingQueue<PollServiceHttpRequest> m_request;
53 private bool m_running = true;
54 private int m_timeout = 250;
55
56 public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout)
57 {
58 m_request = new BlockingQueue<PollServiceHttpRequest>();
59 m_server = pSrv;
60 m_timeout = pTimeout;
61 }
62
63 public void ThreadStart()
64 {
65 Run();
66 }
67
68 public void Run()
69 {
70 while (m_running)
71 {
72 PollServiceHttpRequest req = m_request.Dequeue();
73
74 Watchdog.UpdateThread();
75
76 try
77 {
78 if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
79 {
80 StreamReader str;
81 try
82 {
83 str = new StreamReader(req.Request.Body);
84 }
85 catch (System.ArgumentException)
86 {
87 // Stream was not readable means a child agent
88 // was closed due to logout, leaving the
89 // Event Queue request orphaned.
90 continue;
91 }
92
93 Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd());
94 DoHTTPGruntWork(m_server, req, responsedata);
95 }
96 else
97 {
98 if ((Environment.TickCount - req.RequestTime) > m_timeout)
99 {
100 DoHTTPGruntWork(
101 m_server,
102 req,
103 req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
104 }
105 else
106 {
107 ReQueuePollServiceItem reQueueItem = ReQueue;
108 if (reQueueItem != null)
109 reQueueItem(req);
110 }
111 }
112 }
113 catch (Exception e)
114 {
115 m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
116 }
117 }
118 }
119
120 internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest)
121 {
122 m_request.Enqueue(pPollServiceHttpRequest);
123 }
124
125 /// <summary>
126 /// FIXME: This should be part of BaseHttpServer
127 /// </summary>
128 internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata)
129 {
130 OSHttpResponse response
131 = new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext);
132
133 byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
134
135 response.SendChunked = false;
136 response.ContentLength64 = buffer.Length;
137 response.ContentEncoding = Encoding.UTF8;
138
139 try
140 {
141 response.OutputStream.Write(buffer, 0, buffer.Length);
142 }
143 catch (Exception ex)
144 {
145 m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex));
146 }
147 finally
148 {
149 //response.OutputStream.Close();
150 try
151 {
152 response.OutputStream.Flush();
153 response.Send();
154
155 //if (!response.KeepAlive && response.ReuseContext)
156 // response.FreeContext();
157 }
158 catch (Exception e)
159 {
160 m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e));
161 }
162 }
163 }
164 }
165} \ 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;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.8.3.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33
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
33{ 33{
34 public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); 34 public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request);
35 35
36 public class RestDeserialiseHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler 36 public class RestDeserialiseHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
37 where TRequest : new() 37 where TRequest : new()
38 { 38 {
39 private RestDeserialiseMethod<TRequest, TResponse> m_method; 39 private RestDeserialiseMethod<TRequest, TResponse> m_method;
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
48 m_method = method; 48 m_method = method;
49 } 49 }
50 50
51 public void Handle(string path, Stream request, Stream responseStream, 51 protected override void ProcessRequest(string path, Stream request, Stream responseStream,
52 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 52 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
53 { 53 {
54 TRequest deserial; 54 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
52 request.Method = verb; 52 request.Method = verb;
53 request.ContentType = "text/xml"; 53 request.ContentType = "text/xml";
54 54
55 MemoryStream buffer = new MemoryStream(); 55 using (MemoryStream buffer = new MemoryStream())
56 {
57 XmlWriterSettings settings = new XmlWriterSettings();
58 settings.Encoding = Encoding.UTF8;
56 59
57 XmlWriterSettings settings = new XmlWriterSettings(); 60 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
58 settings.Encoding = Encoding.UTF8; 61 {
62 XmlSerializer serializer = new XmlSerializer(type);
63 serializer.Serialize(writer, obj);
64 writer.Flush();
65 }
59 66
60 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 67 int length = (int)buffer.Length;
61 { 68 request.ContentLength = length;
62 XmlSerializer serializer = new XmlSerializer(type);
63 serializer.Serialize(writer, obj);
64 writer.Flush();
65 }
66 69
67 int length = (int) buffer.Length; 70 using (Stream requestStream = request.GetRequestStream())
68 request.ContentLength = length; 71 requestStream.Write(buffer.ToArray(), 0, length);
72 }
69 73
70 Stream requestStream = request.GetRequestStream();
71 requestStream.Write(buffer.ToArray(), 0, length);
72 // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); 74 // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request);
73 request.BeginGetResponse(AsyncCallback, request); 75 request.BeginGetResponse(AsyncCallback, request);
74 } 76 }
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
60 request.ContentType = "text/xml"; 60 request.ContentType = "text/xml";
61 request.Timeout = 10000; 61 request.Timeout = 10000;
62 62
63 MemoryStream buffer = new MemoryStream(); 63 using (MemoryStream buffer = new MemoryStream())
64 {
65 XmlWriterSettings settings = new XmlWriterSettings();
66 settings.Encoding = Encoding.UTF8;
67
68 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
69 {
70 XmlSerializer serializer = new XmlSerializer(type);
71 serializer.Serialize(writer, obj);
72 writer.Flush();
73 }
64 74
65 XmlWriterSettings settings = new XmlWriterSettings(); 75 int length = (int)buffer.Length;
66 settings.Encoding = Encoding.UTF8; 76 request.ContentLength = length;
67 77
68 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 78 using (Stream requestStream = request.GetRequestStream())
69 { 79 requestStream.Write(buffer.ToArray(), 0, length);
70 XmlSerializer serializer = new XmlSerializer(type);
71 serializer.Serialize(writer, obj);
72 writer.Flush();
73 } 80 }
74 81
75 int length = (int) buffer.Length;
76 request.ContentLength = length;
77
78 Stream requestStream = request.GetRequestStream();
79 requestStream.Write(buffer.ToArray(), 0, length);
80 requestStream.Close();
81 // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); 82 // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request);
82 request.BeginGetResponse(AsyncCallback, request); 83 request.BeginGetResponse(AsyncCallback, request);
83 } 84 }
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
77 request.ContentType = "text/xml"; 77 request.ContentType = "text/xml";
78 request.Timeout = 20000; 78 request.Timeout = 20000;
79 79
80 MemoryStream buffer = new MemoryStream(); 80 using (MemoryStream buffer = new MemoryStream())
81
82 XmlWriterSettings settings = new XmlWriterSettings();
83 settings.Encoding = Encoding.UTF8;
84
85 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
86 { 81 {
87 XmlSerializer serializer = new XmlSerializer(type); 82 XmlWriterSettings settings = new XmlWriterSettings();
88 serializer.Serialize(writer, sobj); 83 settings.Encoding = Encoding.UTF8;
89 writer.Flush();
90 }
91 84
92 int length = (int)buffer.Length; 85 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
93 request.ContentLength = length; 86 {
87 XmlSerializer serializer = new XmlSerializer(type);
88 serializer.Serialize(writer, sobj);
89 writer.Flush();
90 }
94 91
95 Stream requestStream = request.GetRequestStream(); 92 int length = (int)buffer.Length;
96 requestStream.Write(buffer.ToArray(), 0, length); 93 request.ContentLength = length;
97 buffer.Close(); 94
98 requestStream.Close(); 95 using (Stream requestStream = request.GetRequestStream())
96 requestStream.Write(buffer.ToArray(), 0, length);
97 }
99 98
100 TResponse deserial = default(TResponse); 99 TResponse deserial = default(TResponse);
101 using (WebResponse resp = request.GetResponse()) 100 using (WebResponse resp = request.GetResponse())
102 { 101 {
103 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); 102 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
104 Stream respStream = null; 103
105 try 104 using (Stream respStream = resp.GetResponseStream())
106 {
107 respStream = resp.GetResponseStream();
108 deserial = (TResponse)deserializer.Deserialize(respStream); 105 deserial = (TResponse)deserializer.Deserialize(respStream);
109 }
110 catch { }
111 finally
112 {
113 if (respStream != null)
114 respStream.Close();
115 resp.Close();
116 }
117 } 106 }
107
118 return deserial; 108 return deserial;
119 } 109 }
120 } 110 }
@@ -142,25 +132,25 @@ namespace OpenSim.Framework.Servers.HttpServer
142 request.ContentType = "text/xml"; 132 request.ContentType = "text/xml";
143 request.Timeout = 10000; 133 request.Timeout = 10000;
144 134
145 MemoryStream buffer = new MemoryStream(); 135 using (MemoryStream buffer = new MemoryStream())
136 {
137 XmlWriterSettings settings = new XmlWriterSettings();
138 settings.Encoding = Encoding.UTF8;
146 139
147 XmlWriterSettings settings = new XmlWriterSettings(); 140 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
148 settings.Encoding = Encoding.UTF8; 141 {
142 XmlSerializer serializer = new XmlSerializer(type);
143 serializer.Serialize(writer, sobj);
144 writer.Flush();
145 }
149 146
150 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 147 int length = (int)buffer.Length;
151 { 148 request.ContentLength = length;
152 XmlSerializer serializer = new XmlSerializer(type);
153 serializer.Serialize(writer, sobj);
154 writer.Flush();
155 }
156 buffer.Close();
157 149
158 int length = (int)buffer.Length; 150 using (Stream requestStream = request.GetRequestStream())
159 request.ContentLength = length; 151 requestStream.Write(buffer.ToArray(), 0, length);
152 }
160 153
161 Stream requestStream = request.GetRequestStream();
162 requestStream.Write(buffer.ToArray(), 0, length);
163 requestStream.Close();
164 // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); 154 // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request);
165 request.BeginGetResponse(AsyncCallback, request); 155 request.BeginGetResponse(AsyncCallback, request);
166 } 156 }
@@ -192,7 +182,7 @@ namespace OpenSim.Framework.Servers.HttpServer
192 182
193 public delegate bool CheckIdentityMethod(string sid, string aid); 183 public delegate bool CheckIdentityMethod(string sid, string aid);
194 184
195 public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler 185 public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
196 where TRequest : new() 186 where TRequest : new()
197 { 187 {
198 private static readonly ILog m_log 188 private static readonly ILog m_log
@@ -210,7 +200,7 @@ namespace OpenSim.Framework.Servers.HttpServer
210 m_method = method; 200 m_method = method;
211 } 201 }
212 202
213 public void Handle(string path, Stream request, Stream responseStream, 203 protected override void ProcessRequest(string path, Stream request, Stream responseStream,
214 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 204 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
215 { 205 {
216 RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); 206 RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>);
@@ -246,7 +236,7 @@ namespace OpenSim.Framework.Servers.HttpServer
246 236
247 public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); 237 public delegate bool CheckTrustedSourceMethod(IPEndPoint peer);
248 238
249 public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler 239 public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
250 where TRequest : new() 240 where TRequest : new()
251 { 241 {
252 private static readonly ILog m_log 242 private static readonly ILog m_log
@@ -269,7 +259,7 @@ namespace OpenSim.Framework.Servers.HttpServer
269 m_method = method; 259 m_method = method;
270 } 260 }
271 261
272 public void Handle(string path, Stream request, Stream responseStream, 262 protected override void ProcessRequest(string path, Stream request, Stream responseStream,
273 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 263 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
274 { 264 {
275 TRequest deserial = default(TRequest); 265 TRequest deserial = default(TRequest);
@@ -301,6 +291,5 @@ namespace OpenSim.Framework.Servers.HttpServer
301 serializer.Serialize(xmlWriter, response); 291 serializer.Serialize(xmlWriter, response);
302 } 292 }
303 } 293 }
304 } 294 }
305 295} \ No newline at end of file
306}
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
48 m_restMethod = restMethod; 48 m_restMethod = restMethod;
49 } 49 }
50 50
51 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 51 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
52 { 52 {
53 Encoding encoding = Encoding.UTF8; 53 Encoding encoding = Encoding.UTF8;
54 StreamReader streamReader = new StreamReader(request, encoding); 54 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Security.Cryptography;
33using System.Text;
34using System.Threading;
35using HttpServer;
36
37namespace OpenSim.Framework.Servers.HttpServer
38{
39 // Sealed class. If you're going to unseal it, implement IDisposable.
40 /// <summary>
41 /// This class implements websockets. It grabs the network context from C#Webserver and utilizes it directly as a tcp streaming service
42 /// </summary>
43 public sealed class WebSocketHttpServerHandler : BaseRequestHandler
44 {
45
46 private class WebSocketState
47 {
48 public List<byte> ReceivedBytes;
49 public int ExpectedBytes;
50 public WebsocketFrameHeader Header;
51 public bool FrameComplete;
52 public WebSocketFrame ContinuationFrame;
53 }
54
55 /// <summary>
56 /// Binary Data will trigger this event
57 /// </summary>
58 public event DataDelegate OnData;
59
60 /// <summary>
61 /// Textual Data will trigger this event
62 /// </summary>
63 public event TextDelegate OnText;
64
65 /// <summary>
66 /// A ping request form the other side will trigger this event.
67 /// This class responds to the ping automatically. You shouldn't send a pong.
68 /// it's informational.
69 /// </summary>
70 public event PingDelegate OnPing;
71
72 /// <summary>
73 /// This is a response to a ping you sent.
74 /// </summary>
75 public event PongDelegate OnPong;
76
77 /// <summary>
78 /// This is a regular HTTP Request... This may be removed in the future.
79 /// </summary>
80// public event RegularHttpRequestDelegate OnRegularHttpRequest;
81
82 /// <summary>
83 /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired
84 /// </summary>
85 public event UpgradeCompletedDelegate OnUpgradeCompleted;
86
87 /// <summary>
88 /// If the upgrade failed, this will be fired
89 /// </summary>
90 public event UpgradeFailedDelegate OnUpgradeFailed;
91
92 /// <summary>
93 /// When the websocket is closed, this will be fired.
94 /// </summary>
95 public event CloseDelegate OnClose;
96
97 /// <summary>
98 /// Set this delegate to allow your module to validate the origin of the
99 /// Websocket request. Primary line of defense against cross site scripting
100 /// </summary>
101 public ValidateHandshake HandshakeValidateMethodOverride = null;
102
103 private ManualResetEvent _receiveDone = new ManualResetEvent(false);
104
105 private OSHttpRequest _request;
106 private HTTPNetworkContext _networkContext;
107 private IHttpClientContext _clientContext;
108
109 private int _pingtime = 0;
110 private byte[] _buffer;
111 private int _bufferPosition;
112 private int _bufferLength;
113 private bool _closing;
114 private bool _upgraded;
115 private int _maxPayloadBytes = 41943040;
116 private int _initialMsgTimeout = 0;
117 private int _defaultReadTimeout = 10000;
118
119 private const string HandshakeAcceptText =
120 "HTTP/1.1 101 Switching Protocols\r\n" +
121 "upgrade: websocket\r\n" +
122 "Connection: Upgrade\r\n" +
123 "sec-websocket-accept: {0}\r\n\r\n";// +
124 //"{1}";
125
126 private const string HandshakeDeclineText =
127 "HTTP/1.1 {0} {1}\r\n" +
128 "Connection: close\r\n\r\n";
129
130 /// <summary>
131 /// Mysterious constant defined in RFC6455 to append to the client provided security key
132 /// </summary>
133 private const string WebsocketHandshakeAcceptHashConstant = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
134
135 public WebSocketHttpServerHandler(OSHttpRequest preq, IHttpClientContext pContext, int bufferlen)
136 : base(preq.HttpMethod, preq.Url.OriginalString)
137 {
138 _request = preq;
139 _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing();
140 _networkContext.Stream.ReadTimeout = _defaultReadTimeout;
141 _clientContext = pContext;
142 _bufferLength = bufferlen;
143 _buffer = new byte[_bufferLength];
144 }
145
146 // Sealed class implments destructor and an internal dispose method. complies with C# unmanaged resource best practices.
147 ~WebSocketHttpServerHandler()
148 {
149 Dispose();
150
151 }
152
153 /// <summary>
154 /// Sets the length of the stream buffer
155 /// </summary>
156 /// <param name="pChunk">Byte length.</param>
157 public void SetChunksize(int pChunk)
158 {
159 if (!_upgraded)
160 {
161 _buffer = new byte[pChunk];
162 }
163 else
164 {
165 throw new InvalidOperationException("You must set the chunksize before the connection is upgraded");
166 }
167 }
168
169 /// <summary>
170 /// This is the famous nagle.
171 /// </summary>
172 public bool NoDelay_TCP_Nagle
173 {
174 get
175 {
176 if (_networkContext != null && _networkContext.Socket != null)
177 {
178 return _networkContext.Socket.NoDelay;
179 }
180 else
181 {
182 throw new InvalidOperationException("The socket has been shutdown");
183 }
184 }
185 set
186 {
187 if (_networkContext != null && _networkContext.Socket != null)
188 _networkContext.Socket.NoDelay = value;
189 else
190 {
191 throw new InvalidOperationException("The socket has been shutdown");
192 }
193 }
194 }
195
196 /// <summary>
197 /// This triggers the websocket to start the upgrade process...
198 /// This is a Generalized Networking 'common sense' helper method. Some people expect to call Start() instead
199 /// of the more context appropriate HandshakeAndUpgrade()
200 /// </summary>
201 public void Start()
202 {
203 HandshakeAndUpgrade();
204 }
205
206 /// <summary>
207 /// Max Payload Size in bytes. Defaults to 40MB, but could be set upon connection before calling handshake and upgrade.
208 /// </summary>
209 public int MaxPayloadSize
210 {
211 get { return _maxPayloadBytes; }
212 set { _maxPayloadBytes = value; }
213 }
214
215 /// <summary>
216 /// 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
217 /// 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.
218 /// </summary>
219 public int InitialMsgTimeout
220 {
221 get { return _initialMsgTimeout; }
222 set { _initialMsgTimeout = value; }
223 }
224
225 /// <summary>
226 /// This triggers the websocket start the upgrade process
227 /// </summary>
228 public void HandshakeAndUpgrade()
229 {
230 string webOrigin = string.Empty;
231 string websocketKey = string.Empty;
232 string acceptKey = string.Empty;
233 string accepthost = string.Empty;
234 if (!string.IsNullOrEmpty(_request.Headers["origin"]))
235 webOrigin = _request.Headers["origin"];
236
237 if (!string.IsNullOrEmpty(_request.Headers["sec-websocket-key"]))
238 websocketKey = _request.Headers["sec-websocket-key"];
239
240 if (!string.IsNullOrEmpty(_request.Headers["host"]))
241 accepthost = _request.Headers["host"];
242
243 if (string.IsNullOrEmpty(_request.Headers["upgrade"]))
244 {
245 FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no upgrade request submitted");
246 }
247
248 string connectionheader = _request.Headers["upgrade"];
249 if (connectionheader.ToLower() != "websocket")
250 {
251 FailUpgrade(OSHttpStatusCode.ClientErrorBadRequest, "no connection upgrade request submitted");
252 }
253
254 // If the object consumer provided a method to validate the origin, we should call it and give the client a success or fail.
255 // If not.. we should accept any. The assumption here is that there would be no Websocket handlers registered in baseHTTPServer unless
256 // Something asked for it...
257 if (HandshakeValidateMethodOverride != null)
258 {
259 if (HandshakeValidateMethodOverride(webOrigin, websocketKey, accepthost))
260 {
261 acceptKey = GenerateAcceptKey(websocketKey);
262 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
263 SendUpgradeSuccess(rawaccept);
264
265
266 }
267 else
268 {
269 FailUpgrade(OSHttpStatusCode.ClientErrorForbidden, "Origin Validation Failed");
270 }
271 }
272 else
273 {
274 acceptKey = GenerateAcceptKey(websocketKey);
275 string rawaccept = string.Format(HandshakeAcceptText, acceptKey);
276 SendUpgradeSuccess(rawaccept);
277 }
278 }
279 public IPEndPoint GetRemoteIPEndpoint()
280 {
281 return _request.RemoteIPEndPoint;
282 }
283
284 /// <summary>
285 /// Generates a handshake response key string based on the client's
286 /// provided key to prove to the client that we're allowing the Websocket
287 /// upgrade of our own free will and we were not coerced into doing it.
288 /// </summary>
289 /// <param name="key">Client provided security key</param>
290 /// <returns></returns>
291 private static string GenerateAcceptKey(string key)
292 {
293 if (string.IsNullOrEmpty(key))
294 return string.Empty;
295
296 string acceptkey = key + WebsocketHandshakeAcceptHashConstant;
297
298 SHA1 hashobj = SHA1.Create();
299 string ret = Convert.ToBase64String(hashobj.ComputeHash(Encoding.UTF8.GetBytes(acceptkey)));
300 hashobj.Clear();
301
302 return ret;
303 }
304
305 /// <summary>
306 /// Informs the otherside that we accepted their upgrade request
307 /// </summary>
308 /// <param name="pHandshakeResponse">The HTTP 1.1 101 response that says Yay \o/ </param>
309 private void SendUpgradeSuccess(string pHandshakeResponse)
310 {
311 // Create a new websocket state so we can keep track of data in between network reads.
312 WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true};
313
314 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse);
315
316
317
318
319 try
320 {
321 if (_initialMsgTimeout > 0)
322 {
323 _receiveDone.Reset();
324 }
325 // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream.
326 _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState);
327
328 // Write the upgrade handshake success message
329 _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
330 _networkContext.Stream.Flush();
331 _upgraded = true;
332 UpgradeCompletedDelegate d = OnUpgradeCompleted;
333 if (d != null)
334 d(this, new UpgradeCompletedEventArgs());
335 if (_initialMsgTimeout > 0)
336 {
337 if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout)))
338 Close(string.Empty);
339 }
340 }
341 catch (IOException)
342 {
343 Close(string.Empty);
344 }
345 catch (ObjectDisposedException)
346 {
347 Close(string.Empty);
348 }
349 }
350
351 /// <summary>
352 /// The server has decided not to allow the upgrade to a websocket for some reason. The Http 1.1 response that says Nay >:(
353 /// </summary>
354 /// <param name="pCode">HTTP Status reflecting the reason why</param>
355 /// <param name="pMessage">Textual reason for the upgrade fail</param>
356 private void FailUpgrade(OSHttpStatusCode pCode, string pMessage )
357 {
358 string handshakeResponse = string.Format(HandshakeDeclineText, (int)pCode, pMessage.Replace("\n", string.Empty).Replace("\r", string.Empty));
359 byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(handshakeResponse);
360 _networkContext.Stream.Write(bhandshakeResponse, 0, bhandshakeResponse.Length);
361 _networkContext.Stream.Flush();
362 _networkContext.Stream.Dispose();
363
364 UpgradeFailedDelegate d = OnUpgradeFailed;
365 if (d != null)
366 d(this,new UpgradeFailedEventArgs());
367 }
368
369
370 /// <summary>
371 /// This is our ugly Async OnReceive event handler.
372 /// This chunks the input stream based on the length of the provided buffer and processes out
373 /// as many frames as it can. It then moves the unprocessed data to the beginning of the buffer.
374 /// </summary>
375 /// <param name="ar">Our Async State from beginread</param>
376 private void OnReceive(IAsyncResult ar)
377 {
378 WebSocketState _socketState = ar.AsyncState as WebSocketState;
379 try
380 {
381 int bytesRead = _networkContext.Stream.EndRead(ar);
382 if (bytesRead == 0)
383 {
384 // Do Disconnect
385 _networkContext.Stream.Dispose();
386 _networkContext = null;
387 return;
388 }
389 _bufferPosition += bytesRead;
390
391 if (_bufferPosition > _bufferLength)
392 {
393 // Message too big for chunksize.. not sure how this happened...
394 //Close(string.Empty);
395 }
396
397 int offset = 0;
398 bool headerread = true;
399 int headerforwardposition = 0;
400 while (headerread && offset < bytesRead)
401 {
402 if (_socketState.FrameComplete)
403 {
404 WebsocketFrameHeader pheader = WebsocketFrameHeader.ZeroHeader;
405
406 headerread = WebSocketReader.TryReadHeader(_buffer, offset, _bufferPosition - offset, out pheader,
407 out headerforwardposition);
408 offset += headerforwardposition;
409
410 if (headerread)
411 {
412 _socketState.FrameComplete = false;
413 if (pheader.PayloadLen > (ulong) _maxPayloadBytes)
414 {
415 Close("Invalid Payload size");
416
417 return;
418 }
419 if (pheader.PayloadLen > 0)
420 {
421 if ((int) pheader.PayloadLen > _bufferPosition - offset)
422 {
423 byte[] writebytes = new byte[_bufferPosition - offset];
424
425 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition - offset);
426 _socketState.ExpectedBytes = (int) pheader.PayloadLen;
427 _socketState.ReceivedBytes.AddRange(writebytes);
428 _socketState.Header = pheader; // We need to add the header so that we can unmask it
429 offset += (int) _bufferPosition - offset;
430 }
431 else
432 {
433 byte[] writebytes = new byte[pheader.PayloadLen];
434 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) pheader.PayloadLen);
435 WebSocketReader.Mask(pheader.Mask, writebytes);
436 pheader.IsMasked = false;
437 _socketState.FrameComplete = true;
438 _socketState.ReceivedBytes.AddRange(writebytes);
439 _socketState.Header = pheader;
440 offset += (int) pheader.PayloadLen;
441 }
442 }
443 else
444 {
445 pheader.Mask = 0;
446 _socketState.FrameComplete = true;
447 _socketState.Header = pheader;
448 }
449
450 if (_socketState.FrameComplete)
451 {
452 ProcessFrame(_socketState);
453 _socketState.Header.SetDefault();
454 _socketState.ReceivedBytes.Clear();
455 _socketState.ExpectedBytes = 0;
456
457 }
458 }
459 }
460 else
461 {
462 WebsocketFrameHeader frameHeader = _socketState.Header;
463 int bytesleft = _socketState.ExpectedBytes - _socketState.ReceivedBytes.Count;
464
465 if (bytesleft > _bufferPosition)
466 {
467 byte[] writebytes = new byte[_bufferPosition];
468
469 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
470 _socketState.ReceivedBytes.AddRange(writebytes);
471 _socketState.Header = frameHeader; // We need to add the header so that we can unmask it
472 offset += (int) _bufferPosition;
473 }
474 else
475 {
476 byte[] writebytes = new byte[_bufferPosition];
477 Buffer.BlockCopy(_buffer, offset, writebytes, 0, (int) _bufferPosition);
478 _socketState.FrameComplete = true;
479 _socketState.ReceivedBytes.AddRange(writebytes);
480 _socketState.Header = frameHeader;
481 offset += (int) _bufferPosition;
482 }
483 if (_socketState.FrameComplete)
484 {
485 ProcessFrame(_socketState);
486 _socketState.Header.SetDefault();
487 _socketState.ReceivedBytes.Clear();
488 _socketState.ExpectedBytes = 0;
489 // do some processing
490 }
491 }
492 }
493 if (offset > 0)
494 {
495 // If the buffer is maxed out.. we can just move the cursor. Nothing to move to the beginning.
496 if (offset <_buffer.Length)
497 Buffer.BlockCopy(_buffer, offset, _buffer, 0, _bufferPosition - offset);
498 _bufferPosition -= offset;
499 }
500 if (_networkContext.Stream != null && _networkContext.Stream.CanRead && !_closing)
501 {
502 _networkContext.Stream.BeginRead(_buffer, _bufferPosition, _bufferLength - _bufferPosition, OnReceive,
503 _socketState);
504 }
505 else
506 {
507 // We can't read the stream anymore...
508 }
509 }
510 catch (IOException)
511 {
512 Close(string.Empty);
513 }
514 catch (ObjectDisposedException)
515 {
516 Close(string.Empty);
517 }
518 }
519
520 /// <summary>
521 /// Sends a string to the other side
522 /// </summary>
523 /// <param name="message">the string message that is to be sent</param>
524 public void SendMessage(string message)
525 {
526 if (_initialMsgTimeout > 0)
527 {
528 _receiveDone.Set();
529 _initialMsgTimeout = 0;
530 }
531 byte[] messagedata = Encoding.UTF8.GetBytes(message);
532 WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata };
533 textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text;
534 textMessageFrame.Header.IsEnd = true;
535 SendSocket(textMessageFrame.ToBytes());
536
537 }
538
539 public void SendData(byte[] data)
540 {
541 if (_initialMsgTimeout > 0)
542 {
543 _receiveDone.Set();
544 _initialMsgTimeout = 0;
545 }
546 WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data};
547 dataMessageFrame.Header.IsEnd = true;
548 dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary;
549 SendSocket(dataMessageFrame.ToBytes());
550
551 }
552
553 /// <summary>
554 /// Writes raw bytes to the websocket. Unframed data will cause disconnection
555 /// </summary>
556 /// <param name="data"></param>
557 private void SendSocket(byte[] data)
558 {
559 if (!_closing)
560 {
561 try
562 {
563
564 _networkContext.Stream.Write(data, 0, data.Length);
565 }
566 catch (IOException)
567 {
568
569 }
570 }
571 }
572
573 /// <summary>
574 /// 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.
575 /// </summary>
576 public void SendPingCheck()
577 {
578 if (_initialMsgTimeout > 0)
579 {
580 _receiveDone.Set();
581 _initialMsgTimeout = 0;
582 }
583 WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] };
584 pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping;
585 pingFrame.Header.IsEnd = true;
586 _pingtime = Util.EnvironmentTickCount();
587 SendSocket(pingFrame.ToBytes());
588 }
589
590 /// <summary>
591 /// Closes the websocket connection. Sends a close message to the other side if it hasn't already done so.
592 /// </summary>
593 /// <param name="message"></param>
594 public void Close(string message)
595 {
596 if (_initialMsgTimeout > 0)
597 {
598 _receiveDone.Set();
599 _initialMsgTimeout = 0;
600 }
601 if (_networkContext == null)
602 return;
603 if (_networkContext.Stream != null)
604 {
605 if (_networkContext.Stream.CanWrite)
606 {
607 byte[] messagedata = Encoding.UTF8.GetBytes(message);
608 WebSocketFrame closeResponseFrame = new WebSocketFrame()
609 {
610 Header = WebsocketFrameHeader.HeaderDefault(),
611 WebSocketPayload = messagedata
612 };
613 closeResponseFrame.Header.Opcode = WebSocketReader.OpCode.Close;
614 closeResponseFrame.Header.PayloadLen = (ulong) messagedata.Length;
615 closeResponseFrame.Header.IsEnd = true;
616 SendSocket(closeResponseFrame.ToBytes());
617 }
618 }
619 CloseDelegate closeD = OnClose;
620 if (closeD != null)
621 {
622 closeD(this, new CloseEventArgs());
623 }
624
625 _closing = true;
626 }
627
628 /// <summary>
629 /// Processes a websocket frame and triggers consumer events
630 /// </summary>
631 /// <param name="psocketState">We need to modify the websocket state here depending on the frame</param>
632 private void ProcessFrame(WebSocketState psocketState)
633 {
634 if (psocketState.Header.IsMasked)
635 {
636 byte[] unmask = psocketState.ReceivedBytes.ToArray();
637 WebSocketReader.Mask(psocketState.Header.Mask, unmask);
638 psocketState.ReceivedBytes = new List<byte>(unmask);
639 }
640 if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0)
641 {
642 _receiveDone.Set();
643 _initialMsgTimeout = 0;
644 }
645 switch (psocketState.Header.Opcode)
646 {
647 case WebSocketReader.OpCode.Ping:
648 PingDelegate pingD = OnPing;
649 if (pingD != null)
650 {
651 pingD(this, new PingEventArgs());
652 }
653
654 WebSocketFrame pongFrame = new WebSocketFrame(){Header = WebsocketFrameHeader.HeaderDefault(),WebSocketPayload = new byte[0]};
655 pongFrame.Header.Opcode = WebSocketReader.OpCode.Pong;
656 pongFrame.Header.IsEnd = true;
657 SendSocket(pongFrame.ToBytes());
658 break;
659 case WebSocketReader.OpCode.Pong:
660
661 PongDelegate pongD = OnPong;
662 if (pongD != null)
663 {
664 pongD(this, new PongEventArgs(){PingResponseMS = Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),_pingtime)});
665 }
666 break;
667 case WebSocketReader.OpCode.Binary:
668 if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
669 {
670 psocketState.ContinuationFrame = new WebSocketFrame
671 {
672 Header = psocketState.Header,
673 WebSocketPayload =
674 psocketState.ReceivedBytes.ToArray()
675 };
676 }
677 else
678 {
679 // Send Done Event!
680 DataDelegate dataD = OnData;
681 if (dataD != null)
682 {
683 dataD(this,new WebsocketDataEventArgs(){Data = psocketState.ReceivedBytes.ToArray()});
684 }
685 }
686 break;
687 case WebSocketReader.OpCode.Text:
688 if (!psocketState.Header.IsEnd) // Not done, so we need to store this and wait for the end frame.
689 {
690 psocketState.ContinuationFrame = new WebSocketFrame
691 {
692 Header = psocketState.Header,
693 WebSocketPayload =
694 psocketState.ReceivedBytes.ToArray()
695 };
696 }
697 else
698 {
699 TextDelegate textD = OnText;
700 if (textD != null)
701 {
702 textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(psocketState.ReceivedBytes.ToArray()) });
703 }
704
705 // Send Done Event!
706 }
707 break;
708 case WebSocketReader.OpCode.Continue: // Continuation. Multiple frames worth of data for one message. Only valid when not using Control Opcodes
709 //Console.WriteLine("currhead " + psocketState.Header.IsEnd);
710 //Console.WriteLine("Continuation! " + psocketState.ContinuationFrame.Header.IsEnd);
711 byte[] combineddata = new byte[psocketState.ReceivedBytes.Count+psocketState.ContinuationFrame.WebSocketPayload.Length];
712 byte[] newdata = psocketState.ReceivedBytes.ToArray();
713 Buffer.BlockCopy(psocketState.ContinuationFrame.WebSocketPayload, 0, combineddata, 0, psocketState.ContinuationFrame.WebSocketPayload.Length);
714 Buffer.BlockCopy(newdata, 0, combineddata,
715 psocketState.ContinuationFrame.WebSocketPayload.Length, newdata.Length);
716 psocketState.ContinuationFrame.WebSocketPayload = combineddata;
717 psocketState.Header.PayloadLen = (ulong)combineddata.Length;
718 if (psocketState.Header.IsEnd)
719 {
720 if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Text)
721 {
722 // Send Done event
723 TextDelegate textD = OnText;
724 if (textD != null)
725 {
726 textD(this, new WebsocketTextEventArgs() { Data = Encoding.UTF8.GetString(combineddata) });
727 }
728 }
729 else if (psocketState.ContinuationFrame.Header.Opcode == WebSocketReader.OpCode.Binary)
730 {
731 // Send Done event
732 DataDelegate dataD = OnData;
733 if (dataD != null)
734 {
735 dataD(this, new WebsocketDataEventArgs() { Data = combineddata });
736 }
737 }
738 else
739 {
740 // protocol violation
741 }
742 psocketState.ContinuationFrame = null;
743 }
744 break;
745 case WebSocketReader.OpCode.Close:
746 Close(string.Empty);
747
748 break;
749
750 }
751 psocketState.Header.SetDefault();
752 psocketState.ReceivedBytes.Clear();
753 psocketState.ExpectedBytes = 0;
754 }
755 public void Dispose()
756 {
757 if (_initialMsgTimeout > 0)
758 {
759 _receiveDone.Set();
760 _initialMsgTimeout = 0;
761 }
762 if (_networkContext != null && _networkContext.Stream != null)
763 {
764 if (_networkContext.Stream.CanWrite)
765 _networkContext.Stream.Flush();
766 _networkContext.Stream.Close();
767 _networkContext.Stream.Dispose();
768 _networkContext.Stream = null;
769 }
770
771 if (_request != null && _request.InputStream != null)
772 {
773 _request.InputStream.Close();
774 _request.InputStream.Dispose();
775 _request = null;
776 }
777
778 if (_clientContext != null)
779 {
780 _clientContext.Close();
781 _clientContext = null;
782 }
783 }
784 }
785
786 /// <summary>
787 /// Reads a byte stream and returns Websocket frames.
788 /// </summary>
789 public class WebSocketReader
790 {
791 /// <summary>
792 /// Bit to determine if the frame read on the stream is the last frame in a sequence of fragmented frames
793 /// </summary>
794 private const byte EndBit = 0x80;
795
796 /// <summary>
797 /// These are the Frame Opcodes
798 /// </summary>
799 public enum OpCode
800 {
801 // Data Opcodes
802 Continue = 0x0,
803 Text = 0x1,
804 Binary = 0x2,
805
806 // Control flow Opcodes
807 Close = 0x8,
808 Ping = 0x9,
809 Pong = 0xA
810 }
811
812 /// <summary>
813 /// Masks and Unmasks data using the frame mask. Mask is applied per octal
814 /// Note: Frames from clients MUST be masked
815 /// Note: Frames from servers MUST NOT be masked
816 /// </summary>
817 /// <param name="pMask">Int representing 32 bytes of mask data. Mask is applied per octal</param>
818 /// <param name="pBuffer"></param>
819 public static void Mask(int pMask, byte[] pBuffer)
820 {
821 byte[] maskKey = BitConverter.GetBytes(pMask);
822 int currentMaskIndex = 0;
823 for (int i = 0; i < pBuffer.Length; i++)
824 {
825 pBuffer[i] = (byte)(pBuffer[i] ^ maskKey[currentMaskIndex]);
826 if (currentMaskIndex == 3)
827 {
828 currentMaskIndex = 0;
829 }
830 else
831 {
832 currentMaskIndex++;
833
834 }
835
836 }
837 }
838
839 /// <summary>
840 /// Attempts to read a header off the provided buffer. Returns true, exports a WebSocketFrameheader,
841 /// and an int to move the buffer forward when it reads a header. False when it can't read a header
842 /// </summary>
843 /// <param name="pBuffer">Bytes read from the stream</param>
844 /// <param name="pOffset">Starting place in the stream to begin trying to read from</param>
845 /// <param name="length">Lenth in the stream to try and read from. Provided for cases where the
846 /// buffer's length is larger then the data in it</param>
847 /// <param name="oHeader">Outputs the read WebSocket frame header</param>
848 /// <param name="moveBuffer">Informs the calling stream to move the buffer forward</param>
849 /// <returns>True if it got a header, False if it didn't get a header</returns>
850 public static bool TryReadHeader(byte[] pBuffer, int pOffset, int length, out WebsocketFrameHeader oHeader,
851 out int moveBuffer)
852 {
853 oHeader = WebsocketFrameHeader.ZeroHeader;
854 int minumheadersize = 2;
855 if (length > pBuffer.Length - pOffset)
856 throw new ArgumentOutOfRangeException("The Length specified was larger the byte array supplied");
857 if (length < minumheadersize)
858 {
859 moveBuffer = 0;
860 return false;
861 }
862
863 byte nibble1 = (byte)(pBuffer[pOffset] & 0xF0); //FIN/RSV1/RSV2/RSV3
864 byte nibble2 = (byte)(pBuffer[pOffset] & 0x0F); // Opcode block
865
866 oHeader = new WebsocketFrameHeader();
867 oHeader.SetDefault();
868
869 if ((nibble1 & WebSocketReader.EndBit) == WebSocketReader.EndBit)
870 {
871 oHeader.IsEnd = true;
872 }
873 else
874 {
875 oHeader.IsEnd = false;
876 }
877 //Opcode
878 oHeader.Opcode = (WebSocketReader.OpCode)nibble2;
879 //Mask
880 oHeader.IsMasked = Convert.ToBoolean((pBuffer[pOffset + 1] & 0x80) >> 7);
881
882 // Payload length
883 oHeader.PayloadLen = (byte)(pBuffer[pOffset + 1] & 0x7F);
884
885 int index = 2; // LargerPayload length starts at byte 3
886
887 switch (oHeader.PayloadLen)
888 {
889 case 126:
890 minumheadersize += 2;
891 if (length < minumheadersize)
892 {
893 moveBuffer = 0;
894 return false;
895 }
896 Array.Reverse(pBuffer, pOffset + index, 2); // two bytes
897 oHeader.PayloadLen = BitConverter.ToUInt16(pBuffer, pOffset + index);
898 index += 2;
899 break;
900 case 127: // we got more this is a bigger frame
901 // 8 bytes - uint64 - most significant bit 0 network byte order
902 minumheadersize += 8;
903 if (length < minumheadersize)
904 {
905 moveBuffer = 0;
906 return false;
907 }
908 Array.Reverse(pBuffer, pOffset + index, 8);
909 oHeader.PayloadLen = BitConverter.ToUInt64(pBuffer, pOffset + index);
910 index += 8;
911 break;
912
913 }
914 //oHeader.PayloadLeft = oHeader.PayloadLen; // Start the count in case it's chunked over the network. This is different then frame fragmentation
915 if (oHeader.IsMasked)
916 {
917 minumheadersize += 4;
918 if (length < minumheadersize)
919 {
920 moveBuffer = 0;
921 return false;
922 }
923 oHeader.Mask = BitConverter.ToInt32(pBuffer, pOffset + index);
924 index += 4;
925 }
926 moveBuffer = index;
927 return true;
928
929 }
930 }
931
932 /// <summary>
933 /// RFC6455 Websocket Frame
934 /// </summary>
935 public class WebSocketFrame
936 {
937 /*
938 * RFC6455
939nib 0 1 2 3 4 5 6 7
940byt 0 1 2 3
941dec 0 1 2 3
942 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
943 +-+-+-+-+-------+-+-------------+-------------------------------+
944 |F|R|R|R| opcode|M| Payload len | Extended payload length |
945 |I|S|S|S| (4) |A| (7) | (16/64) +
946 |N|V|V|V| |S| | (if payload len==126/127) |
947 | |1|2|3| |K| | +
948 +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
949 | Extended payload length continued, if payload len == 127 |
950 + - - - - - - - - - - - - - - - +-------------------------------+
951 | |Masking-key, if MASK set to 1 |
952 +-------------------------------+-------------------------------+
953 | Masking-key (continued) | Payload Data |
954 +-------------------------------- - - - - - - - - - - - - - - - +
955 : Payload Data continued ... :
956 + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
957 | Payload Data continued ... |
958 +---------------------------------------------------------------+
959
960 * When reading these, the frames are possibly fragmented and interleaved with control frames
961 * the fragmented frames are not interleaved with data frames. Just control frames
962 */
963 public static readonly WebSocketFrame DefaultFrame = new WebSocketFrame(){Header = new WebsocketFrameHeader(),WebSocketPayload = new byte[0]};
964 public WebsocketFrameHeader Header;
965 public byte[] WebSocketPayload;
966
967 public byte[] ToBytes()
968 {
969 Header.PayloadLen = (ulong)WebSocketPayload.Length;
970 return Header.ToBytes(WebSocketPayload);
971 }
972
973 }
974
975 public struct WebsocketFrameHeader
976 {
977 //public byte CurrentMaskIndex;
978 /// <summary>
979 /// The last frame in a sequence of fragmented frames or the one and only frame for this message.
980 /// </summary>
981 public bool IsEnd;
982
983 /// <summary>
984 /// Returns whether the payload data is masked or not. Data from Clients MUST be masked, Data from Servers MUST NOT be masked
985 /// </summary>
986 public bool IsMasked;
987
988 /// <summary>
989 /// A set of cryptologically sound random bytes XoR-ed against the payload octally. Looped
990 /// </summary>
991 public int Mask;
992 /*
993byt 0 1 2 3
994 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
995 +---------------+---------------+---------------+---------------+
996 | Octal 1 | Octal 2 | Octal 3 | Octal 4 |
997 +---------------+---------------+---------------+---------------+
998*/
999
1000
1001 public WebSocketReader.OpCode Opcode;
1002
1003 public UInt64 PayloadLen;
1004 //public UInt64 PayloadLeft;
1005 // Payload is X + Y
1006 //public UInt64 ExtensionDataLength;
1007 //public UInt64 ApplicationDataLength;
1008 public static readonly WebsocketFrameHeader ZeroHeader = WebsocketFrameHeader.HeaderDefault();
1009
1010 public void SetDefault()
1011 {
1012
1013 //CurrentMaskIndex = 0;
1014 IsEnd = true;
1015 IsMasked = true;
1016 Mask = 0;
1017 Opcode = WebSocketReader.OpCode.Close;
1018 // PayloadLeft = 0;
1019 PayloadLen = 0;
1020 // ExtensionDataLength = 0;
1021 // ApplicationDataLength = 0;
1022
1023 }
1024
1025 /// <summary>
1026 /// Returns a byte array representing the Frame header
1027 /// </summary>
1028 /// <param name="payload">This is the frame data payload. The header describes the size of the payload.
1029 /// If payload is null, a Zero sized payload is assumed</param>
1030 /// <returns>Returns a byte array representing the frame header</returns>
1031 public byte[] ToBytes(byte[] payload)
1032 {
1033 List<byte> result = new List<byte>();
1034
1035 // Squeeze in our opcode and our ending bit.
1036 result.Add((byte)((byte)Opcode | (IsEnd?0x80:0x00) ));
1037
1038 // Again with the three different byte interpretations of size..
1039
1040 //bytesize
1041 if (PayloadLen <= 125)
1042 {
1043 result.Add((byte) PayloadLen);
1044 } //Uint16
1045 else if (PayloadLen <= ushort.MaxValue)
1046 {
1047 result.Add(126);
1048 byte[] payloadLengthByte = BitConverter.GetBytes(Convert.ToUInt16(PayloadLen));
1049 Array.Reverse(payloadLengthByte);
1050 result.AddRange(payloadLengthByte);
1051 } //UInt64
1052 else
1053 {
1054 result.Add(127);
1055 byte[] payloadLengthByte = BitConverter.GetBytes(PayloadLen);
1056 Array.Reverse(payloadLengthByte);
1057 result.AddRange(payloadLengthByte);
1058 }
1059
1060 // Only add a payload if it's not null
1061 if (payload != null)
1062 {
1063 result.AddRange(payload);
1064 }
1065 return result.ToArray();
1066 }
1067
1068 /// <summary>
1069 /// A Helper method to define the defaults
1070 /// </summary>
1071 /// <returns></returns>
1072
1073 public static WebsocketFrameHeader HeaderDefault()
1074 {
1075 return new WebsocketFrameHeader
1076 {
1077 //CurrentMaskIndex = 0,
1078 IsEnd = false,
1079 IsMasked = true,
1080 Mask = 0,
1081 Opcode = WebSocketReader.OpCode.Close,
1082 //PayloadLeft = 0,
1083 PayloadLen = 0,
1084 // ExtensionDataLength = 0,
1085 // ApplicationDataLength = 0
1086 };
1087 }
1088 }
1089
1090 public delegate void DataDelegate(object sender, WebsocketDataEventArgs data);
1091
1092 public delegate void TextDelegate(object sender, WebsocketTextEventArgs text);
1093
1094 public delegate void PingDelegate(object sender, PingEventArgs pingdata);
1095
1096 public delegate void PongDelegate(object sender, PongEventArgs pongdata);
1097
1098 public delegate void RegularHttpRequestDelegate(object sender, RegularHttpRequestEvnetArgs request);
1099
1100 public delegate void UpgradeCompletedDelegate(object sender, UpgradeCompletedEventArgs completeddata);
1101
1102 public delegate void UpgradeFailedDelegate(object sender, UpgradeFailedEventArgs faileddata);
1103
1104 public delegate void CloseDelegate(object sender, CloseEventArgs closedata);
1105
1106 public delegate bool ValidateHandshake(string pWebOrigin, string pWebSocketKey, string pHost);
1107
1108
1109 public class WebsocketDataEventArgs : EventArgs
1110 {
1111 public byte[] Data;
1112 }
1113
1114 public class WebsocketTextEventArgs : EventArgs
1115 {
1116 public string Data;
1117 }
1118
1119 public class PingEventArgs : EventArgs
1120 {
1121 /// <summary>
1122 /// The ping event can arbitrarily contain data
1123 /// </summary>
1124 public byte[] Data;
1125 }
1126
1127 public class PongEventArgs : EventArgs
1128 {
1129 /// <summary>
1130 /// The pong event can arbitrarily contain data
1131 /// </summary>
1132 public byte[] Data;
1133
1134 public int PingResponseMS;
1135
1136 }
1137
1138 public class RegularHttpRequestEvnetArgs : EventArgs
1139 {
1140
1141 }
1142
1143 public class UpgradeCompletedEventArgs : EventArgs
1144 {
1145
1146 }
1147
1148 public class UpgradeFailedEventArgs : EventArgs
1149 {
1150
1151 }
1152
1153 public class CloseEventArgs : EventArgs
1154 {
1155
1156 }
1157
1158
1159}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System.Net;
29using Nwc.XmlRpc;
30using OpenSim.Framework;
31
32
33namespace OpenSim.Framework.Servers.HttpServer
34{
35 public class XmlRpcBasicDOSProtector
36 {
37 private readonly XmlRpcMethod _normalMethod;
38 private readonly XmlRpcMethod _throttledMethod;
39
40 private readonly BasicDosProtectorOptions _options;
41 private readonly BasicDOSProtector _dosProtector;
42
43 public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options)
44 {
45 _normalMethod = normalMethod;
46 _throttledMethod = throttledMethod;
47
48 _options = options;
49 _dosProtector = new BasicDOSProtector(_options);
50
51 }
52 public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client)
53 {
54
55 XmlRpcResponse resp = null;
56 string clientstring = GetClientString(request, client);
57 string endpoint = GetEndPoint(request, client);
58 if (_dosProtector.Process(clientstring, endpoint))
59 resp = _normalMethod(request, client);
60 else
61 resp = _throttledMethod(request, client);
62 if (_options.MaxConcurrentSessions > 0)
63 _dosProtector.ProcessEnd(clientstring, endpoint);
64 return resp;
65 }
66
67 private string GetClientString(XmlRpcRequest request, IPEndPoint client)
68 {
69 string clientstring;
70 if (_options.AllowXForwardedFor && request.Params.Count > 3)
71 {
72 object headerstr = request.Params[3];
73 if (headerstr != null && !string.IsNullOrEmpty(headerstr.ToString()))
74 clientstring = request.Params[3].ToString();
75 else
76 clientstring = client.Address.ToString();
77 }
78 else
79 clientstring = client.Address.ToString();
80 return clientstring;
81 }
82
83 private string GetEndPoint(XmlRpcRequest request, IPEndPoint client)
84 {
85 return client.Address.ToString();
86 }
87
88 }
89
90
91}
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
121 + " level >= 2 then long warnings are logged when receiving bad input data.\n" 121 + " level >= 2 then long warnings are logged when receiving bad input data.\n"
122 + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" 122 + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
123 + " level >= 4 then the time taken to fulfill the request is logged.\n" 123 + " level >= 4 then the time taken to fulfill the request is logged.\n"
124 + " level >= 5 then a sample from the beginning of the incoming data is logged.\n" 124 + " level >= 5 then a sample from the beginning of the data is logged.\n"
125 + " level >= 6 then the entire incoming data is logged.\n" 125 + " level >= 6 then the entire data is logged.\n"
126 + " no level is specified then the current level is returned.\n\n" 126 + " no level is specified then the current level is returned.\n\n"
127 + "If out or all and\n" 127 + "If out or all and\n"
128 + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" 128 + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
129 + " level >= 4 then the time taken to fulfill the request is logged.\n", 129 + " level >= 4 then the time taken to fulfill the request is logged.\n"
130 + " level >= 5 then a sample from the beginning of the data is logged.\n"
131 + " level >= 6 then the entire data is logged.\n",
130 HandleDebugHttpCommand); 132 HandleDebugHttpCommand);
131 } 133 }
132 134
@@ -227,9 +229,16 @@ namespace OpenSim.Framework.Servers
227 handlers.AppendFormat("\t{0}\n", s); 229 handlers.AppendFormat("\t{0}\n", s);
228 230
229 handlers.AppendFormat("* HTTP:\n"); 231 handlers.AppendFormat("* HTTP:\n");
230 List<String> poll = httpServer.GetPollServiceHandlerKeys();
231 foreach (String s in httpServer.GetHTTPHandlerKeys()) 232 foreach (String s in httpServer.GetHTTPHandlerKeys())
232 handlers.AppendFormat("\t{0} {1}\n", s, (poll.Contains(s) ? "(poll service)" : string.Empty)); 233 handlers.AppendFormat("\t{0}\n", s);
234
235 handlers.AppendFormat("* HTTP (poll):\n");
236 foreach (String s in httpServer.GetPollServiceHandlerKeys())
237 handlers.AppendFormat("\t{0}\n", s);
238
239 handlers.AppendFormat("* JSONRPC:\n");
240 foreach (String s in httpServer.GetJsonRpcHandlerKeys())
241 handlers.AppendFormat("\t{0}\n", s);
233 242
234// handlers.AppendFormat("* Agent:\n"); 243// handlers.AppendFormat("* Agent:\n");
235// foreach (String s in httpServer.GetAgentHandlerKeys()) 244// foreach (String s in httpServer.GetAgentHandlerKeys())
@@ -276,7 +285,12 @@ namespace OpenSim.Framework.Servers
276 public static bool RemoveHttpServer(uint port) 285 public static bool RemoveHttpServer(uint port)
277 { 286 {
278 lock (m_Servers) 287 lock (m_Servers)
288 {
289 if (instance != null && instance.Port == port)
290 instance = null;
291
279 return m_Servers.Remove(port); 292 return m_Servers.Remove(port);
293 }
280 } 294 }
281 295
282 /// <summary> 296 /// <summary>
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;
29// Build Number 29// Build Number
30// Revision 30// Revision
31// 31//
32[assembly: AssemblyVersion("0.7.5.*")] 32[assembly: AssemblyVersion("0.7.6.*")]
33[assembly: AssemblyFileVersion("1.0.0.0")] 33[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;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Diagnostics; 30using System.Diagnostics;
31using System.IO; 31using System.IO;
32using System.Linq;
32using System.Reflection; 33using System.Reflection;
33using System.Text; 34using System.Text;
34using System.Text.RegularExpressions; 35using System.Text.RegularExpressions;
@@ -62,6 +63,8 @@ namespace OpenSim.Framework.Servers
62 63
63 protected string m_pidFile = String.Empty; 64 protected string m_pidFile = String.Empty;
64 65
66 protected ServerStatsCollector m_serverStatsCollector;
67
65 /// <summary> 68 /// <summary>
66 /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. 69 /// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
67 /// </summary> 70 /// </summary>
@@ -76,6 +79,11 @@ namespace OpenSim.Framework.Servers
76 79
77 protected void CreatePIDFile(string path) 80 protected void CreatePIDFile(string path)
78 { 81 {
82 if (File.Exists(path))
83 m_log.ErrorFormat(
84 "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.",
85 path);
86
79 try 87 try
80 { 88 {
81 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); 89 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
@@ -113,6 +121,26 @@ namespace OpenSim.Framework.Servers
113 } 121 }
114 } 122 }
115 123
124 /// <summary>
125 /// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details,
126 /// etc.).
127 /// </summary>
128 public void LogEnvironmentInformation()
129 {
130 // FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
131 // XmlConfigurator calls first accross servers.
132 m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
133
134 m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version);
135
136 // clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
137 // the clr version number doesn't match the project version number under Mono.
138 //m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
139 m_log.InfoFormat(
140 "[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit",
141 Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
142 }
143
116 public void RegisterCommonAppenders(IConfig startupConfig) 144 public void RegisterCommonAppenders(IConfig startupConfig)
117 { 145 {
118 ILoggerRepository repository = LogManager.GetRepository(); 146 ILoggerRepository repository = LogManager.GetRepository();
@@ -219,7 +247,7 @@ namespace OpenSim.Framework.Servers
219 "Show thread status", HandleShow); 247 "Show thread status", HandleShow);
220 248
221 m_console.Commands.AddCommand( 249 m_console.Commands.AddCommand(
222 "General", false, "threads abort", 250 "Debug", false, "threads abort",
223 "threads abort <thread-id>", 251 "threads abort <thread-id>",
224 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); 252 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
225 253
@@ -229,11 +257,281 @@ namespace OpenSim.Framework.Servers
229 "Show thread status. Synonym for \"show threads\"", 257 "Show thread status. Synonym for \"show threads\"",
230 (string module, string[] args) => Notice(GetThreadsReport())); 258 (string module, string[] args) => Notice(GetThreadsReport()));
231 259
260 m_console.Commands.AddCommand (
261 "Debug", false, "debug comms set",
262 "debug comms set serialosdreq true|false",
263 "Set comms parameters. For debug purposes.",
264 HandleDebugCommsSet);
265
266 m_console.Commands.AddCommand (
267 "Debug", false, "debug comms status",
268 "debug comms status",
269 "Show current debug comms parameters.",
270 HandleDebugCommsStatus);
271
272 m_console.Commands.AddCommand (
273 "Debug", false, "debug threadpool set",
274 "debug threadpool set worker|iocp min|max <n>",
275 "Set threadpool parameters. For debug purposes.",
276 HandleDebugThreadpoolSet);
277
278 m_console.Commands.AddCommand (
279 "Debug", false, "debug threadpool status",
280 "debug threadpool status",
281 "Show current debug threadpool parameters.",
282 HandleDebugThreadpoolStatus);
283
284 m_console.Commands.AddCommand(
285 "Debug", false, "debug threadpool level",
286 "debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL,
287 "Turn on logging of activity in the main thread pool.",
288 "Log levels:\n"
289 + " 0 = no logging\n"
290 + " 1 = only first line of stack trace; don't log common threads\n"
291 + " 2 = full stack trace; don't log common threads\n"
292 + " 3 = full stack trace, including common threads\n",
293 HandleDebugThreadpoolLevel);
294
295// m_console.Commands.AddCommand(
296// "Debug", false, "show threadpool calls active",
297// "show threadpool calls active",
298// "Show details about threadpool calls that are still active (currently waiting or in progress)",
299// HandleShowThreadpoolCallsActive);
300
232 m_console.Commands.AddCommand( 301 m_console.Commands.AddCommand(
233 "General", false, "force gc", 302 "Debug", false, "show threadpool calls complete",
303 "show threadpool calls complete",
304 "Show details about threadpool calls that have been completed.",
305 HandleShowThreadpoolCallsComplete);
306
307 m_console.Commands.AddCommand(
308 "Debug", false, "force gc",
234 "force gc", 309 "force gc",
235 "Manually invoke runtime garbage collection. For debugging purposes", 310 "Manually invoke runtime garbage collection. For debugging purposes",
236 HandleForceGc); 311 HandleForceGc);
312
313 m_console.Commands.AddCommand(
314 "General", false, "quit",
315 "quit",
316 "Quit the application", (mod, args) => Shutdown());
317
318 m_console.Commands.AddCommand(
319 "General", false, "shutdown",
320 "shutdown",
321 "Quit the application", (mod, args) => Shutdown());
322
323 ChecksManager.RegisterConsoleCommands(m_console);
324 StatsManager.RegisterConsoleCommands(m_console);
325 }
326
327 public void RegisterCommonComponents(IConfigSource configSource)
328 {
329 IConfig networkConfig = configSource.Configs["Network"];
330
331 if (networkConfig != null)
332 {
333 WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false);
334 }
335
336 m_serverStatsCollector = new ServerStatsCollector();
337 m_serverStatsCollector.Initialise(configSource);
338 m_serverStatsCollector.Start();
339 }
340
341 private void HandleDebugCommsStatus(string module, string[] args)
342 {
343 Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint);
344 }
345
346 private void HandleDebugCommsSet(string module, string[] args)
347 {
348 if (args.Length != 5)
349 {
350 Notice("Usage: debug comms set serialosdreq true|false");
351 return;
352 }
353
354 if (args[3] != "serialosdreq")
355 {
356 Notice("Usage: debug comms set serialosdreq true|false");
357 return;
358 }
359
360 bool setSerializeOsdRequests;
361
362 if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests))
363 return;
364
365 WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests;
366
367 Notice("serialosdreq is now {0}", setSerializeOsdRequests);
368 }
369
370 private void HandleShowThreadpoolCallsActive(string module, string[] args)
371 {
372 List<KeyValuePair<string, int>> calls = Util.GetFireAndForgetCallsInProgress().ToList();
373 calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value));
374 int namedCalls = 0;
375
376 ConsoleDisplayList cdl = new ConsoleDisplayList();
377 foreach (KeyValuePair<string, int> kvp in calls)
378 {
379 if (kvp.Value > 0)
380 {
381 cdl.AddRow(kvp.Key, kvp.Value);
382 namedCalls += kvp.Value;
383 }
384 }
385
386 cdl.AddRow("TOTAL NAMED", namedCalls);
387
388 long allQueuedCalls = Util.TotalQueuedFireAndForgetCalls;
389 long allRunningCalls = Util.TotalRunningFireAndForgetCalls;
390
391 cdl.AddRow("TOTAL QUEUED", allQueuedCalls);
392 cdl.AddRow("TOTAL RUNNING", allRunningCalls);
393 cdl.AddRow("TOTAL ANONYMOUS", allQueuedCalls + allRunningCalls - namedCalls);
394 cdl.AddRow("TOTAL ALL", allQueuedCalls + allRunningCalls);
395
396 MainConsole.Instance.Output(cdl.ToString());
397 }
398
399 private void HandleShowThreadpoolCallsComplete(string module, string[] args)
400 {
401 List<KeyValuePair<string, int>> calls = Util.GetFireAndForgetCallsMade().ToList();
402 calls.Sort((kvp1, kvp2) => kvp2.Value.CompareTo(kvp1.Value));
403 int namedCallsMade = 0;
404
405 ConsoleDisplayList cdl = new ConsoleDisplayList();
406 foreach (KeyValuePair<string, int> kvp in calls)
407 {
408 cdl.AddRow(kvp.Key, kvp.Value);
409 namedCallsMade += kvp.Value;
410 }
411
412 cdl.AddRow("TOTAL NAMED", namedCallsMade);
413
414 long allCallsMade = Util.TotalFireAndForgetCallsMade;
415 cdl.AddRow("TOTAL ANONYMOUS", allCallsMade - namedCallsMade);
416 cdl.AddRow("TOTAL ALL", allCallsMade);
417
418 MainConsole.Instance.Output(cdl.ToString());
419 }
420
421 private void HandleDebugThreadpoolStatus(string module, string[] args)
422 {
423 int workerThreads, iocpThreads;
424
425 ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
426 Notice("Min worker threads: {0}", workerThreads);
427 Notice("Min IOCP threads: {0}", iocpThreads);
428
429 ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
430 Notice("Max worker threads: {0}", workerThreads);
431 Notice("Max IOCP threads: {0}", iocpThreads);
432
433 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
434 Notice("Available worker threads: {0}", workerThreads);
435 Notice("Available IOCP threads: {0}", iocpThreads);
436 }
437
438 private void HandleDebugThreadpoolSet(string module, string[] args)
439 {
440 if (args.Length != 6)
441 {
442 Notice("Usage: debug threadpool set worker|iocp min|max <n>");
443 return;
444 }
445
446 int newThreads;
447
448 if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads))
449 return;
450
451 string poolType = args[3];
452 string bound = args[4];
453
454 bool fail = false;
455 int workerThreads, iocpThreads;
456
457 if (poolType == "worker")
458 {
459 if (bound == "min")
460 {
461 ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
462
463 if (!ThreadPool.SetMinThreads(newThreads, iocpThreads))
464 fail = true;
465 }
466 else
467 {
468 ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
469
470 if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads))
471 fail = true;
472 }
473 }
474 else
475 {
476 if (bound == "min")
477 {
478 ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
479
480 if (!ThreadPool.SetMinThreads(workerThreads, newThreads))
481 fail = true;
482 }
483 else
484 {
485 ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
486
487 if (!ThreadPool.SetMaxThreads(workerThreads, newThreads))
488 fail = true;
489 }
490 }
491
492 if (fail)
493 {
494 Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads);
495 }
496 else
497 {
498 int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads;
499
500 ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads);
501 ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads);
502
503 Notice("Min worker threads now {0}", minWorkerThreads);
504 Notice("Min IOCP threads now {0}", minIocpThreads);
505 Notice("Max worker threads now {0}", maxWorkerThreads);
506 Notice("Max IOCP threads now {0}", maxIocpThreads);
507 }
508 }
509
510 private static void HandleDebugThreadpoolLevel(string module, string[] cmdparams)
511 {
512 if (cmdparams.Length < 4)
513 {
514 MainConsole.Instance.Output("Usage: debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL);
515 return;
516 }
517
518 string rawLevel = cmdparams[3];
519 int newLevel;
520
521 if (!int.TryParse(rawLevel, out newLevel))
522 {
523 MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawLevel);
524 return;
525 }
526
527 if (newLevel < 0 || newLevel > Util.MAX_THREADPOOL_LEVEL)
528 {
529 MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0.." + Util.MAX_THREADPOOL_LEVEL, newLevel);
530 return;
531 }
532
533 Util.LogThreadPool = newLevel;
534 MainConsole.Instance.OutputFormat("LogThreadPool set to {0}", newLevel);
237 } 535 }
238 536
239 private void HandleForceGc(string module, string[] args) 537 private void HandleForceGc(string module, string[] args)
@@ -575,7 +873,8 @@ namespace OpenSim.Framework.Servers
575 873
576 protected string GetVersionText() 874 protected string GetVersionText()
577 { 875 {
578 return String.Format("Version: {0} (interface version {1})", m_version, VersionInfo.MajorInterfaceVersion); 876 return String.Format("Version: {0} (SIMULATION/{1} - SIMULATION/{2})",
877 m_version, VersionInfo.SimulationServiceVersionSupportedMin, VersionInfo.SimulationServiceVersionSupportedMax);
579 } 878 }
580 879
581 /// <summary> 880 /// <summary>
@@ -621,7 +920,68 @@ namespace OpenSim.Framework.Servers
621 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); 920 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
622 921
623 sb.Append("Main threadpool (excluding script engine pools)\n"); 922 sb.Append("Main threadpool (excluding script engine pools)\n");
624 sb.Append(Util.GetThreadPoolReport()); 923 sb.Append(GetThreadPoolReport());
924
925 return sb.ToString();
926 }
927
928 /// <summary>
929 /// Get a thread pool report.
930 /// </summary>
931 /// <returns></returns>
932 public static string GetThreadPoolReport()
933 {
934 string threadPoolUsed = null;
935 int maxThreads = 0;
936 int minThreads = 0;
937 int allocatedThreads = 0;
938 int inUseThreads = 0;
939 int waitingCallbacks = 0;
940 int completionPortThreads = 0;
941
942 StringBuilder sb = new StringBuilder();
943 if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
944 {
945 STPInfo stpi = Util.GetSmartThreadPoolInfo();
946
947 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
948 if (stpi != null)
949 {
950 threadPoolUsed = "SmartThreadPool";
951 maxThreads = stpi.MaxThreads;
952 minThreads = stpi.MinThreads;
953 inUseThreads = stpi.InUseThreads;
954 allocatedThreads = stpi.ActiveThreads;
955 waitingCallbacks = stpi.WaitingCallbacks;
956 }
957 }
958 else if (
959 Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem
960 || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem)
961 {
962 threadPoolUsed = "BuiltInThreadPool";
963 ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);
964 ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
965 int availableThreads;
966 ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
967 inUseThreads = maxThreads - availableThreads;
968 allocatedThreads = -1;
969 waitingCallbacks = -1;
970 }
971
972 if (threadPoolUsed != null)
973 {
974 sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed);
975 sb.AppendFormat("Max threads : {0}\n", maxThreads);
976 sb.AppendFormat("Min threads : {0}\n", minThreads);
977 sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString());
978 sb.AppendFormat("In use threads : {0}\n", inUseThreads);
979 sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString());
980 }
981 else
982 {
983 sb.AppendFormat("Thread pool not used\n");
984 }
625 985
626 return sb.ToString(); 986 return sb.ToString();
627 } 987 }
@@ -673,5 +1033,16 @@ namespace OpenSim.Framework.Servers
673 if (m_console != null) 1033 if (m_console != null)
674 m_console.OutputFormat(format, components); 1034 m_console.OutputFormat(format, components);
675 } 1035 }
1036
1037 public virtual void Shutdown()
1038 {
1039 m_serverStatsCollector.Close();
1040 ShutdownSpecific();
1041 }
1042
1043 /// <summary>
1044 /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
1045 /// </summary>
1046 protected virtual void ShutdownSpecific() {}
676 } 1047 }
677} \ No newline at end of file 1048}
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
41{ 41{
42 [TestFixture] 42 [TestFixture]
43 public class OSHttpTests : OpenSimTestCase 43 public class OSHttpTests : OpenSimTestCase
44 { 44 {
45 // we need an IHttpClientContext for our tests
46 public class TestHttpClientContext: IHttpClientContext
47 {
48 private bool _secured;
49 public bool IsSecured
50 {
51 get { return _secured; }
52 }
53 public bool Secured
54 {
55 get { return _secured; }
56 }
57
58 public TestHttpClientContext(bool secured)
59 {
60 _secured = secured;
61 }
62
63 public void Disconnect(SocketError error) {}
64 public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body) {}
65 public void Respond(string httpVersion, HttpStatusCode statusCode, string reason) {}
66 public void Respond(string body) {}
67 public void Send(byte[] buffer) {}
68 public void Send(byte[] buffer, int offset, int size) {}
69 public void Respond(string httpVersion, HttpStatusCode statusCode, string reason, string body, string contentType) {}
70 public void Close() { }
71 public bool EndWhenDone { get { return false;} set { return;}}
72
73 public event EventHandler<DisconnectedEventArgs> Disconnected = delegate { };
74 /// <summary>
75 /// A request have been received in the context.
76 /// </summary>
77 public event EventHandler<RequestEventArgs> RequestReceived = delegate { };
78
79 }
80
81 public class TestHttpRequest: IHttpRequest
82 {
83 private string _uriPath;
84 public bool BodyIsComplete
85 {
86 get { return true; }
87 }
88 public string[] AcceptTypes
89 {
90 get {return _acceptTypes; }
91 }
92 private string[] _acceptTypes;
93 public Stream Body
94 {
95 get { return _body; }
96 set { _body = value;}
97 }
98 private Stream _body;
99 public ConnectionType Connection
100 {
101 get { return _connection; }
102 set { _connection = value; }
103 }
104 private ConnectionType _connection;
105 public int ContentLength
106 {
107 get { return _contentLength; }
108 set { _contentLength = value; }
109 }
110 private int _contentLength;
111 public NameValueCollection Headers
112 {
113 get { return _headers; }
114 }
115 private NameValueCollection _headers = new NameValueCollection();
116 public string HttpVersion
117 {
118 get { return _httpVersion; }
119 set { _httpVersion = value; }
120 }
121 private string _httpVersion = null;
122 public string Method
123 {
124 get { return _method; }
125 set { _method = value; }
126 }
127 private string _method = null;
128 public HttpInput QueryString
129 {
130 get { return _queryString; }
131 }
132 private HttpInput _queryString = null;
133 public Uri Uri
134 {
135 get { return _uri; }
136 set { _uri = value; }
137 }
138 private Uri _uri = null;
139 public string[] UriParts
140 {
141 get { return _uri.Segments; }
142 }
143 public HttpParam Param
144 {
145 get { return null; }
146 }
147 public HttpForm Form
148 {
149 get { return null; }
150 }
151 public bool IsAjax
152 {
153 get { return false; }
154 }
155 public RequestCookies Cookies
156 {
157 get { return null; }
158 }
159
160 public TestHttpRequest() {}
161
162 public TestHttpRequest(string contentEncoding, string contentType, string userAgent,
163 string remoteAddr, string remotePort, string[] acceptTypes,
164 ConnectionType connectionType, int contentLength, Uri uri)
165 {
166 _headers["content-encoding"] = contentEncoding;
167 _headers["content-type"] = contentType;
168 _headers["user-agent"] = userAgent;
169 _headers["remote_addr"] = remoteAddr;
170 _headers["remote_port"] = remotePort;
171
172 _acceptTypes = acceptTypes;
173 _connection = connectionType;
174 _contentLength = contentLength;
175 _uri = uri;
176 }
177
178 public void DecodeBody(FormDecoderProvider providers) {}
179 public void SetCookies(RequestCookies cookies) {}
180 public void AddHeader(string name, string value)
181 {
182 _headers.Add(name, value);
183 }
184 public int AddToBody(byte[] bytes, int offset, int length)
185 {
186 return 0;
187 }
188 public void Clear() {}
189
190 public object Clone()
191 {
192 TestHttpRequest clone = new TestHttpRequest();
193 clone._acceptTypes = _acceptTypes;
194 clone._connection = _connection;
195 clone._contentLength = _contentLength;
196 clone._uri = _uri;
197 clone._headers = new NameValueCollection(_headers);
198
199 return clone;
200 }
201 public IHttpResponse CreateResponse(IHttpClientContext context)
202 {
203 return new HttpResponse(context, this);
204 }
205 /// <summary>
206 /// Path and query (will be merged with the host header) and put in Uri
207 /// </summary>
208 /// <see cref="Uri"/>
209 public string UriPath
210 {
211 get { return _uriPath; }
212 set
213 {
214 _uriPath = value;
215
216 }
217 }
218
219 }
220
221 public class TestHttpResponse: IHttpResponse
222 {
223 public Stream Body
224 {
225 get { return _body; }
226
227 set { _body = value; }
228 }
229 private Stream _body;
230
231 public string ProtocolVersion
232 {
233 get { return _protocolVersion; }
234 set { _protocolVersion = value; }
235 }
236 private string _protocolVersion;
237
238 public bool Chunked
239 {
240 get { return _chunked; }
241
242 set { _chunked = value; }
243 }
244 private bool _chunked;
245
246 public ConnectionType Connection
247 {
248 get { return _connection; }
249
250 set { _connection = value; }
251 }
252 private ConnectionType _connection;
253
254 public Encoding Encoding
255 {
256 get { return _encoding; }
257
258 set { _encoding = value; }
259 }
260 private Encoding _encoding;
261
262 public int KeepAlive
263 {
264 get { return _keepAlive; }
265
266 set { _keepAlive = value; }
267 }
268 private int _keepAlive;
269
270 public HttpStatusCode Status
271 {
272 get { return _status; }
273
274 set { _status = value; }
275 }
276 private HttpStatusCode _status;
277
278 public string Reason
279 {
280 get { return _reason; }
281
282 set { _reason = value; }
283 }
284 private string _reason;
285
286 public long ContentLength
287 {
288 get { return _contentLength; }
289
290 set { _contentLength = value; }
291 }
292 private long _contentLength;
293
294 public string ContentType
295 {
296 get { return _contentType; }
297
298 set { _contentType = value; }
299 }
300 private string _contentType;
301
302 public bool HeadersSent
303 {
304 get { return _headersSent; }
305 }
306 private bool _headersSent;
307
308 public bool Sent
309 {
310 get { return _sent; }
311 }
312 private bool _sent;
313
314 public ResponseCookies Cookies
315 {
316 get { return _cookies; }
317 }
318 private ResponseCookies _cookies = null;
319
320 public TestHttpResponse()
321 {
322 _headersSent = false;
323 _sent = false;
324 }
325
326 public void AddHeader(string name, string value) {}
327 public void Send()
328 {
329 if (!_headersSent) SendHeaders();
330 if (_sent) throw new InvalidOperationException("stuff already sent");
331 _sent = true;
332 }
333
334 public void SendBody(byte[] buffer, int offset, int count)
335 {
336 if (!_headersSent) SendHeaders();
337 _sent = true;
338 }
339 public void SendBody(byte[] buffer)
340 {
341 if (!_headersSent) SendHeaders();
342 _sent = true;
343 }
344
345 public void SendHeaders()
346 {
347 if (_headersSent) throw new InvalidOperationException("headers already sent");
348 _headersSent = true;
349 }
350
351 public void Redirect(Uri uri) {}
352 public void Redirect(string url) {}
353 }
354
355
356 public OSHttpRequest req0; 45 public OSHttpRequest req0;
357 public OSHttpRequest req1; 46 public OSHttpRequest req1;
358 47
@@ -424,4 +113,4 @@ namespace OpenSim.Framework.Servers.Tests
424 Assert.That(rsp0.ContentType, Is.EqualTo("text/xml")); 113 Assert.That(rsp0.ContentType, Is.EqualTo("text/xml"));
425 } 114 }
426 } 115 }
427} 116} \ 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
47 { 47 {
48 foreach (VersionInfo.Flavour flavour in Enum.GetValues(typeof(VersionInfo.Flavour))) 48 foreach (VersionInfo.Flavour flavour in Enum.GetValues(typeof(VersionInfo.Flavour)))
49 { 49 {
50 Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.GetVersionString("0.0.0", "0", flavour).Length, "0.0.0/" + flavour + " failed"); 50 Assert.AreEqual(VersionInfo.VERSIONINFO_VERSION_LENGTH, VersionInfo.GetVersionString("0.0.0", flavour).Length, "0.0.0/" + flavour + " failed");
51 } 51 }
52 } 52 }
53 } 53 }
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Net;
32using System.Reflection;
33
34using Nini.Config;
35using log4net;
36
37namespace OpenSim.Framework.ServiceAuth
38{
39 public class BasicHttpAuthentication : IServiceAuth
40 {
41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 public string Name { get { return "BasicHttp"; } }
44
45 private string m_Username, m_Password;
46 private string m_CredentialsB64;
47
48// private string remove_me;
49
50 public string Credentials
51 {
52 get { return m_CredentialsB64; }
53 }
54
55 public BasicHttpAuthentication(IConfigSource config, string section)
56 {
57// remove_me = section;
58 m_Username = Util.GetConfigVarFromSections<string>(config, "HttpAuthUsername", new string[] { "Network", section }, string.Empty);
59 m_Password = Util.GetConfigVarFromSections<string>(config, "HttpAuthPassword", new string[] { "Network", section }, string.Empty);
60 string str = m_Username + ":" + m_Password;
61 byte[] encData_byte = Util.UTF8.GetBytes(str);
62
63 m_CredentialsB64 = Convert.ToBase64String(encData_byte);
64// m_log.DebugFormat("[HTTP BASIC AUTH]: {0} {1} [{2}]", m_Username, m_Password, section);
65 }
66
67 public void AddAuthorization(NameValueCollection headers)
68 {
69 //m_log.DebugFormat("[HTTP BASIC AUTH]: Adding authorization for {0}", remove_me);
70 headers["Authorization"] = "Basic " + m_CredentialsB64;
71 }
72
73 public bool Authenticate(string data)
74 {
75 string recovered = Util.Base64ToString(data);
76 if (!String.IsNullOrEmpty(recovered))
77 {
78 string[] parts = recovered.Split(new char[] { ':' });
79 if (parts.Length >= 2)
80 {
81 return m_Username.Equals(parts[0]) && m_Password.Equals(parts[1]);
82 }
83 }
84
85 return false;
86 }
87
88 public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
89 {
90// m_log.DebugFormat("[HTTP BASIC AUTH]: Authenticate in {0}", "BasicHttpAuthentication");
91
92 string value = requestHeaders.Get("Authorization");
93 if (value != null)
94 {
95 value = value.Trim();
96 if (value.StartsWith("Basic "))
97 {
98 value = value.Replace("Basic ", string.Empty);
99 if (Authenticate(value))
100 {
101 statusCode = HttpStatusCode.OK;
102 return true;
103 }
104 }
105 }
106
107 d("WWW-Authenticate", "Basic realm = \"Asset Server\"");
108
109 statusCode = HttpStatusCode.Unauthorized;
110 return false;
111 }
112 }
113}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
index 1e8c33e..a49952c 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs
+++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs
@@ -25,69 +25,58 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Xml.Serialization; 28using System;
29using System.Collections.Generic;
30using System.Collections.Specialized;
31using System.Linq;
32using System.Net;
29 33
30namespace OpenSim.Framework.Communications.XMPP 34namespace OpenSim.Framework.ServiceAuth
31{ 35{
32 /// <summary> 36 public class CompoundAuthentication : IServiceAuth
33 /// Message types.
34 /// </summary>
35 public enum XmppMessageType
36 { 37 {
37 [XmlEnum("chat")] chat, 38 public string Name { get { return "Compound"; } }
38 [XmlEnum("error")] error,
39 [XmlEnum("groupchat")] groupchat,
40 [XmlEnum("headline")] headline,
41 [XmlEnum("normal")] normal,
42 }
43 39
44 /// <summary> 40 private List<IServiceAuth> m_authentications = new List<IServiceAuth>();
45 /// Message body. 41
46 /// </summary> 42 public int Count { get { return m_authentications.Count; } }
47 public class XmppMessageBody
48 {
49 [XmlText]
50 public string Text;
51 43
52 public XmppMessageBody() 44 public List<IServiceAuth> GetAuthentors()
53 { 45 {
46 return new List<IServiceAuth>(m_authentications);
54 } 47 }
55 48
56 public XmppMessageBody(string message) 49 public void AddAuthenticator(IServiceAuth auth)
57 { 50 {
58 Text = message; 51 m_authentications.Add(auth);
59 } 52 }
60 53
61 new public string ToString() 54 public void RemoveAuthenticator(IServiceAuth auth)
62 { 55 {
63 return Text; 56 m_authentications.Remove(auth);
64 } 57 }
65 }
66
67 [XmlRoot("message")]
68 public class XmppMessageStanza: XmppStanza
69 {
70 /// <summary>
71 /// IQ type: one of set, get, result, error
72 /// </summary>
73 [XmlAttribute("type")]
74 public XmppMessageType MessageType;
75
76 // [XmlAttribute("error")]
77 // public XmppError Error;
78 58
79 [XmlElement("body")] 59 public void AddAuthorization(NameValueCollection headers)
80 public XmppMessageBody Body; 60 {
61 foreach (IServiceAuth auth in m_authentications)
62 auth.AddAuthorization(headers);
63 }
81 64
82 public XmppMessageStanza() : base() 65 public bool Authenticate(string data)
83 { 66 {
67 return m_authentications.TrueForAll(a => a.Authenticate(data));
84 } 68 }
85 69
86 public XmppMessageStanza(string fromJid, string toJid, XmppMessageType mType, string message) : 70 public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
87 base(fromJid, toJid)
88 { 71 {
89 MessageType = mType; 72 foreach (IServiceAuth auth in m_authentications)
90 Body = new XmppMessageBody(message); 73 {
74 if (!auth.Authenticate(requestHeaders, d, out statusCode))
75 return false;
76 }
77
78 statusCode = HttpStatusCode.OK;
79 return true;
91 } 80 }
92 } 81 }
93} 82} \ No newline at end of file
diff --git a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs
index 12263f4..e0c413b 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs
+++ b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs
@@ -25,36 +25,35 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Xml.Serialization; 28using System;
29using System.Collections.Specialized;
30using System.Net;
29 31
30namespace OpenSim.Framework.Communications.XMPP 32namespace OpenSim.Framework.ServiceAuth
31{ 33{
32 /// <summary> 34 public class DisallowLlHttpRequest : IServiceAuth
33 /// An IQ needs to have one of the follow types set.
34 /// </summary>
35 public enum XmppIqType
36 { 35 {
37 [XmlEnum("set")] set, 36 public string Name { get { return "DisallowllHTTPRequest"; } }
38 [XmlEnum("get")] get,
39 [XmlEnum("result")] result,
40 [XmlEnum("error")] error,
41 }
42 37
43 /// <summary> 38 public void AddAuthorization(NameValueCollection headers) {}
44 /// XmppIqStanza needs to be subclassed as the query content is
45 /// specific to the query type.
46 /// </summary>
47 [XmlRoot("iq")]
48 public abstract class XmppIqStanza: XmppStanza
49 {
50 /// <summary>
51 /// IQ type: one of set, get, result, error
52 /// </summary>
53 [XmlAttribute("type")]
54 public XmppIqType Type;
55 39
56 public XmppIqStanza(): base() 40 public bool Authenticate(string data)
57 { 41 {
42 return false;
43 }
44
45 public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode)
46 {
47// Console.WriteLine("DisallowLlHttpRequest");
48
49 if (requestHeaders["X-SecondLife-Shard"] != null)
50 {
51 statusCode = HttpStatusCode.Forbidden;
52 return false;
53 }
54
55 statusCode = HttpStatusCode.OK;
56 return true;
58 } 57 }
59 } 58 }
60} 59} \ 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Net;
30using System.Collections.Generic;
31using System.Collections.Specialized;
32
33namespace OpenSim.Framework.ServiceAuth
34{
35 public delegate void AddHeaderDelegate(string key, string value);
36
37 public interface IServiceAuth
38 {
39 /// <summary>
40 /// Name of this authenticator.
41 /// </summary>
42 string Name { get; }
43
44 bool Authenticate(string data);
45 bool Authenticate(NameValueCollection headers, AddHeaderDelegate d, out HttpStatusCode statusCode);
46 void AddAuthorization(NameValueCollection headers);
47 }
48}
diff --git a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs
index 10bc88a..51012e3 100644
--- a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs
+++ b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -26,38 +26,43 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections.Generic;
30using System.Reflection;
31using log4net;
32using Nini.Config;
29 33
30namespace OpenSim.Framework.Configuration.HTTP 34namespace OpenSim.Framework.ServiceAuth
31{ 35{
32 public class RemoteConfigSettings 36 public class ServiceAuth
33 { 37 {
34 private ConfigurationMember configMember; 38// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
35 39
36 public string baseConfigURL = String.Empty; 40 public static IServiceAuth Create(IConfigSource config, string section)
37
38 public RemoteConfigSettings(string filename)
39 { 41 {
40 configMember = 42 CompoundAuthentication compoundAuth = new CompoundAuthentication();
41 new ConfigurationMember(filename, "REMOTE CONFIG SETTINGS", loadConfigurationOptions,
42 handleIncomingConfiguration,true);
43 configMember.forceConfigurationPluginLibrary("OpenSim.Framework.Configuration.XML.dll");
44 configMember.performConfigurationRetrieve();
45 }
46 43
47 public void loadConfigurationOptions() 44 bool allowLlHttpRequestIn
48 { 45 = Util.GetConfigVarFromSections<bool>(config, "AllowllHTTPRequestIn", new string[] { "Network", section }, false);
49 configMember.addConfigurationOption("base_config_url",
50 ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY,
51 "URL Containing Configuration Files", "http://localhost/", false);
52 }
53 46
54 public bool handleIncomingConfiguration(string configuration_key, object configuration_result) 47 if (!allowLlHttpRequestIn)
55 { 48 compoundAuth.AddAuthenticator(new DisallowLlHttpRequest());
56 if (configuration_key == "base_config_url") 49
50 string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", section }, "None");
51
52 switch (authType)
57 { 53 {
58 baseConfigURL = (string) configuration_result; 54 case "BasicHttpAuthentication":
55 compoundAuth.AddAuthenticator(new BasicHttpAuthentication(config, section));
56 break;
59 } 57 }
60 return true; 58
59// foreach (IServiceAuth auth in compoundAuth.GetAuthentors())
60// m_log.DebugFormat("[SERVICE AUTH]: Configured authenticator {0}", auth.Name);
61
62 if (compoundAuth.Count > 0)
63 return compoundAuth;
64 else
65 return null;
61 } 66 }
62 } 67 }
63} 68} \ 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
124 { 124 {
125 get 125 get
126 { 126 {
127 if (_creatorData != null && _creatorData != string.Empty) 127 if (!string.IsNullOrEmpty(_creatorData))
128 return _creatorID.ToString() + ';' + _creatorData; 128 return _creatorID.ToString() + ';' + _creatorData;
129 else 129 else
130 return _creatorID.ToString(); 130 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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Reflection;
32
33using OpenMetaverse;
34
35using log4net;
36
37namespace OpenSim.Framework
38{
39 public abstract class TerrainData
40 {
41 // Terrain always is a square
42 public int SizeX { get; protected set; }
43 public int SizeY { get; protected set; }
44 public int SizeZ { get; protected set; }
45
46 // A height used when the user doesn't specify anything
47 public const float DefaultTerrainHeight = 21f;
48
49 public abstract float this[int x, int y] { get; set; }
50 // Someday terrain will have caves
51 public abstract float this[int x, int y, int z] { get; set; }
52
53 public abstract bool IsTaintedAt(int xx, int yy);
54 public abstract bool IsTaintedAt(int xx, int yy, bool clearOnTest);
55 public abstract void TaintAllTerrain();
56 public abstract void ClearTaint();
57
58 public abstract void ClearLand();
59 public abstract void ClearLand(float height);
60
61 // Return a representation of this terrain for storing as a blob in the database.
62 // Returns 'true' to say blob was stored in the 'out' locations.
63 public abstract bool GetDatabaseBlob(out int DBFormatRevisionCode, out Array blob);
64
65 // Given a revision code and a blob from the database, create and return the right type of TerrainData.
66 // The sizes passed are the expected size of the region. The database info will be used to
67 // initialize the heightmap of that sized region with as much data is in the blob.
68 // Return created TerrainData or 'null' if unsuccessful.
69 public static TerrainData CreateFromDatabaseBlobFactory(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob)
70 {
71 // For the moment, there is only one implementation class
72 return new HeightmapTerrainData(pSizeX, pSizeY, pSizeZ, pFormatCode, pBlob);
73 }
74
75 // return a special compressed representation of the heightmap in ints
76 public abstract int[] GetCompressedMap();
77 public abstract float CompressionFactor { get; }
78
79 public abstract float[] GetFloatsSerialized();
80 public abstract double[,] GetDoubles();
81 public abstract TerrainData Clone();
82 }
83
84 // The terrain is stored in the database as a blob with a 'revision' field.
85 // Some implementations of terrain storage would fill the revision field with
86 // the time the terrain was stored. When real revisions were added and this
87 // feature removed, that left some old entries with the time in the revision
88 // field.
89 // Thus, if revision is greater than 'RevisionHigh' then terrain db entry is
90 // left over and it is presumed to be 'Legacy256'.
91 // Numbers are arbitrary and are chosen to to reduce possible mis-interpretation.
92 // If a revision does not match any of these, it is assumed to be Legacy256.
93 public enum DBTerrainRevision
94 {
95 // Terrain is 'double[256,256]'
96 Legacy256 = 11,
97 // Terrain is 'int32, int32, float[,]' where the ints are X and Y dimensions
98 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
99 Variable2D = 22,
100 // Terrain is 'int32, int32, int32, int16[]' where the ints are X and Y dimensions
101 // and third int is the 'compression factor'. The heights are compressed as
102 // "int compressedHeight = (int)(height * compressionFactor);"
103 // The dimensions are presumed to be multiples of 16 and, more likely, multiples of 256.
104 Compressed2D = 27,
105 // A revision that is not listed above or any revision greater than this value is 'Legacy256'.
106 RevisionHigh = 1234
107 }
108
109 // Version of terrain that is a heightmap.
110 // This should really be 'LLOptimizedHeightmapTerrainData' as it includes knowledge
111 // of 'patches' which are 16x16 terrain areas which can be sent separately to the viewer.
112 // The heighmap is kept as an array of integers. The integer values are converted to
113 // and from floats by TerrainCompressionFactor.
114 public class HeightmapTerrainData : TerrainData
115 {
116 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
117 private static string LogHeader = "[HEIGHTMAP TERRAIN DATA]";
118
119 // TerrainData.this[x, y]
120 public override float this[int x, int y]
121 {
122 get { return FromCompressedHeight(m_heightmap[x, y]); }
123 set {
124 int newVal = ToCompressedHeight(value);
125 if (m_heightmap[x, y] != newVal)
126 {
127 m_heightmap[x, y] = newVal;
128 m_taint[x / Constants.TerrainPatchSize, y / Constants.TerrainPatchSize] = true;
129 }
130 }
131 }
132
133 // TerrainData.this[x, y, z]
134 public override float this[int x, int y, int z]
135 {
136 get { return this[x, y]; }
137 set { this[x, y] = value; }
138 }
139
140 // TerrainData.ClearTaint
141 public override void ClearTaint()
142 {
143 SetAllTaint(false);
144 }
145
146 // TerrainData.TaintAllTerrain
147 public override void TaintAllTerrain()
148 {
149 SetAllTaint(true);
150 }
151
152 private void SetAllTaint(bool setting)
153 {
154 for (int ii = 0; ii < m_taint.GetLength(0); ii++)
155 for (int jj = 0; jj < m_taint.GetLength(1); jj++)
156 m_taint[ii, jj] = setting;
157 }
158
159 // TerrainData.ClearLand
160 public override void ClearLand()
161 {
162 ClearLand(DefaultTerrainHeight);
163 }
164 // TerrainData.ClearLand(float)
165 public override void ClearLand(float pHeight)
166 {
167 int flatHeight = ToCompressedHeight(pHeight);
168 for (int xx = 0; xx < SizeX; xx++)
169 for (int yy = 0; yy < SizeY; yy++)
170 m_heightmap[xx, yy] = flatHeight;
171 }
172
173 // Return 'true' of the patch that contains these region coordinates has been modified.
174 // Note that checking the taint clears it.
175 // There is existing code that relies on this feature.
176 public override bool IsTaintedAt(int xx, int yy, bool clearOnTest)
177 {
178 int tx = xx / Constants.TerrainPatchSize;
179 int ty = yy / Constants.TerrainPatchSize;
180 bool ret = m_taint[tx, ty];
181 if (ret && clearOnTest)
182 m_taint[tx, ty] = false;
183 return ret;
184 }
185
186 // Old form that clears the taint flag when we check it.
187 public override bool IsTaintedAt(int xx, int yy)
188 {
189 return IsTaintedAt(xx, yy, true /* clearOnTest */);
190 }
191
192 // TerrainData.GetDatabaseBlob
193 // The user wants something to store in the database.
194 public override bool GetDatabaseBlob(out int DBRevisionCode, out Array blob)
195 {
196 bool ret = false;
197 if (SizeX == Constants.RegionSize && SizeY == Constants.RegionSize)
198 {
199 DBRevisionCode = (int)DBTerrainRevision.Legacy256;
200 blob = ToLegacyTerrainSerialization();
201 ret = true;
202 }
203 else
204 {
205 DBRevisionCode = (int)DBTerrainRevision.Compressed2D;
206 blob = ToCompressedTerrainSerialization();
207 ret = true;
208 }
209 return ret;
210 }
211
212 // TerrainData.CompressionFactor
213 private float m_compressionFactor = 100.0f;
214 public override float CompressionFactor { get { return m_compressionFactor; } }
215
216 // TerrainData.GetCompressedMap
217 public override int[] GetCompressedMap()
218 {
219 int[] newMap = new int[SizeX * SizeY];
220
221 int ind = 0;
222 for (int xx = 0; xx < SizeX; xx++)
223 for (int yy = 0; yy < SizeY; yy++)
224 newMap[ind++] = m_heightmap[xx, yy];
225
226 return newMap;
227
228 }
229 // TerrainData.Clone
230 public override TerrainData Clone()
231 {
232 HeightmapTerrainData ret = new HeightmapTerrainData(SizeX, SizeY, SizeZ);
233 ret.m_heightmap = (int[,])this.m_heightmap.Clone();
234 return ret;
235 }
236
237 // TerrainData.GetFloatsSerialized
238 // This one dimensional version is ordered so height = map[y*sizeX+x];
239 // DEPRECATED: don't use this function as it does not retain the dimensions of the terrain
240 // and the caller will probably do the wrong thing if the terrain is not the legacy 256x256.
241 public override float[] GetFloatsSerialized()
242 {
243 int points = SizeX * SizeY;
244 float[] heights = new float[points];
245
246 int idx = 0;
247 for (int jj = 0; jj < SizeY; jj++)
248 for (int ii = 0; ii < SizeX; ii++)
249 {
250 heights[idx++] = FromCompressedHeight(m_heightmap[ii, jj]);
251 }
252
253 return heights;
254 }
255
256 // TerrainData.GetDoubles
257 public override double[,] GetDoubles()
258 {
259 double[,] ret = new double[SizeX, SizeY];
260 for (int xx = 0; xx < SizeX; xx++)
261 for (int yy = 0; yy < SizeY; yy++)
262 ret[xx, yy] = FromCompressedHeight(m_heightmap[xx, yy]);
263
264 return ret;
265 }
266
267
268 // =============================================================
269
270 private int[,] m_heightmap;
271 // Remember subregions of the heightmap that has changed.
272 private bool[,] m_taint;
273
274 // To save space (especially for large regions), keep the height as a short integer
275 // that is coded as the float height times the compression factor (usually '100'
276 // to make for two decimal points).
277 public int ToCompressedHeight(double pHeight)
278 {
279 return (int)(pHeight * CompressionFactor);
280 }
281
282 public float FromCompressedHeight(int pHeight)
283 {
284 return ((float)pHeight) / CompressionFactor;
285 }
286
287 // To keep with the legacy theme, create an instance of this class based on the
288 // way terrain used to be passed around.
289 public HeightmapTerrainData(double[,] pTerrain)
290 {
291 SizeX = pTerrain.GetLength(0);
292 SizeY = pTerrain.GetLength(1);
293 SizeZ = (int)Constants.RegionHeight;
294 m_compressionFactor = 100.0f;
295
296 m_heightmap = new int[SizeX, SizeY];
297 for (int ii = 0; ii < SizeX; ii++)
298 {
299 for (int jj = 0; jj < SizeY; jj++)
300 {
301 m_heightmap[ii, jj] = ToCompressedHeight(pTerrain[ii, jj]);
302
303 }
304 }
305 // m_log.DebugFormat("{0} new by doubles. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
306
307 m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
308 ClearTaint();
309 }
310
311 // Create underlying structures but don't initialize the heightmap assuming the caller will immediately do that
312 public HeightmapTerrainData(int pX, int pY, int pZ)
313 {
314 SizeX = pX;
315 SizeY = pY;
316 SizeZ = pZ;
317 m_compressionFactor = 100.0f;
318 m_heightmap = new int[SizeX, SizeY];
319 m_taint = new bool[SizeX / Constants.TerrainPatchSize, SizeY / Constants.TerrainPatchSize];
320 // m_log.DebugFormat("{0} new by dimensions. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
321 ClearTaint();
322 ClearLand(0f);
323 }
324
325 public HeightmapTerrainData(int[] cmap, float pCompressionFactor, int pX, int pY, int pZ) : this(pX, pY, pZ)
326 {
327 m_compressionFactor = pCompressionFactor;
328 int ind = 0;
329 for (int xx = 0; xx < SizeX; xx++)
330 for (int yy = 0; yy < SizeY; yy++)
331 m_heightmap[xx, yy] = cmap[ind++];
332 // m_log.DebugFormat("{0} new by compressed map. sizeX={1}, sizeY={2}, sizeZ={3}", LogHeader, SizeX, SizeY, SizeZ);
333 }
334
335 // Create a heighmap from a database blob
336 public HeightmapTerrainData(int pSizeX, int pSizeY, int pSizeZ, int pFormatCode, byte[] pBlob) : this(pSizeX, pSizeY, pSizeZ)
337 {
338 switch ((DBTerrainRevision)pFormatCode)
339 {
340 case DBTerrainRevision.Compressed2D:
341 FromCompressedTerrainSerialization(pBlob);
342 m_log.DebugFormat("{0} HeightmapTerrainData create from Compressed2D serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
343 break;
344 default:
345 FromLegacyTerrainSerialization(pBlob);
346 m_log.DebugFormat("{0} HeightmapTerrainData create from legacy serialization. Size=<{1},{2}>", LogHeader, SizeX, SizeY);
347 break;
348 }
349 }
350
351 // Just create an array of doubles. Presumes the caller implicitly knows the size.
352 public Array ToLegacyTerrainSerialization()
353 {
354 Array ret = null;
355
356 using (MemoryStream str = new MemoryStream((int)Constants.RegionSize * (int)Constants.RegionSize * sizeof(double)))
357 {
358 using (BinaryWriter bw = new BinaryWriter(str))
359 {
360 for (int xx = 0; xx < Constants.RegionSize; xx++)
361 {
362 for (int yy = 0; yy < Constants.RegionSize; yy++)
363 {
364 double height = this[xx, yy];
365 if (height == 0.0)
366 height = double.Epsilon;
367 bw.Write(height);
368 }
369 }
370 }
371 ret = str.ToArray();
372 }
373 return ret;
374 }
375
376 // Just create an array of doubles. Presumes the caller implicitly knows the size.
377 public void FromLegacyTerrainSerialization(byte[] pBlob)
378 {
379 // In case database info doesn't match real terrain size, initialize the whole terrain.
380 ClearLand();
381
382 using (MemoryStream mstr = new MemoryStream(pBlob))
383 {
384 using (BinaryReader br = new BinaryReader(mstr))
385 {
386 for (int xx = 0; xx < (int)Constants.RegionSize; xx++)
387 {
388 for (int yy = 0; yy < (int)Constants.RegionSize; yy++)
389 {
390 float val = (float)br.ReadDouble();
391 if (xx < SizeX && yy < SizeY)
392 m_heightmap[xx, yy] = ToCompressedHeight(val);
393 }
394 }
395 }
396 ClearTaint();
397 }
398 }
399
400 // See the reader below.
401 public Array ToCompressedTerrainSerialization()
402 {
403 Array ret = null;
404 using (MemoryStream str = new MemoryStream((3 * sizeof(Int32)) + (SizeX * SizeY * sizeof(Int16))))
405 {
406 using (BinaryWriter bw = new BinaryWriter(str))
407 {
408 bw.Write((Int32)DBTerrainRevision.Compressed2D);
409 bw.Write((Int32)SizeX);
410 bw.Write((Int32)SizeY);
411 bw.Write((Int32)CompressionFactor);
412 for (int yy = 0; yy < SizeY; yy++)
413 for (int xx = 0; xx < SizeX; xx++)
414 {
415 bw.Write((Int16)m_heightmap[xx, yy]);
416 }
417 }
418 ret = str.ToArray();
419 }
420 return ret;
421 }
422
423 // Initialize heightmap from blob consisting of:
424 // int32, int32, int32, int32, int16[]
425 // where the first int32 is format code, next two int32s are the X and y of heightmap data and
426 // the forth int is the compression factor for the following int16s
427 // This is just sets heightmap info. The actual size of the region was set on this instance's
428 // creation and any heights not initialized by theis blob are set to the default height.
429 public void FromCompressedTerrainSerialization(byte[] pBlob)
430 {
431 Int32 hmFormatCode, hmSizeX, hmSizeY, hmCompressionFactor;
432
433 using (MemoryStream mstr = new MemoryStream(pBlob))
434 {
435 using (BinaryReader br = new BinaryReader(mstr))
436 {
437 hmFormatCode = br.ReadInt32();
438 hmSizeX = br.ReadInt32();
439 hmSizeY = br.ReadInt32();
440 hmCompressionFactor = br.ReadInt32();
441
442 m_compressionFactor = hmCompressionFactor;
443
444 // In case database info doesn't match real terrain size, initialize the whole terrain.
445 ClearLand();
446
447 for (int yy = 0; yy < hmSizeY; yy++)
448 {
449 for (int xx = 0; xx < hmSizeX; xx++)
450 {
451 Int16 val = br.ReadInt16();
452 if (xx < SizeX && yy < SizeY)
453 m_heightmap[xx, yy] = val;
454 }
455 }
456 }
457 ClearTaint();
458
459 m_log.InfoFormat("{0} Read compressed 2d heightmap. Heightmap size=<{1},{2}>. Region size=<{3},{4}>. CompFact={5}",
460 LogHeader, hmSizeX, hmSizeY, SizeX, SizeY, hmCompressionFactor);
461 }
462 }
463 }
464}
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;
32using OpenMetaverse.StructuredData; 32using OpenMetaverse.StructuredData;
33using OpenSim.Framework; 33using OpenSim.Framework;
34using OpenSim.Tests.Common; 34using OpenSim.Tests.Common;
35using OpenSim.Tests.Common.Mock;
36using Animation = OpenSim.Framework.Animation; 35using Animation = OpenSim.Framework.Animation;
37 36
38namespace OpenSim.Framework.Tests 37namespace 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
50 CheckContainsReferences(AssetType.ImageJPEG , false); 50 CheckContainsReferences(AssetType.ImageJPEG , false);
51 CheckContainsReferences(AssetType.ImageTGA , false); 51 CheckContainsReferences(AssetType.ImageTGA , false);
52 CheckContainsReferences(AssetType.Landmark , false); 52 CheckContainsReferences(AssetType.Landmark , false);
53 CheckContainsReferences(AssetType.LostAndFoundFolder, false);
54 CheckContainsReferences(AssetType.LSLBytecode, false); 53 CheckContainsReferences(AssetType.LSLBytecode, false);
55 CheckContainsReferences(AssetType.LSLText, false); 54 CheckContainsReferences(AssetType.LSLText, false);
56 CheckContainsReferences(AssetType.Notecard, false); 55 CheckContainsReferences(AssetType.Notecard, false);
57 CheckContainsReferences(AssetType.Object, false); 56 CheckContainsReferences(AssetType.Object, false);
58 CheckContainsReferences(AssetType.RootFolder, false);
59 CheckContainsReferences(AssetType.Simstate, false); 57 CheckContainsReferences(AssetType.Simstate, false);
60 CheckContainsReferences(AssetType.SnapshotFolder, false);
61 CheckContainsReferences(AssetType.Sound, false); 58 CheckContainsReferences(AssetType.Sound, false);
62 CheckContainsReferences(AssetType.SoundWAV, false); 59 CheckContainsReferences(AssetType.SoundWAV, false);
63 CheckContainsReferences(AssetType.Texture, false); 60 CheckContainsReferences(AssetType.Texture, false);
64 CheckContainsReferences(AssetType.TextureTGA, false); 61 CheckContainsReferences(AssetType.TextureTGA, false);
65 CheckContainsReferences(AssetType.TrashFolder, false);
66 CheckContainsReferences(AssetType.Unknown, false); 62 CheckContainsReferences(AssetType.Unknown, false);
67 } 63 }
68 64
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
51 [Test] 51 [Test]
52 public void locationXYRegionHandle() 52 public void locationXYRegionHandle()
53 { 53 {
54 Location TestLocation1 = new Location(256000,256000); 54 Location TestLocation1 = new Location(255000,256000);
55 Location TestLocation2 = new Location(1099511628032000); 55 Location TestLocation2 = new Location(1095216660736000);
56 Assert.That(TestLocation1 == TestLocation2); 56 Assert.That(TestLocation1 == TestLocation2);
57 57
58 Assert.That(TestLocation2.X == 256000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); 58 Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor");
59 Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided");
59 60
60 Assert.That(TestLocation2.RegionHandle == 1099511628032000, 61 Assert.That(TestLocation2.RegionHandle == 1095216660736000,
61 "Location RegionHandle Property didn't match regionhandle provided in constructor"); 62 "Location RegionHandle Property didn't match regionhandle provided in constructor");
62 63
64 ulong RegionHandle = TestLocation1.RegionHandle;
65 Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor");
63 66
64 TestLocation1 = new Location(256001, 256001); 67 TestLocation2 = new Location(RegionHandle);
65 TestLocation2 = new Location(1099511628032000); 68 Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor");
69
70
71 TestLocation1 = new Location(255001, 256001);
72 TestLocation2 = new Location(1095216660736000);
66 Assert.That(TestLocation1 != TestLocation2); 73 Assert.That(TestLocation1 != TestLocation2);
67 74
68 Assert.That(TestLocation1.Equals(256001, 256001), "Equals(x,y) failed to match the position in the constructor"); 75 Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor");
69 76
70 Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); 77 Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode");
71 78
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
100 cadu.AVHeight = Size1.Z; 100 cadu.AVHeight = Size1.Z;
101 101
102 AgentPosition position2 = new AgentPosition(); 102 AgentPosition position2 = new AgentPosition();
103 position2.CopyFrom(cadu); 103 position2.CopyFrom(cadu, position1.SessionID);
104 104
105 Assert.IsTrue( 105 Assert.IsTrue(
106 position2.AgentID == position1.AgentID 106 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
173 [Test] 173 [Test]
174 public void SLUtilTypeConvertTests() 174 public void SLUtilTypeConvertTests()
175 { 175 {
176 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 176 int[] assettypes = new int[]{-1,0,1,2,3,5,6,7,8,10,11,12,13,17,18,19,20,21,22
177 ,23,24,25,46,47,48}; 177 ,24,25};
178 string[] contenttypes = new string[] 178 string[] contenttypes = new string[]
179 { 179 {
180 "application/octet-stream", 180 "application/octet-stream",
@@ -186,26 +186,18 @@ namespace OpenSim.Framework.Tests
186 "application/vnd.ll.primitive", 186 "application/vnd.ll.primitive",
187 "application/vnd.ll.notecard", 187 "application/vnd.ll.notecard",
188 "application/vnd.ll.folder", 188 "application/vnd.ll.folder",
189 "application/vnd.ll.rootfolder",
190 "application/vnd.ll.lsltext", 189 "application/vnd.ll.lsltext",
191 "application/vnd.ll.lslbyte", 190 "application/vnd.ll.lslbyte",
192 "image/tga", 191 "image/tga",
193 "application/vnd.ll.bodypart", 192 "application/vnd.ll.bodypart",
194 "application/vnd.ll.trashfolder",
195 "application/vnd.ll.snapshotfolder",
196 "application/vnd.ll.lostandfoundfolder",
197 "audio/x-wav", 193 "audio/x-wav",
198 "image/tga", 194 "image/tga",
199 "image/jpeg", 195 "image/jpeg",
200 "application/vnd.ll.animation", 196 "application/vnd.ll.animation",
201 "application/vnd.ll.gesture", 197 "application/vnd.ll.gesture",
202 "application/x-metaverse-simstate", 198 "application/x-metaverse-simstate",
203 "application/vnd.ll.favoritefolder",
204 "application/vnd.ll.link", 199 "application/vnd.ll.link",
205 "application/vnd.ll.linkfolder", 200 "application/vnd.ll.linkfolder",
206 "application/vnd.ll.currentoutfitfolder",
207 "application/vnd.ll.outfitfolder",
208 "application/vnd.ll.myoutfitsfolder"
209 }; 201 };
210 for (int i=0;i<assettypes.Length;i++) 202 for (int i=0;i<assettypes.Length;i++)
211 { 203 {
@@ -223,7 +215,7 @@ namespace OpenSim.Framework.Tests
223 String.Format("Incorrect AssetType mapped from Content-Type {0}", contenttypes[i])); 215 String.Format("Incorrect AssetType mapped from Content-Type {0}", contenttypes[i]));
224 } 216 }
225 217
226 int[] inventorytypes = new int[] {-1,0,1,2,3,6,7,8,9,10,15,17,18,20}; 218 int[] inventorytypes = new int[] {-1,0,1,2,3,6,7,8,10,15,17,18,20};
227 string[] invcontenttypes = new string[] 219 string[] invcontenttypes = new string[]
228 { 220 {
229 "application/octet-stream", 221 "application/octet-stream",
@@ -233,7 +225,6 @@ namespace OpenSim.Framework.Tests
233 "application/vnd.ll.landmark", 225 "application/vnd.ll.landmark",
234 "application/vnd.ll.primitive", 226 "application/vnd.ll.primitive",
235 "application/vnd.ll.notecard", 227 "application/vnd.ll.notecard",
236 "application/vnd.ll.folder",
237 "application/vnd.ll.rootfolder", 228 "application/vnd.ll.rootfolder",
238 "application/vnd.ll.lsltext", 229 "application/vnd.ll.lsltext",
239 "image/x-j2c", 230 "image/x-j2c",
@@ -272,8 +263,8 @@ namespace OpenSim.Framework.Tests
272 }; 263 };
273 sbyte[] invtypes = new sbyte[] 264 sbyte[] invtypes = new sbyte[]
274 { 265 {
275 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 18, 18, 18, 18, 6, 6, 7, 7, 8, 9, 10, 10, 10, 10 266 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 3, 18, 18, 18, 18, 6, 6, 7, 7, -1, 8, 10, 10, 10, 10
276 , 8, 8, 8, 19, 19, 20, 20, 15, -1 267 , 14, 15, 16, 19, 19, 20, 20, 15, -1
277 }; 268 };
278 269
279 for (int i = 0; i < invtypes.Length; i++) 270 for (int i = 0; i < invtypes.Length; i++)
@@ -282,5 +273,87 @@ namespace OpenSim.Framework.Tests
282 String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); 273 String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i]));
283 } 274 }
284 } 275 }
276
277 [Test]
278 public void FakeParcelIDTests()
279 {
280 byte[] hexBytes8 = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
281 byte[] hexBytes16 = {
282 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
283 0x77, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f };
284 UInt64 var64Bit = (UInt64)0xfedcba9876543210;
285
286 //Region handle is for location 255000,256000.
287 ulong regionHandle1 = 1095216660736000;
288 uint x1 = 100;
289 uint y1 = 200;
290 uint z1 = 22;
291 ulong regionHandle2;
292 uint x2, y2, z2;
293 UUID fakeParcelID1, uuid;
294
295 ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8);
296 Assert.AreEqual(var64Bit, bigInt64,
297 "BytesToUint64Bit conversion of 8 bytes to UInt64 failed.");
298
299 //Test building and decoding using some typical input values
300 fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1);
301 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2);
302 Assert.AreEqual(regionHandle1, regionHandle2,
303 "region handle decoded from FakeParcelID wth X/Y failed.");
304 Assert.AreEqual(x1, x2,
305 "X coordinate decoded from FakeParcelID wth X/Y failed.");
306 Assert.AreEqual(y1, y2,
307 "Y coordinate decoded from FakeParcelID wth X/Y failed.");
308
309 fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1, z1);
310 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2);
311 Assert.AreEqual(regionHandle1, regionHandle2,
312 "region handle decoded from FakeParcelID with X/Y/Z failed.");
313 Assert.AreEqual(x1, x2,
314 "X coordinate decoded from FakeParcelID with X/Y/Z failed.");
315 Assert.AreEqual(y1, y2,
316 "Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
317 Assert.AreEqual(z1, z2,
318 "Z coordinate decoded from FakeParcelID with X/Y/Z failed.");
319
320 //Do some more extreme tests to check the encoding and decoding
321 x1 = 0x55aa;
322 y1 = 0x9966;
323 z1 = 0x5a96;
324
325 fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1);
326 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2);
327 Assert.AreEqual(var64Bit, regionHandle2,
328 "region handle decoded from FakeParcelID with X/Y/Z failed.");
329 Assert.AreEqual(x1, x2,
330 "X coordinate decoded from FakeParcelID with X/Y/Z failed.");
331 Assert.AreEqual(y1, y2,
332 "Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
333
334 fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1, z1);
335 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2);
336 Assert.AreEqual(var64Bit, regionHandle2,
337 "region handle decoded from FakeParcelID with X/Y/Z failed.");
338 Assert.AreEqual(x1, x2,
339 "X coordinate decoded from FakeParcelID with X/Y/Z failed.");
340 Assert.AreEqual(y1, y2,
341 "Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
342 Assert.AreEqual(z1, z2,
343 "Z coordinate decoded from FakeParcelID with X/Y/Z failed.");
344
345
346 x1 = 64;
347 y1 = 192;
348 fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1);
349 Util.FakeParcelIDToGlobalPosition(fakeParcelID1, out x2, out y2);
350 Assert.AreEqual(255000+x1, x2,
351 "Global X coordinate decoded from regionHandle failed.");
352 Assert.AreEqual(256000+y1, y2,
353 "Global Y coordinate decoded from regionHandle failed.");
354
355 uuid = new UUID("00dd0700-00d1-0700-3800-000032000000");
356 Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2);
357 }
285 } 358 }
286} 359}
diff --git a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs b/OpenSim/Framework/ThreadSafeRandom.cs
index 4d45ac0..58853e6 100644
--- a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs
+++ b/OpenSim/Framework/ThreadSafeRandom.cs
@@ -25,45 +25,48 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System.Xml.Serialization; 28using System;
29 29
30namespace OpenSim.Framework.Communications.XMPP 30namespace OpenSim.Framework
31{ 31{
32 /// <summary> 32 /// <summary>
33 /// Message types. 33 /// A thread-safe Random since the .NET version is not.
34 /// See http://msdn.microsoft.com/en-us/library/system.random%28v=vs.100%29.aspx
34 /// </summary> 35 /// </summary>
35 public enum XmppPresenceType 36 public class ThreadSafeRandom : Random
36 { 37 {
37 [XmlEnum("unavailable")] unavailable, 38 public ThreadSafeRandom() : base() {}
38 [XmlEnum("subscribe")] subscribe,
39 [XmlEnum("subscribed")] subscribed,
40 [XmlEnum("unsubscribe")] unsubscribe,
41 [XmlEnum("unsubscribed")] unsubscribed,
42 [XmlEnum("probe")] probe,
43 [XmlEnum("error")] error,
44 }
45 39
40 public ThreadSafeRandom(int seed): base (seed) {}
46 41
47 [XmlRoot("message")] 42 public override int Next()
48 public class XmppPresenceStanza: XmppStanza 43 {
49 { 44 lock (this)
50 /// <summary> 45 return base.Next();
51 /// IQ type: one of set, get, result, error 46 }
52 /// </summary>
53 [XmlAttribute("type")]
54 public XmppPresenceType PresenceType;
55 47
56 // [XmlAttribute("error")] 48 public override int Next(int maxValue)
57 // public XmppError Error; 49 {
50 lock (this)
51 return base.Next(maxValue);
52 }
53
54 public override int Next(int minValue, int maxValue)
55 {
56 lock (this)
57 return base.Next(minValue, maxValue);
58 }
58 59
59 public XmppPresenceStanza() : base() 60 public override void NextBytes(byte[] buffer)
60 { 61 {
62 lock (this)
63 base.NextBytes(buffer);
61 } 64 }
62 65
63 public XmppPresenceStanza(string fromJid, string toJid, XmppPresenceType pType) : 66 public override double NextDouble()
64 base(fromJid, toJid)
65 { 67 {
66 PresenceType = pType; 68 lock (this)
69 return base.NextDouble();
67 } 70 }
68 } 71 }
69} 72} \ 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
47 Texture = 5, 47 Texture = 5,
48 /// <summary>Non-texture assets</summary> 48 /// <summary>Non-texture assets</summary>
49 Asset = 6, 49 Asset = 6,
50 /// <summary>Avatar and primitive data</summary>
51 /// <remarks>This is a sub-category of Task</remarks>
52 State = 7,
53 } 50 }
54 51
55 [Flags] 52 [Flags]
@@ -61,6 +58,5 @@ namespace OpenSim.Framework
61 Task = 1 << 3, 58 Task = 1 << 3,
62 Texture = 1 << 4, 59 Texture = 1 << 4,
63 Asset = 1 << 5, 60 Asset = 1 << 5,
64 State = 1 << 6,
65 } 61 }
66} 62}
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using System.IO;
31using System.Net;
32using System.Net.Security;
33using System.Text;
34using log4net;
35
36namespace OpenSim.Framework
37{
38 /// <summary>
39 /// Used for requests to untrusted endpoints that may potentially be
40 /// malicious
41 /// </summary>
42 public static class UntrustedHttpWebRequest
43 {
44 /// <summary>Setting this to true will allow HTTP connections to localhost</summary>
45 private const bool DEBUG = true;
46
47 private static readonly ILog m_log =
48 LogManager.GetLogger(
49 System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
50
51 private static readonly ICollection<string> allowableSchemes = new List<string> { "http", "https" };
52
53 /// <summary>
54 /// Creates an HttpWebRequest that is hardened against malicious
55 /// endpoints after ensuring the given Uri is safe to retrieve
56 /// </summary>
57 /// <param name="uri">Web location to request</param>
58 /// <returns>A hardened HttpWebRequest if the uri was determined to be safe</returns>
59 /// <exception cref="ArgumentNullException">If uri is null</exception>
60 /// <exception cref="ArgumentException">If uri is unsafe</exception>
61 public static HttpWebRequest Create(Uri uri)
62 {
63 return Create(uri, DEBUG, 1000 * 5, 1000 * 20, 10);
64 }
65
66 /// <summary>
67 /// Creates an HttpWebRequest that is hardened against malicious
68 /// endpoints after ensuring the given Uri is safe to retrieve
69 /// </summary>
70 /// <param name="uri">Web location to request</param>
71 /// <param name="allowLoopback">True to allow connections to localhost, otherwise false</param>
72 /// <param name="readWriteTimeoutMS">Read write timeout, in milliseconds</param>
73 /// <param name="timeoutMS">Connection timeout, in milliseconds</param>
74 /// <param name="maximumRedirects">Maximum number of allowed redirects</param>
75 /// <returns>A hardened HttpWebRequest if the uri was determined to be safe</returns>
76 /// <exception cref="ArgumentNullException">If uri is null</exception>
77 /// <exception cref="ArgumentException">If uri is unsafe</exception>
78 public static HttpWebRequest Create(Uri uri, bool allowLoopback, int readWriteTimeoutMS, int timeoutMS, int maximumRedirects)
79 {
80 if (uri == null)
81 throw new ArgumentNullException("uri");
82
83 if (!IsUriAllowable(uri, allowLoopback))
84 throw new ArgumentException("Uri " + uri + " was rejected");
85
86 HttpWebRequest httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(uri);
87 httpWebRequest.MaximumAutomaticRedirections = maximumRedirects;
88 httpWebRequest.ReadWriteTimeout = readWriteTimeoutMS;
89 httpWebRequest.Timeout = timeoutMS;
90 httpWebRequest.KeepAlive = false;
91
92 return httpWebRequest;
93 }
94
95 public static string PostToUntrustedUrl(Uri url, string data)
96 {
97 try
98 {
99 byte[] requestData = System.Text.Encoding.UTF8.GetBytes(data);
100
101 HttpWebRequest request = Create(url);
102 request.Method = "POST";
103 request.ContentLength = requestData.Length;
104 request.ContentType = "application/x-www-form-urlencoded";
105
106 using (Stream requestStream = request.GetRequestStream())
107 requestStream.Write(requestData, 0, requestData.Length);
108
109 using (WebResponse response = request.GetResponse())
110 {
111 using (Stream responseStream = response.GetResponseStream())
112 return responseStream.GetStreamString();
113 }
114 }
115 catch (Exception ex)
116 {
117 m_log.Warn("POST to untrusted URL " + url + " failed: " + ex.Message);
118 return null;
119 }
120 }
121
122 public static string GetUntrustedUrl(Uri url)
123 {
124 try
125 {
126 HttpWebRequest request = Create(url);
127
128 using (WebResponse response = request.GetResponse())
129 {
130 using (Stream responseStream = response.GetResponseStream())
131 return responseStream.GetStreamString();
132 }
133 }
134 catch (Exception ex)
135 {
136 m_log.Warn("GET from untrusted URL " + url + " failed: " + ex.Message);
137 return null;
138 }
139 }
140
141 /// <summary>
142 /// Determines whether a URI is allowed based on scheme and host name.
143 /// No requireSSL check is done here
144 /// </summary>
145 /// <param name="allowLoopback">True to allow loopback addresses to be used</param>
146 /// <param name="uri">The URI to test for whether it should be allowed.</param>
147 /// <returns>
148 /// <c>true</c> if [is URI allowable] [the specified URI]; otherwise, <c>false</c>.
149 /// </returns>
150 private static bool IsUriAllowable(Uri uri, bool allowLoopback)
151 {
152 if (!allowableSchemes.Contains(uri.Scheme))
153 {
154 m_log.WarnFormat("Rejecting URL {0} because it uses a disallowed scheme.", uri);
155 return false;
156 }
157
158 // Try to interpret the hostname as an IP address so we can test for internal
159 // IP address ranges. Note that IP addresses can appear in many forms
160 // (e.g. http://127.0.0.1, http://2130706433, http://0x0100007f, http://::1
161 // So we convert them to a canonical IPAddress instance, and test for all
162 // non-routable IP ranges: 10.*.*.*, 127.*.*.*, ::1
163 // Note that Uri.IsLoopback is very unreliable, not catching many of these variants.
164 IPAddress hostIPAddress;
165 if (IPAddress.TryParse(uri.DnsSafeHost, out hostIPAddress))
166 {
167 byte[] addressBytes = hostIPAddress.GetAddressBytes();
168
169 // The host is actually an IP address.
170 switch (hostIPAddress.AddressFamily)
171 {
172 case System.Net.Sockets.AddressFamily.InterNetwork:
173 if (!allowLoopback && (addressBytes[0] == 127 || addressBytes[0] == 10))
174 {
175 m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri);
176 return false;
177 }
178 break;
179 case System.Net.Sockets.AddressFamily.InterNetworkV6:
180 if (!allowLoopback && IsIPv6Loopback(hostIPAddress))
181 {
182 m_log.WarnFormat("Rejecting URL {0} because it is a loopback address.", uri);
183 return false;
184 }
185 break;
186 default:
187 m_log.WarnFormat("Rejecting URL {0} because it does not use an IPv4 or IPv6 address.", uri);
188 return false;
189 }
190 }
191 else
192 {
193 // The host is given by name. We require names to contain periods to
194 // help make sure it's not an internal address.
195 if (!allowLoopback && !uri.Host.Contains("."))
196 {
197 m_log.WarnFormat("Rejecting URL {0} because it does not contain a period in the host name.", uri);
198 return false;
199 }
200 }
201
202 return true;
203 }
204
205 /// <summary>
206 /// Determines whether an IP address is the IPv6 equivalent of "localhost/127.0.0.1".
207 /// </summary>
208 /// <param name="ip">The ip address to check.</param>
209 /// <returns>
210 /// <c>true</c> if this is a loopback IP address; <c>false</c> otherwise.
211 /// </returns>
212 private static bool IsIPv6Loopback(IPAddress ip)
213 {
214 if (ip == null)
215 throw new ArgumentNullException("ip");
216
217 byte[] addressBytes = ip.GetAddressBytes();
218 for (int i = 0; i < addressBytes.Length - 1; i++)
219 {
220 if (addressBytes[i] != 0)
221 return false;
222 }
223
224 if (addressBytes[addressBytes.Length - 1] != 1)
225 return false;
226
227 return true;
228 }
229 }
230}
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
160 public virtual ulong HomeRegion 160 public virtual ulong HomeRegion
161 { 161 {
162 get 162 get
163 { 163 {
164 return Utils.UIntsToLong( 164 return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY));
165 m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); 165 // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize);
166 } 166 }
167 167
168 set 168 set
169 { 169 {
170 m_homeRegionX = (uint) (value >> 40); 170 uint regionWorldLocX, regionWorldLocY;
171 m_homeRegionY = (((uint) (value)) >> 8); 171 Util.RegionHandleToWorldLoc(value, out regionWorldLocX, out regionWorldLocY);
172 m_homeRegionX = Util.WorldToRegionLoc(regionWorldLocX);
173 m_homeRegionY = Util.WorldToRegionLoc(regionWorldLocY);
174 // m_homeRegionX = (uint) (value >> 40);
175 // m_homeRegionY = (((uint) (value)) >> 8);
172 } 176 }
173 } 177 }
174 178
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 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using OpenMetaverse;
30
31namespace OpenSim.Framework
32{
33 public class UserClassifiedAdd
34 {
35 public UUID ClassifiedId = UUID.Zero;
36 public UUID CreatorId = UUID.Zero;
37 public int CreationDate = 0;
38 public int ExpirationDate = 0;
39 public int Category = 0;
40 public string Name = string.Empty;
41 public string Description = string.Empty;
42 public UUID ParcelId = UUID.Zero;
43 public int ParentEstate = 0;
44 public UUID SnapshotId = UUID.Zero;
45 public string SimName = string.Empty;
46 public string GlobalPos = "<0,0,0>";
47 public string ParcelName = string.Empty;
48 public byte Flags = 0;
49 public int Price = 0;
50 }
51
52 public class UserProfileProperties
53 {
54 public UUID UserId = UUID.Zero;
55 public UUID PartnerId = UUID.Zero;
56 public bool PublishProfile = false;
57 public bool PublishMature = false;
58 public string WebUrl = string.Empty;
59 public int WantToMask = 0;
60 public string WantToText = string.Empty;
61 public int SkillsMask = 0;
62 public string SkillsText = string.Empty;
63 public string Language = string.Empty;
64 public UUID ImageId = UUID.Zero;
65 public string AboutText = string.Empty;
66 public UUID FirstLifeImageId = UUID.Zero;
67 public string FirstLifeText = string.Empty;
68 }
69
70 public class UserProfilePick
71 {
72 public UUID PickId = UUID.Zero;
73 public UUID CreatorId = UUID.Zero;
74 public bool TopPick = false;
75 public string Name = string.Empty;
76 public string OriginalName = string.Empty;
77 public string Desc = string.Empty;
78 public UUID ParcelId = UUID.Zero;
79 public UUID SnapshotId = UUID.Zero;
80 public string ParcelName = string.Empty;
81 public string SimName = string.Empty;
82 public string GlobalPos = "<0,0,0>";
83 public string Gatekeeper = string.Empty;
84 public int SortOrder = 0;
85 public bool Enabled = false;
86 }
87
88 public class UserProfileNotes
89 {
90 public UUID UserId;
91 public UUID TargetId;
92 public string Notes;
93 }
94
95 public class UserPreferences
96 {
97 public UUID UserId;
98 public bool IMViaEmail = false;
99 public bool Visible = false;
100 public string EMail = string.Empty;
101 }
102
103 public class UserAccountProperties
104 {
105 public string EmailAddress = string.Empty;
106 public string Firstname = string.Empty;
107 public string LastName = string.Empty;
108 public string Password = string.Empty;
109 public string UserId = string.Empty;
110 }
111
112 public class UserAccountAuth
113 {
114 public string UserId = UUID.Zero.ToString();
115 public string Password = string.Empty;
116 }
117
118 public class UserAppData
119 {
120 public string TagId = string.Empty;
121 public string DataKey = string.Empty;
122 public string UserId = UUID.Zero.ToString();
123 public string DataVal = string.Empty;
124 }
125}
126
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;
45using System.Xml; 45using System.Xml;
46using System.Threading; 46using System.Threading;
47using log4net; 47using log4net;
48using log4net.Appender;
48using Nini.Config; 49using Nini.Config;
49using Nwc.XmlRpc; 50using Nwc.XmlRpc;
50using OpenMetaverse; 51using OpenMetaverse;
51using OpenMetaverse.StructuredData; 52using OpenMetaverse.StructuredData;
52using Amib.Threading; 53using Amib.Threading;
54using System.Collections.Concurrent;
55using System.Collections.Specialized;
56using System.Web;
53 57
54namespace OpenSim.Framework 58namespace OpenSim.Framework
55{ 59{
60 [Flags]
61 public enum PermissionMask : uint
62 {
63 None = 0,
64 Transfer = 1 << 13,
65 Modify = 1 << 14,
66 Copy = 1 << 15,
67 Export = 1 << 16,
68 Move = 1 << 19,
69 Damage = 1 << 20,
70 // All does not contain Export, which is special and must be
71 // explicitly given
72 All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19)
73 }
74
56 /// <summary> 75 /// <summary>
57 /// The method used by Util.FireAndForget for asynchronously firing events 76 /// The method used by Util.FireAndForget for asynchronously firing events
58 /// </summary> 77 /// </summary>
@@ -73,14 +92,53 @@ namespace OpenSim.Framework
73 } 92 }
74 93
75 /// <summary> 94 /// <summary>
95 /// Class for delivering SmartThreadPool statistical information
96 /// </summary>
97 /// <remarks>
98 /// We do it this way so that we do not directly expose STP.
99 /// </remarks>
100 public class STPInfo
101 {
102 public string Name { get; set; }
103 public STPStartInfo STPStartInfo { get; set; }
104 public WIGStartInfo WIGStartInfo { get; set; }
105 public bool IsIdle { get; set; }
106 public bool IsShuttingDown { get; set; }
107 public int MaxThreads { get; set; }
108 public int MinThreads { get; set; }
109 public int InUseThreads { get; set; }
110 public int ActiveThreads { get; set; }
111 public int WaitingCallbacks { get; set; }
112 public int MaxConcurrentWorkItems { get; set; }
113 }
114
115 /// <summary>
76 /// Miscellaneous utility functions 116 /// Miscellaneous utility functions
77 /// </summary> 117 /// </summary>
78 public class Util 118 public static class Util
79 { 119 {
80 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 120 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
81 121
122 /// <summary>
123 /// Log-level for the thread pool:
124 /// 0 = no logging
125 /// 1 = only first line of stack trace; don't log common threads
126 /// 2 = full stack trace; don't log common threads
127 /// 3 = full stack trace, including common threads
128 /// </summary>
129 public static int LogThreadPool { get; set; }
130 public static bool LogOverloads { get; set; }
131
132 public static readonly int MAX_THREADPOOL_LEVEL = 3;
133
134 static Util()
135 {
136 LogThreadPool = 0;
137 LogOverloads = true;
138 }
139
82 private static uint nextXferID = 5000; 140 private static uint nextXferID = 5000;
83 private static Random randomClass = new Random(); 141 private static Random randomClass = new ThreadSafeRandom();
84 142
85 // Get a list of invalid file characters (OS dependent) 143 // Get a list of invalid file characters (OS dependent)
86 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; 144 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
@@ -92,8 +150,11 @@ namespace OpenSim.Framework
92 /// </summary> 150 /// </summary>
93 private static SmartThreadPool m_ThreadPool; 151 private static SmartThreadPool m_ThreadPool;
94 152
153 // Watchdog timer that aborts threads that have timed-out
154 private static Timer m_threadPoolWatchdog;
155
95 // 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. 156 // 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.
96 private static readonly DateTime unixEpoch = 157 public static readonly DateTime UnixEpoch =
97 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); 158 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
98 159
99 private static readonly string rawUUIDPattern 160 private static readonly string rawUUIDPattern
@@ -104,6 +165,11 @@ namespace OpenSim.Framework
104 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; 165 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
105 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; 166 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
106 167
168 public static bool IsPlatformMono
169 {
170 get { return Type.GetType("Mono.Runtime") != null; }
171 }
172
107 /// <summary> 173 /// <summary>
108 /// Gets the name of the directory where the current running executable 174 /// Gets the name of the directory where the current running executable
109 /// is located 175 /// is located
@@ -291,6 +357,49 @@ namespace OpenSim.Framework
291 return Utils.UIntsToLong(X, Y); 357 return Utils.UIntsToLong(X, Y);
292 } 358 }
293 359
360 // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong.
361 // Several places rely on the ability to extract a region's location from its handle.
362 // Note the location is in 'world coordinates' (see below).
363 // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0.
364 public static ulong RegionWorldLocToHandle(uint X, uint Y)
365 {
366 return Utils.UIntsToLong(X, Y);
367 }
368
369 public static ulong RegionLocToHandle(uint X, uint Y)
370 {
371 return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y));
372 }
373
374 public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y)
375 {
376 X = (uint)(handle >> 32);
377 Y = (uint)(handle & (ulong)uint.MaxValue);
378 }
379
380 public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y)
381 {
382 uint worldX, worldY;
383 RegionHandleToWorldLoc(handle, out worldX, out worldY);
384 X = WorldToRegionLoc(worldX);
385 Y = WorldToRegionLoc(worldY);
386 }
387
388 // A region location can be 'world coordinates' (meters from zero) or 'region coordinates'
389 // (number of regions from zero). This measurement of regions relies on the legacy 256 region size.
390 // These routines exist to make what is being converted explicit so the next person knows what was meant.
391 // Convert a region's 'world coordinate' to its 'region coordinate'.
392 public static uint WorldToRegionLoc(uint worldCoord)
393 {
394 return worldCoord / Constants.RegionSize;
395 }
396
397 // Convert a region's 'region coordinate' to its 'world coordinate'.
398 public static uint RegionToWorldLoc(uint regionCoord)
399 {
400 return regionCoord * Constants.RegionSize;
401 }
402
294 public static T Clamp<T>(T x, T min, T max) 403 public static T Clamp<T>(T x, T min, T max)
295 where T : IComparable<T> 404 where T : IComparable<T>
296 { 405 {
@@ -302,15 +411,31 @@ namespace OpenSim.Framework
302 // Clamp the maximum magnitude of a vector 411 // Clamp the maximum magnitude of a vector
303 public static Vector3 ClampV(Vector3 x, float max) 412 public static Vector3 ClampV(Vector3 x, float max)
304 { 413 {
305 Vector3 ret = x;
306 float lenSq = x.LengthSquared(); 414 float lenSq = x.LengthSquared();
307 if (lenSq > (max * max)) 415 if (lenSq > (max * max))
308 { 416 {
309 x = x / x.Length() * max; 417 x = x / x.Length() * max;
310 } 418 }
419
311 return x; 420 return x;
312 } 421 }
313 422
423 /// <summary>
424 /// Check if any of the values in a Vector3 are NaN or Infinity
425 /// </summary>
426 /// <param name="v">Vector3 to check</param>
427 /// <returns></returns>
428 public static bool IsNanOrInfinity(Vector3 v)
429 {
430 if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z))
431 return true;
432
433 if (float.IsInfinity(v.X) || float.IsInfinity(v.Y) || float.IsNaN(v.Z))
434 return true;
435
436 return false;
437 }
438
314 // Inclusive, within range test (true if equal to the endpoints) 439 // Inclusive, within range test (true if equal to the endpoints)
315 public static bool InRange<T>(T x, T min, T max) 440 public static bool InRange<T>(T x, T min, T max)
316 where T : IComparable<T> 441 where T : IComparable<T>
@@ -400,6 +525,19 @@ namespace OpenSim.Framework
400 return sb.ToString(); 525 return sb.ToString();
401 } 526 }
402 527
528 public static byte[] DocToBytes(XmlDocument doc)
529 {
530 using (MemoryStream ms = new MemoryStream())
531 using (XmlTextWriter xw = new XmlTextWriter(ms, null))
532 {
533 xw.Formatting = Formatting.Indented;
534 doc.WriteTo(xw);
535 xw.Flush();
536
537 return ms.ToArray();
538 }
539 }
540
403 /// <summary> 541 /// <summary>
404 /// Is the platform Windows? 542 /// Is the platform Windows?
405 /// </summary> 543 /// </summary>
@@ -416,6 +554,11 @@ namespace OpenSim.Framework
416 554
417 public static bool LoadArchSpecificWindowsDll(string libraryName) 555 public static bool LoadArchSpecificWindowsDll(string libraryName)
418 { 556 {
557 return LoadArchSpecificWindowsDll(libraryName, string.Empty);
558 }
559
560 public static bool LoadArchSpecificWindowsDll(string libraryName, string path)
561 {
419 // We do this so that OpenSimulator on Windows loads the correct native library depending on whether 562 // We do this so that OpenSimulator on Windows loads the correct native library depending on whether
420 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports 563 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
421 // will find it already loaded later on. 564 // will find it already loaded later on.
@@ -425,9 +568,9 @@ namespace OpenSim.Framework
425 string nativeLibraryPath; 568 string nativeLibraryPath;
426 569
427 if (Util.Is64BitProcess()) 570 if (Util.Is64BitProcess())
428 nativeLibraryPath = "lib64/" + libraryName; 571 nativeLibraryPath = Path.Combine(Path.Combine(path, "lib64"), libraryName);
429 else 572 else
430 nativeLibraryPath = "lib32/" + libraryName; 573 nativeLibraryPath = Path.Combine(Path.Combine(path, "lib32"), libraryName);
431 574
432 m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); 575 m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath);
433 576
@@ -479,20 +622,18 @@ namespace OpenSim.Framework
479 622
480 public static int ToUnixTime(DateTime stamp) 623 public static int ToUnixTime(DateTime stamp)
481 { 624 {
482 TimeSpan t = stamp.ToUniversalTime() - unixEpoch; 625 TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
483 return (int) t.TotalSeconds; 626 return (int)t.TotalSeconds;
484 } 627 }
485 628
486 public static DateTime ToDateTime(ulong seconds) 629 public static DateTime ToDateTime(ulong seconds)
487 { 630 {
488 DateTime epoch = unixEpoch; 631 return UnixEpoch.AddSeconds(seconds);
489 return epoch.AddSeconds(seconds);
490 } 632 }
491 633
492 public static DateTime ToDateTime(int seconds) 634 public static DateTime ToDateTime(int seconds)
493 { 635 {
494 DateTime epoch = unixEpoch; 636 return UnixEpoch.AddSeconds(seconds);
495 return epoch.AddSeconds(seconds);
496 } 637 }
497 638
498 /// <summary> 639 /// <summary>
@@ -664,16 +805,6 @@ namespace OpenSim.Framework
664 } 805 }
665 806
666 /// <summary> 807 /// <summary>
667 /// Converts a URL to a IPAddress
668 /// </summary>
669 /// <param name="url">URL Standard Format</param>
670 /// <returns>A resolved IP Address</returns>
671 public static IPAddress GetHostFromURL(string url)
672 {
673 return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]);
674 }
675
676 /// <summary>
677 /// Returns a IP address from a specified DNS, favouring IPv4 addresses. 808 /// Returns a IP address from a specified DNS, favouring IPv4 addresses.
678 /// </summary> 809 /// </summary>
679 /// <param name="dnsAddress">DNS Hostname</param> 810 /// <param name="dnsAddress">DNS Hostname</param>
@@ -763,6 +894,54 @@ namespace OpenSim.Framework
763 } 894 }
764 895
765 /// <summary> 896 /// <summary>
897 /// Parses a foreign asset ID.
898 /// </summary>
899 /// <param name="id">A possibly-foreign asset ID: http://grid.example.com:8002/00000000-0000-0000-0000-000000000000 </param>
900 /// <param name="url">The URL: http://grid.example.com:8002</param>
901 /// <param name="assetID">The asset ID: 00000000-0000-0000-0000-000000000000. Returned even if 'id' isn't foreign.</param>
902 /// <returns>True: this is a foreign asset ID; False: it isn't</returns>
903 public static bool ParseForeignAssetID(string id, out string url, out string assetID)
904 {
905 url = String.Empty;
906 assetID = String.Empty;
907
908 UUID uuid;
909 if (UUID.TryParse(id, out uuid))
910 {
911 assetID = uuid.ToString();
912 return false;
913 }
914
915 if ((id.Length == 0) || (id[0] != 'h' && id[0] != 'H'))
916 return false;
917
918 Uri assetUri;
919 if (!Uri.TryCreate(id, UriKind.Absolute, out assetUri) || assetUri.Scheme != Uri.UriSchemeHttp)
920 return false;
921
922 // Simian
923 if (assetUri.Query != string.Empty)
924 {
925 NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query);
926 assetID = qscoll["id"];
927 if (assetID != null)
928 url = id.Replace(assetID, ""); // Malformed again, as simian expects
929 else
930 url = id; // !!! best effort
931 }
932 else // robust
933 {
934 url = "http://" + assetUri.Authority;
935 assetID = assetUri.LocalPath.Trim(new char[] { '/' });
936 }
937
938 if (!UUID.TryParse(assetID, out uuid))
939 return false;
940
941 return true;
942 }
943
944 /// <summary>
766 /// Removes all invalid path chars (OS dependent) 945 /// Removes all invalid path chars (OS dependent)
767 /// </summary> 946 /// </summary>
768 /// <param name="path">path</param> 947 /// <param name="path">path</param>
@@ -816,9 +995,22 @@ namespace OpenSim.Framework
816 return "."; 995 return ".";
817 } 996 }
818 997
998 public static string logFile()
999 {
1000 foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
1001 {
1002 if (appender is FileAppender)
1003 {
1004 return ((FileAppender)appender).File;
1005 }
1006 }
1007
1008 return "./OpenSim.log";
1009 }
1010
819 public static string logDir() 1011 public static string logDir()
820 { 1012 {
821 return "."; 1013 return Path.GetDirectoryName(logFile());
822 } 1014 }
823 1015
824 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html 1016 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
@@ -849,12 +1041,13 @@ namespace OpenSim.Framework
849 return FileName; 1041 return FileName;
850 } 1042 }
851 1043
852 // Nini (config) related Methods 1044 #region Nini (config) related Methods
1045
853 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) 1046 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName)
854 { 1047 {
855 if (!File.Exists(fileName)) 1048 if (!File.Exists(fileName))
856 { 1049 {
857 //create new file 1050 // create new file
858 } 1051 }
859 XmlConfigSource config = new XmlConfigSource(fileName); 1052 XmlConfigSource config = new XmlConfigSource(fileName);
860 AddDataRowToConfig(config, row); 1053 AddDataRowToConfig(config, row);
@@ -872,6 +1065,202 @@ namespace OpenSim.Framework
872 } 1065 }
873 } 1066 }
874 1067
1068 /// <summary>
1069 /// Gets the value of a configuration variable by looking into
1070 /// multiple sections in order. The latter sections overwrite
1071 /// any values previously found.
1072 /// </summary>
1073 /// <typeparam name="T">Type of the variable</typeparam>
1074 /// <param name="config">The configuration object</param>
1075 /// <param name="varname">The configuration variable</param>
1076 /// <param name="sections">Ordered sequence of sections to look at</param>
1077 /// <returns></returns>
1078 public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections)
1079 {
1080 return GetConfigVarFromSections<T>(config, varname, sections, default(T));
1081 }
1082
1083 /// <summary>
1084 /// Gets the value of a configuration variable by looking into
1085 /// multiple sections in order. The latter sections overwrite
1086 /// any values previously found.
1087 /// </summary>
1088 /// <remarks>
1089 /// If no value is found then the given default value is returned
1090 /// </remarks>
1091 /// <typeparam name="T">Type of the variable</typeparam>
1092 /// <param name="config">The configuration object</param>
1093 /// <param name="varname">The configuration variable</param>
1094 /// <param name="sections">Ordered sequence of sections to look at</param>
1095 /// <param name="val">Default value</param>
1096 /// <returns></returns>
1097 public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections, object val)
1098 {
1099 foreach (string section in sections)
1100 {
1101 IConfig cnf = config.Configs[section];
1102 if (cnf == null)
1103 continue;
1104
1105 if (typeof(T) == typeof(String))
1106 val = cnf.GetString(varname, (string)val);
1107 else if (typeof(T) == typeof(Boolean))
1108 val = cnf.GetBoolean(varname, (bool)val);
1109 else if (typeof(T) == typeof(Int32))
1110 val = cnf.GetInt(varname, (int)val);
1111 else if (typeof(T) == typeof(float))
1112 val = cnf.GetFloat(varname, (float)val);
1113 else
1114 m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T));
1115 }
1116
1117 return (T)val;
1118 }
1119
1120 public static void MergeEnvironmentToConfig(IConfigSource ConfigSource)
1121 {
1122 IConfig enVars = ConfigSource.Configs["Environment"];
1123 // if section does not exist then user isn't expecting them, so don't bother.
1124 if( enVars != null )
1125 {
1126 // load the values from the environment
1127 EnvConfigSource envConfigSource = new EnvConfigSource();
1128 // add the requested keys
1129 string[] env_keys = enVars.GetKeys();
1130 foreach ( string key in env_keys )
1131 {
1132 envConfigSource.AddEnv(key, string.Empty);
1133 }
1134 // load the values from environment
1135 envConfigSource.LoadEnv();
1136 // add them in to the master
1137 ConfigSource.Merge(envConfigSource);
1138 ConfigSource.ExpandKeyValues();
1139 }
1140 }
1141
1142 public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass)
1143 {
1144 Type settingsType = settingsClass.GetType();
1145
1146 FieldInfo[] fieldInfos = settingsType.GetFields();
1147 foreach (FieldInfo fieldInfo in fieldInfos)
1148 {
1149 if (!fieldInfo.IsStatic)
1150 {
1151 if (fieldInfo.FieldType == typeof(System.String))
1152 {
1153 fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
1154 }
1155 else if (fieldInfo.FieldType == typeof(System.Boolean))
1156 {
1157 fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
1158 }
1159 else if (fieldInfo.FieldType == typeof(System.Int32))
1160 {
1161 fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
1162 }
1163 else if (fieldInfo.FieldType == typeof(System.Single))
1164 {
1165 fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
1166 }
1167 else if (fieldInfo.FieldType == typeof(System.UInt32))
1168 {
1169 fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
1170 }
1171 }
1172 }
1173
1174 PropertyInfo[] propertyInfos = settingsType.GetProperties();
1175 foreach (PropertyInfo propInfo in propertyInfos)
1176 {
1177 if ((propInfo.CanRead) && (propInfo.CanWrite))
1178 {
1179 if (propInfo.PropertyType == typeof(System.String))
1180 {
1181 propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
1182 }
1183 else if (propInfo.PropertyType == typeof(System.Boolean))
1184 {
1185 propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
1186 }
1187 else if (propInfo.PropertyType == typeof(System.Int32))
1188 {
1189 propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
1190 }
1191 else if (propInfo.PropertyType == typeof(System.Single))
1192 {
1193 propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
1194 }
1195 if (propInfo.PropertyType == typeof(System.UInt32))
1196 {
1197 propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
1198 }
1199 }
1200 }
1201
1202 return settingsClass;
1203 }
1204
1205 /// <summary>
1206 /// Reads a configuration file, configFile, merging it with the main configuration, config.
1207 /// If the file doesn't exist, it copies a given exampleConfigFile onto configFile, and then
1208 /// merges it.
1209 /// </summary>
1210 /// <param name="config">The main configuration data</param>
1211 /// <param name="configFileName">The name of a configuration file in ConfigDirectory variable, no path</param>
1212 /// <param name="exampleConfigFile">Full path to an example configuration file</param>
1213 /// <param name="configFilePath">Full path ConfigDirectory/configFileName</param>
1214 /// <param name="created">True if the file was created in ConfigDirectory, false if it existed</param>
1215 /// <returns>True if success</returns>
1216 public static bool MergeConfigurationFile(IConfigSource config, string configFileName, string exampleConfigFile, out string configFilePath, out bool created)
1217 {
1218 created = false;
1219 configFilePath = string.Empty;
1220
1221 IConfig cnf = config.Configs["Startup"];
1222 if (cnf == null)
1223 {
1224 m_log.WarnFormat("[UTILS]: Startup section doesn't exist");
1225 return false;
1226 }
1227
1228 string configDirectory = cnf.GetString("ConfigDirectory", ".");
1229 string configFile = Path.Combine(configDirectory, configFileName);
1230
1231 if (!File.Exists(configFile) && !string.IsNullOrEmpty(exampleConfigFile))
1232 {
1233 // We need to copy the example onto it
1234
1235 if (!Directory.Exists(configDirectory))
1236 Directory.CreateDirectory(configDirectory);
1237
1238 try
1239 {
1240 File.Copy(exampleConfigFile, configFile);
1241 created = true;
1242 }
1243 catch (Exception e)
1244 {
1245 m_log.WarnFormat("[UTILS]: Exception copying configuration file {0} to {1}: {2}", configFile, exampleConfigFile, e.Message);
1246 return false;
1247 }
1248 }
1249
1250 if (File.Exists(configFile))
1251 {
1252 // Merge
1253 config.Merge(new IniConfigSource(configFile));
1254 config.ExpandKeyValues();
1255 configFilePath = configFile;
1256 return true;
1257 }
1258 else
1259 return false;
1260 }
1261
1262 #endregion
1263
875 public static float Clip(float x, float min, float max) 1264 public static float Clip(float x, float min, float max)
876 { 1265 {
877 return Math.Min(Math.Max(x, min), max); 1266 return Math.Min(Math.Max(x, min), max);
@@ -999,46 +1388,6 @@ namespace OpenSim.Framework
999 return ret; 1388 return ret;
1000 } 1389 }
1001 1390
1002 public static string Compress(string text)
1003 {
1004 byte[] buffer = Util.UTF8.GetBytes(text);
1005 MemoryStream memory = new MemoryStream();
1006 using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true))
1007 {
1008 compressor.Write(buffer, 0, buffer.Length);
1009 }
1010
1011 memory.Position = 0;
1012
1013 byte[] compressed = new byte[memory.Length];
1014 memory.Read(compressed, 0, compressed.Length);
1015
1016 byte[] compressedBuffer = new byte[compressed.Length + 4];
1017 Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length);
1018 Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4);
1019 return Convert.ToBase64String(compressedBuffer);
1020 }
1021
1022 public static string Decompress(string compressedText)
1023 {
1024 byte[] compressedBuffer = Convert.FromBase64String(compressedText);
1025 using (MemoryStream memory = new MemoryStream())
1026 {
1027 int msgLength = BitConverter.ToInt32(compressedBuffer, 0);
1028 memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4);
1029
1030 byte[] buffer = new byte[msgLength];
1031
1032 memory.Position = 0;
1033 using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress))
1034 {
1035 decompressor.Read(buffer, 0, buffer.Length);
1036 }
1037
1038 return Util.UTF8.GetString(buffer);
1039 }
1040 }
1041
1042 /// <summary> 1391 /// <summary>
1043 /// Copy data from one stream to another, leaving the read position of both streams at the beginning. 1392 /// Copy data from one stream to another, leaving the read position of both streams at the beginning.
1044 /// </summary> 1393 /// </summary>
@@ -1119,7 +1468,7 @@ namespace OpenSim.Framework
1119 byte[] bytes = 1468 byte[] bytes =
1120 { 1469 {
1121 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), 1470 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1122 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), 1471 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1123 (byte)x, (byte)(x >> 8), 0, 0, 1472 (byte)x, (byte)(x >> 8), 0, 0,
1124 (byte)y, (byte)(y >> 8), 0, 0 }; 1473 (byte)y, (byte)(y >> 8), 0, 0 };
1125 return new UUID(bytes, 0); 1474 return new UUID(bytes, 0);
@@ -1130,7 +1479,7 @@ namespace OpenSim.Framework
1130 byte[] bytes = 1479 byte[] bytes =
1131 { 1480 {
1132 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), 1481 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1133 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), 1482 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1134 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), 1483 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
1135 (byte)y, (byte)(y >> 8), 0, 0 }; 1484 (byte)y, (byte)(y >> 8), 0, 0 };
1136 return new UUID(bytes, 0); 1485 return new UUID(bytes, 0);
@@ -1203,7 +1552,7 @@ namespace OpenSim.Framework
1203 ru = "OSX/Mono"; 1552 ru = "OSX/Mono";
1204 else 1553 else
1205 { 1554 {
1206 if (Type.GetType("Mono.Runtime") != null) 1555 if (IsPlatformMono)
1207 ru = "Win/Mono"; 1556 ru = "Win/Mono";
1208 else 1557 else
1209 ru = "Win/.NET"; 1558 ru = "Win/.NET";
@@ -1242,69 +1591,6 @@ namespace OpenSim.Framework
1242 return displayConnectionString; 1591 return displayConnectionString;
1243 } 1592 }
1244 1593
1245 public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass)
1246 {
1247 Type settingsType = settingsClass.GetType();
1248
1249 FieldInfo[] fieldInfos = settingsType.GetFields();
1250 foreach (FieldInfo fieldInfo in fieldInfos)
1251 {
1252 if (!fieldInfo.IsStatic)
1253 {
1254 if (fieldInfo.FieldType == typeof(System.String))
1255 {
1256 fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
1257 }
1258 else if (fieldInfo.FieldType == typeof(System.Boolean))
1259 {
1260 fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
1261 }
1262 else if (fieldInfo.FieldType == typeof(System.Int32))
1263 {
1264 fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
1265 }
1266 else if (fieldInfo.FieldType == typeof(System.Single))
1267 {
1268 fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
1269 }
1270 else if (fieldInfo.FieldType == typeof(System.UInt32))
1271 {
1272 fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
1273 }
1274 }
1275 }
1276
1277 PropertyInfo[] propertyInfos = settingsType.GetProperties();
1278 foreach (PropertyInfo propInfo in propertyInfos)
1279 {
1280 if ((propInfo.CanRead) && (propInfo.CanWrite))
1281 {
1282 if (propInfo.PropertyType == typeof(System.String))
1283 {
1284 propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
1285 }
1286 else if (propInfo.PropertyType == typeof(System.Boolean))
1287 {
1288 propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
1289 }
1290 else if (propInfo.PropertyType == typeof(System.Int32))
1291 {
1292 propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
1293 }
1294 else if (propInfo.PropertyType == typeof(System.Single))
1295 {
1296 propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
1297 }
1298 if (propInfo.PropertyType == typeof(System.UInt32))
1299 {
1300 propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
1301 }
1302 }
1303 }
1304
1305 return settingsClass;
1306 }
1307
1308 public static string Base64ToString(string str) 1594 public static string Base64ToString(string str)
1309 { 1595 {
1310 Decoder utf8Decode = Encoding.UTF8.GetDecoder(); 1596 Decoder utf8Decode = Encoding.UTF8.GetDecoder();
@@ -1317,6 +1603,46 @@ namespace OpenSim.Framework
1317 return result; 1603 return result;
1318 } 1604 }
1319 1605
1606 public static void BinaryToASCII(char[] chars)
1607 {
1608 for (int i = 0; i < chars.Length; i++)
1609 {
1610 char ch = chars[i];
1611 if (ch < 32 || ch > 127)
1612 chars[i] = '.';
1613 }
1614 }
1615
1616 public static string BinaryToASCII(string src)
1617 {
1618 char[] chars = src.ToCharArray();
1619 BinaryToASCII(chars);
1620 return new String(chars);
1621 }
1622
1623 /// <summary>
1624 /// Reads a known number of bytes from a stream.
1625 /// Throws EndOfStreamException if the stream doesn't contain enough data.
1626 /// </summary>
1627 /// <param name="stream">The stream to read data from</param>
1628 /// <param name="data">The array to write bytes into. The array
1629 /// will be completely filled from the stream, so an appropriate
1630 /// size must be given.</param>
1631 public static void ReadStream(Stream stream, byte[] data)
1632 {
1633 int offset = 0;
1634 int remaining = data.Length;
1635
1636 while (remaining > 0)
1637 {
1638 int read = stream.Read(data, offset, remaining);
1639 if (read <= 0)
1640 throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining));
1641 remaining -= read;
1642 offset += read;
1643 }
1644 }
1645
1320 public static Guid GetHashGuid(string data, string salt) 1646 public static Guid GetHashGuid(string data, string salt)
1321 { 1647 {
1322 byte[] hash = ComputeMD5Hash(data + salt); 1648 byte[] hash = ComputeMD5Hash(data + salt);
@@ -1466,32 +1792,6 @@ namespace OpenSim.Framework
1466 return found.ToArray(); 1792 return found.ToArray();
1467 } 1793 }
1468 1794
1469 public static string ServerURI(string uri)
1470 {
1471 if (uri == string.Empty)
1472 return string.Empty;
1473
1474 // Get rid of eventual slashes at the end
1475 uri = uri.TrimEnd('/');
1476
1477 IPAddress ipaddr1 = null;
1478 string port1 = "";
1479 try
1480 {
1481 ipaddr1 = Util.GetHostFromURL(uri);
1482 }
1483 catch { }
1484
1485 try
1486 {
1487 port1 = uri.Split(new char[] { ':' })[2];
1488 }
1489 catch { }
1490
1491 // We tried our best to convert the domain names to IP addresses
1492 return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
1493 }
1494
1495 /// <summary> 1795 /// <summary>
1496 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. 1796 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
1497 /// </summary> 1797 /// </summary>
@@ -1518,17 +1818,26 @@ namespace OpenSim.Framework
1518 /// <returns></returns> 1818 /// <returns></returns>
1519 public static byte[] StringToBytes256(string str) 1819 public static byte[] StringToBytes256(string str)
1520 { 1820 {
1521 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } 1821 if (String.IsNullOrEmpty(str))
1522 if (str.Length > 254) str = str.Remove(254); 1822 return Utils.EmptyBytes;
1523 if (!str.EndsWith("\0")) { str += "\0"; } 1823
1824 if (!str.EndsWith("\0"))
1825 str += "\0";
1524 1826
1525 // Because this is UTF-8 encoding and not ASCII, it's possible we 1827 // Because this is UTF-8 encoding and not ASCII, it's possible we
1526 // might have gotten an oversized array even after the string trim 1828 // might have gotten an oversized array even after the string trim
1527 byte[] data = UTF8.GetBytes(str); 1829 byte[] data = UTF8.GetBytes(str);
1830
1528 if (data.Length > 256) 1831 if (data.Length > 256)
1529 { 1832 {
1530 Array.Resize<byte>(ref data, 256); 1833 int cut = 255;
1531 data[255] = 0; 1834 if((data[cut] & 0x80 ) != 0 )
1835 {
1836 while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
1837 cut--;
1838 }
1839 Array.Resize<byte>(ref data, cut + 1);
1840 data[cut] = 0;
1532 } 1841 }
1533 1842
1534 return data; 1843 return data;
@@ -1560,23 +1869,56 @@ namespace OpenSim.Framework
1560 /// <returns></returns> 1869 /// <returns></returns>
1561 public static byte[] StringToBytes1024(string str) 1870 public static byte[] StringToBytes1024(string str)
1562 { 1871 {
1563 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } 1872 if (String.IsNullOrEmpty(str))
1564 if (str.Length > 1023) str = str.Remove(1023); 1873 return Utils.EmptyBytes;
1565 if (!str.EndsWith("\0")) { str += "\0"; } 1874
1875 if (!str.EndsWith("\0"))
1876 str += "\0";
1566 1877
1567 // Because this is UTF-8 encoding and not ASCII, it's possible we 1878 // Because this is UTF-8 encoding and not ASCII, it's possible we
1568 // might have gotten an oversized array even after the string trim 1879 // might have gotten an oversized array even after the string trim
1569 byte[] data = UTF8.GetBytes(str); 1880 byte[] data = UTF8.GetBytes(str);
1881
1570 if (data.Length > 1024) 1882 if (data.Length > 1024)
1571 { 1883 {
1572 Array.Resize<byte>(ref data, 1024); 1884 int cut = 1023;
1573 data[1023] = 0; 1885 if((data[cut] & 0x80 ) != 0 )
1886 {
1887 while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
1888 cut--;
1889 }
1890 Array.Resize<byte>(ref data, cut + 1);
1891 data[cut] = 0;
1574 } 1892 }
1575 1893
1576 return data; 1894 return data;
1577 } 1895 }
1578 1896
1579 /// <summary> 1897 /// <summary>
1898 /// Pretty format the hashtable contents to a single line.
1899 /// </summary>
1900 /// <remarks>
1901 /// Used for debugging output.
1902 /// </remarks>
1903 /// <param name='ht'></param>
1904 public static string PrettyFormatToSingleLine(Hashtable ht)
1905 {
1906 StringBuilder sb = new StringBuilder();
1907
1908 int i = 0;
1909
1910 foreach (string key in ht.Keys)
1911 {
1912 sb.AppendFormat("{0}:{1}", key, ht[key]);
1913
1914 if (++i < ht.Count)
1915 sb.AppendFormat(", ");
1916 }
1917
1918 return sb.ToString();
1919 }
1920
1921 /// <summary>
1580 /// Used to trigger an early library load on Windows systems. 1922 /// Used to trigger an early library load on Windows systems.
1581 /// </summary> 1923 /// </summary>
1582 /// <remarks> 1924 /// <remarks>
@@ -1646,25 +1988,28 @@ namespace OpenSim.Framework
1646 } 1988 }
1647 } 1989 }
1648 1990
1649 public static void FireAndForget(System.Threading.WaitCallback callback) 1991 public static void InitThreadPool(int minThreads, int maxThreads)
1650 {
1651 FireAndForget(callback, null);
1652 }
1653
1654 public static void InitThreadPool(int maxThreads)
1655 { 1992 {
1656 if (maxThreads < 2) 1993 if (maxThreads < 2)
1657 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); 1994 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
1995
1996 if (minThreads > maxThreads || minThreads < 2)
1997 throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads");
1998
1658 if (m_ThreadPool != null) 1999 if (m_ThreadPool != null)
1659 throw new InvalidOperationException("SmartThreadPool is already initialized"); 2000 {
2001 m_log.Warn("SmartThreadPool is already initialized. Ignoring request.");
2002 return;
2003 }
1660 2004
1661 STPStartInfo startInfo = new STPStartInfo(); 2005 STPStartInfo startInfo = new STPStartInfo();
1662 startInfo.ThreadPoolName = "Util"; 2006 startInfo.ThreadPoolName = "Util";
1663 startInfo.IdleTimeout = 2000; 2007 startInfo.IdleTimeout = 2000;
1664 startInfo.MaxWorkerThreads = maxThreads; 2008 startInfo.MaxWorkerThreads = maxThreads;
1665 startInfo.MinWorkerThreads = 2; 2009 startInfo.MinWorkerThreads = minThreads;
1666 2010
1667 m_ThreadPool = new SmartThreadPool(startInfo); 2011 m_ThreadPool = new SmartThreadPool(startInfo);
2012 m_threadPoolWatchdog = new Timer(ThreadPoolWatchdog, null, 0, 1000);
1668 } 2013 }
1669 2014
1670 public static int FireAndForgetCount() 2015 public static int FireAndForgetCount()
@@ -1687,15 +2032,179 @@ namespace OpenSim.Framework
1687 throw new NotImplementedException(); 2032 throw new NotImplementedException();
1688 } 2033 }
1689 } 2034 }
2035
2036 /// <summary>
2037 /// Additional information about threads in the main thread pool. Used to time how long the
2038 /// thread has been running, and abort it if it has timed-out.
2039 /// </summary>
2040 private class ThreadInfo
2041 {
2042 public long ThreadFuncNum { get; set; }
2043 public string StackTrace { get; set; }
2044 private string context;
2045 public bool LogThread { get; set; }
2046
2047 public IWorkItemResult WorkItem { get; set; }
2048 public Thread Thread { get; set; }
2049 public bool Running { get; set; }
2050 public bool Aborted { get; set; }
2051 private int started;
2052
2053 public ThreadInfo(long threadFuncNum, string context)
2054 {
2055 ThreadFuncNum = threadFuncNum;
2056 this.context = context;
2057 LogThread = false;
2058 Thread = null;
2059 Running = false;
2060 Aborted = false;
2061 }
2062
2063 public void Started()
2064 {
2065 Thread = Thread.CurrentThread;
2066 started = EnvironmentTickCount();
2067 Running = true;
2068 }
2069
2070 public void Ended()
2071 {
2072 Running = false;
2073 }
2074
2075 public int Elapsed()
2076 {
2077 return EnvironmentTickCountSubtract(started);
2078 }
2079
2080 public void Abort()
2081 {
2082 Aborted = true;
2083 WorkItem.Cancel(true);
2084 }
2085
2086 /// <summary>
2087 /// Returns the thread's stack trace.
2088 /// </summary>
2089 /// <remarks>
2090 /// May return one of two stack traces. First, tries to get the thread's active stack
2091 /// trace. But this can fail, so as a fallback this method will return the stack
2092 /// trace that was active when the task was queued.
2093 /// </remarks>
2094 public string GetStackTrace()
2095 {
2096 string ret = (context == null) ? "" : ("(" + context + ") ");
2097
2098 StackTrace activeStackTrace = Util.GetStackTrace(Thread);
2099 if (activeStackTrace != null)
2100 ret += activeStackTrace.ToString();
2101 else if (StackTrace != null)
2102 ret += "(Stack trace when queued) " + StackTrace;
2103 // else, no stack trace available
2104
2105 return ret;
2106 }
2107 }
2108
2109 private static long nextThreadFuncNum = 0;
2110 private static long numQueuedThreadFuncs = 0;
2111 private static long numRunningThreadFuncs = 0;
2112 private static long numTotalThreadFuncsCalled = 0;
2113 private static Int32 threadFuncOverloadMode = 0;
2114
2115 public static long TotalQueuedFireAndForgetCalls { get { return numQueuedThreadFuncs; } }
2116 public static long TotalRunningFireAndForgetCalls { get { return numRunningThreadFuncs; } }
2117
2118 // Maps (ThreadFunc number -> Thread)
2119 private static ConcurrentDictionary<long, ThreadInfo> activeThreads = new ConcurrentDictionary<long, ThreadInfo>();
2120
2121 private static readonly int THREAD_TIMEOUT = 10 * 60 * 1000; // 10 minutes
2122
2123 /// <summary>
2124 /// Finds threads in the main thread pool that have timed-out, and aborts them.
2125 /// </summary>
2126 private static void ThreadPoolWatchdog(object state)
2127 {
2128 foreach (KeyValuePair<long, ThreadInfo> entry in activeThreads)
2129 {
2130 ThreadInfo t = entry.Value;
2131 if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT))
2132 {
2133 m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace());
2134 t.Abort();
2135
2136 ThreadInfo dummy;
2137 activeThreads.TryRemove(entry.Key, out dummy);
2138
2139 // It's possible that the thread won't abort. To make sure the thread pool isn't
2140 // depleted, increase the pool size.
2141 m_ThreadPool.MaxThreads++;
2142 }
2143 }
2144 }
2145
2146 public static long TotalFireAndForgetCallsMade { get { return numTotalThreadFuncsCalled; } }
2147
2148 public static Dictionary<string, int> GetFireAndForgetCallsMade()
2149 {
2150 return new Dictionary<string, int>(m_fireAndForgetCallsMade);
2151 }
2152
2153 private static Dictionary<string, int> m_fireAndForgetCallsMade = new Dictionary<string, int>();
2154
2155 public static Dictionary<string, int> GetFireAndForgetCallsInProgress()
2156 {
2157 return new Dictionary<string, int>(m_fireAndForgetCallsInProgress);
2158 }
2159
2160 private static Dictionary<string, int> m_fireAndForgetCallsInProgress = new Dictionary<string, int>();
2161
2162 public static void FireAndForget(System.Threading.WaitCallback callback)
2163 {
2164 FireAndForget(callback, null, null);
2165 }
1690 2166
1691 public static void FireAndForget(System.Threading.WaitCallback callback, object obj) 2167 public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
1692 { 2168 {
2169 FireAndForget(callback, obj, null);
2170 }
2171
2172 public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context)
2173 {
2174 Interlocked.Increment(ref numTotalThreadFuncsCalled);
2175
2176 if (context != null)
2177 {
2178 if (!m_fireAndForgetCallsMade.ContainsKey(context))
2179 m_fireAndForgetCallsMade[context] = 1;
2180 else
2181 m_fireAndForgetCallsMade[context]++;
2182
2183 if (!m_fireAndForgetCallsInProgress.ContainsKey(context))
2184 m_fireAndForgetCallsInProgress[context] = 1;
2185 else
2186 m_fireAndForgetCallsInProgress[context]++;
2187 }
2188
1693 WaitCallback realCallback; 2189 WaitCallback realCallback;
1694 2190
2191 bool loggingEnabled = LogThreadPool > 0;
2192
2193 long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum);
2194 ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context);
2195
1695 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) 2196 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
1696 { 2197 {
1697 // If we're running regression tests, then we want any exceptions to rise up to the test code. 2198 // If we're running regression tests, then we want any exceptions to rise up to the test code.
1698 realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; 2199 realCallback =
2200 o =>
2201 {
2202 Culture.SetCurrentCulture();
2203 callback(o);
2204
2205 if (context != null)
2206 m_fireAndForgetCallsInProgress[context]--;
2207 };
1699 } 2208 }
1700 else 2209 else
1701 { 2210 {
@@ -1704,118 +2213,291 @@ namespace OpenSim.Framework
1704 // for decimals places but is read by a culture that treats commas as number seperators. 2213 // for decimals places but is read by a culture that treats commas as number seperators.
1705 realCallback = o => 2214 realCallback = o =>
1706 { 2215 {
1707 Culture.SetCurrentCulture(); 2216 long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs);
2217 long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs);
2218 threadInfo.Started();
2219 activeThreads[threadFuncNum] = threadInfo;
1708 2220
1709 try 2221 try
1710 { 2222 {
2223 if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
2224 m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1);
2225
2226 Culture.SetCurrentCulture();
2227
1711 callback(o); 2228 callback(o);
1712 } 2229 }
2230 catch (ThreadAbortException e)
2231 {
2232 m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e);
2233 }
1713 catch (Exception e) 2234 catch (Exception e)
1714 { 2235 {
1715 m_log.ErrorFormat( 2236 m_log.Error(string.Format("[UTIL]: Util STP threadfunc {0} terminated with error ", threadFuncNum), e);
1716 "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", 2237 }
1717 e.Message, e.StackTrace); 2238 finally
2239 {
2240 Interlocked.Decrement(ref numRunningThreadFuncs);
2241 threadInfo.Ended();
2242 ThreadInfo dummy;
2243 activeThreads.TryRemove(threadFuncNum, out dummy);
2244 if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
2245 m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed()));
2246
2247 if (context != null)
2248 m_fireAndForgetCallsInProgress[context]--;
1718 } 2249 }
1719 }; 2250 };
1720 } 2251 }
1721 2252
1722 switch (FireAndForgetMethod) 2253 long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs);
2254 try
1723 { 2255 {
1724 case FireAndForgetMethod.RegressionTest: 2256 long numRunning = numRunningThreadFuncs;
1725 case FireAndForgetMethod.None: 2257
1726 realCallback.Invoke(obj); 2258 if (m_ThreadPool != null && LogOverloads)
1727 break; 2259 {
1728 case FireAndForgetMethod.UnsafeQueueUserWorkItem: 2260 if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads))
1729 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); 2261 {
1730 break; 2262 if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0)
1731 case FireAndForgetMethod.QueueUserWorkItem: 2263 m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning);
1732 ThreadPool.QueueUserWorkItem(realCallback, obj); 2264 }
1733 break; 2265 else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads * 2) / 3))
1734 case FireAndForgetMethod.BeginInvoke: 2266 {
1735 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; 2267 if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1)
1736 wrapper.FireAndForget(realCallback, obj); 2268 m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning);
1737 break; 2269 }
1738 case FireAndForgetMethod.SmartThreadPool: 2270 }
1739 if (m_ThreadPool == null) 2271
1740 InitThreadPool(15); 2272 if (loggingEnabled || (threadFuncOverloadMode == 1))
1741 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 2273 {
1742 break; 2274 string full, partial;
1743 case FireAndForgetMethod.Thread: 2275 GetFireAndForgetStackTrace(out full, out partial);
1744 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 2276 threadInfo.StackTrace = full;
1745 thread.Start(obj); 2277 threadInfo.LogThread = ShouldLogThread(partial);
1746 break; 2278
1747 default: 2279 if (threadInfo.LogThread)
1748 throw new NotImplementedException(); 2280 {
2281 m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}",
2282 threadFuncNum, numQueued, numRunningThreadFuncs,
2283 (context == null) ? "" : ("(" + context + ") "),
2284 (LogThreadPool >= 2) ? full : partial);
2285 }
2286 }
2287 else
2288 {
2289 // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either.
2290 // Those log lines aren't useful when we don't know which function is running in the thread.
2291 threadInfo.LogThread = false;
2292 }
2293
2294 switch (FireAndForgetMethod)
2295 {
2296 case FireAndForgetMethod.RegressionTest:
2297 case FireAndForgetMethod.None:
2298 realCallback.Invoke(obj);
2299 break;
2300 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
2301 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj);
2302 break;
2303 case FireAndForgetMethod.QueueUserWorkItem:
2304 ThreadPool.QueueUserWorkItem(realCallback, obj);
2305 break;
2306 case FireAndForgetMethod.BeginInvoke:
2307 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance;
2308 wrapper.FireAndForget(realCallback, obj);
2309 break;
2310 case FireAndForgetMethod.SmartThreadPool:
2311 if (m_ThreadPool == null)
2312 InitThreadPool(2, 15);
2313 threadInfo.WorkItem = m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
2314 break;
2315 case FireAndForgetMethod.Thread:
2316 Thread thread = new Thread(delegate(object o) { realCallback(o); });
2317 thread.Start(obj);
2318 break;
2319 default:
2320 throw new NotImplementedException();
2321 }
2322 }
2323 catch (Exception)
2324 {
2325 Interlocked.Decrement(ref numQueuedThreadFuncs);
2326 ThreadInfo dummy;
2327 activeThreads.TryRemove(threadFuncNum, out dummy);
2328 throw;
1749 } 2329 }
1750 } 2330 }
1751 2331
1752 /// <summary> 2332 /// <summary>
1753 /// Get a thread pool report. 2333 /// Returns whether the thread should be logged. Some very common threads aren't logged,
2334 /// to avoid filling up the log.
1754 /// </summary> 2335 /// </summary>
1755 /// <returns></returns> 2336 /// <param name="stackTrace">A partial stack trace of where the thread was queued</param>
1756 public static string GetThreadPoolReport() 2337 /// <returns>Whether to log this thread</returns>
2338 private static bool ShouldLogThread(string stackTrace)
1757 { 2339 {
1758 string threadPoolUsed = null; 2340 if (LogThreadPool < 3)
1759 int maxThreads = 0; 2341 {
1760 int minThreads = 0; 2342 if (stackTrace.Contains("BeginFireQueueEmpty"))
1761 int allocatedThreads = 0; 2343 return false;
1762 int inUseThreads = 0; 2344 }
1763 int waitingCallbacks = 0; 2345
1764 int completionPortThreads = 0; 2346 return true;
2347 }
1765 2348
1766 StringBuilder sb = new StringBuilder(); 2349 /// <summary>
1767 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) 2350 /// Returns a stack trace for a thread added using FireAndForget().
2351 /// </summary>
2352 /// <param name="full">Will contain the full stack trace</param>
2353 /// <param name="partial">Will contain only the first frame of the stack trace</param>
2354 private static void GetFireAndForgetStackTrace(out string full, out string partial)
2355 {
2356 string src = Environment.StackTrace;
2357 string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
2358
2359 StringBuilder dest = new StringBuilder(src.Length);
2360
2361 bool started = false;
2362 bool first = true;
2363 partial = "";
2364
2365 for (int i = 0; i < lines.Length; i++)
1768 { 2366 {
1769 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. 2367 string line = lines[i];
1770 if (m_ThreadPool != null) 2368
2369 if (!started)
2370 {
2371 // Skip the initial stack frames, because they're of no interest for debugging
2372 if (line.Contains("StackTrace") || line.Contains("FireAndForget"))
2373 continue;
2374 started = true;
2375 }
2376
2377 if (first)
1771 { 2378 {
1772 threadPoolUsed = "SmartThreadPool"; 2379 line = line.TrimStart();
1773 maxThreads = m_ThreadPool.MaxThreads; 2380 first = false;
1774 minThreads = m_ThreadPool.MinThreads; 2381 partial = line;
1775 inUseThreads = m_ThreadPool.InUseThreads;
1776 allocatedThreads = m_ThreadPool.ActiveThreads;
1777 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1778 } 2382 }
2383
2384 bool last = (i == lines.Length - 1);
2385 if (last)
2386 dest.Append(line);
2387 else
2388 dest.AppendLine(line);
1779 } 2389 }
1780 else if ( 2390
1781 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem 2391 full = dest.ToString();
1782 || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) 2392 }
2393
2394#pragma warning disable 0618
2395 /// <summary>
2396 /// Return the stack trace of a different thread.
2397 /// </summary>
2398 /// <remarks>
2399 /// This is complicated because the thread needs to be paused in order to get its stack
2400 /// trace. And pausing another thread can cause a deadlock. This method attempts to
2401 /// avoid deadlock by using a short timeout (200ms), after which it gives up and
2402 /// returns 'null' instead of the stack trace.
2403 ///
2404 /// Take from: http://stackoverflow.com/a/14935378
2405 ///
2406 /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691
2407 ///
2408 /// </remarks>
2409 /// <returns>The stack trace, or null if failed to get it</returns>
2410 private static StackTrace GetStackTrace(Thread targetThread)
2411 {
2412 if (IsPlatformMono)
1783 { 2413 {
1784 threadPoolUsed = "BuiltInThreadPool"; 2414 // This doesn't work in Mono
1785 ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); 2415 return null;
1786 ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
1787 int availableThreads;
1788 ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
1789 inUseThreads = maxThreads - availableThreads;
1790 allocatedThreads = -1;
1791 waitingCallbacks = -1;
1792 } 2416 }
1793 2417
1794 if (threadPoolUsed != null) 2418 ManualResetEventSlim fallbackThreadReady = new ManualResetEventSlim();
2419 ManualResetEventSlim exitedSafely = new ManualResetEventSlim();
2420
2421 try
1795 { 2422 {
1796 sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); 2423 new Thread(delegate()
1797 sb.AppendFormat("Max threads : {0}\n", maxThreads); 2424 {
1798 sb.AppendFormat("Min threads : {0}\n", minThreads); 2425 fallbackThreadReady.Set();
1799 sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); 2426 while (!exitedSafely.Wait(200))
1800 sb.AppendFormat("In use threads : {0}\n", inUseThreads); 2427 {
1801 sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); 2428 try
2429 {
2430 targetThread.Resume();
2431 }
2432 catch (Exception)
2433 {
2434 // Whatever happens, do never stop to resume the main-thread regularly until the main-thread has exited safely.
2435 }
2436 }
2437 }).Start();
2438
2439 fallbackThreadReady.Wait();
2440 // From here, you have about 200ms to get the stack-trace
2441
2442 targetThread.Suspend();
2443
2444 StackTrace trace = null;
2445 try
2446 {
2447 trace = new StackTrace(targetThread, true);
2448 }
2449 catch (ThreadStateException)
2450 {
2451 //failed to get stack trace, since the fallback-thread resumed the thread
2452 //possible reasons:
2453 //1.) This thread was just too slow
2454 //2.) A deadlock ocurred
2455 //Automatic retry seems too risky here, so just return null.
2456 }
2457
2458 try
2459 {
2460 targetThread.Resume();
2461 }
2462 catch (ThreadStateException)
2463 {
2464 // Thread is running again already
2465 }
2466
2467 return trace;
1802 } 2468 }
1803 else 2469 finally
1804 { 2470 {
1805 sb.AppendFormat("Thread pool not used\n"); 2471 // Signal the fallack-thread to stop
2472 exitedSafely.Set();
1806 } 2473 }
1807
1808 return sb.ToString();
1809 } 2474 }
2475#pragma warning restore 0618
1810 2476
1811 private static object SmartThreadPoolCallback(object o) 2477 /// <summary>
2478 /// Get information about the current state of the smart thread pool.
2479 /// </summary>
2480 /// <returns>
2481 /// null if this isn't the pool being used for non-scriptengine threads.
2482 /// </returns>
2483 public static STPInfo GetSmartThreadPoolInfo()
1812 { 2484 {
1813 object[] array = (object[])o; 2485 if (m_ThreadPool == null)
1814 WaitCallback callback = (WaitCallback)array[0]; 2486 return null;
1815 object obj = array[1];
1816 2487
1817 callback(obj); 2488 STPInfo stpi = new STPInfo();
1818 return null; 2489 stpi.Name = m_ThreadPool.Name;
2490 stpi.STPStartInfo = m_ThreadPool.STPStartInfo;
2491 stpi.IsIdle = m_ThreadPool.IsIdle;
2492 stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown;
2493 stpi.MaxThreads = m_ThreadPool.MaxThreads;
2494 stpi.MinThreads = m_ThreadPool.MinThreads;
2495 stpi.InUseThreads = m_ThreadPool.InUseThreads;
2496 stpi.ActiveThreads = m_ThreadPool.ActiveThreads;
2497 stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks;
2498 stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency;
2499
2500 return stpi;
1819 } 2501 }
1820 2502
1821 #endregion FireAndForget Threading Pattern 2503 #endregion FireAndForget Threading Pattern
@@ -1876,6 +2558,60 @@ namespace OpenSim.Framework
1876 } 2558 }
1877 2559
1878 /// <summary> 2560 /// <summary>
2561 /// Formats a duration (given in milliseconds).
2562 /// </summary>
2563 public static string FormatDuration(int ms)
2564 {
2565 TimeSpan span = new TimeSpan(ms * TimeSpan.TicksPerMillisecond);
2566
2567 string str = "";
2568 string suffix = null;
2569
2570 int hours = (int)span.TotalHours;
2571 if (hours > 0)
2572 {
2573 str += hours.ToString(str.Length == 0 ? "0" : "00");
2574 suffix = "hours";
2575 }
2576
2577 if ((hours > 0) || (span.Minutes > 0))
2578 {
2579 if (str.Length > 0)
2580 str += ":";
2581 str += span.Minutes.ToString(str.Length == 0 ? "0" : "00");
2582 if (suffix == null)
2583 suffix = "min";
2584 }
2585
2586 if ((hours > 0) || (span.Minutes > 0) || (span.Seconds > 0))
2587 {
2588 if (str.Length > 0)
2589 str += ":";
2590 str += span.Seconds.ToString(str.Length == 0 ? "0" : "00");
2591 if (suffix == null)
2592 suffix = "sec";
2593 }
2594
2595 if (suffix == null)
2596 suffix = "ms";
2597
2598 if (span.TotalMinutes < 1)
2599 {
2600 int ms1 = span.Milliseconds;
2601 if (str.Length > 0)
2602 {
2603 ms1 /= 100;
2604 str += ".";
2605 }
2606 str += ms1.ToString("0");
2607 }
2608
2609 str += " " + suffix;
2610
2611 return str;
2612 }
2613
2614 /// <summary>
1879 /// Prints the call stack at any given point. Useful for debugging. 2615 /// Prints the call stack at any given point. Useful for debugging.
1880 /// </summary> 2616 /// </summary>
1881 public static void PrintCallStack() 2617 public static void PrintCallStack()
@@ -1942,16 +2678,18 @@ namespace OpenSim.Framework
1942 } 2678 }
1943 2679
1944 #region Xml Serialization Utilities 2680 #region Xml Serialization Utilities
1945 public static bool ReadBoolean(XmlTextReader reader) 2681 public static bool ReadBoolean(XmlReader reader)
1946 { 2682 {
2683 // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this.
1947 reader.ReadStartElement(); 2684 reader.ReadStartElement();
1948 bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); 2685 string val = reader.ReadContentAsString().ToLower();
2686 bool result = val.Equals("true") || val.Equals("1");
1949 reader.ReadEndElement(); 2687 reader.ReadEndElement();
1950 2688
1951 return result; 2689 return result;
1952 } 2690 }
1953 2691
1954 public static UUID ReadUUID(XmlTextReader reader, string name) 2692 public static UUID ReadUUID(XmlReader reader, string name)
1955 { 2693 {
1956 UUID id; 2694 UUID id;
1957 string idStr; 2695 string idStr;
@@ -1970,7 +2708,7 @@ namespace OpenSim.Framework
1970 return id; 2708 return id;
1971 } 2709 }
1972 2710
1973 public static Vector3 ReadVector(XmlTextReader reader, string name) 2711 public static Vector3 ReadVector(XmlReader reader, string name)
1974 { 2712 {
1975 Vector3 vec; 2713 Vector3 vec;
1976 2714
@@ -1983,7 +2721,7 @@ namespace OpenSim.Framework
1983 return vec; 2721 return vec;
1984 } 2722 }
1985 2723
1986 public static Quaternion ReadQuaternion(XmlTextReader reader, string name) 2724 public static Quaternion ReadQuaternion(XmlReader reader, string name)
1987 { 2725 {
1988 Quaternion quat = new Quaternion(); 2726 Quaternion quat = new Quaternion();
1989 2727
@@ -2012,7 +2750,7 @@ namespace OpenSim.Framework
2012 return quat; 2750 return quat;
2013 } 2751 }
2014 2752
2015 public static T ReadEnum<T>(XmlTextReader reader, string name) 2753 public static T ReadEnum<T>(XmlReader reader, string name)
2016 { 2754 {
2017 string value = reader.ReadElementContentAsString(name, String.Empty); 2755 string value = reader.ReadElementContentAsString(name, String.Empty);
2018 // !!!!! to deal with flags without commas 2756 // !!!!! to deal with flags without commas
@@ -2024,7 +2762,9 @@ namespace OpenSim.Framework
2024 #endregion 2762 #endregion
2025 2763
2026 #region Universal User Identifiers 2764 #region Universal User Identifiers
2027 /// <summary> 2765
2766 /// <summary>
2767 /// Attempts to parse a UUI into its components: UUID, name and URL.
2028 /// </summary> 2768 /// </summary>
2029 /// <param name="value">uuid[;endpoint[;first last[;secret]]]</param> 2769 /// <param name="value">uuid[;endpoint[;first last[;secret]]]</param>
2030 /// <param name="uuid">the uuid part</param> 2770 /// <param name="uuid">the uuid part</param>
@@ -2034,7 +2774,7 @@ namespace OpenSim.Framework
2034 /// <param name="secret">the secret part</param> 2774 /// <param name="secret">the secret part</param>
2035 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) 2775 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret)
2036 { 2776 {
2037 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; 2777 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty;
2038 2778
2039 string[] parts = value.Split(';'); 2779 string[] parts = value.Split(';');
2040 if (parts.Length >= 1) 2780 if (parts.Length >= 1)
@@ -2060,6 +2800,27 @@ namespace OpenSim.Framework
2060 } 2800 }
2061 2801
2062 /// <summary> 2802 /// <summary>
2803 /// For foreign avatars, extracts their original name and Server URL from their First Name and Last Name.
2804 /// </summary>
2805 public static bool ParseForeignAvatarName(string firstname, string lastname,
2806 out string realFirstName, out string realLastName, out string serverURI)
2807 {
2808 realFirstName = realLastName = serverURI = string.Empty;
2809
2810 if (!lastname.Contains("@"))
2811 return false;
2812
2813 if (!firstname.Contains("."))
2814 return false;
2815
2816 realFirstName = firstname.Split('.')[0];
2817 realLastName = firstname.Split('.')[1];
2818 serverURI = new Uri("http://" + lastname.Replace("@", "")).ToString();
2819
2820 return true;
2821 }
2822
2823 /// <summary>
2063 /// Produces a universal (HG) system-facing identifier given the information 2824 /// Produces a universal (HG) system-facing identifier given the information
2064 /// </summary> 2825 /// </summary>
2065 /// <param name="acircuit"></param> 2826 /// <param name="acircuit"></param>
@@ -2092,10 +2853,15 @@ namespace OpenSim.Framework
2092 { 2853 {
2093 string[] parts = firstName.Split(new char[] { '.' }); 2854 string[] parts = firstName.Split(new char[] { '.' });
2094 if (parts.Length == 2) 2855 if (parts.Length == 2)
2095 return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; 2856 return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]);
2096 } 2857 }
2097 return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; 2858
2859 return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName);
2860 }
2098 2861
2862 private static string CalcUniversalIdentifier(UUID id, string agentsURI, string name)
2863 {
2864 return id.ToString() + ";" + agentsURI + ";" + name;
2099 } 2865 }
2100 2866
2101 /// <summary> 2867 /// <summary>
@@ -2119,5 +2885,221 @@ namespace OpenSim.Framework
2119 return firstName + "." + lastName + " " + "@" + uri.Authority; 2885 return firstName + "." + lastName + " " + "@" + uri.Authority;
2120 } 2886 }
2121 #endregion 2887 #endregion
2888
2889 /// <summary>
2890 /// Escapes the special characters used in "LIKE".
2891 /// </summary>
2892 /// <remarks>
2893 /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz"
2894 /// </remarks>
2895 public static string EscapeForLike(string str)
2896 {
2897 return str.Replace("_", "\\_").Replace("%", "\\%");
2898 }
2899
2900 /// <summary>
2901 /// Returns the name of the user's viewer.
2902 /// </summary>
2903 /// <remarks>
2904 /// This method handles two ways that viewers specify their name:
2905 /// 1. Viewer = "Firestorm-Release 4.4.2.34167", Channel = "(don't care)" -> "Firestorm-Release 4.4.2.34167"
2906 /// 2. Viewer = "4.5.1.38838", Channel = "Firestorm-Beta" -> "Firestorm-Beta 4.5.1.38838"
2907 /// </remarks>
2908 public static string GetViewerName(AgentCircuitData agent)
2909 {
2910 string name = agent.Viewer;
2911 if (name == null)
2912 name = "";
2913 else
2914 name = name.Trim();
2915
2916 // Check if 'Viewer' is just a version number. If it's *not*, then we
2917 // assume that it contains the real viewer name, and we return it.
2918 foreach (char c in name)
2919 {
2920 if (Char.IsLetter(c))
2921 return name;
2922 }
2923
2924 // The 'Viewer' string contains just a version number. If there's anything in
2925 // 'Channel' then assume that it's the viewer name.
2926 if ((agent.Channel != null) && (agent.Channel.Length > 0))
2927 name = agent.Channel.Trim() + " " + name;
2928
2929 return name;
2930 }
2931
2932 public static void LogFailedXML(string message, string xml)
2933 {
2934 int length = xml.Length;
2935 if (length > 2000)
2936 xml = xml.Substring(0, 2000) + "...";
2937
2938 m_log.ErrorFormat("{0} Failed XML ({1} bytes) = {2}", message, length, xml);
2939 }
2940
2941 }
2942
2943 public class DoubleQueue<T> where T:class
2944 {
2945 private Queue<T> m_lowQueue = new Queue<T>();
2946 private Queue<T> m_highQueue = new Queue<T>();
2947
2948 private object m_syncRoot = new object();
2949 private Semaphore m_s = new Semaphore(0, 1);
2950
2951 public DoubleQueue()
2952 {
2953 }
2954
2955 public virtual int Count
2956 {
2957 get
2958 {
2959 lock (m_syncRoot)
2960 return m_highQueue.Count + m_lowQueue.Count;
2961 }
2962 }
2963
2964 public virtual void Enqueue(T data)
2965 {
2966 Enqueue(m_lowQueue, data);
2967 }
2968
2969 public virtual void EnqueueLow(T data)
2970 {
2971 Enqueue(m_lowQueue, data);
2972 }
2973
2974 public virtual void EnqueueHigh(T data)
2975 {
2976 Enqueue(m_highQueue, data);
2977 }
2978
2979 private void Enqueue(Queue<T> q, T data)
2980 {
2981 lock (m_syncRoot)
2982 {
2983 q.Enqueue(data);
2984 m_s.WaitOne(0);
2985 m_s.Release();
2986 }
2987 }
2988
2989 public virtual T Dequeue()
2990 {
2991 return Dequeue(Timeout.Infinite);
2992 }
2993
2994 public virtual T Dequeue(int tmo)
2995 {
2996 return Dequeue(TimeSpan.FromMilliseconds(tmo));
2997 }
2998
2999 public virtual T Dequeue(TimeSpan wait)
3000 {
3001 T res = null;
3002
3003 if (!Dequeue(wait, ref res))
3004 return null;
3005
3006 return res;
3007 }
3008
3009 public bool Dequeue(int timeout, ref T res)
3010 {
3011 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
3012 }
3013
3014 public bool Dequeue(TimeSpan wait, ref T res)
3015 {
3016 if (!m_s.WaitOne(wait))
3017 return false;
3018
3019 lock (m_syncRoot)
3020 {
3021 if (m_highQueue.Count > 0)
3022 res = m_highQueue.Dequeue();
3023 else if (m_lowQueue.Count > 0)
3024 res = m_lowQueue.Dequeue();
3025
3026 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
3027 return true;
3028
3029 try
3030 {
3031 m_s.Release();
3032 }
3033 catch
3034 {
3035 }
3036
3037 return true;
3038 }
3039 }
3040
3041 public virtual void Clear()
3042 {
3043
3044 lock (m_syncRoot)
3045 {
3046 // Make sure sem count is 0
3047 m_s.WaitOne(0);
3048
3049 m_lowQueue.Clear();
3050 m_highQueue.Clear();
3051 }
3052 }
3053 }
3054
3055 public class BetterRandom
3056 {
3057 private const int BufferSize = 1024; // must be a multiple of 4
3058 private byte[] RandomBuffer;
3059 private int BufferOffset;
3060 private RNGCryptoServiceProvider rng;
3061 public BetterRandom()
3062 {
3063 RandomBuffer = new byte[BufferSize];
3064 rng = new RNGCryptoServiceProvider();
3065 BufferOffset = RandomBuffer.Length;
3066 }
3067 private void FillBuffer()
3068 {
3069 rng.GetBytes(RandomBuffer);
3070 BufferOffset = 0;
3071 }
3072 public int Next()
3073 {
3074 if (BufferOffset >= RandomBuffer.Length)
3075 {
3076 FillBuffer();
3077 }
3078 int val = BitConverter.ToInt32(RandomBuffer, BufferOffset) & 0x7fffffff;
3079 BufferOffset += sizeof(int);
3080 return val;
3081 }
3082 public int Next(int maxValue)
3083 {
3084 return Next() % maxValue;
3085 }
3086 public int Next(int minValue, int maxValue)
3087 {
3088 if (maxValue < minValue)
3089 {
3090 throw new ArgumentOutOfRangeException("maxValue must be greater than or equal to minValue");
3091 }
3092 int range = maxValue - minValue;
3093 return minValue + Next(range);
3094 }
3095 public double NextDouble()
3096 {
3097 int val = Next();
3098 return (double)val / int.MaxValue;
3099 }
3100 public void GetBytes(byte[] buff)
3101 {
3102 rng.GetBytes(buff);
3103 }
2122 } 3104 }
2123} 3105}
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/VersionInfo.cs
index 54af95e..356e720 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/VersionInfo.cs
@@ -29,7 +29,7 @@ namespace OpenSim
29{ 29{
30 public class VersionInfo 30 public class VersionInfo
31 { 31 {
32 private const string VERSION_NUMBER = "0.7.5"; 32 public const string VersionNumber = "0.8.2.1";
33 private const string IG_BUILD_NUMBER = "4"; 33 private const string IG_BUILD_NUMBER = "4";
34 private const Flavour VERSION_FLAVOUR = Flavour.IG; 34 private const Flavour VERSION_FLAVOUR = Flavour.IG;
35 35
@@ -39,6 +39,7 @@ namespace OpenSim
39 Dev, 39 Dev,
40 RC1, 40 RC1,
41 RC2, 41 RC2,
42 RC3,
42 Release, 43 Release,
43 Post_Fixes, 44 Post_Fixes,
44 Extended, 45 Extended,
@@ -47,7 +48,7 @@ namespace OpenSim
47 48
48 public static string Version 49 public static string Version
49 { 50 {
50 get { return GetVersionString(VERSION_NUMBER, IG_BUILD_NUMBER, VERSION_FLAVOUR); } 51 get { return GetVersionString(VersionNumber, IG_BUILD_NUMBER, IG_BUILD_NUMBER, VERSION_FLAVOUR); }
51 } 52 }
52 53
53 public static string GetVersionString(string versionNumber, string buildNumber, Flavour flavour) 54 public static string GetVersionString(string versionNumber, string buildNumber, Flavour flavour)
@@ -61,17 +62,31 @@ namespace OpenSim
61 /// <value> 62 /// <value>
62 /// This is the external interface version. It is separate from the OpenSimulator project version. 63 /// This is the external interface version. It is separate from the OpenSimulator project version.
63 /// 64 ///
64 /// This version number should be
65 /// increased by 1 every time a code change makes the previous OpenSimulator revision incompatible
66 /// with the new revision. This will usually be due to interregion or grid facing interface changes.
67 ///
68 /// Changes which are compatible with an older revision (e.g. older revisions experience degraded functionality
69 /// but not outright failure) do not need a version number increment.
70 ///
71 /// Having this version number allows the grid service to reject connections from regions running a version
72 /// of the code that is too old.
73 ///
74 /// </value> 65 /// </value>
75 public readonly static int MajorInterfaceVersion = 7; 66 /// Commented because it's not used anymore, see below for new
67 /// versioning method.
68 //public readonly static int MajorInterfaceVersion = 8;
69
70 /// <summary>
71 /// This rules versioning regarding teleports, and compatibility between simulators in that regard.
72 /// </summary>
73 ///
74 /// <remarks>
75 /// The protocol version that we will use for outgoing transfers
76 /// Valid values are
77 /// "SIMULATION/0.3"
78 /// - This is the latest, and it supports teleports to variable-sized regions
79 /// - Older versions can teleport to this one, but only if the destination region
80 /// is 256x256
81 /// "SIMULATION/0.2"
82 /// - A source simulator which only implements "SIMULATION/0.1" can still teleport here
83 /// - this protocol is more efficient than "SIMULATION/0.1"
84 /// "SIMULATION/0.1"
85 /// - this is an older teleport protocol used in OpenSimulator 0.7.5 and before.
86 /// </remarks>
87 public readonly static float SimulationServiceVersionAcceptedMin = 0.3f;
88 public readonly static float SimulationServiceVersionAcceptedMax = 0.5f;
89 public readonly static float SimulationServiceVersionSupportedMin = 0.3f;
90 public readonly static float SimulationServiceVersionSupportedMax = 0.5f;
76 } 91 }
77} 92}
diff --git a/OpenSim/Framework/WearableCacheItem.cs b/OpenSim/Framework/WearableCacheItem.cs
new file mode 100644
index 0000000..1aecf79
--- /dev/null
+++ b/OpenSim/Framework/WearableCacheItem.cs
@@ -0,0 +1,157 @@
1/*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31using OpenMetaverse.StructuredData;
32
33namespace OpenSim.Framework
34{
35 [Serializable]
36 public class WearableCacheItem
37 {
38 public uint TextureIndex { get; set; }
39 public UUID CacheId { get; set; }
40 public UUID TextureID { get; set; }
41 public AssetBase TextureAsset { get; set; }
42
43
44 public static WearableCacheItem[] GetDefaultCacheItem()
45 {
46 int itemmax = 21;
47 WearableCacheItem[] retitems = new WearableCacheItem[itemmax];
48 for (uint i=0;i<itemmax;i++)
49 retitems[i] = new WearableCacheItem() {CacheId = UUID.Zero, TextureID = UUID.Zero, TextureIndex = i + 1};
50 return retitems;
51 }
52 public static WearableCacheItem[] FromOSD(OSD pInput, IImprovedAssetCache dataCache)
53 {
54 List<WearableCacheItem> ret = new List<WearableCacheItem>();
55 if (pInput.Type == OSDType.Array)
56 {
57 OSDArray itemarray = (OSDArray) pInput;
58 foreach (OSDMap item in itemarray)
59 {
60 ret.Add(new WearableCacheItem()
61 {
62 TextureIndex = item["textureindex"].AsUInteger(),
63 CacheId = item["cacheid"].AsUUID(),
64 TextureID = item["textureid"].AsUUID()
65 });
66
67 if (dataCache != null && item.ContainsKey("assetdata"))
68 {
69 AssetBase asset = new AssetBase(item["textureid"].AsUUID(),"BakedTexture",(sbyte)AssetType.Texture,UUID.Zero.ToString());
70 asset.Temporary = true;
71 asset.Data = item["assetdata"].AsBinary();
72 dataCache.Cache(asset);
73 }
74 }
75 }
76 else if (pInput.Type == OSDType.Map)
77 {
78 OSDMap item = (OSDMap) pInput;
79 ret.Add(new WearableCacheItem(){
80 TextureIndex = item["textureindex"].AsUInteger(),
81 CacheId = item["cacheid"].AsUUID(),
82 TextureID = item["textureid"].AsUUID()
83 });
84 if (dataCache != null && item.ContainsKey("assetdata"))
85 {
86 string assetCreator = item["assetcreator"].AsString();
87 string assetName = item["assetname"].AsString();
88 AssetBase asset = new AssetBase(item["textureid"].AsUUID(), assetName, (sbyte)AssetType.Texture, assetCreator);
89 asset.Temporary = true;
90 asset.Data = item["assetdata"].AsBinary();
91 dataCache.Cache(asset);
92 }
93 }
94 else
95 {
96 return new WearableCacheItem[0];
97 }
98 return ret.ToArray();
99
100 }
101 public static OSD ToOSD(WearableCacheItem[] pcacheItems, IImprovedAssetCache dataCache)
102 {
103 OSDArray arr = new OSDArray();
104 foreach (WearableCacheItem item in pcacheItems)
105 {
106 OSDMap itemmap = new OSDMap();
107 itemmap.Add("textureindex", OSD.FromUInteger(item.TextureIndex));
108 itemmap.Add("cacheid", OSD.FromUUID(item.CacheId));
109 itemmap.Add("textureid", OSD.FromUUID(item.TextureID));
110 if (dataCache != null)
111 {
112 if (dataCache.Check(item.TextureID.ToString()))
113 {
114 AssetBase assetItem = dataCache.Get(item.TextureID.ToString());
115 if (assetItem != null)
116 {
117 itemmap.Add("assetdata", OSD.FromBinary(assetItem.Data));
118 itemmap.Add("assetcreator", OSD.FromString(assetItem.CreatorID));
119 itemmap.Add("assetname", OSD.FromString(assetItem.Name));
120 }
121 }
122 }
123 arr.Add(itemmap);
124 }
125 return arr;
126 }
127 public static WearableCacheItem SearchTextureIndex(uint pTextureIndex,WearableCacheItem[] pcacheItems)
128 {
129 for (int i = 0; i < pcacheItems.Length; i++)
130 {
131 if (pcacheItems[i].TextureIndex == pTextureIndex)
132 return pcacheItems[i];
133 }
134 return null;
135 }
136 public static WearableCacheItem SearchTextureCacheId(UUID pCacheId, WearableCacheItem[] pcacheItems)
137 {
138 for (int i = 0; i < pcacheItems.Length; i++)
139 {
140 if (pcacheItems[i].CacheId == pCacheId)
141 return pcacheItems[i];
142 }
143 return null;
144 }
145 public static WearableCacheItem SearchTextureTextureId(UUID pTextureId, WearableCacheItem[] pcacheItems)
146 {
147 for (int i = 0; i < pcacheItems.Length; i++)
148 {
149 if (pcacheItems[i].TextureID == pTextureId)
150 return pcacheItems[i];
151 }
152 return null;
153 }
154 }
155
156
157}
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index 5c34cf4..b180c8a 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -39,8 +39,13 @@ using System.Text;
39using System.Web; 39using System.Web;
40using System.Xml; 40using System.Xml;
41using System.Xml.Serialization; 41using System.Xml.Serialization;
42using System.Xml.Linq;
42using log4net; 43using log4net;
44using Nwc.XmlRpc;
43using OpenMetaverse.StructuredData; 45using OpenMetaverse.StructuredData;
46using XMLResponseHelper = OpenSim.Framework.SynchronousRestObjectRequester.XMLResponseHelper;
47
48using OpenSim.Framework.ServiceAuth;
44 49
45namespace OpenSim.Framework 50namespace OpenSim.Framework
46{ 51{
@@ -64,7 +69,12 @@ namespace OpenSim.Framework
64 /// <summary> 69 /// <summary>
65 /// Request number for diagnostic purposes. 70 /// Request number for diagnostic purposes.
66 /// </summary> 71 /// </summary>
67 public static int RequestNumber { get; internal set; } 72 public static int RequestNumber { get; set; }
73
74 /// <summary>
75 /// Control where OSD requests should be serialized per endpoint.
76 /// </summary>
77 public static bool SerializeOSDRequestsPerEndpoint { get; set; }
68 78
69 /// <summary> 79 /// <summary>
70 /// this is the header field used to communicate the local request id 80 /// this is the header field used to communicate the local request id
@@ -84,8 +94,9 @@ namespace OpenSim.Framework
84 /// <remarks> 94 /// <remarks>
85 /// This is to truncate any really large post data, such as an asset. In theory, the first section should 95 /// This is to truncate any really large post data, such as an asset. In theory, the first section should
86 /// give us useful information about the call (which agent it relates to if applicable, etc.). 96 /// give us useful information about the call (which agent it relates to if applicable, etc.).
97 /// This is also used to truncate messages when using DebugLevel 5.
87 /// </remarks> 98 /// </remarks>
88 public const int MaxRequestDiagLength = 100; 99 public const int MaxRequestDiagLength = 200;
89 100
90 /// <summary> 101 /// <summary>
91 /// Dictionary of end points 102 /// Dictionary of end points
@@ -120,45 +131,104 @@ namespace OpenSim.Framework
120 /// </summary> 131 /// </summary>
121 public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout) 132 public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout)
122 { 133 {
123 return ServiceOSDRequest(url,data, "PUT", timeout, true); 134 return ServiceOSDRequest(url,data, "PUT", timeout, true, false);
124 } 135 }
125 136
126 public static OSDMap PutToService(string url, OSDMap data, int timeout) 137 public static OSDMap PutToService(string url, OSDMap data, int timeout)
127 { 138 {
128 return ServiceOSDRequest(url,data, "PUT", timeout, false); 139 return ServiceOSDRequest(url,data, "PUT", timeout, false, false);
129 } 140 }
130 141
131 public static OSDMap PostToService(string url, OSDMap data, int timeout) 142 public static OSDMap PostToService(string url, OSDMap data, int timeout, bool rpc)
132 { 143 {
133 return ServiceOSDRequest(url, data, "POST", timeout, false); 144 return ServiceOSDRequest(url, data, "POST", timeout, false, rpc);
134 } 145 }
135 146
136 public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout) 147 public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout)
137 { 148 {
138 return ServiceOSDRequest(url, data, "POST", timeout, true); 149 return ServiceOSDRequest(url, data, "POST", timeout, true, false);
139 } 150 }
140 151
141 public static OSDMap GetFromService(string url, int timeout) 152 public static OSDMap GetFromService(string url, int timeout)
142 { 153 {
143 return ServiceOSDRequest(url, null, "GET", timeout, false); 154 return ServiceOSDRequest(url, null, "GET", timeout, false, false);
144 } 155 }
145 156
146 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) 157 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc)
147 { 158 {
148 lock (EndPointLock(url)) 159 if (SerializeOSDRequestsPerEndpoint)
160 {
161 lock (EndPointLock(url))
162 {
163 return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc);
164 }
165 }
166 else
149 { 167 {
150 return ServiceOSDRequestWorker(url,data,method,timeout,compressed); 168 return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc);
151 } 169 }
152 } 170 }
153 171
154 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) 172 public static void LogOutgoingDetail(Stream outputStream)
173 {
174 LogOutgoingDetail("", outputStream);
175 }
176
177 public static void LogOutgoingDetail(string context, Stream outputStream)
178 {
179 using (Stream stream = Util.Copy(outputStream))
180 using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
181 {
182 string output;
183
184 if (DebugLevel == 5)
185 {
186 char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed
187 int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1);
188 output = new string(chars, 0, len);
189 }
190 else
191 {
192 output = reader.ReadToEnd();
193 }
194
195 LogOutgoingDetail(context, output);
196 }
197 }
198
199 public static void LogOutgoingDetail(string type, int reqnum, string output)
200 {
201 LogOutgoingDetail(string.Format("{0} {1}: ", type, reqnum), output);
202 }
203
204 public static void LogOutgoingDetail(string context, string output)
205 {
206 if (DebugLevel == 5)
207 {
208 if (output.Length > MaxRequestDiagLength)
209 output = output.Substring(0, MaxRequestDiagLength) + "...";
210 }
211
212 m_log.DebugFormat("[LOGHTTP]: {0}{1}", context, Util.BinaryToASCII(output));
213 }
214
215 public static void LogResponseDetail(int reqnum, Stream inputStream)
216 {
217 LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), inputStream);
218 }
219
220 public static void LogResponseDetail(int reqnum, string input)
221 {
222 LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), input);
223 }
224
225 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc)
155 { 226 {
156 int reqnum = RequestNumber++; 227 int reqnum = RequestNumber++;
157 228
158 if (DebugLevel >= 3) 229 if (DebugLevel >= 3)
159 m_log.DebugFormat( 230 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} JSON-RPC {1} to {2}",
160 "[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})", 231 reqnum, method, url);
161 reqnum, method, url, timeout, compressed);
162 232
163 string errorMessage = "unknown error"; 233 string errorMessage = "unknown error";
164 int tickstart = Util.EnvironmentTickCount(); 234 int tickstart = Util.EnvironmentTickCount();
@@ -178,20 +248,27 @@ namespace OpenSim.Framework
178 // If there is some input, write it into the request 248 // If there is some input, write it into the request
179 if (data != null) 249 if (data != null)
180 { 250 {
181 strBuffer = OSDParser.SerializeJsonString(data); 251 strBuffer = OSDParser.SerializeJsonString(data);
252
253 if (DebugLevel >= 5)
254 LogOutgoingDetail("SEND", reqnum, strBuffer);
255
182 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); 256 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer);
183 257
258 request.ContentType = rpc ? "application/json-rpc" : "application/json";
259
184 if (compressed) 260 if (compressed)
185 { 261 {
186 request.ContentType = "application/x-gzip"; 262 request.Headers["X-Content-Encoding"] = "gzip"; // can't set "Content-Encoding" because old OpenSims fail if they get an unrecognized Content-Encoding
263
187 using (MemoryStream ms = new MemoryStream()) 264 using (MemoryStream ms = new MemoryStream())
188 { 265 {
189 using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress)) 266 using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress, true))
190 { 267 {
191 comp.Write(buffer, 0, buffer.Length); 268 comp.Write(buffer, 0, buffer.Length);
192 // We need to close the gzip stream before we write it anywhere 269 // We need to close the gzip stream before we write it anywhere
193 // because apparently something important related to gzip compression 270 // because apparently something important related to gzip compression
194 // gets written on the strteam upon Dispose() 271 // gets written on the stream upon Dispose()
195 } 272 }
196 byte[] buf = ms.ToArray(); 273 byte[] buf = ms.ToArray();
197 request.ContentLength = buf.Length; //Count bytes to send 274 request.ContentLength = buf.Length; //Count bytes to send
@@ -201,10 +278,9 @@ namespace OpenSim.Framework
201 } 278 }
202 else 279 else
203 { 280 {
204 request.ContentType = "application/json";
205 request.ContentLength = buffer.Length; //Count bytes to send 281 request.ContentLength = buffer.Length; //Count bytes to send
206 using (Stream requestStream = request.GetRequestStream()) 282 using (Stream requestStream = request.GetRequestStream())
207 requestStream.Write(buffer, 0, buffer.Length); //Send it 283 requestStream.Write(buffer, 0, buffer.Length); //Send it
208 } 284 }
209 } 285 }
210 286
@@ -216,10 +292,13 @@ namespace OpenSim.Framework
216 { 292 {
217 using (Stream responseStream = response.GetResponseStream()) 293 using (Stream responseStream = response.GetResponseStream())
218 { 294 {
219 string responseStr = null; 295 using (StreamReader reader = new StreamReader(responseStream))
220 responseStr = responseStream.GetStreamString(); 296 {
221 // m_log.DebugFormat("[WEB UTIL]: <{0}> response is <{1}>",reqnum,responseStr); 297 string responseStr = reader.ReadToEnd();
222 return CanonicalizeResults(responseStr); 298 if (WebUtil.DebugLevel >= 5)
299 WebUtil.LogResponseDetail(reqnum, responseStr);
300 return CanonicalizeResults(responseStr);
301 }
223 } 302 }
224 } 303 }
225 } 304 }
@@ -228,8 +307,8 @@ namespace OpenSim.Framework
228 errorMessage = we.Message; 307 errorMessage = we.Message;
229 if (we.Status == WebExceptionStatus.ProtocolError) 308 if (we.Status == WebExceptionStatus.ProtocolError)
230 { 309 {
231 HttpWebResponse webResponse = (HttpWebResponse)we.Response; 310 using (HttpWebResponse webResponse = (HttpWebResponse)we.Response)
232 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); 311 errorMessage = String.Format("[{0}] {1}", webResponse.StatusCode, webResponse.StatusDescription);
233 } 312 }
234 } 313 }
235 catch (Exception ex) 314 catch (Exception ex)
@@ -240,24 +319,23 @@ namespace OpenSim.Framework
240 { 319 {
241 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 320 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
242 if (tickdiff > LongCallTime) 321 if (tickdiff > LongCallTime)
322 {
243 m_log.InfoFormat( 323 m_log.InfoFormat(
244 "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 324 "[LOGHTTP]: Slow JSON-RPC request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
245 reqnum, 325 reqnum, method, url, tickdiff, tickdata,
246 method,
247 url,
248 tickdiff,
249 tickdata,
250 strBuffer != null 326 strBuffer != null
251 ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) 327 ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
252 : ""); 328 : "");
329 }
253 else if (DebugLevel >= 4) 330 else if (DebugLevel >= 4)
254 m_log.DebugFormat( 331 {
255 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 332 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
256 reqnum, tickdiff, tickdata); 333 reqnum, tickdiff, tickdata);
334 }
257 } 335 }
258 336
259 m_log.DebugFormat( 337 m_log.DebugFormat(
260 "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage); 338 "[LOGHTTP]: JSON-RPC request {0} {1} to {2} FAILED: {3}", reqnum, method, url, errorMessage);
261 339
262 return ErrorResponseMap(errorMessage); 340 return ErrorResponseMap(errorMessage);
263 } 341 }
@@ -335,9 +413,8 @@ namespace OpenSim.Framework
335 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; 413 string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
336 414
337 if (DebugLevel >= 3) 415 if (DebugLevel >= 3)
338 m_log.DebugFormat( 416 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} ServiceForm '{1}' to {2}",
339 "[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})", 417 reqnum, method, url);
340 reqnum, method, url, timeout);
341 418
342 string errorMessage = "unknown error"; 419 string errorMessage = "unknown error";
343 int tickstart = Util.EnvironmentTickCount(); 420 int tickstart = Util.EnvironmentTickCount();
@@ -357,6 +434,10 @@ namespace OpenSim.Framework
357 if (data != null) 434 if (data != null)
358 { 435 {
359 queryString = BuildQueryString(data); 436 queryString = BuildQueryString(data);
437
438 if (DebugLevel >= 5)
439 LogOutgoingDetail("SEND", reqnum, queryString);
440
360 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); 441 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString);
361 442
362 request.ContentLength = buffer.Length; 443 request.ContentLength = buffer.Length;
@@ -373,12 +454,16 @@ namespace OpenSim.Framework
373 { 454 {
374 using (Stream responseStream = response.GetResponseStream()) 455 using (Stream responseStream = response.GetResponseStream())
375 { 456 {
376 string responseStr = null; 457 using (StreamReader reader = new StreamReader(responseStream))
458 {
459 string responseStr = reader.ReadToEnd();
460 if (WebUtil.DebugLevel >= 5)
461 WebUtil.LogResponseDetail(reqnum, responseStr);
462 OSD responseOSD = OSDParser.Deserialize(responseStr);
377 463
378 responseStr = responseStream.GetStreamString(); 464 if (responseOSD.Type == OSDType.Map)
379 OSD responseOSD = OSDParser.Deserialize(responseStr); 465 return (OSDMap)responseOSD;
380 if (responseOSD.Type == OSDType.Map) 466 }
381 return (OSDMap)responseOSD;
382 } 467 }
383 } 468 }
384 } 469 }
@@ -387,8 +472,8 @@ namespace OpenSim.Framework
387 errorMessage = we.Message; 472 errorMessage = we.Message;
388 if (we.Status == WebExceptionStatus.ProtocolError) 473 if (we.Status == WebExceptionStatus.ProtocolError)
389 { 474 {
390 HttpWebResponse webResponse = (HttpWebResponse)we.Response; 475 using (HttpWebResponse webResponse = (HttpWebResponse)we.Response)
391 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription); 476 errorMessage = String.Format("[{0}] {1}",webResponse.StatusCode,webResponse.StatusDescription);
392 } 477 }
393 } 478 }
394 catch (Exception ex) 479 catch (Exception ex)
@@ -399,23 +484,22 @@ namespace OpenSim.Framework
399 { 484 {
400 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 485 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
401 if (tickdiff > LongCallTime) 486 if (tickdiff > LongCallTime)
487 {
402 m_log.InfoFormat( 488 m_log.InfoFormat(
403 "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 489 "[LOGHTTP]: Slow ServiceForm request {0} '{1}' to {2} took {3}ms, {4}ms writing, {5}",
404 reqnum, 490 reqnum, method, url, tickdiff, tickdata,
405 method,
406 url,
407 tickdiff,
408 tickdata,
409 queryString != null 491 queryString != null
410 ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString 492 ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
411 : ""); 493 : "");
494 }
412 else if (DebugLevel >= 4) 495 else if (DebugLevel >= 4)
413 m_log.DebugFormat( 496 {
414 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 497 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
415 reqnum, tickdiff, tickdata); 498 reqnum, tickdiff, tickdata);
499 }
416 } 500 }
417 501
418 m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage); 502 m_log.WarnFormat("[LOGHTTP]: ServiceForm request {0} '{1}' to {2} failed: {3}", reqnum, method, url, errorMessage);
419 503
420 return ErrorResponseMap(errorMessage); 504 return ErrorResponseMap(errorMessage);
421 } 505 }
@@ -592,38 +676,6 @@ namespace OpenSim.Framework
592 return totalCopiedBytes; 676 return totalCopiedBytes;
593 } 677 }
594 678
595 /// <summary>
596 /// Converts an entire stream to a string, regardless of current stream
597 /// position
598 /// </summary>
599 /// <param name="stream">The stream to convert to a string</param>
600 /// <returns></returns>
601 /// <remarks>When this method is done, the stream position will be
602 /// reset to its previous position before this method was called</remarks>
603 public static string GetStreamString(this Stream stream)
604 {
605 string value = null;
606
607 if (stream != null && stream.CanRead)
608 {
609 long rewindPos = -1;
610
611 if (stream.CanSeek)
612 {
613 rewindPos = stream.Position;
614 stream.Seek(0, SeekOrigin.Begin);
615 }
616
617 StreamReader reader = new StreamReader(stream);
618 value = reader.ReadToEnd();
619
620 if (rewindPos >= 0)
621 stream.Seek(rewindPos, SeekOrigin.Begin);
622 }
623
624 return value;
625 }
626
627 #endregion Stream 679 #endregion Stream
628 680
629 public class QBasedComparer : IComparer 681 public class QBasedComparer : IComparer
@@ -667,7 +719,7 @@ namespace OpenSim.Framework
667 /// <returns></returns> 719 /// <returns></returns>
668 public static string[] GetPreferredImageTypes(string accept) 720 public static string[] GetPreferredImageTypes(string accept)
669 { 721 {
670 if (accept == null || accept == string.Empty) 722 if (string.IsNullOrEmpty(accept))
671 return new string[0]; 723 return new string[0];
672 724
673 string[] types = accept.Split(new char[] { ',' }); 725 string[] types = accept.Split(new char[] { ',' });
@@ -724,11 +776,17 @@ namespace OpenSim.Framework
724 string requestUrl, TRequest obj, Action<TResponse> action, 776 string requestUrl, TRequest obj, Action<TResponse> action,
725 int maxConnections) 777 int maxConnections)
726 { 778 {
779 MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, maxConnections, null);
780 }
781
782 public static void MakeRequest<TRequest, TResponse>(string verb,
783 string requestUrl, TRequest obj, Action<TResponse> action,
784 int maxConnections, IServiceAuth auth)
785 {
727 int reqnum = WebUtil.RequestNumber++; 786 int reqnum = WebUtil.RequestNumber++;
728 787
729 if (WebUtil.DebugLevel >= 3) 788 if (WebUtil.DebugLevel >= 3)
730 m_log.DebugFormat( 789 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} AsynchronousRequestObject {1} to {2}",
731 "[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}",
732 reqnum, verb, requestUrl); 790 reqnum, verb, requestUrl);
733 791
734 int tickstart = Util.EnvironmentTickCount(); 792 int tickstart = Util.EnvironmentTickCount();
@@ -738,171 +796,174 @@ namespace OpenSim.Framework
738 796
739 WebRequest request = WebRequest.Create(requestUrl); 797 WebRequest request = WebRequest.Create(requestUrl);
740 HttpWebRequest ht = (HttpWebRequest)request; 798 HttpWebRequest ht = (HttpWebRequest)request;
799
800 if (auth != null)
801 auth.AddAuthorization(ht.Headers);
802
741 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) 803 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
742 ht.ServicePoint.ConnectionLimit = maxConnections; 804 ht.ServicePoint.ConnectionLimit = maxConnections;
743 805
744 WebResponse response = null;
745 TResponse deserial = default(TResponse); 806 TResponse deserial = default(TResponse);
746 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
747 807
748 request.Method = verb; 808 request.Method = verb;
809
749 MemoryStream buffer = null; 810 MemoryStream buffer = null;
750 811
751 if (verb == "POST") 812 try
752 { 813 {
753 request.ContentType = "text/xml"; 814 if (verb == "POST")
815 {
816 request.ContentType = "text/xml";
754 817
755 buffer = new MemoryStream(); 818 buffer = new MemoryStream();
756 819
757 XmlWriterSettings settings = new XmlWriterSettings(); 820 XmlWriterSettings settings = new XmlWriterSettings();
758 settings.Encoding = Encoding.UTF8; 821 settings.Encoding = Encoding.UTF8;
759 822
760 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 823 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
761 { 824 {
762 XmlSerializer serializer = new XmlSerializer(type); 825 XmlSerializer serializer = new XmlSerializer(type);
763 serializer.Serialize(writer, obj); 826 serializer.Serialize(writer, obj);
764 writer.Flush(); 827 writer.Flush();
765 } 828 }
766 829
767 int length = (int)buffer.Length; 830 int length = (int)buffer.Length;
768 request.ContentLength = length; 831 request.ContentLength = length;
832 byte[] data = buffer.ToArray();
769 833
770 request.BeginGetRequestStream(delegate(IAsyncResult res) 834 if (WebUtil.DebugLevel >= 5)
771 { 835 WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
772 Stream requestStream = request.EndGetRequestStream(res);
773 836
774 requestStream.Write(buffer.ToArray(), 0, length); 837 request.BeginGetRequestStream(delegate(IAsyncResult res)
775 requestStream.Close(); 838 {
839 using (Stream requestStream = request.EndGetRequestStream(res))
840 requestStream.Write(data, 0, length);
776 841
777 // capture how much time was spent writing 842 // capture how much time was spent writing
778 tickdata = Util.EnvironmentTickCountSubtract(tickstart); 843 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
779 844
780 request.BeginGetResponse(delegate(IAsyncResult ar) 845 request.BeginGetResponse(delegate(IAsyncResult ar)
781 {
782 response = request.EndGetResponse(ar);
783 Stream respStream = null;
784 try
785 { 846 {
786 respStream = response.GetResponseStream(); 847 using (WebResponse response = request.EndGetResponse(ar))
787 deserial = (TResponse)deserializer.Deserialize( 848 {
788 respStream); 849 try
789 } 850 {
790 catch (System.InvalidOperationException) 851 using (Stream respStream = response.GetResponseStream())
791 { 852 {
792 } 853 deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
793 finally 854 reqnum, respStream, response.ContentLength);
794 { 855 }
795 // Let's not close this 856 }
796 //buffer.Close(); 857 catch (System.InvalidOperationException)
797 respStream.Close(); 858 {
798 response.Close(); 859 }
799 } 860 }
800 861
801 action(deserial); 862 action(deserial);
802 863
864 }, null);
803 }, null); 865 }, null);
804 }, null); 866 }
805 } 867 else
806 else
807 {
808 request.BeginGetResponse(delegate(IAsyncResult res2)
809 { 868 {
810 try 869 request.BeginGetResponse(delegate(IAsyncResult res2)
811 { 870 {
812 // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
813 // documented in MSDN
814 response = request.EndGetResponse(res2);
815
816 Stream respStream = null;
817 try 871 try
818 { 872 {
819 respStream = response.GetResponseStream(); 873 // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
820 deserial = (TResponse)deserializer.Deserialize(respStream); 874 // documented in MSDN
821 } 875 using (WebResponse response = request.EndGetResponse(res2))
822 catch (System.InvalidOperationException) 876 {
823 { 877 try
824 } 878 {
825 finally 879 using (Stream respStream = response.GetResponseStream())
826 { 880 {
827 respStream.Close(); 881 deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
828 response.Close(); 882 reqnum, respStream, response.ContentLength);
883 }
884 }
885 catch (System.InvalidOperationException)
886 {
887 }
888 }
829 } 889 }
830 } 890 catch (WebException e)
831 catch (WebException e)
832 {
833 if (e.Status == WebExceptionStatus.ProtocolError)
834 { 891 {
835 if (e.Response is HttpWebResponse) 892 if (e.Status == WebExceptionStatus.ProtocolError)
836 { 893 {
837 HttpWebResponse httpResponse = (HttpWebResponse)e.Response; 894 if (e.Response is HttpWebResponse)
838
839 if (httpResponse.StatusCode != HttpStatusCode.NotFound)
840 { 895 {
841 // We don't appear to be handling any other status codes, so log these feailures to that 896 using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response)
842 // people don't spend unnecessary hours hunting phantom bugs. 897 {
843 m_log.DebugFormat( 898 if (httpResponse.StatusCode != HttpStatusCode.NotFound)
844 "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", 899 {
845 verb, requestUrl, httpResponse.StatusCode); 900 // We don't appear to be handling any other status codes, so log these feailures to that
901 // people don't spend unnecessary hours hunting phantom bugs.
902 m_log.DebugFormat(
903 "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}",
904 verb, requestUrl, httpResponse.StatusCode);
905 }
906 }
846 } 907 }
847 } 908 }
909 else
910 {
911 m_log.ErrorFormat(
912 "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}",
913 verb, requestUrl, e.Status, e.Message);
914 }
848 } 915 }
849 else 916 catch (Exception e)
850 { 917 {
851 m_log.ErrorFormat( 918 m_log.ErrorFormat(
852 "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", 919 "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}",
853 verb, requestUrl, e.Status, e.Message); 920 verb, requestUrl, e.Message, e.StackTrace);
854 } 921 }
855 } 922
856 catch (Exception e) 923 // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
857 {
858 m_log.ErrorFormat(
859 "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}",
860 verb, requestUrl, e.Message, e.StackTrace);
861 }
862
863 // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
864 924
865 try 925 try
866 { 926 {
867 action(deserial); 927 action(deserial);
868 } 928 }
869 catch (Exception e) 929 catch (Exception e)
930 {
931 m_log.ErrorFormat(
932 "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}",
933 verb, requestUrl, e.Message, e.StackTrace);
934 }
935
936 }, null);
937 }
938
939 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
940 if (tickdiff > WebUtil.LongCallTime)
941 {
942 string originalRequest = null;
943
944 if (buffer != null)
870 { 945 {
871 m_log.ErrorFormat( 946 originalRequest = Encoding.UTF8.GetString(buffer.ToArray());
872 "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}",
873 verb, requestUrl, e.Message, e.StackTrace);
874 }
875
876 }, null);
877 }
878 947
879 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 948 if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
880 if (tickdiff > WebUtil.LongCallTime) 949 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
881 { 950 }
882 string originalRequest = null;
883 951
884 if (buffer != null) 952 m_log.InfoFormat(
953 "[LOGHTTP]: Slow AsynchronousRequestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
954 reqnum, verb, requestUrl, tickdiff, tickdata,
955 originalRequest);
956 }
957 else if (WebUtil.DebugLevel >= 4)
885 { 958 {
886 originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); 959 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
887 960 reqnum, tickdiff, tickdata);
888 if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
889 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
890 } 961 }
891
892 m_log.InfoFormat(
893 "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}",
894 reqnum,
895 verb,
896 requestUrl,
897 tickdiff,
898 tickdata,
899 originalRequest);
900 } 962 }
901 else if (WebUtil.DebugLevel >= 4) 963 finally
902 { 964 {
903 m_log.DebugFormat( 965 if (buffer != null)
904 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 966 buffer.Dispose();
905 reqnum, tickdiff, tickdata);
906 } 967 }
907 } 968 }
908 } 969 }
@@ -917,17 +978,17 @@ namespace OpenSim.Framework
917 /// <param name="verb"></param> 978 /// <param name="verb"></param>
918 /// <param name="requestUrl"></param> 979 /// <param name="requestUrl"></param>
919 /// <param name="obj"> </param> 980 /// <param name="obj"> </param>
981 /// <param name="timeoutsecs"> </param>
920 /// <returns></returns> 982 /// <returns></returns>
921 /// 983 ///
922 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting 984 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
923 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> 985 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
924 public static string MakeRequest(string verb, string requestUrl, string obj) 986 public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs, IServiceAuth auth)
925 { 987 {
926 int reqnum = WebUtil.RequestNumber++; 988 int reqnum = WebUtil.RequestNumber++;
927 989
928 if (WebUtil.DebugLevel >= 3) 990 if (WebUtil.DebugLevel >= 3)
929 m_log.DebugFormat( 991 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestForms {1} to {2}",
930 "[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}",
931 reqnum, verb, requestUrl); 992 reqnum, verb, requestUrl);
932 993
933 int tickstart = Util.EnvironmentTickCount(); 994 int tickstart = Util.EnvironmentTickCount();
@@ -935,6 +996,12 @@ namespace OpenSim.Framework
935 996
936 WebRequest request = WebRequest.Create(requestUrl); 997 WebRequest request = WebRequest.Create(requestUrl);
937 request.Method = verb; 998 request.Method = verb;
999 if (timeoutsecs > 0)
1000 request.Timeout = timeoutsecs * 1000;
1001
1002 if (auth != null)
1003 auth.AddAuthorization(request.Headers);
1004
938 string respstring = String.Empty; 1005 string respstring = String.Empty;
939 1006
940 using (MemoryStream buffer = new MemoryStream()) 1007 using (MemoryStream buffer = new MemoryStream())
@@ -952,22 +1019,27 @@ namespace OpenSim.Framework
952 1019
953 length = (int)obj.Length; 1020 length = (int)obj.Length;
954 request.ContentLength = length; 1021 request.ContentLength = length;
1022 byte[] data = buffer.ToArray();
1023
1024 if (WebUtil.DebugLevel >= 5)
1025 WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
955 1026
956 Stream requestStream = null; 1027 Stream requestStream = null;
957 try 1028 try
958 { 1029 {
959 requestStream = request.GetRequestStream(); 1030 requestStream = request.GetRequestStream();
960 requestStream.Write(buffer.ToArray(), 0, length); 1031 requestStream.Write(data, 0, length);
961 } 1032 }
962 catch (Exception e) 1033 catch (Exception e)
963 { 1034 {
964 m_log.DebugFormat( 1035 m_log.InfoFormat("[FORMS]: Error sending request to {0}: {1}. Request: {2}", requestUrl, e.Message,
965 "[FORMS]: exception occured {0} {1}: {2}{3}", verb, requestUrl, e.Message, e.StackTrace); 1036 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1037 throw e;
966 } 1038 }
967 finally 1039 finally
968 { 1040 {
969 if (requestStream != null) 1041 if (requestStream != null)
970 requestStream.Close(); 1042 requestStream.Dispose();
971 1043
972 // capture how much time was spent writing 1044 // capture how much time was spent writing
973 tickdata = Util.EnvironmentTickCountSubtract(tickstart); 1045 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
@@ -980,53 +1052,54 @@ namespace OpenSim.Framework
980 { 1052 {
981 if (resp.ContentLength != 0) 1053 if (resp.ContentLength != 0)
982 { 1054 {
983 Stream respStream = null; 1055 using (Stream respStream = resp.GetResponseStream())
984 try
985 {
986 respStream = resp.GetResponseStream();
987 using (StreamReader reader = new StreamReader(respStream)) 1056 using (StreamReader reader = new StreamReader(respStream))
988 {
989 respstring = reader.ReadToEnd(); 1057 respstring = reader.ReadToEnd();
990 }
991 }
992 catch (Exception e)
993 {
994 m_log.DebugFormat(
995 "[FORMS]: Exception occured on receiving {0} {1}: {2}{3}",
996 verb, requestUrl, e.Message, e.StackTrace);
997 }
998 finally
999 {
1000 if (respStream != null)
1001 respStream.Close();
1002 }
1003 } 1058 }
1004 } 1059 }
1005 } 1060 }
1006 catch (System.InvalidOperationException) 1061 catch (Exception e)
1007 { 1062 {
1008 // This is what happens when there is invalid XML 1063 m_log.InfoFormat("[FORMS]: Error receiving response from {0}: {1}. Request: {2}", requestUrl, e.Message,
1009 m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving {0} {1}", verb, requestUrl); 1064 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1065 throw e;
1010 } 1066 }
1011 } 1067 }
1012 1068
1013 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 1069 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
1014 if (tickdiff > WebUtil.LongCallTime) 1070 if (tickdiff > WebUtil.LongCallTime)
1071 {
1015 m_log.InfoFormat( 1072 m_log.InfoFormat(
1016 "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 1073 "[LOGHTTP]: Slow SynchronousRestForms request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
1017 reqnum, 1074 reqnum, verb, requestUrl, tickdiff, tickdata,
1018 verb,
1019 requestUrl,
1020 tickdiff,
1021 tickdata,
1022 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); 1075 obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
1076 }
1023 else if (WebUtil.DebugLevel >= 4) 1077 else if (WebUtil.DebugLevel >= 4)
1024 m_log.DebugFormat( 1078 {
1025 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 1079 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
1026 reqnum, tickdiff, tickdata); 1080 reqnum, tickdiff, tickdata);
1081 }
1082
1083 if (WebUtil.DebugLevel >= 5)
1084 WebUtil.LogResponseDetail(reqnum, respstring);
1027 1085
1028 return respstring; 1086 return respstring;
1029 } 1087 }
1088
1089 public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs)
1090 {
1091 return MakeRequest(verb, requestUrl, obj, timeoutsecs, null);
1092 }
1093
1094 public static string MakeRequest(string verb, string requestUrl, string obj)
1095 {
1096 return MakeRequest(verb, requestUrl, obj, -1);
1097 }
1098
1099 public static string MakeRequest(string verb, string requestUrl, string obj, IServiceAuth auth)
1100 {
1101 return MakeRequest(verb, requestUrl, obj, -1, auth);
1102 }
1030 } 1103 }
1031 1104
1032 public class SynchronousRestObjectRequester 1105 public class SynchronousRestObjectRequester
@@ -1040,28 +1113,80 @@ namespace OpenSim.Framework
1040 /// </summary> 1113 /// </summary>
1041 /// <param name="verb"></param> 1114 /// <param name="verb"></param>
1042 /// <param name="requestUrl"></param> 1115 /// <param name="requestUrl"></param>
1043 /// <param name="obj"> </param> 1116 /// <param name="obj"></param>
1044 /// <returns></returns> 1117 /// <returns>
1045 /// 1118 /// The response. If there was an internal exception, then the default(TResponse) is returned.
1046 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting 1119 /// </returns>
1047 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
1048 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) 1120 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
1049 { 1121 {
1050 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0); 1122 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0);
1051 } 1123 }
1052 1124
1125 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, IServiceAuth auth)
1126 {
1127 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0, auth);
1128 }
1129 /// <summary>
1130 /// Perform a synchronous REST request.
1131 /// </summary>
1132 /// <param name="verb"></param>
1133 /// <param name="requestUrl"></param>
1134 /// <param name="obj"></param>
1135 /// <param name="pTimeout">
1136 /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
1137 /// </param>
1138 /// <returns>
1139 /// The response. If there was an internal exception or the request timed out,
1140 /// then the default(TResponse) is returned.
1141 /// </returns>
1053 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout) 1142 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
1054 { 1143 {
1055 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0); 1144 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
1056 } 1145 }
1057 1146
1147 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth)
1148 {
1149 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0, auth);
1150 }
1151
1152 /// Perform a synchronous REST request.
1153 /// </summary>
1154 /// <param name="verb"></param>
1155 /// <param name="requestUrl"></param>
1156 /// <param name="obj"></param>
1157 /// <param name="pTimeout">
1158 /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
1159 /// </param>
1160 /// <param name="maxConnections"></param>
1161 /// <returns>
1162 /// The response. If there was an internal exception or the request timed out,
1163 /// then the default(TResponse) is returned.
1164 /// </returns>
1058 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) 1165 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
1059 { 1166 {
1167 return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, maxConnections, null);
1168 }
1169
1170 /// <summary>
1171 /// Perform a synchronous REST request.
1172 /// </summary>
1173 /// <param name="verb"></param>
1174 /// <param name="requestUrl"></param>
1175 /// <param name="obj"></param>
1176 /// <param name="pTimeout">
1177 /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
1178 /// </param>
1179 /// <param name="maxConnections"></param>
1180 /// <returns>
1181 /// The response. If there was an internal exception or the request timed out,
1182 /// then the default(TResponse) is returned.
1183 /// </returns>
1184 public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections, IServiceAuth auth)
1185 {
1060 int reqnum = WebUtil.RequestNumber++; 1186 int reqnum = WebUtil.RequestNumber++;
1061 1187
1062 if (WebUtil.DebugLevel >= 3) 1188 if (WebUtil.DebugLevel >= 3)
1063 m_log.DebugFormat( 1189 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestObject {1} to {2}",
1064 "[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}",
1065 reqnum, verb, requestUrl); 1190 reqnum, verb, requestUrl);
1066 1191
1067 int tickstart = Util.EnvironmentTickCount(); 1192 int tickstart = Util.EnvironmentTickCount();
@@ -1072,129 +1197,252 @@ namespace OpenSim.Framework
1072 1197
1073 WebRequest request = WebRequest.Create(requestUrl); 1198 WebRequest request = WebRequest.Create(requestUrl);
1074 HttpWebRequest ht = (HttpWebRequest)request; 1199 HttpWebRequest ht = (HttpWebRequest)request;
1200
1201 if (auth != null)
1202 auth.AddAuthorization(ht.Headers);
1203
1204 if (pTimeout != 0)
1205 ht.Timeout = pTimeout;
1206
1075 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) 1207 if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections)
1076 ht.ServicePoint.ConnectionLimit = maxConnections; 1208 ht.ServicePoint.ConnectionLimit = maxConnections;
1077 1209
1078 request.Method = verb; 1210 request.Method = verb;
1079 MemoryStream buffer = null; 1211 MemoryStream buffer = null;
1080 1212
1081 if ((verb == "POST") || (verb == "PUT")) 1213 try
1082 { 1214 {
1083 request.ContentType = "text/xml"; 1215 if ((verb == "POST") || (verb == "PUT"))
1216 {
1217 request.ContentType = "text/xml";
1084 1218
1085 buffer = new MemoryStream(); 1219 buffer = new MemoryStream();
1086 1220
1087 XmlWriterSettings settings = new XmlWriterSettings(); 1221 XmlWriterSettings settings = new XmlWriterSettings();
1088 settings.Encoding = Encoding.UTF8; 1222 settings.Encoding = Encoding.UTF8;
1089 1223
1090 using (XmlWriter writer = XmlWriter.Create(buffer, settings)) 1224 using (XmlWriter writer = XmlWriter.Create(buffer, settings))
1091 { 1225 {
1092 XmlSerializer serializer = new XmlSerializer(type); 1226 XmlSerializer serializer = new XmlSerializer(type);
1093 serializer.Serialize(writer, obj); 1227 serializer.Serialize(writer, obj);
1094 writer.Flush(); 1228 writer.Flush();
1095 } 1229 }
1230
1231 int length = (int)buffer.Length;
1232 request.ContentLength = length;
1233 byte[] data = buffer.ToArray();
1234
1235 if (WebUtil.DebugLevel >= 5)
1236 WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data));
1237
1238 try
1239 {
1240 using (Stream requestStream = request.GetRequestStream())
1241 requestStream.Write(data, 0, length);
1242 }
1243 catch (Exception e)
1244 {
1245 m_log.DebugFormat(
1246 "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}",
1247 verb, requestUrl, e.Message, e.StackTrace);
1096 1248
1097 int length = (int)buffer.Length; 1249 return deserial;
1098 request.ContentLength = length; 1250 }
1251 finally
1252 {
1253 // capture how much time was spent writing
1254 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
1255 }
1256 }
1099 1257
1100 Stream requestStream = null;
1101 try 1258 try
1102 { 1259 {
1103 requestStream = request.GetRequestStream(); 1260 using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
1104 requestStream.Write(buffer.ToArray(), 0, length); 1261 {
1262 if (resp.ContentLength != 0)
1263 {
1264 using (Stream respStream = resp.GetResponseStream())
1265 {
1266 deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
1267 reqnum, respStream, resp.ContentLength);
1268 }
1269 }
1270 else
1271 {
1272 m_log.DebugFormat(
1273 "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}",
1274 verb, requestUrl);
1275 }
1276 }
1105 } 1277 }
1106 catch (Exception e) 1278 catch (WebException e)
1107 { 1279 {
1280 using (HttpWebResponse hwr = (HttpWebResponse)e.Response)
1281 {
1282 if (hwr != null)
1283 {
1284 if (hwr.StatusCode == HttpStatusCode.NotFound)
1285 return deserial;
1286 if (hwr.StatusCode == HttpStatusCode.Unauthorized)
1287 {
1288 m_log.Error(string.Format(
1289 "[SynchronousRestObjectRequester]: Web request {0} requires authentication ",
1290 requestUrl));
1291 return deserial;
1292 }
1293 }
1294 else
1295 m_log.Error(string.Format(
1296 "[SynchronousRestObjectRequester]: WebException for {0} {1} {2} ",
1297 verb, requestUrl, typeof(TResponse).ToString()), e);
1298 }
1299 }
1300 catch (System.InvalidOperationException)
1301 {
1302 // This is what happens when there is invalid XML
1108 m_log.DebugFormat( 1303 m_log.DebugFormat(
1109 "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", 1304 "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}",
1110 verb, requestUrl, e.Message, e.StackTrace); 1305 verb, requestUrl, typeof(TResponse).ToString());
1111
1112 return deserial;
1113 } 1306 }
1114 finally 1307 catch (Exception e)
1115 { 1308 {
1116 if (requestStream != null) 1309 m_log.Debug(string.Format(
1117 requestStream.Close(); 1310 "[SynchronousRestObjectRequester]: Exception on response from {0} {1} ",
1118 1311 verb, requestUrl), e);
1119 // capture how much time was spent writing
1120 tickdata = Util.EnvironmentTickCountSubtract(tickstart);
1121 } 1312 }
1122 }
1123 1313
1124 try 1314 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
1125 { 1315 if (tickdiff > WebUtil.LongCallTime)
1126 using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
1127 { 1316 {
1128 if (resp.ContentLength != 0) 1317 string originalRequest = null;
1129 { 1318
1130 Stream respStream = resp.GetResponseStream(); 1319 if (buffer != null)
1131 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
1132 deserial = (TResponse)deserializer.Deserialize(respStream);
1133 respStream.Close();
1134 }
1135 else
1136 { 1320 {
1137 m_log.DebugFormat( 1321 originalRequest = Encoding.UTF8.GetString(buffer.ToArray());
1138 "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", 1322
1139 verb, requestUrl); 1323 if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
1324 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
1140 } 1325 }
1141 }
1142 }
1143 catch (WebException e)
1144 {
1145 HttpWebResponse hwr = (HttpWebResponse)e.Response;
1146 1326
1147 if (hwr != null && hwr.StatusCode == HttpStatusCode.NotFound) 1327 m_log.InfoFormat(
1148 return deserial; 1328 "[LOGHTTP]: Slow SynchronousRestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}",
1149 else 1329 reqnum, verb, requestUrl, tickdiff, tickdata,
1150 m_log.ErrorFormat( 1330 originalRequest);
1151 "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}", 1331 }
1152 verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); 1332 else if (WebUtil.DebugLevel >= 4)
1333 {
1334 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing",
1335 reqnum, tickdiff, tickdata);
1336 }
1153 } 1337 }
1154 catch (System.InvalidOperationException) 1338 finally
1155 { 1339 {
1156 // This is what happens when there is invalid XML 1340 if (buffer != null)
1157 m_log.DebugFormat( 1341 buffer.Dispose();
1158 "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}",
1159 verb, requestUrl, typeof(TResponse).ToString());
1160 } 1342 }
1161 catch (Exception e) 1343
1344 return deserial;
1345 }
1346
1347
1348 public static class XMLResponseHelper
1349 {
1350 public static TResponse LogAndDeserialize<TRequest, TResponse>(int reqnum, Stream respStream, long contentLength)
1162 { 1351 {
1163 m_log.DebugFormat( 1352 XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
1164 "[SynchronousRestObjectRequester]: Exception on response from {0} {1}: {2}{3}", 1353
1165 verb, requestUrl, e.Message, e.StackTrace); 1354 if (WebUtil.DebugLevel >= 5)
1355 {
1356 byte[] data = new byte[contentLength];
1357 Util.ReadStream(respStream, data);
1358
1359 WebUtil.LogResponseDetail(reqnum, System.Text.Encoding.UTF8.GetString(data));
1360
1361 using (MemoryStream temp = new MemoryStream(data))
1362 return (TResponse)deserializer.Deserialize(temp);
1363 }
1364 else
1365 {
1366 return (TResponse)deserializer.Deserialize(respStream);
1367 }
1166 } 1368 }
1369 }
1370 }
1167 1371
1168 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); 1372
1169 if (tickdiff > WebUtil.LongCallTime) 1373 public static class XMLRPCRequester
1374 {
1375 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
1376
1377 public static Hashtable SendRequest(Hashtable ReqParams, string method, string url)
1378 {
1379 int reqnum = WebUtil.RequestNumber++;
1380
1381 if (WebUtil.DebugLevel >= 3)
1382 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} XML-RPC '{1}' to {2}",
1383 reqnum, method, url);
1384
1385 int tickstart = Util.EnvironmentTickCount();
1386 string responseStr = null;
1387
1388 try
1170 { 1389 {
1171 string originalRequest = null; 1390 ArrayList SendParams = new ArrayList();
1391 SendParams.Add(ReqParams);
1172 1392
1173 if (buffer != null) 1393 XmlRpcRequest Req = new XmlRpcRequest(method, SendParams);
1394
1395 if (WebUtil.DebugLevel >= 5)
1396 {
1397 string str = Req.ToString();
1398 str = XElement.Parse(str).ToString(SaveOptions.DisableFormatting);
1399 WebUtil.LogOutgoingDetail("SEND", reqnum, str);
1400 }
1401
1402 XmlRpcResponse Resp = Req.Send(url, 30000);
1403
1404 try
1174 { 1405 {
1175 originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); 1406 responseStr = Resp.ToString();
1407 responseStr = XElement.Parse(responseStr).ToString(SaveOptions.DisableFormatting);
1176 1408
1177 if (originalRequest.Length > WebUtil.MaxRequestDiagLength) 1409 if (WebUtil.DebugLevel >= 5)
1178 originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); 1410 WebUtil.LogResponseDetail(reqnum, responseStr);
1411 }
1412 catch (Exception e)
1413 {
1414 m_log.Error("Error parsing XML-RPC response", e);
1415 }
1416
1417 if (Resp.IsFault)
1418 {
1419 m_log.DebugFormat(
1420 "[LOGHTTP]: XML-RPC request {0} '{1}' to {2} FAILED: FaultCode={3}, FaultMessage={4}",
1421 reqnum, method, url, Resp.FaultCode, Resp.FaultString);
1422 return null;
1179 } 1423 }
1180 1424
1181 m_log.InfoFormat( 1425 Hashtable RespData = (Hashtable)Resp.Value;
1182 "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", 1426 return RespData;
1183 reqnum,
1184 verb,
1185 requestUrl,
1186 tickdiff,
1187 tickdata,
1188 originalRequest);
1189 } 1427 }
1190 else if (WebUtil.DebugLevel >= 4) 1428 finally
1191 { 1429 {
1192 m_log.DebugFormat( 1430 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
1193 "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", 1431 if (tickdiff > WebUtil.LongCallTime)
1194 reqnum, tickdiff, tickdata); 1432 {
1433 m_log.InfoFormat(
1434 "[LOGHTTP]: Slow XML-RPC request {0} '{1}' to {2} took {3}ms, {4}",
1435 reqnum, method, url, tickdiff,
1436 responseStr != null
1437 ? (responseStr.Length > WebUtil.MaxRequestDiagLength ? responseStr.Remove(WebUtil.MaxRequestDiagLength) : responseStr)
1438 : "");
1439 }
1440 else if (WebUtil.DebugLevel >= 4)
1441 {
1442 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms", reqnum, tickdiff);
1443 }
1195 } 1444 }
1196
1197 return deserial;
1198 } 1445 }
1446
1199 } 1447 }
1200} 1448}