diff options
Diffstat (limited to '')
159 files changed, 12739 insertions, 4602 deletions
diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs index 1095b23..cf0de1d 100644 --- a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs +++ b/OpenSim/Addons/Groups/Properties/AssemblyInfo.cs | |||
@@ -1,16 +1,17 @@ | |||
1 | using System.Reflection; | 1 | using System.Reflection; |
2 | using System.Runtime.CompilerServices; | 2 | using System.Runtime.CompilerServices; |
3 | using System.Runtime.InteropServices; | 3 | using System.Runtime.InteropServices; |
4 | using Mono.Addins; | ||
4 | 5 | ||
5 | // General Information about an assembly is controlled through the following | 6 | // General Information about an assembly is controlled through the following |
6 | // set of attributes. Change these attribute values to modify the information | 7 | // set of attributes. Change these attribute values to modify the information |
7 | // associated with an assembly. | 8 | // associated with an assembly. |
8 | [assembly: AssemblyTitle("OpenSim.Framework.Configuration.XML")] | 9 | [assembly: AssemblyTitle("OpenSim.Addons.Groups")] |
9 | [assembly: AssemblyDescription("")] | 10 | [assembly: AssemblyDescription("")] |
10 | [assembly: AssemblyConfiguration("")] | 11 | [assembly: AssemblyConfiguration("")] |
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | 12 | [assembly: AssemblyCompany("http://opensimulator.org")] |
12 | [assembly: AssemblyProduct("OpenSim")] | 13 | [assembly: AssemblyProduct("OpenSim.Addons.Groups")] |
13 | [assembly: AssemblyCopyright("OpenSimulator developers")] | 14 | [assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] |
14 | [assembly: AssemblyTrademark("")] | 15 | [assembly: AssemblyTrademark("")] |
15 | [assembly: AssemblyCulture("")] | 16 | [assembly: AssemblyCulture("")] |
16 | 17 | ||
@@ -20,7 +21,7 @@ using System.Runtime.InteropServices; | |||
20 | [assembly: ComVisible(false)] | 21 | [assembly: ComVisible(false)] |
21 | 22 | ||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | 23 | // 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 | [assembly: Guid("313d4865-d179-4735-9b5a-fe74885878b2")] |
24 | 25 | ||
25 | // Version information for an assembly consists of the following four values: | 26 | // Version information for an assembly consists of the following four values: |
26 | // | 27 | // |
@@ -29,5 +30,7 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 30 | // Build Number |
30 | // Revision | 31 | // Revision |
31 | // | 32 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 33 | [assembly: AssemblyVersion("0.8.3.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 34 | |
35 | [assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)] | ||
36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | ||
diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs index 0674656..0699660 100644 --- a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs +++ b/OpenSim/Addons/OfflineIM/Properties/AssemblyInfo.cs | |||
@@ -1,16 +1,17 @@ | |||
1 | using System.Reflection; | 1 | using System.Reflection; |
2 | using System.Runtime.CompilerServices; | 2 | using System.Runtime.CompilerServices; |
3 | using System.Runtime.InteropServices; | 3 | using System.Runtime.InteropServices; |
4 | using Mono.Addins; | ||
4 | 5 | ||
5 | // General Information about an assembly is controlled through the following | 6 | // General Information about an assembly is controlled through the following |
6 | // set of attributes. Change these attribute values to modify the information | 7 | // set of attributes. Change these attribute values to modify the information |
7 | // associated with an assembly. | 8 | // associated with an assembly. |
8 | [assembly: AssemblyTitle("OpenSim.Framework.Configuration.HTTP")] | 9 | [assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")] |
9 | [assembly: AssemblyDescription("")] | 10 | [assembly: AssemblyDescription("")] |
10 | [assembly: AssemblyConfiguration("")] | 11 | [assembly: AssemblyConfiguration("")] |
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | 12 | [assembly: AssemblyCompany("http://opensimulator.org")] |
12 | [assembly: AssemblyProduct("OpenSim")] | 13 | [assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")] |
13 | [assembly: AssemblyCopyright("OpenSimulator develoeprs")] | 14 | [assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")] |
14 | [assembly: AssemblyTrademark("")] | 15 | [assembly: AssemblyTrademark("")] |
15 | [assembly: AssemblyCulture("")] | 16 | [assembly: AssemblyCulture("")] |
16 | 17 | ||
@@ -20,7 +21,7 @@ using System.Runtime.InteropServices; | |||
20 | [assembly: ComVisible(false)] | 21 | [assembly: ComVisible(false)] |
21 | 22 | ||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | 23 | // 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 | [assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")] |
24 | 25 | ||
25 | // Version information for an assembly consists of the following four values: | 26 | // Version information for an assembly consists of the following four values: |
26 | // | 27 | // |
@@ -29,5 +30,7 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 30 | // Build Number |
30 | // Revision | 31 | // Revision |
31 | // | 32 | // |
32 | [assembly: AssemblyVersion("0.7.5.*")] | 33 | [assembly: AssemblyVersion("0.8.3.*")] |
33 | [assembly: AssemblyFileVersion("1.0.0.0")] | 34 | |
35 | [assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)] | ||
36 | [assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)] | ||
diff --git a/OpenSim/Framework/IRegionLoader.cs b/OpenSim/ApplicationPlugins/LoadRegions/IRegionLoader.cs index c566fc7..2d1505d 100644 --- a/OpenSim/Framework/IRegionLoader.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/IRegionLoader.cs | |||
@@ -26,8 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using Nini.Config; | 28 | using Nini.Config; |
29 | using OpenSim.Framework; | ||
29 | 30 | ||
30 | namespace OpenSim.Framework | 31 | namespace OpenSim.ApplicationPlugins.LoadRegions |
31 | { | 32 | { |
32 | public interface IRegionLoader | 33 | public interface IRegionLoader |
33 | { | 34 | { |
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs index 8332c14..1873a06 100644 --- a/OpenSim/Framework/RegionLoader/Filesystem/RegionLoaderFileSystem.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderFileSystem.cs | |||
@@ -31,8 +31,9 @@ using System.Collections.Generic; | |||
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenSim.Framework; | ||
34 | 35 | ||
35 | namespace OpenSim.Framework.RegionLoader.Filesystem | 36 | namespace OpenSim.ApplicationPlugins.LoadRegions |
36 | { | 37 | { |
37 | public class RegionLoaderFileSystem : IRegionLoader | 38 | public class RegionLoaderFileSystem : IRegionLoader |
38 | { | 39 | { |
diff --git a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderWebServer.cs index a2f5d9c..850f3e0 100644 --- a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs +++ b/OpenSim/ApplicationPlugins/LoadRegions/RegionLoaderWebServer.cs | |||
@@ -32,8 +32,9 @@ using System.Reflection; | |||
32 | using System.Xml; | 32 | using System.Xml; |
33 | using log4net; | 33 | using log4net; |
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using OpenSim.Framework; | ||
35 | 36 | ||
36 | namespace OpenSim.Framework.RegionLoader.Web | 37 | namespace OpenSim.ApplicationPlugins.LoadRegions |
37 | { | 38 | { |
38 | public class RegionLoaderWebServer : IRegionLoader | 39 | public class RegionLoaderWebServer : IRegionLoader |
39 | { | 40 | { |
@@ -74,21 +75,31 @@ namespace OpenSim.Framework.RegionLoader.Web | |||
74 | 75 | ||
75 | try | 76 | try |
76 | { | 77 | { |
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; | 78 | string xmlSource = String.Empty; |
81 | string tempStr = reader.ReadLine(); | 79 | |
82 | while (tempStr != null) | 80 | using (HttpWebResponse webResponse = (HttpWebResponse) webRequest.GetResponse()) |
83 | { | 81 | { |
84 | xmlSource = xmlSource + tempStr; | 82 | m_log.Debug("[WEBLOADER]: Downloading region information..."); |
85 | tempStr = reader.ReadLine(); | 83 | |
84 | using (Stream s = webResponse.GetResponseStream()) | ||
85 | { | ||
86 | using (StreamReader reader = new StreamReader(s)) | ||
87 | { | ||
88 | string tempStr = reader.ReadLine(); | ||
89 | while (tempStr != null) | ||
90 | { | ||
91 | xmlSource = xmlSource + tempStr; | ||
92 | tempStr = reader.ReadLine(); | ||
93 | } | ||
94 | } | ||
95 | } | ||
86 | } | 96 | } |
97 | |||
87 | m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + | 98 | m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + |
88 | xmlSource.Length); | 99 | xmlSource.Length); |
89 | XmlDocument xmlDoc = new XmlDocument(); | 100 | XmlDocument xmlDoc = new XmlDocument(); |
90 | xmlDoc.LoadXml(xmlSource); | 101 | xmlDoc.LoadXml(xmlSource); |
91 | if (xmlDoc.FirstChild.Name == "Regions") | 102 | if (xmlDoc.FirstChild.Name == "Nini") |
92 | { | 103 | { |
93 | regionCount = xmlDoc.FirstChild.ChildNodes.Count; | 104 | regionCount = xmlDoc.FirstChild.ChildNodes.Count; |
94 | 105 | ||
@@ -107,17 +118,24 @@ namespace OpenSim.Framework.RegionLoader.Web | |||
107 | } | 118 | } |
108 | catch (WebException ex) | 119 | catch (WebException ex) |
109 | { | 120 | { |
110 | if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound) | 121 | using (HttpWebResponse response = (HttpWebResponse)ex.Response) |
111 | { | 122 | { |
112 | if (!allowRegionless) | 123 | if (response.StatusCode == HttpStatusCode.NotFound) |
124 | { | ||
125 | if (!allowRegionless) | ||
126 | throw ex; | ||
127 | } | ||
128 | else | ||
129 | { | ||
113 | throw ex; | 130 | throw ex; |
131 | } | ||
114 | } | 132 | } |
115 | else | ||
116 | throw ex; | ||
117 | } | 133 | } |
118 | 134 | ||
119 | if (regionCount > 0 | allowRegionless) | 135 | if (regionCount > 0 | allowRegionless) |
136 | { | ||
120 | return regionInfos; | 137 | return regionInfos; |
138 | } | ||
121 | else | 139 | else |
122 | { | 140 | { |
123 | m_log.Error("[WEBLOADER]: No region configs were available."); | 141 | m_log.Error("[WEBLOADER]: No region configs were available."); |
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 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | |||
32 | namespace 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/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs new file mode 100644 index 0000000..239fc56 --- /dev/null +++ b/OpenSim/Framework/CachedTextureEventArg.cs | |||
@@ -0,0 +1,46 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Framework | ||
33 | { | ||
34 | public class CachedTextureRequestArg | ||
35 | { | ||
36 | public int BakedTextureIndex; | ||
37 | public UUID WearableHashID; | ||
38 | } | ||
39 | |||
40 | public class CachedTextureResponseArg | ||
41 | { | ||
42 | public int BakedTextureIndex; | ||
43 | public UUID BakedTextureID; | ||
44 | public String HostName; | ||
45 | } | ||
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 | /* | ||
2 | Copyright (c) 2012, Alex Regueiro | ||
3 | All rights reserved. | ||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the | ||
5 | following conditions are met: | ||
6 | |||
7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
8 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer | ||
9 | in the documentation and/or other materials provided with the distribution. | ||
10 | |||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, | ||
12 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
13 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | ||
14 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | ||
15 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
16 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
17 | POSSIBILITY OF SUCH DAMAGE. | ||
18 | */ | ||
19 | using System; | ||
20 | using System.Collections; | ||
21 | using System.Collections.Generic; | ||
22 | using System.Threading; | ||
23 | |||
24 | namespace 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 | |||
28 | using System; | ||
29 | using System.Threading; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Services.Interfaces; | ||
32 | |||
33 | namespace 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 | |||
28 | namespace 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/NullLimitStrategy.cs b/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs deleted file mode 100644 index 7672653..0000000 --- a/OpenSim/Framework/Communications/Limit/NullLimitStrategy.cs +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
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 | |||
28 | namespace OpenSim.Framework.Communications.Limit | ||
29 | { | ||
30 | /// <summary> | ||
31 | /// Strategy which polices no limits | ||
32 | /// </summary> | ||
33 | public class NullLimitStrategy<TId> : IRequestLimitStrategy<TId> | ||
34 | { | ||
35 | public bool AllowRequest(TId id) { return true; } | ||
36 | public bool IsFirstRefusal(TId id) { return false; } | ||
37 | public void MonitorRequests(TId id) { /* intentionally blank */ } | ||
38 | public bool IsMonitoringRequests(TId id) { return false; } | ||
39 | } | ||
40 | } | ||
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 | |||
28 | using System.Collections.Generic; | ||
29 | |||
30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | |||
31 | namespace 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 | |||
28 | using System.Reflection; | ||
29 | using 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Xml; | ||
31 | using System.Xml.Serialization; | ||
32 | |||
33 | namespace 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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework.Configuration.XML; | ||
35 | |||
36 | namespace 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/RemoteConfigSettings.cs b/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs deleted file mode 100644 index 10bc88a..0000000 --- a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs +++ /dev/null | |||
@@ -1,63 +0,0 @@ | |||
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 | |||
28 | using System; | ||
29 | |||
30 | namespace OpenSim.Framework.Configuration.HTTP | ||
31 | { | ||
32 | public class RemoteConfigSettings | ||
33 | { | ||
34 | private ConfigurationMember configMember; | ||
35 | |||
36 | public string baseConfigURL = String.Empty; | ||
37 | |||
38 | public RemoteConfigSettings(string filename) | ||
39 | { | ||
40 | configMember = | ||
41 | new ConfigurationMember(filename, "REMOTE CONFIG SETTINGS", loadConfigurationOptions, | ||
42 | handleIncomingConfiguration,true); | ||
43 | configMember.forceConfigurationPluginLibrary("OpenSim.Framework.Configuration.XML.dll"); | ||
44 | configMember.performConfigurationRetrieve(); | ||
45 | } | ||
46 | |||
47 | public void loadConfigurationOptions() | ||
48 | { | ||
49 | configMember.addConfigurationOption("base_config_url", | ||
50 | ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, | ||
51 | "URL Containing Configuration Files", "http://localhost/", false); | ||
52 | } | ||
53 | |||
54 | public bool handleIncomingConfiguration(string configuration_key, object configuration_result) | ||
55 | { | ||
56 | if (configuration_key == "base_config_url") | ||
57 | { | ||
58 | baseConfigURL = (string) configuration_result; | ||
59 | } | ||
60 | return true; | ||
61 | } | ||
62 | } | ||
63 | } | ||
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 | |||
28 | using System; | ||
29 | using System.IO; | ||
30 | using System.Xml; | ||
31 | |||
32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Globalization; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Xml; | ||
34 | using log4net; | ||
35 | using OpenMetaverse; | ||
36 | //using OpenSim.Framework.Console; | ||
37 | |||
38 | namespace 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/ApplicationPlugins/Rest/Inventory/IRest.cs b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs index 8b43d42..6417663 100644 --- a/OpenSim/ApplicationPlugins/Rest/Inventory/IRest.cs +++ b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs | |||
@@ -25,19 +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 | ||
28 | namespace OpenSim.ApplicationPlugins.Rest.Inventory | 28 | using System; |
29 | |||
30 | namespace OpenSim.Framework.Console | ||
29 | { | 31 | { |
30 | /// <summary> | 32 | /// <summary> |
31 | /// This interface represents the boundary between the general purpose | 33 | /// This will be a set of typical column sizes to allow greater consistency between console commands. |
32 | /// REST plugin handling, and the functionally specific handlers. The | ||
33 | /// handler knows only to initialize and terminate all such handlers | ||
34 | /// that it finds. Implementing this interface identifies the class as | ||
35 | /// a REST handler implementation. | ||
36 | /// </summary> | 34 | /// </summary> |
37 | 35 | public static class ConsoleDisplayUtil | |
38 | internal interface IRest | ||
39 | { | 36 | { |
40 | void Initialize(); | 37 | public const int CoordTupleSize = 11; |
41 | void Close(); | 38 | public const int PortSize = 5; |
39 | |||
40 | public const int EstateNameSize = 20; | ||
41 | public const int ParcelNameSize = 40; | ||
42 | public const int RegionNameSize = 20; | ||
43 | public const int UserNameSize = 35; | ||
44 | |||
45 | public const int UuidSize = 36; | ||
46 | public const int VectorSize = 15; | ||
42 | } | 47 | } |
43 | } | 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; | |||
32 | using System.Text; | 32 | using System.Text; |
33 | using System.Text.RegularExpressions; | 33 | using System.Text.RegularExpressions; |
34 | using System.Threading; | 34 | using System.Threading; |
35 | using System.IO; | ||
36 | using Nini.Config; | ||
35 | using log4net; | 37 | using log4net; |
36 | 38 | ||
37 | namespace OpenSim.Framework.Console | 39 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | using System.Xml; | ||
35 | using System.Xml.Schema; | ||
36 | using System.Xml.Serialization; | ||
37 | using log4net; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.StructuredData; | ||
40 | |||
41 | namespace 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/Communications/XMPP/XmppMessageStanza.cs b/OpenSim/Framework/DOMap.cs index 1e8c33e..f5b650b 100644 --- a/OpenSim/Framework/Communications/XMPP/XmppMessageStanza.cs +++ b/OpenSim/Framework/DOMap.cs | |||
@@ -25,69 +25,74 @@ | |||
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 | ||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Text; | ||
33 | using System.Xml; | ||
34 | using System.Xml.Schema; | ||
28 | using System.Xml.Serialization; | 35 | using System.Xml.Serialization; |
36 | using OpenMetaverse; | ||
37 | using OpenMetaverse.StructuredData; | ||
29 | 38 | ||
30 | namespace OpenSim.Framework.Communications.XMPP | 39 | namespace OpenSim.Framework |
31 | { | 40 | { |
32 | /// <summary> | 41 | /// <summary> |
33 | /// Message types. | 42 | /// This class stores and retrieves dynamic objects. |
34 | /// </summary> | 43 | /// </summary> |
35 | public enum XmppMessageType | 44 | /// <remarks> |
45 | /// Experimental - DO NOT USE. Does not yet have namespace support. | ||
46 | /// </remarks> | ||
47 | public class DOMap | ||
36 | { | 48 | { |
37 | [XmlEnum("chat")] chat, | 49 | private IDictionary<string, object> m_map; |
38 | [XmlEnum("error")] error, | 50 | |
39 | [XmlEnum("groupchat")] groupchat, | 51 | public void Add(string ns, string objName, object dynObj) |
40 | [XmlEnum("headline")] headline, | ||
41 | [XmlEnum("normal")] normal, | ||
42 | } | ||
43 | |||
44 | /// <summary> | ||
45 | /// Message body. | ||
46 | /// </summary> | ||
47 | public class XmppMessageBody | ||
48 | { | ||
49 | [XmlText] | ||
50 | public string Text; | ||
51 | |||
52 | public XmppMessageBody() | ||
53 | { | 52 | { |
54 | } | 53 | DAMap.ValidateNamespace(ns); |
55 | 54 | ||
56 | public XmppMessageBody(string message) | 55 | lock (this) |
57 | { | 56 | { |
58 | Text = message; | 57 | if (m_map == null) |
58 | m_map = new Dictionary<string, object>(); | ||
59 | |||
60 | m_map.Add(objName, dynObj); | ||
61 | } | ||
59 | } | 62 | } |
60 | 63 | ||
61 | new public string ToString() | 64 | public bool ContainsKey(string key) |
62 | { | 65 | { |
63 | return Text; | 66 | return Get(key) != null; |
64 | } | 67 | } |
65 | } | ||
66 | 68 | ||
67 | [XmlRoot("message")] | ||
68 | public class XmppMessageStanza: XmppStanza | ||
69 | { | ||
70 | /// <summary> | 69 | /// <summary> |
71 | /// IQ type: one of set, get, result, error | 70 | /// Get a dynamic object |
72 | /// </summary> | 71 | /// </summary> |
73 | [XmlAttribute("type")] | 72 | /// <remarks> |
74 | public XmppMessageType MessageType; | 73 | /// Not providing an index method so that users can't casually overwrite each other's objects. |
75 | 74 | /// </remarks> | |
76 | // [XmlAttribute("error")] | 75 | /// <param name='key'></param> |
77 | // public XmppError Error; | 76 | public object Get(string key) |
78 | |||
79 | [XmlElement("body")] | ||
80 | public XmppMessageBody Body; | ||
81 | |||
82 | public XmppMessageStanza() : base() | ||
83 | { | 77 | { |
78 | lock (this) | ||
79 | { | ||
80 | if (m_map == null) | ||
81 | return null; | ||
82 | else | ||
83 | return m_map[key]; | ||
84 | } | ||
84 | } | 85 | } |
85 | 86 | ||
86 | public XmppMessageStanza(string fromJid, string toJid, XmppMessageType mType, string message) : | 87 | public bool Remove(string key) |
87 | base(fromJid, toJid) | ||
88 | { | 88 | { |
89 | MessageType = mType; | 89 | lock (this) |
90 | Body = new XmppMessageBody(message); | 90 | { |
91 | if (m_map == null) | ||
92 | return false; | ||
93 | else | ||
94 | return m_map.Remove(key); | ||
95 | } | ||
91 | } | 96 | } |
92 | } | 97 | } |
93 | } | 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 | ||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | |||
28 | using OpenMetaverse; | 32 | using OpenMetaverse; |
29 | 33 | ||
30 | namespace OpenSim.Framework | 34 | namespace 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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.IO; | 30 | using System.IO; |
31 | using System.Reflection; | ||
31 | using OpenMetaverse; | 32 | using OpenMetaverse; |
32 | 33 | ||
33 | namespace OpenSim.Framework | 34 | namespace 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/ExtraPhysicsData.cs b/OpenSim/Framework/ExtraPhysicsData.cs new file mode 100644 index 0000000..9e7334f --- /dev/null +++ b/OpenSim/Framework/ExtraPhysicsData.cs | |||
@@ -0,0 +1,50 @@ | |||
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 | |||
28 | using OpenMetaverse; | ||
29 | |||
30 | namespace OpenSim.Framework | ||
31 | { | ||
32 | public enum PhysShapeType : byte | ||
33 | { | ||
34 | prim = 0, | ||
35 | none = 1, | ||
36 | convex = 2, | ||
37 | |||
38 | invalid = 255 // use to mark invalid data in ExtraPhysicsData | ||
39 | } | ||
40 | |||
41 | public struct ExtraPhysicsData | ||
42 | { | ||
43 | public float Density; | ||
44 | public float GravitationModifier; | ||
45 | public float Friction; | ||
46 | public float Bounce; | ||
47 | public PhysShapeType PhysShapeType; | ||
48 | |||
49 | } | ||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace 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/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs b/OpenSim/Framework/LogWriter.cs index fd8d5e3..2e0bf4a 100755 --- a/OpenSim/Region/CoreModules/Framework/Statistics/Logging/LogWriter.cs +++ b/OpenSim/Framework/LogWriter.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 | * |
@@ -30,7 +30,7 @@ using System.IO; | |||
30 | using System.Text; | 30 | using System.Text; |
31 | using log4net; | 31 | using log4net; |
32 | 32 | ||
33 | namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | 33 | namespace OpenSim.Framework |
34 | { | 34 | { |
35 | /// <summary> | 35 | /// <summary> |
36 | /// Class for writing a high performance, high volume log file. | 36 | /// Class for writing a high performance, high volume log file. |
@@ -52,6 +52,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
52 | private TimeSpan m_logFileLife; | 52 | private TimeSpan m_logFileLife; |
53 | private DateTime m_logFileEndTime; | 53 | private DateTime m_logFileEndTime; |
54 | private Object m_logFileWriteLock = new Object(); | 54 | private Object m_logFileWriteLock = new Object(); |
55 | private bool m_flushWrite; | ||
55 | 56 | ||
56 | // set externally when debugging. If let 'null', this does not write any error messages. | 57 | // set externally when debugging. If let 'null', this does not write any error messages. |
57 | public ILog ErrorLogger = null; | 58 | public ILog ErrorLogger = null; |
@@ -73,7 +74,9 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
73 | /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> | 74 | /// <param name="dir">The directory to create the log file in. May be 'null' for default.</param> |
74 | /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> | 75 | /// <param name="headr">The characters that begin the log file name. May be 'null' for default.</param> |
75 | /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> | 76 | /// <param name="maxFileTime">Maximum age of a log file in minutes. If zero, will set default.</param> |
76 | public LogWriter(string dir, string headr, int maxFileTime) | 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) | ||
77 | { | 80 | { |
78 | m_logDirectory = dir == null ? "." : dir; | 81 | m_logDirectory = dir == null ? "." : dir; |
79 | 82 | ||
@@ -86,8 +89,14 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
86 | m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); | 89 | m_logFileLife = new TimeSpan(0, m_logMaxFileTimeMin, 0); |
87 | m_logFileEndTime = DateTime.Now + m_logFileLife; | 90 | m_logFileEndTime = DateTime.Now + m_logFileLife; |
88 | 91 | ||
92 | m_flushWrite = flushWrite; | ||
93 | |||
89 | Enabled = true; | 94 | Enabled = true; |
90 | } | 95 | } |
96 | // Constructor that assumes flushWrite is off. | ||
97 | public LogWriter(string dir, string headr, int maxFileTime) : this(dir, headr, maxFileTime, false) | ||
98 | { | ||
99 | } | ||
91 | 100 | ||
92 | public void Dispose() | 101 | public void Dispose() |
93 | { | 102 | { |
@@ -127,7 +136,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
127 | { | 136 | { |
128 | lock (m_logFileWriteLock) | 137 | lock (m_logFileWriteLock) |
129 | { | 138 | { |
130 | DateTime now = DateTime.Now; | 139 | DateTime now = DateTime.UtcNow; |
131 | if (m_logFile == null || now > m_logFileEndTime) | 140 | if (m_logFile == null || now > m_logFileEndTime) |
132 | { | 141 | { |
133 | if (m_logFile != null) | 142 | if (m_logFile != null) |
@@ -142,7 +151,7 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
142 | string path = (m_logDirectory.Length > 0 ? m_logDirectory | 151 | string path = (m_logDirectory.Length > 0 ? m_logDirectory |
143 | + System.IO.Path.DirectorySeparatorChar.ToString() : "") | 152 | + System.IO.Path.DirectorySeparatorChar.ToString() : "") |
144 | + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); | 153 | + String.Format("{0}{1}.log", LogFileHeader, now.ToString("yyyyMMddHHmmss")); |
145 | m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write)); | 154 | m_logFile = new StreamWriter(File.Open(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite)); |
146 | } | 155 | } |
147 | if (m_logFile != null) | 156 | if (m_logFile != null) |
148 | { | 157 | { |
@@ -153,6 +162,8 @@ namespace OpenSim.Region.CoreModules.Framework.Statistics.Logging | |||
153 | buff.Append(line); | 162 | buff.Append(line); |
154 | buff.Append("\r\n"); | 163 | buff.Append("\r\n"); |
155 | m_logFile.Write(buff.ToString()); | 164 | m_logFile.Write(buff.ToString()); |
165 | if (m_flushWrite) | ||
166 | m_logFile.Flush(); | ||
156 | } | 167 | } |
157 | } | 168 | } |
158 | } | 169 | } |
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 | ||
28 | using System; | 28 | using System; |
29 | using OpenMetaverse; | 29 | using OpenMetaverse; |
30 | using OpenMetaverse.StructuredData; | ||
30 | 31 | ||
31 | namespace OpenSim.Framework | 32 | namespace 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 | ||
28 | using OpenMetaverse; | 28 | using OpenMetaverse; |
29 | using OpenMetaverse.StructuredData; | ||
29 | 30 | ||
30 | namespace OpenSim.Framework | 31 | namespace 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 @@ | |||
1 | using System; | ||
2 | using System.Diagnostics; | ||
3 | |||
4 | namespace 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 @@ | |||
28 | using System; | 28 | using System; |
29 | using System.Timers; | 29 | using System.Timers; |
30 | 30 | ||
31 | using OpenMetaverse.StructuredData; | ||
32 | |||
31 | namespace OpenSim.Framework.Monitoring | 33 | namespace 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 | |||
28 | using System; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using log4net; | ||
34 | |||
35 | namespace 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 | ||
28 | using OpenMetaverse.StructuredData; | ||
29 | |||
28 | namespace OpenSim.Framework.Monitoring | 30 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Concurrent; | ||
30 | using System.Reflection; | ||
31 | using System.Threading; | ||
32 | using log4net; | ||
33 | using OpenSim.Framework; | ||
34 | |||
35 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.Linq; | ||
32 | using System.Net.NetworkInformation; | ||
33 | using System.Text; | ||
34 | using System.Threading; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | ||
39 | |||
40 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; | ||
31 | using System.Linq; | ||
30 | using System.Text; | 32 | using System.Text; |
31 | using OpenMetaverse; | 33 | using OpenMetaverse; |
32 | using OpenMetaverse.StructuredData; | 34 | using 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenMetaverse.StructuredData; | ||
34 | |||
35 | namespace OpenSim.Framework.Monitoring | ||
36 | { | ||
37 | // A statistic that wraps a counter. | ||
38 | // Built this way mostly so histograms and history can be created. | ||
39 | public 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenMetaverse.StructuredData; | ||
34 | |||
35 | namespace 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) | ||
41 | public 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; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | 31 | ||
32 | using OpenMetaverse.StructuredData; | ||
33 | |||
32 | namespace OpenSim.Framework.Monitoring | 34 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
30 | using System.Text; | 32 | using System.Text; |
33 | using log4net; | ||
34 | using OpenMetaverse.StructuredData; | ||
31 | 35 | ||
32 | namespace OpenSim.Framework.Monitoring | 36 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.Timers; | ||
34 | using log4net; | ||
35 | |||
36 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Linq; | ||
30 | using System.Text; | 32 | using System.Text; |
31 | 33 | ||
34 | using OpenSim.Framework; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | |||
32 | namespace OpenSim.Framework.Monitoring | 37 | namespace 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 | ||
28 | using System.Timers; | 28 | using System.Timers; |
29 | 29 | ||
30 | using OpenMetaverse.StructuredData; | ||
31 | |||
30 | namespace OpenSim.Framework.Monitoring | 32 | namespace 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 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using System.Threading; | ||
31 | using log4net; | ||
32 | |||
33 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using log4net; | ||
34 | using LukeSkywalker.IPNetwork; | ||
35 | using Nini.Config; | ||
36 | |||
37 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using log4net; | ||
33 | |||
34 | namespace 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 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using 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/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 @@ | |||
1 | using System.Reflection; | ||
2 | using System.Runtime.CompilerServices; | ||
3 | using 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/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; | |||
35 | using System.Web; | 35 | using System.Web; |
36 | using log4net; | 36 | using log4net; |
37 | 37 | ||
38 | namespace OpenSim.Framework.Communications | 38 | using OpenSim.Framework.ServiceAuth; |
39 | |||
40 | namespace 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 | ||
28 | using OpenMetaverse; | ||
28 | using System; | 29 | using System; |
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Xml; | ||
33 | using log4net; | ||
34 | using OpenMetaverse; | ||
35 | 31 | ||
36 | namespace OpenSim.Framework | 32 | namespace 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; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; | ||
32 | 33 | ||
33 | namespace OpenSim.Framework.Serialization | 34 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; | ||
30 | using System.IO; | 31 | using System.IO; |
31 | using System.Reflection; | 32 | using System.Reflection; |
32 | using System.Xml; | 33 | using 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; | |||
45 | using OpenSim.Framework.Servers; | 45 | using OpenSim.Framework.Servers; |
46 | using OpenSim.Framework.Servers.HttpServer; | 46 | using OpenSim.Framework.Servers.HttpServer; |
47 | using Timer=System.Timers.Timer; | 47 | using Timer=System.Timers.Timer; |
48 | using Nini.Config; | ||
48 | 49 | ||
49 | namespace OpenSim.Framework.Servers | 50 | namespace 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; | |||
46 | using HttpListener=System.Net.HttpListener; | 46 | using HttpListener=System.Net.HttpListener; |
47 | using LogPrio=HttpServer.LogPrio; | 47 | using LogPrio=HttpServer.LogPrio; |
48 | using OpenSim.Framework.Monitoring; | 48 | using OpenSim.Framework.Monitoring; |
49 | using System.IO.Compression; | ||
49 | 50 | ||
50 | namespace OpenSim.Framework.Servers.HttpServer | 51 | namespace 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/XmppPresenceStanza.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs index 4d45ac0..72b3065 100644 --- a/OpenSim/Framework/Communications/XMPP/XmppPresenceStanza.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs | |||
@@ -25,45 +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 | ||
28 | using System.Xml.Serialization; | 28 | using System.IO; |
29 | 29 | ||
30 | namespace OpenSim.Framework.Communications.XMPP | 30 | namespace OpenSim.Framework.Servers.HttpServer |
31 | { | 31 | { |
32 | /// <summary> | 32 | /// <summary> |
33 | /// Message types. | 33 | /// Base handler for writing to an output stream |
34 | /// </summary> | 34 | /// </summary> |
35 | public enum XmppPresenceType | 35 | /// <remarks> |
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
38 | public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler | ||
36 | { | 39 | { |
37 | [XmlEnum("unavailable")] unavailable, | 40 | protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} |
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 | 41 | ||
42 | protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description) | ||
43 | : base(httpMethod, path, name, description) {} | ||
46 | 44 | ||
47 | [XmlRoot("message")] | 45 | public virtual void Handle( |
48 | public class XmppPresenceStanza: XmppStanza | 46 | string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
49 | { | 47 | { |
50 | /// <summary> | 48 | RequestsReceived++; |
51 | /// IQ type: one of set, get, result, error | ||
52 | /// </summary> | ||
53 | [XmlAttribute("type")] | ||
54 | public XmppPresenceType PresenceType; | ||
55 | 49 | ||
56 | // [XmlAttribute("error")] | 50 | ProcessRequest(path, request, response, httpRequest, httpResponse); |
57 | // public XmppError Error; | ||
58 | 51 | ||
59 | public XmppPresenceStanza() : base() | 52 | RequestsHandled++; |
60 | { | ||
61 | } | 53 | } |
62 | 54 | ||
63 | public XmppPresenceStanza(string fromJid, string toJid, XmppPresenceType pType) : | 55 | protected virtual void ProcessRequest( |
64 | base(fromJid, toJid) | 56 | string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
65 | { | 57 | { |
66 | PresenceType = pType; | ||
67 | } | 58 | } |
68 | } | 59 | } |
69 | } | 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 | ||
28 | using System; | 28 | using System; |
29 | using OpenSim.Framework.Monitoring; | ||
29 | 30 | ||
30 | namespace OpenSim.Framework.Servers.HttpServer | 31 | namespace 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 | ||
28 | using System.IO; | 28 | using System.IO; |
29 | using System.Net; | ||
30 | using OpenSim.Framework.ServiceAuth; | ||
29 | 31 | ||
30 | namespace OpenSim.Framework.Servers.HttpServer | 32 | namespace 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 | */ | ||
27 | using OpenSim.Framework; | ||
28 | using System.IO; | ||
29 | |||
30 | namespace 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 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace 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/Servers/HttpServer/JsonRPCMethod.cs b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs new file mode 100644 index 0000000..5bab508 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/JsonRPCMethod.cs | |||
@@ -0,0 +1,34 @@ | |||
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 | |||
28 | using System.Net; | ||
29 | using OpenMetaverse.StructuredData; | ||
30 | |||
31 | namespace OpenSim.Framework.Servers.HttpServer | ||
32 | { | ||
33 | public delegate bool JsonRPCMethod(OSDMap jsonRpcRequest, ref JsonRpcResponse response); | ||
34 | } | ||
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 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using System.Net.Sockets; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using System.IO; | ||
34 | using OpenMetaverse.StructuredData; | ||
35 | using OpenMetaverse; | ||
36 | using log4net; | ||
37 | |||
38 | namespace 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 | */ | ||
27 | using System; | ||
28 | using System.Net; | ||
29 | using OpenMetaverse.StructuredData; | ||
30 | |||
31 | namespace 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 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
29 | using HttpServer; | 32 | using HttpServer; |
33 | using log4net; | ||
30 | using OpenMetaverse; | 34 | using OpenMetaverse; |
31 | 35 | ||
32 | namespace OpenSim.Framework.Servers.HttpServer | 36 | namespace 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; | |||
33 | using HttpServer; | 33 | using HttpServer; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Monitoring; | 35 | using OpenSim.Framework.Monitoring; |
36 | using Amib.Threading; | ||
37 | using System.IO; | ||
38 | using System.Text; | ||
39 | using System.Collections.Generic; | ||
36 | 40 | ||
37 | namespace OpenSim.Framework.Servers.HttpServer | 41 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Text; | ||
33 | using HttpServer; | ||
34 | using OpenMetaverse; | ||
35 | using System.Reflection; | ||
36 | using log4net; | ||
37 | using OpenSim.Framework.Monitoring; | ||
38 | |||
39 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Security.Cryptography; | ||
33 | using System.Text; | ||
34 | using System.Threading; | ||
35 | using HttpServer; | ||
36 | |||
37 | namespace 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 | ||
939 | nib 0 1 2 3 4 5 6 7 | ||
940 | byt 0 1 2 3 | ||
941 | dec 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 | /* | ||
993 | byt 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 | |||
28 | using System.Net; | ||
29 | using Nwc.XmlRpc; | ||
30 | using OpenSim.Framework; | ||
31 | |||
32 | |||
33 | namespace 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; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Diagnostics; | 30 | using System.Diagnostics; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Linq; | ||
32 | using System.Reflection; | 33 | using System.Reflection; |
33 | using System.Text; | 34 | using System.Text; |
34 | using System.Text.RegularExpressions; | 35 | using 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | |||
34 | using Nini.Config; | ||
35 | using log4net; | ||
36 | |||
37 | namespace 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/Region/Framework/Scenes/Scripting/NullScriptHost.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs index d7198f0..a49952c 100644 --- a/OpenSim/Region/Framework/Scenes/Scripting/NullScriptHost.cs +++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs | |||
@@ -26,66 +26,57 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenMetaverse; | 29 | using System.Collections.Generic; |
30 | using log4net; | 30 | using System.Collections.Specialized; |
31 | using System.Reflection; | 31 | using System.Linq; |
32 | using OpenSim.Framework; | 32 | using System.Net; |
33 | 33 | ||
34 | namespace OpenSim.Region.Framework.Scenes.Scripting | 34 | namespace OpenSim.Framework.ServiceAuth |
35 | { | 35 | { |
36 | public class NullScriptHost : IScriptHost | 36 | public class CompoundAuthentication : IServiceAuth |
37 | { | 37 | { |
38 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 38 | public string Name { get { return "Compound"; } } |
39 | 39 | ||
40 | private Vector3 m_pos = new Vector3(((int)Constants.RegionSize * 0.5f), ((int)Constants.RegionSize * 0.5f), 30); | 40 | private List<IServiceAuth> m_authentications = new List<IServiceAuth>(); |
41 | 41 | ||
42 | public string Name | 42 | public int Count { get { return m_authentications.Count; } } |
43 | { | ||
44 | get { return "Object"; } | ||
45 | set { } | ||
46 | } | ||
47 | 43 | ||
48 | public string SitName | 44 | public List<IServiceAuth> GetAuthentors() |
49 | { | 45 | { |
50 | get { return String.Empty; } | 46 | return new List<IServiceAuth>(m_authentications); |
51 | set { } | ||
52 | } | 47 | } |
53 | 48 | ||
54 | public string TouchName | 49 | public void AddAuthenticator(IServiceAuth auth) |
55 | { | 50 | { |
56 | get { return String.Empty; } | 51 | m_authentications.Add(auth); |
57 | set { } | ||
58 | } | 52 | } |
59 | 53 | ||
60 | public string Description | 54 | public void RemoveAuthenticator(IServiceAuth auth) |
61 | { | 55 | { |
62 | get { return String.Empty; } | 56 | m_authentications.Remove(auth); |
63 | set { } | ||
64 | } | 57 | } |
65 | 58 | ||
66 | public UUID UUID | 59 | public void AddAuthorization(NameValueCollection headers) |
67 | { | 60 | { |
68 | get { return UUID.Zero; } | 61 | foreach (IServiceAuth auth in m_authentications) |
62 | auth.AddAuthorization(headers); | ||
69 | } | 63 | } |
70 | 64 | ||
71 | public UUID OwnerID | 65 | public bool Authenticate(string data) |
72 | { | 66 | { |
73 | get { return UUID.Zero; } | 67 | return m_authentications.TrueForAll(a => a.Authenticate(data)); |
74 | } | 68 | } |
75 | 69 | ||
76 | public UUID CreatorID | 70 | public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) |
77 | { | 71 | { |
78 | get { return UUID.Zero; } | 72 | foreach (IServiceAuth auth in m_authentications) |
79 | } | 73 | { |
74 | if (!auth.Authenticate(requestHeaders, d, out statusCode)) | ||
75 | return false; | ||
76 | } | ||
80 | 77 | ||
81 | public Vector3 AbsolutePosition | 78 | statusCode = HttpStatusCode.OK; |
82 | { | 79 | return true; |
83 | get { return m_pos; } | ||
84 | } | ||
85 | |||
86 | public void SetText(string text, Vector3 color, double alpha) | ||
87 | { | ||
88 | m_log.Warn("Tried to SetText "+text+" on NullScriptHost"); | ||
89 | } | 80 | } |
90 | } | 81 | } |
91 | } | 82 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs new file mode 100644 index 0000000..e0c413b --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs | |||
@@ -0,0 +1,59 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Specialized; | ||
30 | using System.Net; | ||
31 | |||
32 | namespace OpenSim.Framework.ServiceAuth | ||
33 | { | ||
34 | public class DisallowLlHttpRequest : IServiceAuth | ||
35 | { | ||
36 | public string Name { get { return "DisallowllHTTPRequest"; } } | ||
37 | |||
38 | public void AddAuthorization(NameValueCollection headers) {} | ||
39 | |||
40 | public bool Authenticate(string data) | ||
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; | ||
57 | } | ||
58 | } | ||
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 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Collections.Specialized; | ||
32 | |||
33 | namespace 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/ServiceAuth/ServiceAuth.cs b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs new file mode 100644 index 0000000..51012e3 --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/ServiceAuth.cs | |||
@@ -0,0 +1,68 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | |||
34 | namespace OpenSim.Framework.ServiceAuth | ||
35 | { | ||
36 | public class ServiceAuth | ||
37 | { | ||
38 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
39 | |||
40 | public static IServiceAuth Create(IConfigSource config, string section) | ||
41 | { | ||
42 | CompoundAuthentication compoundAuth = new CompoundAuthentication(); | ||
43 | |||
44 | bool allowLlHttpRequestIn | ||
45 | = Util.GetConfigVarFromSections<bool>(config, "AllowllHTTPRequestIn", new string[] { "Network", section }, false); | ||
46 | |||
47 | if (!allowLlHttpRequestIn) | ||
48 | compoundAuth.AddAuthenticator(new DisallowLlHttpRequest()); | ||
49 | |||
50 | string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", section }, "None"); | ||
51 | |||
52 | switch (authType) | ||
53 | { | ||
54 | case "BasicHttpAuthentication": | ||
55 | compoundAuth.AddAuthenticator(new BasicHttpAuthentication(config, section)); | ||
56 | break; | ||
57 | } | ||
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; | ||
66 | } | ||
67 | } | ||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | |||
33 | using OpenMetaverse; | ||
34 | |||
35 | using log4net; | ||
36 | |||
37 | namespace 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; | |||
32 | using OpenMetaverse.StructuredData; | 32 | using OpenMetaverse.StructuredData; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Tests.Common; | 34 | using OpenSim.Tests.Common; |
35 | using OpenSim.Tests.Common.Mock; | ||
36 | using Animation = OpenSim.Framework.Animation; | 35 | using Animation = OpenSim.Framework.Animation; |
37 | 36 | ||
38 | namespace OpenSim.Framework.Tests | 37 | namespace OpenSim.Framework.Tests |
diff --git a/OpenSim/Framework/Tests/AssetBaseTest.cs b/OpenSim/Framework/Tests/AssetBaseTest.cs index 25d2393..1975a4d 100644 --- a/OpenSim/Framework/Tests/AssetBaseTest.cs +++ b/OpenSim/Framework/Tests/AssetBaseTest.cs | |||
@@ -50,19 +50,15 @@ namespace OpenSim.Framework.Tests | |||
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/ApplicationPlugins/Rest/RestXmlWriter.cs b/OpenSim/Framework/ThreadSafeRandom.cs index 283fa2e..58853e6 100644 --- a/OpenSim/ApplicationPlugins/Rest/RestXmlWriter.cs +++ b/OpenSim/Framework/ThreadSafeRandom.cs | |||
@@ -25,48 +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 | ||
28 | using System.IO; | 28 | using System; |
29 | using System.Text; | ||
30 | using System.Xml; | ||
31 | 29 | ||
32 | namespace OpenSim.ApplicationPlugins.Rest | 30 | namespace OpenSim.Framework |
33 | { | 31 | { |
34 | public class RestXmlWriter: XmlTextWriter | 32 | /// <summary> |
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 | ||
35 | /// </summary> | ||
36 | public class ThreadSafeRandom : Random | ||
35 | { | 37 | { |
36 | private StringWriter m_sw = null; | 38 | public ThreadSafeRandom() : base() {} |
37 | 39 | ||
38 | public RestXmlWriter(StringWriter sw) : base(sw) | 40 | public ThreadSafeRandom(int seed): base (seed) {} |
39 | { | ||
40 | m_sw = sw; | ||
41 | Formatting = Formatting.Indented; | ||
42 | } | ||
43 | |||
44 | public RestXmlWriter(TextWriter textWriter) : base(textWriter) | ||
45 | { | ||
46 | } | ||
47 | 41 | ||
48 | public RestXmlWriter(Stream stream) | 42 | public override int Next() |
49 | : this(stream, Encoding.UTF8) | ||
50 | { | 43 | { |
44 | lock (this) | ||
45 | return base.Next(); | ||
51 | } | 46 | } |
52 | 47 | ||
53 | public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc) | 48 | public override int Next(int maxValue) |
54 | { | 49 | { |
50 | lock (this) | ||
51 | return base.Next(maxValue); | ||
55 | } | 52 | } |
56 | 53 | ||
57 | public override void WriteStartDocument() | 54 | public override int Next(int minValue, int maxValue) |
58 | { | 55 | { |
56 | lock (this) | ||
57 | return base.Next(minValue, maxValue); | ||
59 | } | 58 | } |
60 | 59 | ||
61 | public override void WriteStartDocument(bool standalone) | 60 | public override void NextBytes(byte[] buffer) |
62 | { | 61 | { |
62 | lock (this) | ||
63 | base.NextBytes(buffer); | ||
63 | } | 64 | } |
64 | 65 | ||
65 | public override string ToString() | 66 | public override double NextDouble() |
66 | { | 67 | { |
67 | Flush(); | 68 | lock (this) |
68 | Close(); | 69 | return base.NextDouble(); |
69 | return m_sw.ToString(); | ||
70 | } | 70 | } |
71 | } | 71 | } |
72 | } | 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Net.Security; | ||
33 | using System.Text; | ||
34 | using log4net; | ||
35 | |||
36 | namespace 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 | |||
28 | using System; | ||
29 | using OpenMetaverse; | ||
30 | |||
31 | namespace 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; | |||
45 | using System.Xml; | 45 | using System.Xml; |
46 | using System.Threading; | 46 | using System.Threading; |
47 | using log4net; | 47 | using log4net; |
48 | using log4net.Appender; | ||
48 | using Nini.Config; | 49 | using Nini.Config; |
49 | using Nwc.XmlRpc; | 50 | using Nwc.XmlRpc; |
50 | using OpenMetaverse; | 51 | using OpenMetaverse; |
51 | using OpenMetaverse.StructuredData; | 52 | using OpenMetaverse.StructuredData; |
52 | using Amib.Threading; | 53 | using Amib.Threading; |
54 | using System.Collections.Concurrent; | ||
55 | using System.Collections.Specialized; | ||
56 | using System.Web; | ||
53 | 57 | ||
54 | namespace OpenSim.Framework | 58 | namespace 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenMetaverse.StructuredData; | ||
32 | |||
33 | namespace 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; | |||
39 | using System.Web; | 39 | using System.Web; |
40 | using System.Xml; | 40 | using System.Xml; |
41 | using System.Xml.Serialization; | 41 | using System.Xml.Serialization; |
42 | using System.Xml.Linq; | ||
42 | using log4net; | 43 | using log4net; |
44 | using Nwc.XmlRpc; | ||
43 | using OpenMetaverse.StructuredData; | 45 | using OpenMetaverse.StructuredData; |
46 | using XMLResponseHelper = OpenSim.Framework.SynchronousRestObjectRequester.XMLResponseHelper; | ||
47 | |||
48 | using OpenSim.Framework.ServiceAuth; | ||
44 | 49 | ||
45 | namespace OpenSim.Framework | 50 | namespace 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 | } |
diff --git a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs index 5312a31..78a43db 100644 --- a/OpenSim/Framework/Communications/XMPP/XmppStanza.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainFeature.cs | |||
@@ -26,45 +26,35 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Xml.Serialization; | 29 | using OpenSim.Region.Framework.Interfaces; |
30 | 30 | ||
31 | namespace OpenSim.Framework.Communications.XMPP | 31 | namespace OpenSim.Region.CoreModules.World.Terrain |
32 | { | 32 | { |
33 | public abstract class XmppStanza | 33 | public interface ITerrainFeature |
34 | { | 34 | { |
35 | /// <summary> | 35 | /// <summary> |
36 | /// counter used for generating ID | 36 | /// Creates the feature. |
37 | /// </summary> | 37 | /// </summary> |
38 | [XmlIgnore] | 38 | /// <returns> |
39 | private static ulong _ctr = 0; | 39 | /// Empty string if successful, otherwise error message. |
40 | /// </returns> | ||
41 | /// <param name='map'> | ||
42 | /// ITerrainChannel holding terrain data. | ||
43 | /// </param> | ||
44 | /// <param name='args'> | ||
45 | /// command-line arguments from console. | ||
46 | /// </param> | ||
47 | string CreateFeature(ITerrainChannel map, string[] args); | ||
40 | 48 | ||
41 | /// <summary> | 49 | /// <summary> |
42 | /// recipient JID | 50 | /// Gets a string describing the usage. |
43 | /// </summary> | 51 | /// </summary> |
44 | [XmlAttribute("to")] | 52 | /// <returns> |
45 | public string ToJid; | 53 | /// A string describing parameters for creating the feature. |
46 | 54 | /// Format is "feature-name <arg1> <arg2> ..." | |
47 | /// <summary> | 55 | /// </returns> |
48 | /// sender JID | 56 | string GetUsage(); |
49 | /// </summary> | ||
50 | [XmlAttribute("from")] | ||
51 | public string FromJid; | ||
52 | |||
53 | /// <summary> | ||
54 | /// unique ID. | ||
55 | /// </summary> | ||
56 | [XmlAttribute("id")] | ||
57 | public string MessageId; | ||
58 | |||
59 | public XmppStanza() | ||
60 | { | ||
61 | } | ||
62 | |||
63 | public XmppStanza(string fromJid, string toJid) | ||
64 | { | ||
65 | ToJid = toJid; | ||
66 | FromJid = fromJid; | ||
67 | MessageId = String.Format("OpenSim_{0}{1}", DateTime.UtcNow.Ticks, _ctr++); | ||
68 | } | ||
69 | } | 57 | } |
58 | |||
70 | } | 59 | } |
60 | |||
diff --git a/OpenSim/Framework/ForeignUserProfileData.cs b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs index 2beaf80..0e0a0e4 100644 --- a/OpenSim/Framework/ForeignUserProfileData.cs +++ b/OpenSim/Region/CoreModules/World/Terrain/ITerrainModifier.cs | |||
@@ -26,52 +26,52 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenSim.Region.Framework.Interfaces; | ||
29 | 30 | ||
30 | namespace OpenSim.Framework | 31 | namespace OpenSim.Region.CoreModules.World.Terrain |
31 | { | 32 | { |
32 | public class ForeignUserProfileData : UserProfileData | 33 | public interface ITerrainModifier |
33 | { | 34 | { |
34 | /// <summary> | 35 | /// <summary> |
35 | /// The address of the users home sim, used for foreigners. | 36 | /// Creates the feature. |
36 | /// </summary> | 37 | /// </summary> |
37 | private string _userUserServerURI = String.Empty; | 38 | /// <returns> |
39 | /// Empty string if successful, otherwise error message. | ||
40 | /// </returns> | ||
41 | /// <param name='map'> | ||
42 | /// ITerrainChannel holding terrain data. | ||
43 | /// </param> | ||
44 | /// <param name='args'> | ||
45 | /// command-line arguments from console. | ||
46 | /// </param> | ||
47 | string ModifyTerrain(ITerrainChannel map, string[] args); | ||
38 | 48 | ||
39 | /// <summary> | 49 | /// <summary> |
40 | /// The address of the users home sim, used for foreigners. | 50 | /// Gets a string describing the usage. |
41 | /// </summary> | 51 | /// </summary> |
42 | private string _userHomeAddress = String.Empty; | 52 | /// <returns> |
53 | /// A string describing parameters for creating the feature. | ||
54 | /// Format is "feature-name <arg1> <arg2> ..." | ||
55 | /// </returns> | ||
56 | string GetUsage(); | ||
43 | 57 | ||
44 | /// <summary> | 58 | /// <summary> |
45 | /// The port of the users home sim, used for foreigners. | 59 | /// Apply the appropriate operation on the specified map, at (x, y). |
46 | /// </summary> | 60 | /// </summary> |
47 | private string _userHomePort = String.Empty; | 61 | /// <param name='map'> |
48 | /// <summary> | 62 | /// Map. |
49 | /// The remoting port of the users home sim, used for foreigners. | 63 | /// </param> |
50 | /// </summary> | 64 | /// <param name='data'> |
51 | private string _userHomeRemotingPort = String.Empty; | 65 | /// Data. |
52 | 66 | /// </param> | |
53 | public string UserServerURI | 67 | /// <param name='x'> |
54 | { | 68 | /// X. |
55 | get { return _userUserServerURI; } | 69 | /// </param> |
56 | set { _userUserServerURI = value; } | 70 | /// <param name='y'> |
57 | } | 71 | /// Y. |
58 | 72 | /// </param> | |
59 | public string UserHomeAddress | 73 | double operate(double[,] map, TerrainModifierData data, int x, int y); |
60 | { | ||
61 | get { return _userHomeAddress; } | ||
62 | set { _userHomeAddress = value; } | ||
63 | } | ||
64 | |||
65 | public string UserHomePort | ||
66 | { | ||
67 | get { return _userHomePort; } | ||
68 | set { _userHomePort = value; } | ||
69 | } | ||
70 | |||
71 | public string UserHomeRemotingPort | ||
72 | { | ||
73 | get { return _userHomeRemotingPort; } | ||
74 | set { _userHomeRemotingPort = value; } | ||
75 | } | ||
76 | } | 74 | } |
75 | |||
77 | } | 76 | } |
77 | |||
diff --git a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs b/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs index 12263f4..a730cfd 100644 --- a/OpenSim/Framework/Communications/XMPP/XmppIqStanza.cs +++ b/OpenSim/Region/Framework/Interfaces/IExternalCapsModule.cs | |||
@@ -25,36 +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 | ||
28 | using System.Xml.Serialization; | 28 | using System; |
29 | using OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | using Caps=OpenSim.Framework.Capabilities.Caps; | ||
29 | 32 | ||
30 | namespace OpenSim.Framework.Communications.XMPP | 33 | namespace OpenSim.Region.Framework.Interfaces |
31 | { | 34 | { |
32 | /// <summary> | 35 | public interface IExternalCapsModule |
33 | /// An IQ needs to have one of the follow types set. | ||
34 | /// </summary> | ||
35 | public enum XmppIqType | ||
36 | { | ||
37 | [XmlEnum("set")] set, | ||
38 | [XmlEnum("get")] get, | ||
39 | [XmlEnum("result")] result, | ||
40 | [XmlEnum("error")] error, | ||
41 | } | ||
42 | |||
43 | /// <summary> | ||
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 | { | 36 | { |
50 | /// <summary> | 37 | /// <summary> |
51 | /// IQ type: one of set, get, result, error | 38 | /// This function extends the simple URL configuration in the caps handlers |
39 | /// to facilitate more interesting computation when an external handler is | ||
40 | /// sent to the viewer. | ||
52 | /// </summary> | 41 | /// </summary> |
53 | [XmlAttribute("type")] | 42 | /// <param name="agentID">New user UUID</param> |
54 | public XmppIqType Type; | 43 | /// <param name="caps">Internal caps registry, where the external handler will be registered</param> |
55 | 44 | /// <param name="capName">Name of the specific cap we are registering</param> | |
56 | public XmppIqStanza(): base() | 45 | /// <param name="urlSkel">The skeleton URL provided in the caps configuration</param> |
57 | { | 46 | bool RegisterExternalUserCapsHandler(UUID agentID, Caps caps, String capName, String urlSkel); |
58 | } | ||
59 | } | 47 | } |
60 | } | 48 | } |
diff --git a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs index 415d808..0be1f4c 100644..100755 --- a/OpenSim/Framework/Communications/XMPP/XmppWriter.cs +++ b/OpenSim/Region/PhysicsModules/BulletS/Tests/BulletSimTests.cs | |||
@@ -1,57 +1,56 @@ | |||
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 | * |
5 | * Redistribution and use in source and binary forms, with or without | 5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions are met: | 6 | * modification, are permitted provided that the following conditions are met: |
7 | * * Redistributions of source code must retain the above copyright | 7 | * * Redistributions of source code must retain the above copyright |
8 | * notice, this list of conditions and the following disclaimer. | 8 | * notice, this list of conditions and the following disclaimer. |
9 | * * Redistributions in binary form must reproduce the above copyright | 9 | * * Redistributions in binary form must reproduce the above copyright |
10 | * notice, this list of conditions and the following disclaimer in the | 10 | * notice, this list of conditions and the following disclaimer in the |
11 | * documentation and/or other materials provided with the distribution. | 11 | * documentation and/or other materials provided with the distribution. |
12 | * * Neither the name of the OpenSimulator Project nor the | 12 | * * Neither the name of the OpenSimulator Project nor the |
13 | * names of its contributors may be used to endorse or promote products | 13 | * names of its contributors may be used to endorse or promote products |
14 | * derived from this software without specific prior written permission. | 14 | * derived from this software without specific prior written permission. |
15 | * | 15 | * |
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | 16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY |
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | 17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | 19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | 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 | 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 | 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 | 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. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System.IO; | 28 | using System; |
29 | using System.Text; | 29 | using System.Collections.Generic; |
30 | using System.Xml; | 30 | using System.Linq; |
31 | using IOStream = System.IO.Stream; | 31 | using System.Text; |
32 | 32 | ||
33 | namespace OpenSim.Framework.Communications.XMPP | 33 | using NUnit.Framework; |
34 | { | 34 | using log4net; |
35 | public class XMPPWriter: XmlTextWriter | 35 | |
36 | { | 36 | using OpenSim.Tests.Common; |
37 | public XMPPWriter(TextWriter textWriter) : base(textWriter) | 37 | |
38 | { | 38 | namespace OpenSim.Region.PhysicsModule.BulletS.Tests |
39 | } | 39 | { |
40 | 40 | [TestFixture] | |
41 | public XMPPWriter(IOStream stream) : this(stream, Util.UTF8) | 41 | public class BulletSimTests : OpenSimTestCase |
42 | { | 42 | { |
43 | } | 43 | // Documentation on attributes: http://www.nunit.org/index.php?p=attributes&r=2.6.1 |
44 | 44 | // Documentation on assertions: http://www.nunit.org/index.php?p=assertions&r=2.6.1 | |
45 | public XMPPWriter(IOStream stream, Encoding enc) : base(stream, enc) | 45 | |
46 | { | 46 | [TestFixtureSetUp] |
47 | } | 47 | public void Init() |
48 | 48 | { | |
49 | public override void WriteStartDocument() | 49 | } |
50 | { | 50 | |
51 | } | 51 | [TestFixtureTearDown] |
52 | 52 | public void TearDown() | |
53 | public override void WriteStartDocument(bool standalone) | 53 | { |
54 | { | 54 | } |
55 | } | 55 | } |
56 | } | 56 | } |
57 | } | ||
diff --git a/OpenSim/Framework/Communications/XMPP/XmppError.cs b/OpenSim/Services/Interfaces/IBakedTextureService.cs index 3d36e9c..69df4a0 100644 --- a/OpenSim/Framework/Communications/XMPP/XmppError.cs +++ b/OpenSim/Services/Interfaces/IBakedTextureService.cs | |||
@@ -25,15 +25,14 @@ | |||
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 | ||
28 | using System.Xml.Serialization; | 28 | using System; |
29 | using Nini.Config; | ||
29 | 30 | ||
30 | namespace OpenSim.Framework.Communications.XMPP | 31 | namespace OpenSim.Services.Interfaces |
31 | { | 32 | { |
32 | [XmlRoot("error")] | 33 | public interface IBakedTextureService |
33 | public class XmppErrorStanza | ||
34 | { | 34 | { |
35 | public XmppErrorStanza() | 35 | string Get(string id); |
36 | { | 36 | void Store(string id, string data); |
37 | } | ||
38 | } | 37 | } |
39 | } | 38 | } |