diff options
Diffstat (limited to 'OpenSim/Framework')
86 files changed, 5308 insertions, 1974 deletions
diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index f2fe494..0d053e4 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs | |||
@@ -321,6 +321,8 @@ namespace OpenSim.Framework | |||
321 | Mac = args["mac"].AsString(); | 321 | Mac = args["mac"].AsString(); |
322 | if (args["id0"] != null) | 322 | if (args["id0"] != null) |
323 | Id0 = args["id0"].AsString(); | 323 | Id0 = args["id0"].AsString(); |
324 | if (args["teleport_flags"] != null) | ||
325 | teleportFlags = args["teleport_flags"].AsUInteger(); | ||
324 | 326 | ||
325 | if (args["start_pos"] != null) | 327 | if (args["start_pos"] != null) |
326 | 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 3425505..e958b75 100644 --- a/OpenSim/Framework/Animation.cs +++ b/OpenSim/Framework/Animation.cs | |||
@@ -132,6 +132,11 @@ namespace OpenSim.Framework | |||
132 | return base.Equals(obj); | 132 | return base.Equals(obj); |
133 | } | 133 | } |
134 | 134 | ||
135 | public override int GetHashCode() | ||
136 | { | ||
137 | return base.GetHashCode(); | ||
138 | } | ||
139 | |||
135 | public override string ToString() | 140 | public override string ToString() |
136 | { | 141 | { |
137 | return "AnimID=" + AnimID.ToString() | 142 | return "AnimID=" + AnimID.ToString() |
diff --git a/OpenSim/Framework/AssemblyInfo.cs b/OpenSim/Framework/AssemblyInfo.cs index 287b988..a797424 100644 --- a/OpenSim/Framework/AssemblyInfo.cs +++ b/OpenSim/Framework/AssemblyInfo.cs | |||
@@ -59,4 +59,4 @@ using System.Runtime.InteropServices; | |||
59 | // Revision | 59 | // Revision |
60 | // | 60 | // |
61 | 61 | ||
62 | [assembly : AssemblyVersion("0.8.0.*")] | 62 | [assembly : AssemblyVersion("0.8.2.*")] |
diff --git a/OpenSim/Framework/AssetBase.cs b/OpenSim/Framework/AssetBase.cs index 5da8e11..3937d9c 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> |
@@ -135,7 +138,7 @@ namespace OpenSim.Framework | |||
135 | get | 138 | get |
136 | { | 139 | { |
137 | return | 140 | return |
138 | (Type == (sbyte) AssetType.Animation || | 141 | (Type == (sbyte)AssetType.Animation || |
139 | Type == (sbyte)AssetType.Gesture || | 142 | Type == (sbyte)AssetType.Gesture || |
140 | Type == (sbyte)AssetType.Simstate || | 143 | Type == (sbyte)AssetType.Simstate || |
141 | Type == (sbyte)AssetType.Unknown || | 144 | Type == (sbyte)AssetType.Unknown || |
@@ -145,14 +148,14 @@ namespace OpenSim.Framework | |||
145 | Type == (sbyte)AssetType.Texture || | 148 | Type == (sbyte)AssetType.Texture || |
146 | Type == (sbyte)AssetType.TextureTGA || | 149 | Type == (sbyte)AssetType.TextureTGA || |
147 | Type == (sbyte)AssetType.Folder || | 150 | Type == (sbyte)AssetType.Folder || |
148 | Type == (sbyte)AssetType.RootFolder || | ||
149 | Type == (sbyte)AssetType.LostAndFoundFolder || | ||
150 | Type == (sbyte)AssetType.SnapshotFolder || | ||
151 | Type == (sbyte)AssetType.TrashFolder || | ||
152 | Type == (sbyte)AssetType.ImageJPEG || | 151 | Type == (sbyte)AssetType.ImageJPEG || |
153 | Type == (sbyte)AssetType.ImageTGA || | 152 | Type == (sbyte)AssetType.ImageTGA || |
153 | <<<<<<< HEAD | ||
154 | Type == (sbyte)AssetType.LSLBytecode); | ||
155 | ======= | ||
154 | Type == (sbyte)AssetType.Mesh || | 156 | Type == (sbyte)AssetType.Mesh || |
155 | Type == (sbyte) AssetType.LSLBytecode); | 157 | Type == (sbyte) AssetType.LSLBytecode); |
158 | >>>>>>> avn/ubitvar | ||
156 | } | 159 | } |
157 | } | 160 | } |
158 | 161 | ||
diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs index 11fece3..cd182d6 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.8.0.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/AvatarAppearance.cs b/OpenSim/Framework/AvatarAppearance.cs index 3874c47..72c6bfc 100644 --- a/OpenSim/Framework/AvatarAppearance.cs +++ b/OpenSim/Framework/AvatarAppearance.cs | |||
@@ -536,6 +536,12 @@ namespace OpenSim.Framework | |||
536 | if (!m_attachments.ContainsKey(attach.AttachPoint)) | 536 | if (!m_attachments.ContainsKey(attach.AttachPoint)) |
537 | m_attachments[attach.AttachPoint] = new List<AvatarAttachment>(); | 537 | m_attachments[attach.AttachPoint] = new List<AvatarAttachment>(); |
538 | 538 | ||
539 | foreach (AvatarAttachment prev in m_attachments[attach.AttachPoint]) | ||
540 | { | ||
541 | if (prev.ItemID == attach.ItemID) | ||
542 | return; | ||
543 | } | ||
544 | |||
539 | m_attachments[attach.AttachPoint].Add(attach); | 545 | m_attachments[attach.AttachPoint].Add(attach); |
540 | } | 546 | } |
541 | } | 547 | } |
diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index aef1192..daf99a8 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs | |||
@@ -97,11 +97,11 @@ namespace OpenSim.Framework | |||
97 | /// </remarks> | 97 | /// </remarks> |
98 | public bool Contains(T item) | 98 | public bool Contains(T item) |
99 | { | 99 | { |
100 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | ||
101 | return false; | ||
102 | |||
103 | lock (m_queueSync) | 100 | lock (m_queueSync) |
104 | { | 101 | { |
102 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | ||
103 | return false; | ||
104 | |||
105 | if (m_pqueue.Contains(item)) | 105 | if (m_pqueue.Contains(item)) |
106 | return true; | 106 | return true; |
107 | return m_queue.Contains(item); | 107 | return m_queue.Contains(item); |
@@ -111,12 +111,10 @@ namespace OpenSim.Framework | |||
111 | /// <summary> | 111 | /// <summary> |
112 | /// Return a count of the number of requests on this queue. | 112 | /// Return a count of the number of requests on this queue. |
113 | /// </summary> | 113 | /// </summary> |
114 | /// <remarks> | ||
115 | /// This method is not thread-safe. Do not rely on the result without consistent external locking. | ||
116 | /// </remarks> | ||
117 | public int Count() | 114 | public int Count() |
118 | { | 115 | { |
119 | return m_queue.Count + m_pqueue.Count; | 116 | lock (m_queueSync) |
117 | return m_queue.Count + m_pqueue.Count; | ||
120 | } | 118 | } |
121 | 119 | ||
122 | /// <summary> | 120 | /// <summary> |
@@ -127,11 +125,11 @@ namespace OpenSim.Framework | |||
127 | /// </remarks> | 125 | /// </remarks> |
128 | public T[] GetQueueArray() | 126 | public T[] GetQueueArray() |
129 | { | 127 | { |
130 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | ||
131 | return new T[0]; | ||
132 | |||
133 | lock (m_queueSync) | 128 | lock (m_queueSync) |
134 | { | 129 | { |
130 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | ||
131 | return new T[0]; | ||
132 | |||
135 | return m_queue.ToArray(); | 133 | return m_queue.ToArray(); |
136 | } | 134 | } |
137 | } | 135 | } |
diff --git a/OpenSim/Framework/ClientInfo.cs b/OpenSim/Framework/ClientInfo.cs index 9021315..98e4465 100644 --- a/OpenSim/Framework/ClientInfo.cs +++ b/OpenSim/Framework/ClientInfo.cs | |||
@@ -55,6 +55,11 @@ namespace OpenSim.Framework | |||
55 | public int textureThrottle; | 55 | public int textureThrottle; |
56 | public int totalThrottle; | 56 | public int totalThrottle; |
57 | 57 | ||
58 | // Used by adaptive only | ||
59 | public int targetThrottle; | ||
60 | |||
61 | public int maxThrottle; | ||
62 | |||
58 | public Dictionary<string, int> SyncRequests = new Dictionary<string,int>(); | 63 | public Dictionary<string, int> SyncRequests = new Dictionary<string,int>(); |
59 | public Dictionary<string, int> AsyncRequests = new Dictionary<string,int>(); | 64 | public Dictionary<string, int> AsyncRequests = new Dictionary<string,int>(); |
60 | public Dictionary<string, int> GenericRequests = new Dictionary<string,int>(); | 65 | public Dictionary<string, int> GenericRequests = new Dictionary<string,int>(); |
diff --git a/OpenSim/Framework/Communications/OutboundUrlFilter.cs b/OpenSim/Framework/Communications/OutboundUrlFilter.cs new file mode 100644 index 0000000..8b572d1 --- /dev/null +++ b/OpenSim/Framework/Communications/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.Communications | ||
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.Communications.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/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs index 09611fa..b398167 100644 --- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs | |||
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices; | |||
61 | // You can specify all the values or you can default the Revision and Build Numbers | 61 | // You can specify all the values or you can default the Revision and Build Numbers |
62 | // by using the '*' as shown below: | 62 | // by using the '*' as shown below: |
63 | 63 | ||
64 | [assembly : AssemblyVersion("0.8.0.*")] | 64 | [assembly : AssemblyVersion("0.8.2.*")] |
65 | 65 | ||
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs index ce36fbf..4403f40 100644 --- a/OpenSim/Framework/Communications/RestClient.cs +++ b/OpenSim/Framework/Communications/RestClient.cs | |||
@@ -35,6 +35,8 @@ using System.Threading; | |||
35 | using System.Web; | 35 | using System.Web; |
36 | using log4net; | 36 | using log4net; |
37 | 37 | ||
38 | using OpenSim.Framework.ServiceAuth; | ||
39 | |||
38 | namespace OpenSim.Framework.Communications | 40 | namespace OpenSim.Framework.Communications |
39 | { | 41 | { |
40 | /// <summary> | 42 | /// <summary> |
@@ -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,23 +344,49 @@ 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 | if (_response != null) | 392 | if (_response != null) |
@@ -332,6 +395,8 @@ namespace OpenSim.Framework.Communications | |||
332 | return null; | 395 | return null; |
333 | } | 396 | } |
334 | 397 | ||
398 | <<<<<<< HEAD | ||
399 | ======= | ||
335 | using (Stream src = _response.GetResponseStream()) | 400 | using (Stream src = _response.GetResponseStream()) |
336 | { | 401 | { |
337 | int length = src.Read(_readbuf, 0, BufferSize); | 402 | int length = src.Read(_readbuf, 0, BufferSize); |
@@ -349,6 +414,7 @@ namespace OpenSim.Framework.Communications | |||
349 | // _allDone.WaitOne(); | 414 | // _allDone.WaitOne(); |
350 | if (_response != null) | 415 | if (_response != null) |
351 | _response.Close(); | 416 | _response.Close(); |
417 | >>>>>>> avn/ubitvar | ||
352 | if (_asyncException != null) | 418 | if (_asyncException != null) |
353 | throw _asyncException; | 419 | throw _asyncException; |
354 | 420 | ||
@@ -358,11 +424,14 @@ namespace OpenSim.Framework.Communications | |||
358 | _resource.Seek(0, SeekOrigin.Begin); | 424 | _resource.Seek(0, SeekOrigin.Begin); |
359 | } | 425 | } |
360 | 426 | ||
427 | if (WebUtil.DebugLevel >= 5) | ||
428 | WebUtil.LogResponseDetail(reqnum, _resource); | ||
429 | |||
361 | return _resource; | 430 | return _resource; |
362 | } | 431 | } |
363 | } | 432 | } |
364 | 433 | ||
365 | public Stream Request(Stream src) | 434 | public Stream Request(Stream src, IServiceAuth auth) |
366 | { | 435 | { |
367 | _request = (HttpWebRequest) WebRequest.Create(buildUri()); | 436 | _request = (HttpWebRequest) WebRequest.Create(buildUri()); |
368 | _request.KeepAlive = false; | 437 | _request.KeepAlive = false; |
@@ -371,13 +440,28 @@ namespace OpenSim.Framework.Communications | |||
371 | _request.Method = RequestMethod; | 440 | _request.Method = RequestMethod; |
372 | _asyncException = null; | 441 | _asyncException = null; |
373 | _request.ContentLength = src.Length; | 442 | _request.ContentLength = src.Length; |
443 | if (auth != null) | ||
444 | auth.AddAuthorization(_request.Headers); | ||
374 | 445 | ||
375 | m_log.InfoFormat("[REST]: Request Length {0}", _request.ContentLength); | ||
376 | m_log.InfoFormat("[REST]: Sending Web Request {0}", buildUri()); | ||
377 | src.Seek(0, SeekOrigin.Begin); | 446 | src.Seek(0, SeekOrigin.Begin); |
447 | <<<<<<< HEAD | ||
448 | |||
449 | int reqnum = WebUtil.RequestNumber++; | ||
450 | if (WebUtil.DebugLevel >= 3) | ||
451 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri); | ||
452 | if (WebUtil.DebugLevel >= 5) | ||
453 | WebUtil.LogOutgoingDetail(string.Format("SEND {0}: ", reqnum), src); | ||
454 | |||
455 | Stream dst = _request.GetRequestStream(); | ||
456 | |||
457 | byte[] buf = new byte[1024]; | ||
458 | int length = src.Read(buf, 0, 1024); | ||
459 | while (length > 0) | ||
460 | ======= | ||
378 | m_log.Info("[REST]: Seek is ok"); | 461 | m_log.Info("[REST]: Seek is ok"); |
379 | 462 | ||
380 | using (Stream dst = _request.GetRequestStream()) | 463 | using (Stream dst = _request.GetRequestStream()) |
464 | >>>>>>> avn/ubitvar | ||
381 | { | 465 | { |
382 | m_log.Info("[REST]: GetRequestStream is ok"); | 466 | m_log.Info("[REST]: GetRequestStream is ok"); |
383 | 467 | ||
@@ -391,7 +475,37 @@ namespace OpenSim.Framework.Communications | |||
391 | } | 475 | } |
392 | } | 476 | } |
393 | 477 | ||
394 | _response = (HttpWebResponse) _request.GetResponse(); | 478 | try |
479 | { | ||
480 | _response = (HttpWebResponse)_request.GetResponse(); | ||
481 | } | ||
482 | catch (WebException e) | ||
483 | { | ||
484 | m_log.WarnFormat("[REST]: Request {0} {1} failed with status {2} and message {3}", | ||
485 | RequestMethod, _request.RequestUri, e.Status, e.Message); | ||
486 | return null; | ||
487 | } | ||
488 | catch (Exception e) | ||
489 | { | ||
490 | m_log.WarnFormat( | ||
491 | "[REST]: Request {0} {1} failed with exception {2} {3}", | ||
492 | RequestMethod, _request.RequestUri, e.Message, e.StackTrace); | ||
493 | return null; | ||
494 | } | ||
495 | |||
496 | if (WebUtil.DebugLevel >= 5) | ||
497 | { | ||
498 | using (Stream responseStream = _response.GetResponseStream()) | ||
499 | { | ||
500 | using (StreamReader reader = new StreamReader(responseStream)) | ||
501 | { | ||
502 | string responseStr = reader.ReadToEnd(); | ||
503 | WebUtil.LogResponseDetail(reqnum, responseStr); | ||
504 | } | ||
505 | } | ||
506 | } | ||
507 | |||
508 | _response.Close(); | ||
395 | 509 | ||
396 | if (_response != null) | 510 | if (_response != null) |
397 | _response.Close(); | 511 | _response.Close(); |
@@ -413,7 +527,7 @@ namespace OpenSim.Framework.Communications | |||
413 | /// In case, we are invoked asynchroneously this object will keep track of the state | 527 | /// In case, we are invoked asynchroneously this object will keep track of the state |
414 | /// </summary> | 528 | /// </summary> |
415 | AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state); | 529 | AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state); |
416 | Util.FireAndForget(RequestHelper, ar); | 530 | Util.FireAndForget(RequestHelper, ar, "RestClient.BeginRequest"); |
417 | return ar; | 531 | return ar; |
418 | } | 532 | } |
419 | 533 | ||
@@ -433,7 +547,7 @@ namespace OpenSim.Framework.Communications | |||
433 | try | 547 | try |
434 | { | 548 | { |
435 | // Perform the operation; if sucessful set the result | 549 | // Perform the operation; if sucessful set the result |
436 | Stream s = Request(); | 550 | Stream s = Request(null); |
437 | ar.SetAsCompleted(s, false); | 551 | ar.SetAsCompleted(s, false); |
438 | } | 552 | } |
439 | catch (Exception e) | 553 | catch (Exception e) |
diff --git a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs b/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs deleted file mode 100644 index 6681c37..0000000 --- a/OpenSim/Framework/Configuration/HTTP/HTTPConfiguration.cs +++ /dev/null | |||
@@ -1,123 +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 | using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) | ||
69 | { | ||
70 | using (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 | } | ||
84 | while (count > 0); | ||
85 | |||
86 | LoadDataFromString(sb.ToString()); | ||
87 | } | ||
88 | } | ||
89 | } | ||
90 | catch (WebException) | ||
91 | { | ||
92 | m_log.Warn("Unable to connect to remote configuration file (" + | ||
93 | remoteConfigSettings.baseConfigURL + configFileName + | ||
94 | "). Creating local file instead."); | ||
95 | xmlConfig.SetFileName(configFileName); | ||
96 | xmlConfig.LoadData(); | ||
97 | } | ||
98 | } | ||
99 | |||
100 | public void LoadDataFromString(string data) | ||
101 | { | ||
102 | xmlConfig.LoadDataFromString(data); | ||
103 | } | ||
104 | |||
105 | public string GetAttribute(string attributeName) | ||
106 | { | ||
107 | return xmlConfig.GetAttribute(attributeName); | ||
108 | } | ||
109 | |||
110 | public bool SetAttribute(string attributeName, string attributeValue) | ||
111 | { | ||
112 | return true; | ||
113 | } | ||
114 | |||
115 | public void Commit() | ||
116 | { | ||
117 | } | ||
118 | |||
119 | public void Close() | ||
120 | { | ||
121 | } | ||
122 | } | ||
123 | } | ||
diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs deleted file mode 100644 index 05a2e0e..0000000 --- a/OpenSim/Framework/Configuration/HTTP/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.Configuration.HTTP")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | ||
12 | [assembly: AssemblyProduct("OpenSim")] | ||
13 | [assembly: AssemblyCopyright("OpenSimulator develoeprs")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("cb78b672-d000-4f93-88f9-dae151cc0061")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | [assembly: AssemblyVersion("0.8.0.*")] | ||
33 | |||
diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs deleted file mode 100644 index d928a94..0000000 --- a/OpenSim/Framework/Configuration/XML/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.Configuration.XML")] | ||
9 | [assembly: AssemblyDescription("")] | ||
10 | [assembly: AssemblyConfiguration("")] | ||
11 | [assembly: AssemblyCompany("http://opensimulator.org")] | ||
12 | [assembly: AssemblyProduct("OpenSim")] | ||
13 | [assembly: AssemblyCopyright("OpenSimulator developers")] | ||
14 | [assembly: AssemblyTrademark("")] | ||
15 | [assembly: AssemblyCulture("")] | ||
16 | |||
17 | // Setting ComVisible to false makes the types in this assembly not visible | ||
18 | // to COM components. If you need to access a type in this assembly from | ||
19 | // COM, set the ComVisible attribute to true on that type. | ||
20 | [assembly: ComVisible(false)] | ||
21 | |||
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM | ||
23 | [assembly: Guid("eeb880df-0112-4c3d-87ed-b2108d614c55")] | ||
24 | |||
25 | // Version information for an assembly consists of the following four values: | ||
26 | // | ||
27 | // Major Version | ||
28 | // Minor Version | ||
29 | // Build Number | ||
30 | // Revision | ||
31 | // | ||
32 | [assembly: AssemblyVersion("0.8.0.*")] | ||
33 | |||
diff --git a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs b/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs deleted file mode 100644 index 3152a7d..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 (string.IsNullOrEmpty(fileName)) | ||
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 ba59025..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.8.0.*")] | 58 | [assembly : AssemblyVersion("0.8.2.*")] |
diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index 9490013..851fbed 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs | |||
@@ -429,9 +429,9 @@ namespace OpenSim.Framework.Console | |||
429 | return new string[] { new List<string>(current.Keys)[0] }; | 429 | return new string[] { new List<string>(current.Keys)[0] }; |
430 | } | 430 | } |
431 | 431 | ||
432 | public string[] Resolve(string[] cmd) | 432 | private CommandInfo ResolveCommand(string[] cmd, out string[] result) |
433 | { | 433 | { |
434 | string[] result = cmd; | 434 | result = cmd; |
435 | int index = -1; | 435 | int index = -1; |
436 | 436 | ||
437 | Dictionary<string, object> current = tree; | 437 | Dictionary<string, object> current = tree; |
@@ -463,7 +463,7 @@ namespace OpenSim.Framework.Console | |||
463 | } | 463 | } |
464 | else if (found.Count > 0) | 464 | else if (found.Count > 0) |
465 | { | 465 | { |
466 | return new string[0]; | 466 | return null; |
467 | } | 467 | } |
468 | else | 468 | else |
469 | { | 469 | { |
@@ -472,21 +472,37 @@ namespace OpenSim.Framework.Console | |||
472 | } | 472 | } |
473 | 473 | ||
474 | if (current.ContainsKey(String.Empty)) | 474 | if (current.ContainsKey(String.Empty)) |
475 | return (CommandInfo)current[String.Empty]; | ||
476 | |||
477 | return null; | ||
478 | } | ||
479 | |||
480 | public bool HasCommand(string command) | ||
481 | { | ||
482 | string[] result; | ||
483 | return ResolveCommand(Parser.Parse(command), out result) != null; | ||
484 | } | ||
485 | |||
486 | public string[] Resolve(string[] cmd) | ||
487 | { | ||
488 | string[] result; | ||
489 | CommandInfo ci = ResolveCommand(cmd, out result); | ||
490 | |||
491 | if (ci == null) | ||
492 | return new string[0]; | ||
493 | |||
494 | if (ci.fn.Count == 0) | ||
495 | return new string[0]; | ||
496 | |||
497 | foreach (CommandDelegate fn in ci.fn) | ||
475 | { | 498 | { |
476 | CommandInfo ci = (CommandInfo)current[String.Empty]; | 499 | if (fn != null) |
477 | if (ci.fn.Count == 0) | 500 | fn(ci.module, result); |
501 | else | ||
478 | return new string[0]; | 502 | return new string[0]; |
479 | foreach (CommandDelegate fn in ci.fn) | ||
480 | { | ||
481 | if (fn != null) | ||
482 | fn(ci.module, result); | ||
483 | else | ||
484 | return new string[0]; | ||
485 | } | ||
486 | return result; | ||
487 | } | 503 | } |
488 | 504 | ||
489 | return new string[0]; | 505 | return result; |
490 | } | 506 | } |
491 | 507 | ||
492 | public XmlElement GetXml(XmlDocument doc) | 508 | public XmlElement GetXml(XmlDocument doc) |
diff --git a/OpenSim/Framework/Console/ConsoleDisplayUtil.cs b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs new file mode 100644 index 0000000..6417663 --- /dev/null +++ b/OpenSim/Framework/Console/ConsoleDisplayUtil.cs | |||
@@ -0,0 +1,48 @@ | |||
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.Console | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// This will be a set of typical column sizes to allow greater consistency between console commands. | ||
34 | /// </summary> | ||
35 | public static class ConsoleDisplayUtil | ||
36 | { | ||
37 | public const int CoordTupleSize = 11; | ||
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; | ||
47 | } | ||
48 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs index 794bfaf..44f6dc1 100644 --- a/OpenSim/Framework/Console/ConsoleUtil.cs +++ b/OpenSim/Framework/Console/ConsoleUtil.cs | |||
@@ -156,7 +156,7 @@ namespace OpenSim.Framework.Console | |||
156 | } | 156 | } |
157 | 157 | ||
158 | /// <summary> | 158 | /// <summary> |
159 | /// Convert a console integer to an int, automatically complaining if a console is given. | 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> |
@@ -176,7 +176,7 @@ namespace OpenSim.Framework.Console | |||
176 | } | 176 | } |
177 | 177 | ||
178 | /// <summary> | 178 | /// <summary> |
179 | /// Convert a console integer to an int, automatically complaining if a console is given. | 179 | /// Convert a console input to an int, automatically complaining if a console is given. |
180 | /// </summary> | 180 | /// </summary> |
181 | /// <param name='console'>Can be null if no console is available.</param> | 181 | /// <param name='console'>Can be null if no console is available.</param> |
182 | /// <param name='rawConsoleInt'>/param> | 182 | /// <param name='rawConsoleInt'>/param> |
@@ -196,6 +196,46 @@ namespace OpenSim.Framework.Console | |||
196 | } | 196 | } |
197 | 197 | ||
198 | /// <summary> | 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> | ||
199 | /// Convert a console integer to a natural int, automatically complaining if a console is given. | 239 | /// Convert a console integer to a natural int, automatically complaining if a console is given. |
200 | /// </summary> | 240 | /// </summary> |
201 | /// <param name='console'>Can be null if no console is available.</param> | 241 | /// <param name='console'>Can be null if no console is available.</param> |
@@ -252,24 +292,82 @@ namespace OpenSim.Framework.Console | |||
252 | /// 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 |
253 | /// Other than that, component values must be numeric. | 293 | /// Other than that, component values must be numeric. |
254 | /// </param> | 294 | /// </param> |
255 | /// <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> | ||
256 | /// <param name='vector'></param> | 298 | /// <param name='vector'></param> |
257 | /// <returns></returns> | 299 | /// <returns></returns> |
258 | public static bool TryParseConsoleVector( | 300 | public static bool TryParseConsoleVector( |
259 | string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector) | 301 | string rawConsoleVector, Func<string, string> blankComponentFunc, out Vector3 vector) |
260 | { | 302 | { |
261 | List<string> components = rawConsoleVector.Split(VectorSeparatorChars).ToList(); | 303 | return Vector3.TryParse(CookVector(rawConsoleVector, 3, blankComponentFunc), out vector); |
262 | 304 | } | |
263 | 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) | ||
264 | { | 329 | { |
265 | vector = Vector3.Zero; | 330 | vector = Vector2.Zero; |
331 | |||
266 | return false; | 332 | return false; |
267 | } | 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(); | ||
268 | 357 | ||
269 | for (int i = components.Count; i < 3; i++) | 358 | if (components.Count < 1 || components.Count > dimensions) |
270 | components.Add(""); | 359 | return null; |
271 | 360 | ||
272 | 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 | ||
273 | = components.ConvertAll<string>( | 371 | = components.ConvertAll<string>( |
274 | c => | 372 | c => |
275 | { | 373 | { |
@@ -283,11 +381,7 @@ namespace OpenSim.Framework.Console | |||
283 | return c; | 381 | return c; |
284 | }); | 382 | }); |
285 | 383 | ||
286 | string semiDigestedConsoleVector = string.Join(VectorSeparator, semiDigestedComponents.ToArray()); | 384 | return string.Join(VectorSeparator, cookedComponents.ToArray()); |
287 | |||
288 | // m_log.DebugFormat("[CONSOLE UTIL]: Parsing {0} into OpenMetaverse.Vector3", semiDigestedConsoleVector); | ||
289 | |||
290 | return Vector3.TryParse(semiDigestedConsoleVector, out vector); | ||
291 | } | 385 | } |
292 | } | 386 | } |
293 | } \ 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 a967db6..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 | { |
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/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 5ddbd61..3aec437 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 |
@@ -430,5 +431,119 @@ namespace OpenSim.Framework | |||
430 | { | 431 | { |
431 | return l_EstateGroups.Contains(groupID); | 432 | return l_EstateGroups.Contains(groupID); |
432 | } | 433 | } |
434 | |||
435 | public Dictionary<string, object> ToMap() | ||
436 | { | ||
437 | Dictionary<string, object> map = new Dictionary<string, object>(); | ||
438 | PropertyInfo[] properties = this.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance); | ||
439 | foreach (PropertyInfo p in properties) | ||
440 | { | ||
441 | // EstateBans is a complex type, let's treat it as special | ||
442 | if (p.Name == "EstateBans") | ||
443 | continue; | ||
444 | |||
445 | object value = p.GetValue(this, null); | ||
446 | if (value != null) | ||
447 | { | ||
448 | if (p.PropertyType.IsArray) // of UUIDs | ||
449 | { | ||
450 | if (((Array)value).Length > 0) | ||
451 | { | ||
452 | string[] args = new string[((Array)value).Length]; | ||
453 | int index = 0; | ||
454 | foreach (object o in (Array)value) | ||
455 | args[index++] = o.ToString(); | ||
456 | map[p.Name] = String.Join(",", args); | ||
457 | } | ||
458 | } | ||
459 | else // simple types | ||
460 | map[p.Name] = value; | ||
461 | } | ||
462 | } | ||
463 | |||
464 | // EstateBans are special | ||
465 | if (EstateBans.Length > 0) | ||
466 | { | ||
467 | Dictionary<string, object> bans = new Dictionary<string, object>(); | ||
468 | int i = 0; | ||
469 | foreach (EstateBan ban in EstateBans) | ||
470 | bans["ban" + i++] = ban.ToMap(); | ||
471 | map["EstateBans"] = bans; | ||
472 | } | ||
473 | |||
474 | return map; | ||
475 | } | ||
476 | |||
477 | /// <summary> | ||
478 | /// For debugging | ||
479 | /// </summary> | ||
480 | /// <returns></returns> | ||
481 | public override string ToString() | ||
482 | { | ||
483 | Dictionary<string, object> map = ToMap(); | ||
484 | String result = String.Empty; | ||
485 | |||
486 | foreach (KeyValuePair<string, object> kvp in map) | ||
487 | { | ||
488 | if (kvp.Key == "EstateBans") | ||
489 | { | ||
490 | result += "EstateBans:" + Environment.NewLine; | ||
491 | foreach (KeyValuePair<string, object> ban in (Dictionary<string, object>)kvp.Value) | ||
492 | result += ban.Value.ToString(); | ||
493 | } | ||
494 | else | ||
495 | result += string.Format("{0}: {1} {2}", kvp.Key, kvp.Value.ToString(), Environment.NewLine); | ||
496 | } | ||
497 | |||
498 | return result; | ||
499 | } | ||
500 | |||
501 | public EstateSettings(Dictionary<string, object> map) | ||
502 | { | ||
503 | foreach (KeyValuePair<string, object> kvp in map) | ||
504 | { | ||
505 | PropertyInfo p = this.GetType().GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance); | ||
506 | if (p == null) | ||
507 | continue; | ||
508 | |||
509 | // EstateBans is a complex type, let's treat it as special | ||
510 | if (p.Name == "EstateBans") | ||
511 | continue; | ||
512 | |||
513 | if (p.PropertyType.IsArray) | ||
514 | { | ||
515 | string[] elements = ((string)map[p.Name]).Split(new char[] { ',' }); | ||
516 | UUID[] uuids = new UUID[elements.Length]; | ||
517 | int i = 0; | ||
518 | foreach (string e in elements) | ||
519 | uuids[i++] = new UUID(e); | ||
520 | p.SetValue(this, uuids, null); | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | object value = p.GetValue(this, null); | ||
525 | if (value is String) | ||
526 | p.SetValue(this, map[p.Name], null); | ||
527 | else if (value is UInt32) | ||
528 | p.SetValue(this, UInt32.Parse((string)map[p.Name]), null); | ||
529 | else if (value is Boolean) | ||
530 | p.SetValue(this, Boolean.Parse((string)map[p.Name]), null); | ||
531 | else if (value is UUID) | ||
532 | p.SetValue(this, UUID.Parse((string)map[p.Name]), null); | ||
533 | } | ||
534 | } | ||
535 | |||
536 | // EstateBans are special | ||
537 | if (map.ContainsKey("EstateBans")) | ||
538 | { | ||
539 | var banData = ((Dictionary<string, object>)map["EstateBans"]).Values; | ||
540 | EstateBan[] bans = new EstateBan[banData.Count]; | ||
541 | int b = 0; | ||
542 | foreach (Dictionary<string, object> ban in banData) | ||
543 | bans[b++] = new EstateBan(ban); | ||
544 | PropertyInfo bansProperty = this.GetType().GetProperty("EstateBans", BindingFlags.Public | BindingFlags.Instance); | ||
545 | bansProperty.SetValue(this, bans, null); | ||
546 | } | ||
547 | } | ||
433 | } | 548 | } |
434 | } | 549 | } |
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/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index 8d15119..db1496c 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; } |
diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs index b88e103..8d274d0 100644 --- a/OpenSim/Framework/IPeople.cs +++ b/OpenSim/Framework/IPeople.cs | |||
@@ -38,6 +38,8 @@ namespace OpenSim.Framework | |||
38 | public string LastName { get; set; } | 38 | public string LastName { get; set; } |
39 | public string HomeURL { get; set; } | 39 | public string HomeURL { get; set; } |
40 | public Dictionary<string, object> ServerURLs { get; set; } | 40 | public Dictionary<string, object> ServerURLs { get; set; } |
41 | public bool IsUnknownUser { get; set; } | ||
42 | public bool HasGridUserTried { get; set; } | ||
41 | } | 43 | } |
42 | 44 | ||
43 | public interface IPeople | 45 | public interface IPeople |
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 558dfd0..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 | { |
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/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/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs index 07971bf..b08e4f7 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.8.0.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs index e6c73d3..be4a8b4 100644 --- a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs | |||
@@ -82,6 +82,9 @@ namespace OpenSim.Framework.Monitoring | |||
82 | // IRegionModuleBase.Initialize | 82 | // IRegionModuleBase.Initialize |
83 | public void Initialise(IConfigSource source) | 83 | public void Initialise(IConfigSource source) |
84 | { | 84 | { |
85 | if (source == null) | ||
86 | return; | ||
87 | |||
85 | IConfig cfg = source.Configs["Monitoring"]; | 88 | IConfig cfg = source.Configs["Monitoring"]; |
86 | 89 | ||
87 | if (cfg != null) | 90 | if (cfg != null) |
@@ -141,19 +144,19 @@ namespace OpenSim.Framework.Monitoring | |||
141 | processorPercentPerfCounter = new PerfCounterControl(tempPC); | 144 | processorPercentPerfCounter = new PerfCounterControl(tempPC); |
142 | // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. | 145 | // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy. |
143 | tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, | 146 | tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, |
144 | StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, | 147 | StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter); }, |
145 | StatVerbosity.Info); | 148 | StatVerbosity.Info); |
146 | StatsManager.RegisterStat(tempStat); | 149 | StatsManager.RegisterStat(tempStat); |
147 | RegisteredStats.Add(tempName, tempStat); | 150 | RegisteredStats.Add(tempName, tempStat); |
148 | 151 | ||
149 | MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, | 152 | MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, |
150 | (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); | 153 | (s) => { s.Value = Math.Round(Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds, 3); }); |
151 | 154 | ||
152 | MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, | 155 | MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, |
153 | (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); | 156 | (s) => { s.Value = Math.Round(Process.GetCurrentProcess().UserProcessorTime.TotalSeconds, 3); }); |
154 | 157 | ||
155 | MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, | 158 | MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, |
156 | (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); | 159 | (s) => { s.Value = Math.Round(Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds, 3); }); |
157 | 160 | ||
158 | MakeStat("Threads", null, "threads", ContainerProcessor, | 161 | MakeStat("Threads", null, "threads", ContainerProcessor, |
159 | (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); | 162 | (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); |
@@ -296,28 +299,22 @@ namespace OpenSim.Framework.Monitoring | |||
296 | // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c | 299 | // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c |
297 | // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters | 300 | // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters |
298 | private delegate double PerfCounterNextValue(); | 301 | private delegate double PerfCounterNextValue(); |
302 | |||
299 | private void GetNextValue(Stat stat, PerfCounterControl perfControl) | 303 | private void GetNextValue(Stat stat, PerfCounterControl perfControl) |
300 | { | 304 | { |
301 | GetNextValue(stat, perfControl, 1.0); | ||
302 | } | ||
303 | private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) | ||
304 | { | ||
305 | if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) | 305 | if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) |
306 | { | 306 | { |
307 | if (perfControl != null && perfControl.perfCounter != null) | 307 | if (perfControl != null && perfControl.perfCounter != null) |
308 | { | 308 | { |
309 | try | 309 | try |
310 | { | 310 | { |
311 | // Kludge for factor to run double duty. If -1, subtract the value from one | 311 | stat.Value = Math.Round(perfControl.perfCounter.NextValue(), 3); |
312 | if (factor == -1) | ||
313 | stat.Value = 1 - perfControl.perfCounter.NextValue(); | ||
314 | else | ||
315 | stat.Value = perfControl.perfCounter.NextValue() / factor; | ||
316 | } | 312 | } |
317 | catch (Exception e) | 313 | catch (Exception e) |
318 | { | 314 | { |
319 | m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); | 315 | m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); |
320 | } | 316 | } |
317 | |||
321 | perfControl.lastFetch = Util.EnvironmentTickCount(); | 318 | perfControl.lastFetch = Util.EnvironmentTickCount(); |
322 | } | 319 | } |
323 | } | 320 | } |
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs index f6f458d..e4df7ee 100644..100755 --- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs | |||
@@ -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.Linq; | 31 | using System.Linq; |
31 | using System.Text; | 32 | using System.Text; |
32 | using OpenMetaverse; | 33 | using OpenMetaverse; |
@@ -71,6 +72,11 @@ namespace OpenSim.Framework.Monitoring | |||
71 | private volatile float pendingUploads; | 72 | private volatile float pendingUploads; |
72 | private volatile float activeScripts; | 73 | private volatile float activeScripts; |
73 | private volatile float scriptLinesPerSecond; | 74 | private volatile float scriptLinesPerSecond; |
75 | private volatile float m_frameDilation; | ||
76 | private volatile float m_usersLoggingIn; | ||
77 | private volatile float m_totalGeoPrims; | ||
78 | private volatile float m_totalMeshes; | ||
79 | private volatile float m_inUseThreads; | ||
74 | 80 | ||
75 | // /// <summary> | 81 | // /// <summary> |
76 | // /// 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 |
@@ -249,6 +255,10 @@ namespace OpenSim.Framework.Monitoring | |||
249 | { | 255 | { |
250 | // 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 |
251 | // 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 | ||
252 | timeDilation = stats.StatsBlock[0].StatValue; | 262 | timeDilation = stats.StatsBlock[0].StatValue; |
253 | simFps = stats.StatsBlock[1].StatValue; | 263 | simFps = stats.StatsBlock[1].StatValue; |
254 | physicsFps = stats.StatsBlock[2].StatValue; | 264 | physicsFps = stats.StatsBlock[2].StatValue; |
@@ -270,6 +280,11 @@ namespace OpenSim.Framework.Monitoring | |||
270 | pendingUploads = stats.StatsBlock[18].StatValue; | 280 | pendingUploads = stats.StatsBlock[18].StatValue; |
271 | activeScripts = stats.StatsBlock[19].StatValue; | 281 | activeScripts = stats.StatsBlock[19].StatValue; |
272 | 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; | ||
273 | } | 288 | } |
274 | 289 | ||
275 | /// <summary> | 290 | /// <summary> |
@@ -407,6 +422,27 @@ Asset service request failures: {3}" + Environment.NewLine, | |||
407 | /// <returns></returns> | 422 | /// <returns></returns> |
408 | public override OSDMap OReport(string uptime, string version) | 423 | public override OSDMap OReport(string uptime, string version) |
409 | { | 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 | |||
410 | OSDMap args = new OSDMap(30); | 446 | OSDMap args = new OSDMap(30); |
411 | // args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache)); | 447 | // args["AssetsInCache"] = OSD.FromString (String.Format ("{0:0.##}", AssetsInCache)); |
412 | // args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}", | 448 | // args["TimeAfterCacheMiss"] = OSD.FromString (String.Format ("{0:0.##}", |
@@ -443,6 +479,22 @@ Asset service request failures: {3}" + Environment.NewLine, | |||
443 | args["Memory"] = OSD.FromString (base.XReport (uptime, version)); | 479 | args["Memory"] = OSD.FromString (base.XReport (uptime, version)); |
444 | args["Uptime"] = OSD.FromString (uptime); | 480 | args["Uptime"] = OSD.FromString (uptime); |
445 | args["Version"] = OSD.FromString (version); | 481 | args["Version"] = OSD.FromString (version); |
482 | |||
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)); | ||
446 | 498 | ||
447 | return args; | 499 | return args; |
448 | } | 500 | } |
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index bd757d0..916fa53 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs | |||
@@ -171,7 +171,8 @@ namespace OpenSim.Framework.Monitoring | |||
171 | foreach (char c in DisallowedShortNameCharacters) | 171 | foreach (char c in DisallowedShortNameCharacters) |
172 | { | 172 | { |
173 | if (shortName.IndexOf(c) != -1) | 173 | if (shortName.IndexOf(c) != -1) |
174 | throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c)); | 174 | shortName = shortName.Replace(c, '#'); |
175 | // throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c)); | ||
175 | } | 176 | } |
176 | 177 | ||
177 | ShortName = shortName; | 178 | ShortName = shortName; |
diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs index 1e4fa11..15a37aa 100644 --- a/OpenSim/Framework/Monitoring/StatsLogger.cs +++ b/OpenSim/Framework/Monitoring/StatsLogger.cs | |||
@@ -26,7 +26,10 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
29 | using System.Reflection; | 31 | using System.Reflection; |
32 | using System.Text; | ||
30 | using System.Timers; | 33 | using System.Timers; |
31 | using log4net; | 34 | using log4net; |
32 | 35 | ||
@@ -45,37 +48,67 @@ namespace OpenSim.Framework.Monitoring | |||
45 | public static void RegisterConsoleCommands(ICommandConsole console) | 48 | public static void RegisterConsoleCommands(ICommandConsole console) |
46 | { | 49 | { |
47 | console.Commands.AddCommand( | 50 | console.Commands.AddCommand( |
48 | "Debug", | 51 | "General", |
49 | false, | 52 | false, |
50 | "debug stats record", | 53 | "stats record", |
51 | "debug stats record start|stop", | 54 | "stats record start|stop", |
52 | "Control whether stats are being regularly recorded to a separate file.", | 55 | "Control whether stats are being regularly recorded to a separate file.", |
53 | "For debug purposes. Experimental.", | 56 | "For debug purposes. Experimental.", |
54 | HandleStatsRecordCommand); | 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); | ||
55 | } | 67 | } |
56 | 68 | ||
57 | public static void HandleStatsRecordCommand(string module, string[] cmd) | 69 | public static void HandleStatsRecordCommand(string module, string[] cmd) |
58 | { | 70 | { |
59 | ICommandConsole con = MainConsole.Instance; | 71 | ICommandConsole con = MainConsole.Instance; |
60 | 72 | ||
61 | if (cmd.Length != 4) | 73 | if (cmd.Length != 3) |
62 | { | 74 | { |
63 | con.Output("Usage: debug stats record start|stop"); | 75 | con.Output("Usage: stats record start|stop"); |
64 | return; | 76 | return; |
65 | } | 77 | } |
66 | 78 | ||
67 | if (cmd[3] == "start") | 79 | if (cmd[2] == "start") |
68 | { | 80 | { |
69 | Start(); | 81 | Start(); |
70 | con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs); | 82 | con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs); |
71 | } | 83 | } |
72 | else if (cmd[3] == "stop") | 84 | else if (cmd[2] == "stop") |
73 | { | 85 | { |
74 | Stop(); | 86 | Stop(); |
75 | con.Output("Stopped recording stats to file."); | 87 | con.Output("Stopped recording stats to file."); |
76 | } | 88 | } |
77 | } | 89 | } |
78 | 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 | |||
79 | public static void Start() | 112 | public static void Start() |
80 | { | 113 | { |
81 | if (m_loggingTimer != null) | 114 | if (m_loggingTimer != null) |
@@ -97,12 +130,22 @@ namespace OpenSim.Framework.Monitoring | |||
97 | 130 | ||
98 | private static void Log(object sender, ElapsedEventArgs e) | 131 | private static void Log(object sender, ElapsedEventArgs e) |
99 | { | 132 | { |
100 | m_statsLog.InfoFormat("*** STATS REPORT AT {0} ***", DateTime.Now); | 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)); | ||
101 | 144 | ||
102 | foreach (string report in StatsManager.GetAllStatsReports()) | 145 | foreach (string report in StatsManager.GetAllStatsReports()) |
103 | m_statsLog.Info(report); | 146 | lines.Add(report); |
104 | 147 | ||
105 | m_loggingTimer.Start(); | 148 | return lines; |
106 | } | 149 | } |
107 | } | 150 | } |
108 | } \ No newline at end of file | 151 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 249cef6..a167b55 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs | |||
@@ -72,8 +72,8 @@ namespace OpenSim.Framework.Monitoring | |||
72 | console.Commands.AddCommand( | 72 | console.Commands.AddCommand( |
73 | "General", | 73 | "General", |
74 | false, | 74 | false, |
75 | "show stats", | 75 | "stats show", |
76 | "show stats [list|all|(<category>[.<container>])+", | 76 | "stats show [list|all|(<category>[.<container>])+", |
77 | "Show statistical information for this server", | 77 | "Show statistical information for this server", |
78 | "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" |
79 | + "'list' argument will show statistic categories.\n" | 79 | + "'list' argument will show statistic categories.\n" |
@@ -84,6 +84,14 @@ namespace OpenSim.Framework.Monitoring | |||
84 | + "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", |
85 | HandleShowStatsCommand); | 85 | HandleShowStatsCommand); |
86 | 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 | |||
87 | StatsLogger.RegisterConsoleCommands(console); | 95 | StatsLogger.RegisterConsoleCommands(console); |
88 | } | 96 | } |
89 | 97 | ||
@@ -99,6 +107,7 @@ namespace OpenSim.Framework.Monitoring | |||
99 | 107 | ||
100 | string categoryName = components[0]; | 108 | string categoryName = components[0]; |
101 | string containerName = components.Length > 1 ? components[1] : null; | 109 | string containerName = components.Length > 1 ? components[1] : null; |
110 | string statName = components.Length > 2 ? components[2] : null; | ||
102 | 111 | ||
103 | if (categoryName == AllSubCommand) | 112 | if (categoryName == AllSubCommand) |
104 | { | 113 | { |
@@ -128,7 +137,23 @@ namespace OpenSim.Framework.Monitoring | |||
128 | SortedDictionary<string, Stat> container; | 137 | SortedDictionary<string, Stat> container; |
129 | if (category.TryGetValue(containerName, out container)) | 138 | if (category.TryGetValue(containerName, out container)) |
130 | { | 139 | { |
131 | OutputContainerStatsToConsole(con, container); | 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 | } | ||
132 | } | 157 | } |
133 | else | 158 | else |
134 | { | 159 | { |
@@ -200,6 +225,11 @@ namespace OpenSim.Framework.Monitoring | |||
200 | con.Output(report); | 225 | con.Output(report); |
201 | } | 226 | } |
202 | 227 | ||
228 | private static void OutputStatToConsole(ICommandConsole con, Stat stat) | ||
229 | { | ||
230 | con.Output(stat.ToConsoleString()); | ||
231 | } | ||
232 | |||
203 | // Creates an OSDMap of the format: | 233 | // Creates an OSDMap of the format: |
204 | // { categoryName: { | 234 | // { categoryName: { |
205 | // containerName: { | 235 | // containerName: { |
@@ -288,7 +318,7 @@ namespace OpenSim.Framework.Monitoring | |||
288 | 318 | ||
289 | if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); | 319 | if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); |
290 | if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); | 320 | if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); |
291 | if (request.ContainsKey("stat")) pStatName = request["cat"].ToString(); | 321 | if (request.ContainsKey("stat")) pStatName = request["stat"].ToString(); |
292 | 322 | ||
293 | string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); | 323 | string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); |
294 | 324 | ||
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs index 32724ec..0cab427 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> |
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/PluginLoader.cs b/OpenSim/Framework/PluginLoader.cs index cc80943..5fa27d6 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,12 +239,21 @@ 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 | ||
248 | <<<<<<< HEAD | ||
249 | try | ||
250 | { | ||
251 | if (Directory.Exists(dir + "/addin-db-000")) | ||
252 | Directory.Delete(dir + "/addin-db-000", true); | ||
253 | |||
254 | if (Directory.Exists(dir + "/addin-db-001")) | ||
255 | Directory.Delete(dir + "/addin-db-001", true); | ||
256 | ======= | ||
248 | string customDir = Environment.GetEnvironmentVariable ("MONO_ADDINS_REGISTRY"); | 257 | string customDir = Environment.GetEnvironmentVariable ("MONO_ADDINS_REGISTRY"); |
249 | string v0 = "addin-db-000"; | 258 | string v0 = "addin-db-000"; |
250 | string v1 = "addin-db-001"; | 259 | string v1 = "addin-db-001"; |
@@ -260,6 +269,7 @@ namespace OpenSim.Framework | |||
260 | 269 | ||
261 | if (Directory.Exists(v1)) | 270 | if (Directory.Exists(v1)) |
262 | Directory.Delete(v1, true); | 271 | Directory.Delete(v1, true); |
272 | >>>>>>> avn/ubitvar | ||
263 | } | 273 | } |
264 | catch (IOException) | 274 | catch (IOException) |
265 | { | 275 | { |
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 019fffc..d75a6cf 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs | |||
@@ -102,9 +102,12 @@ namespace OpenSim.Framework | |||
102 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 102 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
103 | private static readonly string LogHeader = "[REGION INFO]"; | 103 | private static readonly string LogHeader = "[REGION INFO]"; |
104 | 104 | ||
105 | <<<<<<< HEAD | ||
106 | ======= | ||
105 | public bool commFailTF = false; | 107 | public bool commFailTF = false; |
106 | public ConfigurationMember configMember; | 108 | public ConfigurationMember configMember; |
107 | public string DataStore = String.Empty; | 109 | public string DataStore = String.Empty; |
110 | >>>>>>> avn/ubitvar | ||
108 | public string RegionFile = String.Empty; | 111 | public string RegionFile = String.Empty; |
109 | public bool isSandbox = false; | 112 | public bool isSandbox = false; |
110 | public bool Persistent = true; | 113 | public bool Persistent = true; |
@@ -129,8 +132,8 @@ namespace OpenSim.Framework | |||
129 | private int m_physPrimMax = 0; | 132 | private int m_physPrimMax = 0; |
130 | private bool m_clampPrimSize = false; | 133 | private bool m_clampPrimSize = false; |
131 | private int m_objectCapacity = 0; | 134 | private int m_objectCapacity = 0; |
135 | private int m_maxPrimsPerUser = -1; | ||
132 | private int m_linksetCapacity = 0; | 136 | private int m_linksetCapacity = 0; |
133 | private int m_agentCapacity = 0; | ||
134 | private string m_regionType = String.Empty; | 137 | private string m_regionType = String.Empty; |
135 | private RegionLightShareData m_windlight = new RegionLightShareData(); | 138 | private RegionLightShareData m_windlight = new RegionLightShareData(); |
136 | protected uint m_httpPort; | 139 | protected uint m_httpPort; |
@@ -226,7 +229,6 @@ namespace OpenSim.Framework | |||
226 | try | 229 | try |
227 | { | 230 | { |
228 | // This will throw if it's not legal Nini XML format | 231 | // This will throw if it's not legal Nini XML format |
229 | // and thereby toss it to the legacy loader | ||
230 | // | 232 | // |
231 | IConfigSource xmlsource = new XmlConfigSource(filename); | 233 | IConfigSource xmlsource = new XmlConfigSource(filename); |
232 | 234 | ||
@@ -239,11 +241,6 @@ namespace OpenSim.Framework | |||
239 | catch (Exception) | 241 | catch (Exception) |
240 | { | 242 | { |
241 | } | 243 | } |
242 | |||
243 | configMember = | ||
244 | new ConfigurationMember(filename, description, loadConfigurationOptions, handleIncomingConfiguration, !skipConsoleConfig); | ||
245 | configMember.performConfigurationRetrieve(); | ||
246 | RegionFile = filename; | ||
247 | } | 244 | } |
248 | 245 | ||
249 | // The web loader uses this | 246 | // The web loader uses this |
@@ -350,16 +347,18 @@ namespace OpenSim.Framework | |||
350 | get { return m_objectCapacity; } | 347 | get { return m_objectCapacity; } |
351 | } | 348 | } |
352 | 349 | ||
353 | public int LinksetCapacity | 350 | public int MaxPrimsPerUser |
354 | { | 351 | { |
355 | get { return m_linksetCapacity; } | 352 | get { return m_maxPrimsPerUser; } |
356 | } | 353 | } |
357 | 354 | ||
358 | public int AgentCapacity | 355 | public int LinksetCapacity |
359 | { | 356 | { |
360 | get { return m_agentCapacity; } | 357 | get { return m_linksetCapacity; } |
361 | } | 358 | } |
362 | 359 | ||
360 | public int AgentCapacity { get; set; } | ||
361 | |||
363 | public byte AccessLevel | 362 | public byte AccessLevel |
364 | { | 363 | { |
365 | get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); } | 364 | get { return (byte)Util.ConvertMaturityToAccessLevel((uint)RegionSettings.Maturity); } |
@@ -374,6 +373,8 @@ namespace OpenSim.Framework | |||
374 | { | 373 | { |
375 | get { return m_maptileStaticUUID; } | 374 | get { return m_maptileStaticUUID; } |
376 | } | 375 | } |
376 | |||
377 | public string MaptileStaticFile { get; private set; } | ||
377 | 378 | ||
378 | /// <summary> | 379 | /// <summary> |
379 | /// The port by which http communication occurs with the region (most noticeably, CAPS communication) | 380 | /// The port by which http communication occurs with the region (most noticeably, CAPS communication) |
@@ -523,7 +524,7 @@ namespace OpenSim.Framework | |||
523 | m_internalEndPoint = tmpEPE; | 524 | m_internalEndPoint = tmpEPE; |
524 | } | 525 | } |
525 | 526 | ||
526 | public string GetOtherSetting(string key) | 527 | public string GetSetting(string key) |
527 | { | 528 | { |
528 | string val; | 529 | string val; |
529 | string keylower = key.ToLower(); | 530 | string keylower = key.ToLower(); |
@@ -533,7 +534,11 @@ namespace OpenSim.Framework | |||
533 | return null; | 534 | return null; |
534 | } | 535 | } |
535 | 536 | ||
537 | <<<<<<< HEAD | ||
538 | private void SetExtraSetting(string key, string value) | ||
539 | ======= | ||
536 | public void SetExtraSetting(string key, string value) | 540 | public void SetExtraSetting(string key, string value) |
541 | >>>>>>> avn/ubitvar | ||
537 | { | 542 | { |
538 | string keylower = key.ToLower(); | 543 | string keylower = key.ToLower(); |
539 | m_extraSettings[keylower] = value; | 544 | m_extraSettings[keylower] = value; |
@@ -732,6 +737,9 @@ namespace OpenSim.Framework | |||
732 | m_objectCapacity = config.GetInt("MaxPrims", 15000); | 737 | m_objectCapacity = config.GetInt("MaxPrims", 15000); |
733 | allKeys.Remove("MaxPrims"); | 738 | allKeys.Remove("MaxPrims"); |
734 | 739 | ||
740 | m_maxPrimsPerUser = config.GetInt("MaxPrimsPerUser", -1); | ||
741 | allKeys.Remove("MaxPrimsPerUser"); | ||
742 | |||
735 | m_linksetCapacity = config.GetInt("LinksetPrims", 0); | 743 | m_linksetCapacity = config.GetInt("LinksetPrims", 0); |
736 | allKeys.Remove("LinksetPrims"); | 744 | allKeys.Remove("LinksetPrims"); |
737 | 745 | ||
@@ -741,10 +749,13 @@ namespace OpenSim.Framework | |||
741 | { | 749 | { |
742 | config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); | 750 | config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); |
743 | } | 751 | } |
752 | |||
753 | MaptileStaticFile = config.GetString("MaptileStaticFile", String.Empty); | ||
754 | allKeys.Remove("MaptileStaticFile"); | ||
744 | 755 | ||
745 | #endregion | 756 | #endregion |
746 | 757 | ||
747 | m_agentCapacity = config.GetInt("MaxAgents", 100); | 758 | AgentCapacity = config.GetInt("MaxAgents", 100); |
748 | allKeys.Remove("MaxAgents"); | 759 | allKeys.Remove("MaxAgents"); |
749 | 760 | ||
750 | // Multi-tenancy | 761 | // Multi-tenancy |
@@ -823,15 +834,22 @@ namespace OpenSim.Framework | |||
823 | string location = String.Format("{0},{1}", RegionLocX, RegionLocY); | 834 | string location = String.Format("{0},{1}", RegionLocX, RegionLocY); |
824 | config.Set("Location", location); | 835 | config.Set("Location", location); |
825 | 836 | ||
837 | <<<<<<< HEAD | ||
838 | if (RegionSizeX > 0) | ||
839 | ======= | ||
826 | if (DataStore != String.Empty) | 840 | if (DataStore != String.Empty) |
827 | config.Set("Datastore", DataStore); | 841 | config.Set("Datastore", DataStore); |
828 | 842 | ||
829 | if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) | 843 | if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) |
830 | { | 844 | { |
845 | >>>>>>> avn/ubitvar | ||
831 | config.Set("SizeX", RegionSizeX); | 846 | config.Set("SizeX", RegionSizeX); |
847 | |||
848 | if (RegionSizeY > 0) | ||
832 | config.Set("SizeY", RegionSizeY); | 849 | config.Set("SizeY", RegionSizeY); |
833 | config.Set("SizeZ", RegionSizeZ); | 850 | |
834 | } | 851 | // if (RegionSizeZ > 0) |
852 | // config.Set("SizeZ", RegionSizeZ); | ||
835 | 853 | ||
836 | config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); | 854 | config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); |
837 | config.Set("InternalPort", m_internalEndPoint.Port); | 855 | config.Set("InternalPort", m_internalEndPoint.Port); |
@@ -857,11 +875,14 @@ namespace OpenSim.Framework | |||
857 | if (m_objectCapacity > 0) | 875 | if (m_objectCapacity > 0) |
858 | config.Set("MaxPrims", m_objectCapacity); | 876 | config.Set("MaxPrims", m_objectCapacity); |
859 | 877 | ||
878 | if (m_maxPrimsPerUser > -1) | ||
879 | config.Set("MaxPrimsPerUser", m_maxPrimsPerUser); | ||
880 | |||
860 | if (m_linksetCapacity > 0) | 881 | if (m_linksetCapacity > 0) |
861 | config.Set("LinksetPrims", m_linksetCapacity); | 882 | config.Set("LinksetPrims", m_linksetCapacity); |
862 | 883 | ||
863 | if (m_agentCapacity > 0) | 884 | if (AgentCapacity > 0) |
864 | config.Set("MaxAgents", m_agentCapacity); | 885 | config.Set("MaxAgents", AgentCapacity); |
865 | 886 | ||
866 | if (ScopeID != UUID.Zero) | 887 | if (ScopeID != UUID.Zero) |
867 | config.Set("ScopeID", ScopeID.ToString()); | 888 | config.Set("ScopeID", ScopeID.ToString()); |
@@ -871,11 +892,9 @@ namespace OpenSim.Framework | |||
871 | 892 | ||
872 | if (m_maptileStaticUUID != UUID.Zero) | 893 | if (m_maptileStaticUUID != UUID.Zero) |
873 | config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); | 894 | config.Set("MaptileStaticUUID", m_maptileStaticUUID.ToString()); |
874 | } | ||
875 | 895 | ||
876 | public bool ignoreIncomingConfiguration(string configuration_key, object configuration_result) | 896 | if (MaptileStaticFile != null && MaptileStaticFile != String.Empty) |
877 | { | 897 | config.Set("MaptileStaticFile", MaptileStaticFile); |
878 | return true; | ||
879 | } | 898 | } |
880 | 899 | ||
881 | public void SaveRegionToFile(string description, string filename) | 900 | public void SaveRegionToFile(string description, string filename) |
@@ -897,17 +916,12 @@ namespace OpenSim.Framework | |||
897 | 916 | ||
898 | return; | 917 | return; |
899 | } | 918 | } |
900 | else if (filename.ToLower().EndsWith(".xml")) | ||
901 | { | ||
902 | configMember = new ConfigurationMember(filename, description, loadConfigurationOptionsFromMe, | ||
903 | ignoreIncomingConfiguration, false); | ||
904 | configMember.performConfigurationRetrieve(); | ||
905 | RegionFile = filename; | ||
906 | } | ||
907 | else | 919 | else |
908 | throw new Exception("Invalid file type for region persistence."); | 920 | throw new Exception("Invalid file type for region persistence."); |
909 | } | 921 | } |
910 | 922 | ||
923 | <<<<<<< HEAD | ||
924 | ======= | ||
911 | public void loadConfigurationOptionsFromMe() | 925 | public void loadConfigurationOptionsFromMe() |
912 | { | 926 | { |
913 | configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE, | 927 | configMember.addConfigurationOption("sim_UUID", ConfigurationOption.ConfigurationTypes.TYPE_UUID_NULL_FREE, |
@@ -1133,16 +1147,11 @@ namespace OpenSim.Framework | |||
1133 | return true; | 1147 | return true; |
1134 | } | 1148 | } |
1135 | 1149 | ||
1150 | >>>>>>> avn/ubitvar | ||
1136 | public void SaveLastMapUUID(UUID mapUUID) | 1151 | public void SaveLastMapUUID(UUID mapUUID) |
1137 | { | 1152 | { |
1138 | lastMapUUID = mapUUID; | 1153 | lastMapUUID = mapUUID; |
1139 | lastMapRefresh = Util.UnixTimeSinceEpoch().ToString(); | 1154 | lastMapRefresh = Util.UnixTimeSinceEpoch().ToString(); |
1140 | |||
1141 | if (configMember == null) | ||
1142 | return; | ||
1143 | |||
1144 | configMember.forceSetConfigurationOption("lastmap_uuid", mapUUID.ToString()); | ||
1145 | configMember.forceSetConfigurationOption("lastmap_refresh", lastMapRefresh); | ||
1146 | } | 1155 | } |
1147 | 1156 | ||
1148 | public OSDMap PackRegionInfoData() | 1157 | public OSDMap PackRegionInfoData() |
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs index 563bcb9..3bcbe2f 100644 --- a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/RegionLoader/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.8.0.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs index ab36f10..1b2519c 100644 --- a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/RegionLoader/Web/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.8.0.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs index 65de563..487c087 100644 --- a/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs +++ b/OpenSim/Framework/RegionLoader/Web/RegionLoaderWebServer.cs | |||
@@ -121,12 +121,39 @@ namespace OpenSim.Framework.RegionLoader.Web | |||
121 | throw ex; | 121 | throw ex; |
122 | } | 122 | } |
123 | 123 | ||
124 | <<<<<<< HEAD | ||
125 | m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " + | ||
126 | xmlSource.Length); | ||
127 | XmlDocument xmlDoc = new XmlDocument(); | ||
128 | xmlDoc.LoadXml(xmlSource); | ||
129 | if (xmlDoc.FirstChild.Name == "Nini") | ||
130 | { | ||
131 | regionCount = xmlDoc.FirstChild.ChildNodes.Count; | ||
132 | |||
133 | if (regionCount > 0) | ||
134 | { | ||
135 | regionInfos = new RegionInfo[regionCount]; | ||
136 | int i; | ||
137 | for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++) | ||
138 | { | ||
139 | m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml); | ||
140 | regionInfos[i] = | ||
141 | new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i],false,m_configSource); | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | } | ||
146 | catch (WebException ex) | ||
147 | { | ||
148 | using (HttpWebResponse response = (HttpWebResponse)ex.Response) | ||
149 | ======= | ||
124 | if (regionCount > 0 | allowRegionless) | 150 | if (regionCount > 0 | allowRegionless) |
125 | return regionInfos; | 151 | return regionInfos; |
126 | 152 | ||
127 | m_log.Debug("[WEBLOADER]: Request yielded no regions."); | 153 | m_log.Debug("[WEBLOADER]: Request yielded no regions."); |
128 | tries--; | 154 | tries--; |
129 | if (tries > 0) | 155 | if (tries > 0) |
156 | >>>>>>> avn/ubitvar | ||
130 | { | 157 | { |
131 | m_log.Debug("[WEBLOADER]: Retrying"); | 158 | m_log.Debug("[WEBLOADER]: Retrying"); |
132 | System.Threading.Thread.Sleep(wait); | 159 | System.Threading.Thread.Sleep(wait); |
diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 9249105..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 | { |
@@ -68,7 +64,7 @@ namespace OpenSim.Framework | |||
68 | private class TypeMapping | 64 | private class TypeMapping |
69 | { | 65 | { |
70 | private sbyte assetType; | 66 | private sbyte assetType; |
71 | private InventoryType inventoryType; | 67 | private sbyte inventoryType; |
72 | private string contentType; | 68 | private string contentType; |
73 | private string contentType2; | 69 | private string contentType2; |
74 | private string extension; | 70 | private string extension; |
@@ -83,7 +79,7 @@ namespace OpenSim.Framework | |||
83 | get { return AssetTypeFromCode(assetType); } | 79 | get { return AssetTypeFromCode(assetType); } |
84 | } | 80 | } |
85 | 81 | ||
86 | public InventoryType InventoryType | 82 | public sbyte InventoryType |
87 | { | 83 | { |
88 | get { return inventoryType; } | 84 | get { return inventoryType; } |
89 | } | 85 | } |
@@ -103,7 +99,7 @@ namespace OpenSim.Framework | |||
103 | get { return extension; } | 99 | get { return extension; } |
104 | } | 100 | } |
105 | 101 | ||
106 | 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) |
107 | { | 103 | { |
108 | this.assetType = assetType; | 104 | this.assetType = assetType; |
109 | this.inventoryType = inventoryType; | 105 | this.inventoryType = inventoryType; |
@@ -112,18 +108,28 @@ namespace OpenSim.Framework | |||
112 | this.extension = extension; | 108 | this.extension = extension; |
113 | } | 109 | } |
114 | 110 | ||
115 | 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) |
116 | : this((sbyte)assetType, inventoryType, contentType, contentType2, extension) | 112 | : this((sbyte)assetType, inventoryType, contentType, contentType2, extension) |
117 | { | 113 | { |
118 | } | 114 | } |
119 | 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 | |||
120 | public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension) | 121 | public TypeMapping(AssetType assetType, InventoryType inventoryType, string contentType, string extension) |
121 | : 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) | ||
122 | { | 128 | { |
123 | } | 129 | } |
124 | 130 | ||
125 | public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension) | 131 | public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension) |
126 | : this((sbyte)assetType, inventoryType, contentType, null, extension) | 132 | : this((sbyte)assetType, (sbyte)inventoryType, contentType, null, extension) |
127 | { | 133 | { |
128 | } | 134 | } |
129 | } | 135 | } |
@@ -149,53 +155,65 @@ namespace OpenSim.Framework | |||
149 | 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"), |
150 | 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"), |
151 | 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"), |
152 | new TypeMapping(AssetType.Folder, InventoryType.Folder, "application/vnd.ll.folder", "folder"), | ||
153 | new TypeMapping(AssetType.RootFolder, InventoryType.RootCategory, "application/vnd.ll.rootfolder", "rootfolder"), | ||
154 | 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"), |
155 | 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"), |
156 | 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"), |
157 | new TypeMapping(AssetType.TrashFolder, InventoryType.Folder, "application/vnd.ll.trashfolder", "trashfolder"), | ||
158 | new TypeMapping(AssetType.SnapshotFolder, InventoryType.Folder, "application/vnd.ll.snapshotfolder", "snapshotfolder"), | ||
159 | new TypeMapping(AssetType.LostAndFoundFolder, InventoryType.Folder, "application/vnd.ll.lostandfoundfolder", "lostandfoundfolder"), | ||
160 | 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"), |
161 | 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"), |
162 | new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"), | 163 | new TypeMapping(AssetType.Simstate, InventoryType.Snapshot, "application/x-metaverse-simstate", "simstate"), |
163 | new TypeMapping(AssetType.FavoriteFolder, InventoryType.Unknown, "application/vnd.ll.favoritefolder", "favoritefolder"), | ||
164 | new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"), | 164 | new TypeMapping(AssetType.Link, InventoryType.Unknown, "application/vnd.ll.link", "link"), |
165 | new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"), | 165 | new TypeMapping(AssetType.LinkFolder, InventoryType.Unknown, "application/vnd.ll.linkfolder", "linkfolder"), |
166 | new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), | ||
167 | new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), | ||
168 | new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), | ||
169 | new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"), | 166 | new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"), |
167 | |||
168 | // The next few items are about inventory folders | ||
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"), | ||
170 | 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 | ||
171 | new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material") | 185 | new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material") |
172 | }; | 186 | }; |
173 | 187 | ||
174 | private static Dictionary<sbyte, string> asset2Content; | 188 | private static Dictionary<sbyte, string> asset2Content; |
175 | private static Dictionary<sbyte, string> asset2Extension; | 189 | private static Dictionary<sbyte, string> asset2Extension; |
176 | private static Dictionary<InventoryType, string> inventory2Content; | 190 | private static Dictionary<sbyte, string> inventory2Content; |
177 | private static Dictionary<string, sbyte> content2Asset; | 191 | private static Dictionary<string, sbyte> content2Asset; |
178 | private static Dictionary<string, InventoryType> content2Inventory; | 192 | private static Dictionary<string, sbyte> content2Inventory; |
179 | 193 | ||
180 | static SLUtil() | 194 | static SLUtil() |
181 | { | 195 | { |
182 | asset2Content = new Dictionary<sbyte, string>(); | 196 | asset2Content = new Dictionary<sbyte, string>(); |
183 | asset2Extension = new Dictionary<sbyte, string>(); | 197 | asset2Extension = new Dictionary<sbyte, string>(); |
184 | inventory2Content = new Dictionary<InventoryType, string>(); | 198 | inventory2Content = new Dictionary<sbyte, string>(); |
185 | content2Asset = new Dictionary<string, sbyte>(); | 199 | content2Asset = new Dictionary<string, sbyte>(); |
186 | content2Inventory = new Dictionary<string, InventoryType>(); | 200 | content2Inventory = new Dictionary<string, sbyte>(); |
187 | 201 | ||
188 | foreach (TypeMapping mapping in MAPPINGS) | 202 | foreach (TypeMapping mapping in MAPPINGS) |
189 | { | 203 | { |
190 | sbyte assetType = mapping.AssetTypeCode; | 204 | sbyte assetType = mapping.AssetTypeCode; |
191 | if (!asset2Content.ContainsKey(assetType)) | 205 | if (!asset2Content.ContainsKey(assetType)) |
192 | asset2Content.Add(assetType, mapping.ContentType); | 206 | asset2Content.Add(assetType, mapping.ContentType); |
207 | |||
193 | if (!asset2Extension.ContainsKey(assetType)) | 208 | if (!asset2Extension.ContainsKey(assetType)) |
194 | asset2Extension.Add(assetType, mapping.Extension); | 209 | asset2Extension.Add(assetType, mapping.Extension); |
210 | |||
195 | if (!inventory2Content.ContainsKey(mapping.InventoryType)) | 211 | if (!inventory2Content.ContainsKey(mapping.InventoryType)) |
196 | inventory2Content.Add(mapping.InventoryType, mapping.ContentType); | 212 | inventory2Content.Add(mapping.InventoryType, mapping.ContentType); |
213 | |||
197 | if (!content2Asset.ContainsKey(mapping.ContentType)) | 214 | if (!content2Asset.ContainsKey(mapping.ContentType)) |
198 | content2Asset.Add(mapping.ContentType, assetType); | 215 | content2Asset.Add(mapping.ContentType, assetType); |
216 | |||
199 | if (!content2Inventory.ContainsKey(mapping.ContentType)) | 217 | if (!content2Inventory.ContainsKey(mapping.ContentType)) |
200 | content2Inventory.Add(mapping.ContentType, mapping.InventoryType); | 218 | content2Inventory.Add(mapping.ContentType, mapping.InventoryType); |
201 | 219 | ||
@@ -220,8 +238,8 @@ namespace OpenSim.Framework | |||
220 | public static string SLInvTypeToContentType(int invType) | 238 | public static string SLInvTypeToContentType(int invType) |
221 | { | 239 | { |
222 | string contentType; | 240 | string contentType; |
223 | if (!inventory2Content.TryGetValue((InventoryType)invType, out contentType)) | 241 | if (!inventory2Content.TryGetValue((sbyte)invType, out contentType)) |
224 | contentType = inventory2Content[InventoryType.Unknown]; | 242 | contentType = inventory2Content[(sbyte)InventoryType.Unknown]; |
225 | return contentType; | 243 | return contentType; |
226 | } | 244 | } |
227 | 245 | ||
@@ -235,9 +253,9 @@ namespace OpenSim.Framework | |||
235 | 253 | ||
236 | public static sbyte ContentTypeToSLInvType(string contentType) | 254 | public static sbyte ContentTypeToSLInvType(string contentType) |
237 | { | 255 | { |
238 | InventoryType invType; | 256 | sbyte invType; |
239 | if (!content2Inventory.TryGetValue(contentType, out invType)) | 257 | if (!content2Inventory.TryGetValue(contentType, out invType)) |
240 | invType = InventoryType.Unknown; | 258 | invType = (sbyte)InventoryType.Unknown; |
241 | return (sbyte)invType; | 259 | return (sbyte)invType; |
242 | } | 260 | } |
243 | 261 | ||
@@ -251,106 +269,270 @@ namespace OpenSim.Framework | |||
251 | 269 | ||
252 | #endregion SL / file extension / content-type conversions | 270 | #endregion SL / file extension / content-type conversions |
253 | 271 | ||
254 | /// <summary> | 272 | private class NotecardReader |
255 | /// Parse a notecard in Linden format to a string of ordinary text. | ||
256 | /// </summary> | ||
257 | /// <param name="rawInput"></param> | ||
258 | /// <returns></returns> | ||
259 | public static string ParseNotecardToString(string rawInput) | ||
260 | { | 273 | { |
261 | string[] output = ParseNotecardToList(rawInput).ToArray(); | 274 | private string rawInput; |
275 | private int lineNumber; | ||
262 | 276 | ||
263 | // foreach (string line in output) | 277 | public int LineNumber |
264 | // m_log.DebugFormat("[PARSE NOTECARD]: ParseNotecardToString got line {0}", line); | 278 | { |
265 | 279 | get | |
266 | 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 | } | ||
267 | } | 335 | } |
268 | 336 | ||
269 | /// <summary> | 337 | public class NotANotecardFormatException : Exception |
270 | /// Parse a notecard in Linden format to a list of ordinary lines. | 338 | { |
271 | /// </summary> | 339 | public int lineNumber; |
272 | /// <param name="rawInput"></param> | 340 | public NotANotecardFormatException(int _lineNumber) |
273 | /// <returns></returns> | 341 | : base() |
274 | public static List<string> ParseNotecardToList(string rawInput) | 342 | { |
343 | lineNumber = _lineNumber; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | private static void skipSection(NotecardReader reader) | ||
348 | { | ||
349 | if (reader.getLine() != "{") | ||
350 | throw new NotANotecardFormatException(reader.LineNumber); | ||
351 | |||
352 | string line; | ||
353 | while ((line = reader.getLine()) != "}") | ||
354 | { | ||
355 | if(line.IndexOf('{')>=0) | ||
356 | { | ||
357 | throw new NotANotecardFormatException(reader.LineNumber); | ||
358 | } | ||
359 | } | ||
360 | } | ||
361 | |||
362 | private static void skipInventoryItem(NotecardReader reader) | ||
275 | { | 363 | { |
276 | string[] input; | 364 | if (reader.getLine() != "{") |
277 | int idx = 0; | 365 | throw new NotANotecardFormatException(reader.LineNumber); |
278 | int level = 0; | 366 | |
279 | List<string> output = new List<string>(); | 367 | string line; |
280 | string[] words; | 368 | while((line = reader.getLine()) != "}") |
281 | |||
282 | //The Linden format always ends with a } after the input data. | ||
283 | //Strip off trailing } so there is nothing after the input data. | ||
284 | int i = rawInput.LastIndexOf("}"); | ||
285 | rawInput = rawInput.Remove(i, rawInput.Length-i); | ||
286 | input = rawInput.Replace("\r", "").Split('\n'); | ||
287 | |||
288 | while (idx < input.Length) | ||
289 | { | 369 | { |
290 | if (input[idx] == "{") | 370 | string[] data = line.Split(' '); |
371 | if(data.Length == 0) | ||
291 | { | 372 | { |
292 | level++; | ||
293 | idx++; | ||
294 | continue; | 373 | continue; |
295 | } | 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 | } | ||
296 | 389 | ||
297 | if (input[idx]== "}") | 390 | private static void skipInventoryItems(NotecardReader reader) |
391 | { | ||
392 | if(reader.getLine() != "{") | ||
393 | { | ||
394 | throw new NotANotecardFormatException(reader.LineNumber); | ||
395 | } | ||
396 | |||
397 | string line; | ||
398 | while((line = reader.getLine()) != "}") | ||
399 | { | ||
400 | string[] data = line.Split(' '); | ||
401 | if(data.Length == 0) | ||
298 | { | 402 | { |
299 | level--; | ||
300 | idx++; | ||
301 | continue; | 403 | continue; |
302 | } | 404 | } |
303 | 405 | ||
304 | switch (level) | 406 | if(data[0] == "inv_item") |
305 | { | 407 | { |
306 | case 0: | 408 | skipInventoryItem(reader); |
307 | words = input[idx].Split(' '); // Linden text ver | 409 | } |
308 | // Notecards are created *really* empty. Treat that as "no text" (just like after saving an empty notecard) | 410 | else if (line.IndexOf('{') >= 0) |
309 | if (words.Length < 3) | 411 | { |
310 | return output; | 412 | throw new NotANotecardFormatException(reader.LineNumber); |
311 | 413 | } | |
312 | int version = int.Parse(words[3]); | ||
313 | if (version != 2) | ||
314 | return output; | ||
315 | break; | ||
316 | case 1: | ||
317 | words = input[idx].Split(' '); | ||
318 | if (words[0] == "LLEmbeddedItems") | ||
319 | break; | ||
320 | if (words[0] == "Text") | ||
321 | { | ||
322 | idx++; //Now points to first line of notecard text | ||
323 | 414 | ||
324 | //Number of lines in notecard. | 415 | } |
325 | int lines = input.Length - idx; | 416 | } |
326 | int line = 0; | ||
327 | 417 | ||
328 | while (line < lines) | 418 | private static void skipInventory(NotecardReader reader) |
329 | { | 419 | { |
330 | // m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", input[idx]); | 420 | if (reader.getLine() != "{") |
331 | output.Add(input[idx]); | 421 | throw new NotANotecardFormatException(reader.LineNumber); |
332 | idx++; | ||
333 | line++; | ||
334 | } | ||
335 | 422 | ||
336 | return output; | 423 | string line; |
337 | } | 424 | while((line = reader.getLine()) != "}") |
338 | break; | 425 | { |
339 | case 2: | 426 | string[] data = line.Split(' '); |
340 | words = input[idx].Split(' '); // count | 427 | if(data[0] == "count") |
341 | if (words[0] == "count") | 428 | { |
429 | int count = Int32.Parse(data[1]); | ||
430 | for(int i = 0; i < count; ++i) | ||
342 | { | 431 | { |
343 | int c = int.Parse(words[1]); | 432 | skipInventoryItems(reader); |
344 | if (c > 0) | ||
345 | return output; | ||
346 | break; | ||
347 | } | 433 | } |
348 | break; | ||
349 | } | 434 | } |
350 | idx++; | 435 | else if (line.IndexOf('{') >= 0) |
436 | { | ||
437 | throw new NotANotecardFormatException(reader.LineNumber); | ||
438 | } | ||
351 | } | 439 | } |
352 | 440 | } | |
353 | return output; | 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 | } | ||
456 | |||
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 | } | ||
470 | |||
471 | } | ||
472 | return notecardString; | ||
473 | } | ||
474 | |||
475 | private static string readNotecard(byte[] rawInput) | ||
476 | { | ||
477 | string rawIntermedInput = string.Empty; | ||
478 | |||
479 | /* make up a Raw Encoding here */ | ||
480 | foreach(byte c in rawInput) | ||
481 | { | ||
482 | char d = (char)c; | ||
483 | rawIntermedInput += d; | ||
484 | } | ||
485 | |||
486 | NotecardReader reader = new NotecardReader(rawIntermedInput); | ||
487 | string line; | ||
488 | try | ||
489 | { | ||
490 | line = reader.getLine(); | ||
491 | } | ||
492 | catch(Exception) | ||
493 | { | ||
494 | return System.Text.Encoding.UTF8.GetString(rawInput); | ||
495 | } | ||
496 | string[] versioninfo = line.Split(' '); | ||
497 | if(versioninfo.Length < 3) | ||
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]; | ||
513 | } | ||
514 | return System.Text.Encoding.UTF8.GetString(a); | ||
515 | } | ||
516 | } | ||
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'); | ||
354 | } | 536 | } |
355 | } | 537 | } |
356 | } | 538 | } |
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs index 73ebfae..ab3c285 100644 --- a/OpenSim/Framework/Serialization/ArchiveConstants.cs +++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs | |||
@@ -115,20 +115,16 @@ namespace OpenSim.Framework.Serialization | |||
115 | 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"; |
116 | 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"; |
117 | 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"; |
118 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.LostAndFoundFolder] = ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"; // Not sure if we'll ever see this | ||
119 | 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"; |
120 | 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"; |
121 | 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"; |
122 | 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"; |
123 | 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"; |
124 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.RootFolder] = ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"; // Not sure if we'll ever see this | ||
125 | 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 |
126 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.SnapshotFolder] = ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"; // Not sure if we'll ever see this | ||
127 | 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"; |
128 | 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"; |
129 | 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"; |
130 | 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"; |
131 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this | ||
132 | ASSET_TYPE_TO_EXTENSION[(sbyte)OpenSimAssetType.Material] = ASSET_EXTENSION_SEPARATOR + "material.xml"; // 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 |
133 | 129 | ||
134 | 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; |
@@ -140,21 +136,17 @@ namespace OpenSim.Framework.Serialization | |||
140 | 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; |
141 | 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; |
142 | 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; |
143 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "lostandfoundfolder.txt"] = (sbyte)AssetType.LostAndFoundFolder; | ||
144 | 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; |
145 | 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; |
146 | 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; |
147 | 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; |
148 | 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; |
149 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "rootfolder.txt"] = (sbyte)AssetType.RootFolder; | ||
150 | 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; |
151 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "snapshotfolder.txt"] = (sbyte)AssetType.SnapshotFolder; | ||
152 | 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; |
153 | 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; |
154 | 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; |
155 | 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; |
156 | 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; |
157 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "material.xml"] = (sbyte)OpenSimAssetType.Material; | ||
158 | } | 150 | } |
159 | 151 | ||
160 | 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 f2a6b8b..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 | } |
@@ -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 3f04148..0cce722 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.8.0.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 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 3055865..60702d4 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,10 +57,20 @@ 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 | <<<<<<< HEAD | ||
69 | private int m_periodDiagnosticTimerMS = 60 * 60 * 1000; | ||
70 | private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); | ||
71 | ======= | ||
62 | // private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); | 72 | // private Timer m_periodicDiagnosticsTimer = new Timer(60 * 60 * 1000); |
73 | >>>>>>> avn/ubitvar | ||
63 | 74 | ||
64 | /// <summary> | 75 | /// <summary> |
65 | /// Random uuid for private data | 76 | /// Random uuid for private data |
@@ -77,8 +88,11 @@ namespace OpenSim.Framework.Servers | |||
77 | // Random uuid for private data | 88 | // Random uuid for private data |
78 | m_osSecret = UUID.Random().ToString(); | 89 | m_osSecret = UUID.Random().ToString(); |
79 | 90 | ||
91 | <<<<<<< HEAD | ||
92 | ======= | ||
80 | // m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); | 93 | // m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); |
81 | // m_periodicDiagnosticsTimer.Enabled = true; | 94 | // m_periodicDiagnosticsTimer.Enabled = true; |
95 | >>>>>>> avn/ubitvar | ||
82 | } | 96 | } |
83 | 97 | ||
84 | /// <summary> | 98 | /// <summary> |
@@ -89,6 +103,16 @@ namespace OpenSim.Framework.Servers | |||
89 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); | 103 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); |
90 | RegisterCommonCommands(); | 104 | RegisterCommonCommands(); |
91 | RegisterCommonComponents(Config); | 105 | RegisterCommonComponents(Config); |
106 | |||
107 | IConfig startupConfig = Config.Configs["Startup"]; | ||
108 | int logShowStatsSeconds = startupConfig.GetInt("LogShowStatsSeconds", m_periodDiagnosticTimerMS / 1000); | ||
109 | m_periodDiagnosticTimerMS = logShowStatsSeconds * 1000; | ||
110 | m_periodicDiagnosticsTimer.Elapsed += new ElapsedEventHandler(LogDiagnostics); | ||
111 | if (m_periodDiagnosticTimerMS != 0) | ||
112 | { | ||
113 | m_periodicDiagnosticsTimer.Interval = m_periodDiagnosticTimerMS; | ||
114 | m_periodicDiagnosticsTimer.Enabled = true; | ||
115 | } | ||
92 | } | 116 | } |
93 | 117 | ||
94 | protected override void ShutdownSpecific() | 118 | protected override void ShutdownSpecific() |
@@ -99,7 +123,8 @@ namespace OpenSim.Framework.Servers | |||
99 | 123 | ||
100 | base.ShutdownSpecific(); | 124 | base.ShutdownSpecific(); |
101 | 125 | ||
102 | Environment.Exit(0); | 126 | if (!SuppressExit) |
127 | Environment.Exit(0); | ||
103 | } | 128 | } |
104 | 129 | ||
105 | /// <summary> | 130 | /// <summary> |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 1363eab..616c673 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,7 @@ 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); | ||
56 | 58 | ||
57 | /// <summary> | 59 | /// <summary> |
58 | /// This is a pending websocket request before it got an sucessful upgrade response. | 60 | /// This is a pending websocket request before it got an sucessful upgrade response. |
@@ -113,7 +115,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
113 | 115 | ||
114 | protected IPAddress m_listenIPAddress = IPAddress.Any; | 116 | protected IPAddress m_listenIPAddress = IPAddress.Any; |
115 | 117 | ||
116 | private PollServiceRequestManager m_PollServiceManager; | 118 | public PollServiceRequestManager PollServiceRequestManager { get; private set; } |
117 | 119 | ||
118 | public uint SSLPort | 120 | public uint SSLPort |
119 | { | 121 | { |
@@ -374,7 +376,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
374 | return true; | 376 | return true; |
375 | } | 377 | } |
376 | 378 | ||
377 | private void OnRequest(object source, RequestEventArgs args) | 379 | public void OnRequest(object source, RequestEventArgs args) |
378 | { | 380 | { |
379 | RequestNumber++; | 381 | RequestNumber++; |
380 | 382 | ||
@@ -430,7 +432,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
430 | psEvArgs.Request(psreq.RequestID, keysvals); | 432 | psEvArgs.Request(psreq.RequestID, keysvals); |
431 | } | 433 | } |
432 | 434 | ||
433 | m_PollServiceManager.Enqueue(psreq); | 435 | PollServiceRequestManager.Enqueue(psreq); |
434 | } | 436 | } |
435 | else | 437 | else |
436 | { | 438 | { |
@@ -492,8 +494,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
492 | try | 494 | try |
493 | { | 495 | { |
494 | byte[] buffer500 = SendHTML500(response); | 496 | byte[] buffer500 = SendHTML500(response); |
495 | response.Body.Write(buffer500,0,buffer500.Length); | 497 | response.OutputStream.Write(buffer500, 0, buffer500.Length); |
496 | response.Body.Close(); | 498 | response.Send(); |
497 | } | 499 | } |
498 | catch | 500 | catch |
499 | { | 501 | { |
@@ -691,6 +693,23 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
691 | 693 | ||
692 | if (buffer != null) | 694 | if (buffer != null) |
693 | { | 695 | { |
696 | if (WebUtil.DebugLevel >= 5) | ||
697 | { | ||
698 | string output = System.Text.Encoding.UTF8.GetString(buffer); | ||
699 | |||
700 | if (WebUtil.DebugLevel >= 6) | ||
701 | { | ||
702 | // Always truncate binary blobs. We don't have a ContentType, so detect them using the request name. | ||
703 | if ((requestHandler != null && requestHandler.Name == "GetMesh")) | ||
704 | { | ||
705 | if (output.Length > WebUtil.MaxRequestDiagLength) | ||
706 | output = output.Substring(0, WebUtil.MaxRequestDiagLength) + "..."; | ||
707 | } | ||
708 | } | ||
709 | |||
710 | WebUtil.LogResponseDetail(RequestNumber, output); | ||
711 | } | ||
712 | |||
694 | if (!response.SendChunked && response.ContentLength64 <= 0) | 713 | if (!response.SendChunked && response.ContentLength64 <= 0) |
695 | response.ContentLength64 = buffer.LongLength; | 714 | response.ContentLength64 = buffer.LongLength; |
696 | 715 | ||
@@ -721,16 +740,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
721 | } | 740 | } |
722 | catch (IOException e) | 741 | catch (IOException e) |
723 | { | 742 | { |
724 | m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); | 743 | m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e); |
725 | } | 744 | } |
726 | catch (Exception e) | 745 | catch (Exception e) |
727 | { | 746 | { |
728 | m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e); | 747 | m_log.Error("[BASE HTTP SERVER]: HandleRequest() threw exception ", e); |
729 | try | 748 | try |
730 | { | 749 | { |
731 | byte[] buffer500 = SendHTML500(response); | 750 | byte[] buffer500 = SendHTML500(response); |
732 | response.Body.Write(buffer500, 0, buffer500.Length); | 751 | response.OutputStream.Write(buffer500, 0, buffer500.Length); |
733 | response.Body.Close(); | 752 | response.Send(); |
734 | } | 753 | } |
735 | catch | 754 | catch |
736 | { | 755 | { |
@@ -744,7 +763,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
744 | if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture")) | 763 | if (tickdiff > 3000 && (requestHandler == null || requestHandler.Name == null || requestHandler.Name != "GetTexture")) |
745 | { | 764 | { |
746 | m_log.InfoFormat( | 765 | m_log.InfoFormat( |
747 | "[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", | 766 | "[LOGHTTP] Slow handling of {0} {1} {2} {3} {4} from {5} took {6}ms", |
748 | RequestNumber, | 767 | RequestNumber, |
749 | requestMethod, | 768 | requestMethod, |
750 | uriString, | 769 | uriString, |
@@ -756,7 +775,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
756 | else if (DebugLevel >= 4) | 775 | else if (DebugLevel >= 4) |
757 | { | 776 | { |
758 | m_log.DebugFormat( | 777 | m_log.DebugFormat( |
759 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} took {2}ms", | 778 | "[LOGHTTP] HTTP IN {0} :{1} took {2}ms", |
760 | RequestNumber, | 779 | RequestNumber, |
761 | Port, | 780 | Port, |
762 | tickdiff); | 781 | tickdiff); |
@@ -767,7 +786,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
767 | private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) | 786 | private void LogIncomingToStreamHandler(OSHttpRequest request, IRequestHandler requestHandler) |
768 | { | 787 | { |
769 | m_log.DebugFormat( | 788 | m_log.DebugFormat( |
770 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", | 789 | "[LOGHTTP] HTTP IN {0} :{1} stream handler {2} {3} {4} {5} from {6}", |
771 | RequestNumber, | 790 | RequestNumber, |
772 | Port, | 791 | Port, |
773 | request.HttpMethod, | 792 | request.HttpMethod, |
@@ -783,7 +802,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
783 | private void LogIncomingToContentTypeHandler(OSHttpRequest request) | 802 | private void LogIncomingToContentTypeHandler(OSHttpRequest request) |
784 | { | 803 | { |
785 | m_log.DebugFormat( | 804 | m_log.DebugFormat( |
786 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | 805 | "[LOGHTTP] HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", |
787 | RequestNumber, | 806 | RequestNumber, |
788 | Port, | 807 | Port, |
789 | string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType, | 808 | string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType, |
@@ -798,7 +817,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
798 | private void LogIncomingToXmlRpcHandler(OSHttpRequest request) | 817 | private void LogIncomingToXmlRpcHandler(OSHttpRequest request) |
799 | { | 818 | { |
800 | m_log.DebugFormat( | 819 | m_log.DebugFormat( |
801 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", | 820 | "[LOGHTTP] HTTP IN {0} :{1} assumed generic XMLRPC request {2} {3} from {4}", |
802 | RequestNumber, | 821 | RequestNumber, |
803 | Port, | 822 | Port, |
804 | request.HttpMethod, | 823 | request.HttpMethod, |
@@ -811,29 +830,49 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
811 | 830 | ||
812 | private void LogIncomingInDetail(OSHttpRequest request) | 831 | private void LogIncomingInDetail(OSHttpRequest request) |
813 | { | 832 | { |
814 | using (StreamReader reader = new StreamReader(Util.Copy(request.InputStream), Encoding.UTF8)) | 833 | if (request.ContentType == "application/octet-stream") |
815 | { | 834 | return; // never log these; they're just binary data |
816 | string output; | ||
817 | 835 | ||
818 | if (DebugLevel == 5) | 836 | Stream inputStream = Util.Copy(request.InputStream); |
837 | Stream innerStream = null; | ||
838 | try | ||
839 | { | ||
840 | if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip")) | ||
819 | { | 841 | { |
820 | const int sampleLength = 80; | 842 | innerStream = inputStream; |
821 | char[] sampleChars = new char[sampleLength + 3]; | 843 | inputStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress); |
822 | reader.Read(sampleChars, 0, sampleLength); | ||
823 | sampleChars[80] = '.'; | ||
824 | sampleChars[81] = '.'; | ||
825 | sampleChars[82] = '.'; | ||
826 | output = new string(sampleChars); | ||
827 | } | 844 | } |
828 | else | 845 | |
846 | using (StreamReader reader = new StreamReader(inputStream, Encoding.UTF8)) | ||
829 | { | 847 | { |
830 | output = reader.ReadToEnd(); | 848 | string output; |
831 | } | 849 | |
850 | if (DebugLevel == 5) | ||
851 | { | ||
852 | char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed | ||
853 | int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1); | ||
854 | output = new string(chars, 0, Math.Min(len, WebUtil.MaxRequestDiagLength)); | ||
855 | if (len > WebUtil.MaxRequestDiagLength) | ||
856 | output += "..."; | ||
857 | } | ||
858 | else | ||
859 | { | ||
860 | output = reader.ReadToEnd(); | ||
861 | } | ||
832 | 862 | ||
833 | m_log.DebugFormat("[BASE HTTP SERVER]: {0}", output.Replace("\n", @"\n")); | 863 | m_log.DebugFormat("[LOGHTTP] {0}", Util.BinaryToASCII(output)); |
864 | } | ||
865 | } | ||
866 | finally | ||
867 | { | ||
868 | if (innerStream != null) | ||
869 | innerStream.Dispose(); | ||
870 | inputStream.Dispose(); | ||
834 | } | 871 | } |
835 | } | 872 | } |
836 | 873 | ||
874 | private readonly string HANDLER_SEPARATORS = "/?&#-"; | ||
875 | |||
837 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) | 876 | private bool TryGetStreamHandler(string handlerKey, out IRequestHandler streamHandler) |
838 | { | 877 | { |
839 | string bestMatch = null; | 878 | string bestMatch = null; |
@@ -842,7 +881,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
842 | { | 881 | { |
843 | foreach (string pattern in m_streamHandlers.Keys) | 882 | foreach (string pattern in m_streamHandlers.Keys) |
844 | { | 883 | { |
845 | if (handlerKey.StartsWith(pattern)) | 884 | if ((handlerKey == pattern) |
885 | || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) | ||
846 | { | 886 | { |
847 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | 887 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) |
848 | { | 888 | { |
@@ -872,7 +912,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
872 | { | 912 | { |
873 | foreach (string pattern in m_pollHandlers.Keys) | 913 | foreach (string pattern in m_pollHandlers.Keys) |
874 | { | 914 | { |
875 | if (handlerKey.StartsWith(pattern)) | 915 | if ((handlerKey == pattern) |
916 | || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) | ||
876 | { | 917 | { |
877 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | 918 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) |
878 | { | 919 | { |
@@ -904,7 +945,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
904 | { | 945 | { |
905 | foreach (string pattern in m_HTTPHandlers.Keys) | 946 | foreach (string pattern in m_HTTPHandlers.Keys) |
906 | { | 947 | { |
907 | if (handlerKey.StartsWith(pattern)) | 948 | if ((handlerKey == pattern) |
949 | || (handlerKey.StartsWith(pattern) && (HANDLER_SEPARATORS.IndexOf(handlerKey[pattern.Length]) >= 0))) | ||
908 | { | 950 | { |
909 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) | 951 | if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length) |
910 | { | 952 | { |
@@ -953,16 +995,33 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
953 | /// <param name="response"></param> | 995 | /// <param name="response"></param> |
954 | private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) | 996 | private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response) |
955 | { | 997 | { |
998 | String requestBody; | ||
999 | |||
956 | Stream requestStream = request.InputStream; | 1000 | Stream requestStream = request.InputStream; |
1001 | Stream innerStream = null; | ||
1002 | try | ||
1003 | { | ||
1004 | if ((request.Headers["Content-Encoding"] == "gzip") || (request.Headers["X-Content-Encoding"] == "gzip")) | ||
1005 | { | ||
1006 | innerStream = requestStream; | ||
1007 | requestStream = new GZipStream(innerStream, System.IO.Compression.CompressionMode.Decompress); | ||
1008 | } | ||
957 | 1009 | ||
958 | Encoding encoding = Encoding.UTF8; | 1010 | using (StreamReader reader = new StreamReader(requestStream, Encoding.UTF8)) |
959 | StreamReader reader = new StreamReader(requestStream, encoding); | 1011 | { |
1012 | requestBody = reader.ReadToEnd(); | ||
1013 | } | ||
1014 | } | ||
1015 | finally | ||
1016 | { | ||
1017 | if (innerStream != null) | ||
1018 | innerStream.Dispose(); | ||
1019 | requestStream.Dispose(); | ||
1020 | } | ||
960 | 1021 | ||
961 | string requestBody = reader.ReadToEnd(); | ||
962 | reader.Close(); | ||
963 | requestStream.Close(); | ||
964 | //m_log.Debug(requestBody); | 1022 | //m_log.Debug(requestBody); |
965 | requestBody = requestBody.Replace("<base64></base64>", ""); | 1023 | requestBody = requestBody.Replace("<base64></base64>", ""); |
1024 | |||
966 | string responseString = String.Empty; | 1025 | string responseString = String.Empty; |
967 | XmlRpcRequest xmlRprcRequest = null; | 1026 | XmlRpcRequest xmlRprcRequest = null; |
968 | 1027 | ||
@@ -1073,18 +1132,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1073 | 1132 | ||
1074 | response.ContentType = "text/xml"; | 1133 | response.ContentType = "text/xml"; |
1075 | using (MemoryStream outs = new MemoryStream()) | 1134 | using (MemoryStream outs = new MemoryStream()) |
1135 | using (XmlTextWriter writer = new XmlTextWriter(outs, UTF8NoBOM)) | ||
1076 | { | 1136 | { |
1077 | using (XmlTextWriter writer = new XmlTextWriter(outs, Encoding.UTF8)) | 1137 | writer.Formatting = Formatting.None; |
1138 | XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); | ||
1139 | writer.Flush(); | ||
1140 | outs.Flush(); | ||
1141 | outs.Position = 0; | ||
1142 | using (StreamReader sr = new StreamReader(outs)) | ||
1078 | { | 1143 | { |
1079 | writer.Formatting = Formatting.None; | 1144 | responseString = sr.ReadToEnd(); |
1080 | XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); | ||
1081 | writer.Flush(); | ||
1082 | outs.Flush(); | ||
1083 | outs.Position = 0; | ||
1084 | using (StreamReader sr = new StreamReader(outs)) | ||
1085 | { | ||
1086 | responseString = sr.ReadToEnd(); | ||
1087 | } | ||
1088 | } | 1145 | } |
1089 | } | 1146 | } |
1090 | } | 1147 | } |
@@ -1842,10 +1899,17 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1842 | 1899 | ||
1843 | public void Start() | 1900 | public void Start() |
1844 | { | 1901 | { |
1845 | StartHTTP(); | 1902 | Start(true); |
1846 | } | 1903 | } |
1847 | 1904 | ||
1848 | private void StartHTTP() | 1905 | /// <summary> |
1906 | /// Start the http server | ||
1907 | /// </summary> | ||
1908 | /// <param name='processPollRequestsAsync'> | ||
1909 | /// If true then poll responses are performed asynchronsly. | ||
1910 | /// Option exists to allow regression tests to perform processing synchronously. | ||
1911 | /// </param> | ||
1912 | public void Start(bool performPollResponsesAsync) | ||
1849 | { | 1913 | { |
1850 | m_log.InfoFormat( | 1914 | m_log.InfoFormat( |
1851 | "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); | 1915 | "[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port); |
@@ -1883,8 +1947,14 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1883 | m_httpListener2.Start(64); | 1947 | m_httpListener2.Start(64); |
1884 | 1948 | ||
1885 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events | 1949 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events |
1950 | <<<<<<< HEAD | ||
1951 | PollServiceRequestManager = new PollServiceRequestManager(this, performPollResponsesAsync, 3, 25000); | ||
1952 | PollServiceRequestManager.Start(); | ||
1953 | |||
1954 | ======= | ||
1886 | m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); | 1955 | m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); |
1887 | m_PollServiceManager.Start(); | 1956 | m_PollServiceManager.Start(); |
1957 | >>>>>>> avn/ubitvar | ||
1888 | HTTPDRunning = true; | 1958 | HTTPDRunning = true; |
1889 | 1959 | ||
1890 | //HttpListenerContext context; | 1960 | //HttpListenerContext context; |
@@ -1955,7 +2025,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1955 | 2025 | ||
1956 | try | 2026 | try |
1957 | { | 2027 | { |
1958 | m_PollServiceManager.Stop(); | 2028 | PollServiceRequestManager.Stop(); |
1959 | 2029 | ||
1960 | m_httpListener2.ExceptionThrown -= httpServerException; | 2030 | m_httpListener2.ExceptionThrown -= httpServerException; |
1961 | //m_httpListener2.DisconnectHandler = null; | 2031 | //m_httpListener2.DisconnectHandler = null; |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index bbac699..d4a1ec3 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs | |||
@@ -26,6 +26,7 @@ | |||
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 | { |
@@ -61,6 +62,24 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
61 | Description = description; | 62 | Description = description; |
62 | m_httpMethod = httpMethod; | 63 | m_httpMethod = httpMethod; |
63 | 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 | } | ||
64 | } | 83 | } |
65 | 84 | ||
66 | 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 252cc2a..41aa19b 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs | |||
@@ -26,6 +26,8 @@ | |||
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 | { |
@@ -37,16 +39,36 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
37 | /// </remarks> | 39 | /// </remarks> |
38 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler | 40 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler |
39 | { | 41 | { |
40 | protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} | 42 | protected IServiceAuth m_Auth; |
43 | |||
44 | protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) { } | ||
41 | 45 | ||
42 | protected BaseStreamHandler(string httpMethod, string path, string name, string description) | 46 | protected BaseStreamHandler(string httpMethod, string path, string name, string description) |
43 | : base(httpMethod, path, name, description) {} | 47 | : base(httpMethod, path, name, description) {} |
44 | 48 | ||
49 | protected BaseStreamHandler(string httpMethod, string path, IServiceAuth auth) | ||
50 | : base(httpMethod, path, null, null) | ||
51 | { | ||
52 | m_Auth = auth; | ||
53 | } | ||
54 | |||
45 | public virtual byte[] Handle( | 55 | public virtual byte[] Handle( |
46 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 56 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
47 | { | 57 | { |
48 | RequestsReceived++; | 58 | RequestsReceived++; |
49 | 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 | |||
50 | byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); | 72 | byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); |
51 | 73 | ||
52 | RequestsHandled++; | 74 | RequestsHandled++; |
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/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/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 5bd63a6..49cd110 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs | |||
@@ -93,7 +93,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
93 | } | 93 | } |
94 | catch (Exception ex) | 94 | catch (Exception ex) |
95 | { | 95 | { |
96 | m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); | 96 | m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", ex); |
97 | } | 97 | } |
98 | finally | 98 | finally |
99 | { | 99 | { |
@@ -108,7 +108,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
108 | } | 108 | } |
109 | catch (Exception e) | 109 | catch (Exception e) |
110 | { | 110 | { |
111 | m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); | 111 | m_log.Warn("[POLL SERVICE WORKER THREAD]: Error ", e); |
112 | } | 112 | } |
113 | 113 | ||
114 | PollServiceArgs.RequestsHandled++; | 114 | PollServiceArgs.RequestsHandled++; |
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index b56ade8..4ffe6e5 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | |||
@@ -44,6 +44,25 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
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 | /// <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; } | ||
65 | |||
47 | private readonly BaseHttpServer m_server; | 66 | private readonly BaseHttpServer m_server; |
48 | 67 | ||
49 | private Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>> m_bycontext; | 68 | private Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>> m_bycontext; |
@@ -55,17 +74,52 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
55 | private Thread[] m_workerThreads; | 74 | private Thread[] m_workerThreads; |
56 | private Thread m_retrysThread; | 75 | private Thread m_retrysThread; |
57 | 76 | ||
77 | <<<<<<< HEAD | ||
78 | private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2); | ||
79 | |||
80 | // private int m_timeout = 1000; // increase timeout 250; now use the event one | ||
81 | ======= | ||
58 | private bool m_running = true; | 82 | private bool m_running = true; |
59 | private int slowCount = 0; | 83 | private int slowCount = 0; |
60 | 84 | ||
61 | private SmartThreadPool m_threadPool; | 85 | private SmartThreadPool m_threadPool; |
86 | >>>>>>> avn/ubitvar | ||
62 | 87 | ||
63 | public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout) | 88 | public PollServiceRequestManager( |
89 | BaseHttpServer pSrv, bool performResponsesAsync, uint pWorkerThreadCount, int pTimeout) | ||
64 | { | 90 | { |
65 | m_server = pSrv; | 91 | m_server = pSrv; |
92 | PerformResponsesAsync = performResponsesAsync; | ||
66 | m_WorkerThreadCount = pWorkerThreadCount; | 93 | m_WorkerThreadCount = pWorkerThreadCount; |
67 | m_workerThreads = new Thread[m_WorkerThreadCount]; | 94 | m_workerThreads = new Thread[m_WorkerThreadCount]; |
68 | 95 | ||
96 | <<<<<<< HEAD | ||
97 | StatsManager.RegisterStat( | ||
98 | new Stat( | ||
99 | "QueuedPollResponses", | ||
100 | "Number of poll responses queued for processing.", | ||
101 | "", | ||
102 | "", | ||
103 | "httpserver", | ||
104 | m_server.Port.ToString(), | ||
105 | StatType.Pull, | ||
106 | MeasuresOfInterest.AverageChangeOverTime, | ||
107 | stat => stat.Value = m_requests.Count(), | ||
108 | StatVerbosity.Debug)); | ||
109 | |||
110 | StatsManager.RegisterStat( | ||
111 | new Stat( | ||
112 | "ProcessedPollResponses", | ||
113 | "Number of poll responses processed.", | ||
114 | "", | ||
115 | "", | ||
116 | "httpserver", | ||
117 | m_server.Port.ToString(), | ||
118 | StatType.Pull, | ||
119 | MeasuresOfInterest.AverageChangeOverTime, | ||
120 | stat => stat.Value = ResponsesProcessed, | ||
121 | StatVerbosity.Debug)); | ||
122 | ======= | ||
69 | PollServiceHttpRequestComparer preqCp = new PollServiceHttpRequestComparer(); | 123 | PollServiceHttpRequestComparer preqCp = new PollServiceHttpRequestComparer(); |
70 | m_bycontext = new Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>>(preqCp); | 124 | m_bycontext = new Dictionary<PollServiceHttpRequest, Queue<PollServiceHttpRequest>>(preqCp); |
71 | 125 | ||
@@ -78,10 +132,40 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
78 | startInfo.ThreadPoolName = "PoolService"; | 132 | startInfo.ThreadPoolName = "PoolService"; |
79 | 133 | ||
80 | m_threadPool = new SmartThreadPool(startInfo); | 134 | m_threadPool = new SmartThreadPool(startInfo); |
135 | >>>>>>> avn/ubitvar | ||
81 | } | 136 | } |
82 | 137 | ||
83 | public void Start() | 138 | public void Start() |
84 | { | 139 | { |
140 | <<<<<<< HEAD | ||
141 | IsRunning = true; | ||
142 | |||
143 | if (PerformResponsesAsync) | ||
144 | { | ||
145 | //startup worker threads | ||
146 | for (uint i = 0; i < m_WorkerThreadCount; i++) | ||
147 | { | ||
148 | m_workerThreads[i] | ||
149 | = WorkManager.StartThread( | ||
150 | PoolWorkerJob, | ||
151 | string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), | ||
152 | ThreadPriority.Normal, | ||
153 | false, | ||
154 | false, | ||
155 | null, | ||
156 | int.MaxValue); | ||
157 | } | ||
158 | |||
159 | WorkManager.StartThread( | ||
160 | this.CheckLongPollThreads, | ||
161 | string.Format("LongPollServiceWatcherThread:{0}", m_server.Port), | ||
162 | ThreadPriority.Normal, | ||
163 | false, | ||
164 | true, | ||
165 | null, | ||
166 | 1000 * 60 * 10); | ||
167 | } | ||
168 | ======= | ||
85 | m_threadPool.Start(); | 169 | m_threadPool.Start(); |
86 | //startup worker threads | 170 | //startup worker threads |
87 | for (uint i = 0; i < m_WorkerThreadCount; i++) | 171 | for (uint i = 0; i < m_WorkerThreadCount; i++) |
@@ -105,11 +189,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
105 | true, | 189 | true, |
106 | null, | 190 | null, |
107 | 1000 * 60 * 10); | 191 | 1000 * 60 * 10); |
192 | >>>>>>> avn/ubitvar | ||
108 | } | 193 | } |
109 | 194 | ||
110 | private void ReQueueEvent(PollServiceHttpRequest req) | 195 | private void ReQueueEvent(PollServiceHttpRequest req) |
111 | { | 196 | { |
112 | if (m_running) | 197 | if (IsRunning) |
113 | { | 198 | { |
114 | lock (m_retryRequests) | 199 | lock (m_retryRequests) |
115 | m_retryRequests.Enqueue(req); | 200 | m_retryRequests.Enqueue(req); |
@@ -157,7 +242,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
157 | 242 | ||
158 | public void EnqueueInt(PollServiceHttpRequest req) | 243 | public void EnqueueInt(PollServiceHttpRequest req) |
159 | { | 244 | { |
160 | if (m_running) | 245 | if (IsRunning) |
161 | { | 246 | { |
162 | if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll) | 247 | if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll) |
163 | { | 248 | { |
@@ -173,12 +258,36 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
173 | 258 | ||
174 | private void CheckRetries() | 259 | private void CheckRetries() |
175 | { | 260 | { |
261 | <<<<<<< HEAD | ||
262 | // The only purpose of this thread is to check the EQs for events. | ||
263 | // If there are events, that thread will be placed in the "ready-to-serve" queue, m_requests. | ||
264 | // If there are no events, that thread will be back to its "waiting" queue, m_longPollRequests. | ||
265 | // All other types of tasks (Inventory handlers, http-in, etc) don't have the long-poll nature, | ||
266 | // so if they aren't ready to be served by a worker thread (no events), they are placed | ||
267 | // directly back in the "ready-to-serve" queue by the worker thread. | ||
268 | while (IsRunning) | ||
269 | ======= | ||
176 | while (m_running) | 270 | while (m_running) |
271 | >>>>>>> avn/ubitvar | ||
177 | { | 272 | { |
178 | Thread.Sleep(100); // let the world move .. back to faster rate | 273 | Thread.Sleep(100); // let the world move .. back to faster rate |
179 | Watchdog.UpdateThread(); | 274 | Watchdog.UpdateThread(); |
180 | lock (m_retryRequests) | 275 | lock (m_retryRequests) |
181 | { | 276 | { |
277 | <<<<<<< HEAD | ||
278 | if (m_longPollRequests.Count > 0 && IsRunning) | ||
279 | { | ||
280 | List<PollServiceHttpRequest> ready = m_longPollRequests.FindAll(req => | ||
281 | (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id) || // there are events in this EQ | ||
282 | (Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) // no events, but timeout | ||
283 | ); | ||
284 | |||
285 | ready.ForEach(req => | ||
286 | { | ||
287 | m_requests.Enqueue(req); | ||
288 | m_longPollRequests.Remove(req); | ||
289 | }); | ||
290 | ======= | ||
182 | while (m_retryRequests.Count > 0 && m_running) | 291 | while (m_retryRequests.Count > 0 && m_running) |
183 | m_requests.Enqueue(m_retryRequests.Dequeue()); | 292 | m_requests.Enqueue(m_retryRequests.Dequeue()); |
184 | } | 293 | } |
@@ -186,6 +295,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
186 | if (slowCount >= 10) | 295 | if (slowCount >= 10) |
187 | { | 296 | { |
188 | slowCount = 0; | 297 | slowCount = 0; |
298 | >>>>>>> avn/ubitvar | ||
189 | 299 | ||
190 | lock (m_slowRequests) | 300 | lock (m_slowRequests) |
191 | { | 301 | { |
@@ -198,7 +308,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
198 | 308 | ||
199 | public void Stop() | 309 | public void Stop() |
200 | { | 310 | { |
311 | <<<<<<< HEAD | ||
312 | IsRunning = false; | ||
313 | // m_timeout = -10000; // cause all to expire | ||
314 | ======= | ||
201 | m_running = false; | 315 | m_running = false; |
316 | >>>>>>> avn/ubitvar | ||
202 | Thread.Sleep(1000); // let the world move | 317 | Thread.Sleep(1000); // let the world move |
203 | 318 | ||
204 | foreach (Thread t in m_workerThreads) | 319 | foreach (Thread t in m_workerThreads) |
@@ -226,8 +341,13 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
226 | 341 | ||
227 | lock (m_slowRequests) | 342 | lock (m_slowRequests) |
228 | { | 343 | { |
344 | <<<<<<< HEAD | ||
345 | if (m_longPollRequests.Count > 0 && IsRunning) | ||
346 | m_longPollRequests.ForEach(req => m_requests.Enqueue(req)); | ||
347 | ======= | ||
229 | while (m_slowRequests.Count > 0) | 348 | while (m_slowRequests.Count > 0) |
230 | m_requests.Enqueue(m_slowRequests.Dequeue()); | 349 | m_requests.Enqueue(m_slowRequests.Dequeue()); |
350 | >>>>>>> avn/ubitvar | ||
231 | } | 351 | } |
232 | 352 | ||
233 | while (m_requests.Count() > 0) | 353 | while (m_requests.Count() > 0) |
@@ -235,7 +355,13 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
235 | try | 355 | try |
236 | { | 356 | { |
237 | wreq = m_requests.Dequeue(0); | 357 | wreq = m_requests.Dequeue(0); |
358 | <<<<<<< HEAD | ||
359 | ResponsesProcessed++; | ||
360 | wreq.DoHTTPGruntWork( | ||
361 | m_server, wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id)); | ||
362 | ======= | ||
238 | wreq.DoHTTPstop(m_server); | 363 | wreq.DoHTTPstop(m_server); |
364 | >>>>>>> avn/ubitvar | ||
239 | } | 365 | } |
240 | catch | 366 | catch |
241 | { | 367 | { |
@@ -249,35 +375,91 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
249 | 375 | ||
250 | private void PoolWorkerJob() | 376 | private void PoolWorkerJob() |
251 | { | 377 | { |
252 | while (m_running) | 378 | while (IsRunning) |
253 | { | 379 | { |
380 | <<<<<<< HEAD | ||
381 | ======= | ||
254 | PollServiceHttpRequest req = m_requests.Dequeue(5000); | 382 | PollServiceHttpRequest req = m_requests.Dequeue(5000); |
255 | 383 | ||
384 | >>>>>>> avn/ubitvar | ||
256 | Watchdog.UpdateThread(); | 385 | Watchdog.UpdateThread(); |
257 | if (req != null) | 386 | WaitPerformResponse(); |
387 | } | ||
388 | } | ||
389 | |||
390 | public void WaitPerformResponse() | ||
391 | { | ||
392 | PollServiceHttpRequest req = m_requests.Dequeue(5000); | ||
393 | // m_log.DebugFormat("[YYY]: Dequeued {0}", (req == null ? "null" : req.PollServiceArgs.Type.ToString())); | ||
394 | |||
395 | if (req != null) | ||
396 | { | ||
397 | try | ||
258 | { | 398 | { |
259 | try | 399 | if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) |
260 | { | 400 | { |
261 | if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id)) | 401 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); |
262 | { | 402 | |
263 | Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id); | 403 | <<<<<<< HEAD |
404 | if (responsedata == null) | ||
405 | return; | ||
264 | 406 | ||
407 | // This is the event queue. | ||
408 | // Even if we're not running we can still perform responses by explicit request. | ||
409 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll | ||
410 | || !PerformResponsesAsync) | ||
411 | { | ||
412 | try | ||
413 | { | ||
414 | ResponsesProcessed++; | ||
415 | req.DoHTTPGruntWork(m_server, responsedata); | ||
416 | } | ||
417 | catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream | ||
418 | { | ||
419 | // Ignore it, no need to reply | ||
420 | m_log.Error(e); | ||
421 | } | ||
422 | } | ||
423 | else | ||
424 | { | ||
425 | m_threadPool.QueueWorkItem(x => | ||
426 | ======= | ||
265 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue | 427 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue |
428 | >>>>>>> avn/ubitvar | ||
266 | { | 429 | { |
267 | try | 430 | try |
268 | { | 431 | { |
432 | ResponsesProcessed++; | ||
269 | req.DoHTTPGruntWork(m_server, responsedata); | 433 | req.DoHTTPGruntWork(m_server, responsedata); |
270 | byContextDequeue(req); | 434 | byContextDequeue(req); |
271 | } | 435 | } |
272 | catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream | 436 | catch (ObjectDisposedException e) // Browser aborted before we could read body, server closed the stream |
273 | { | 437 | { |
274 | // Ignore it, no need to reply | 438 | // Ignore it, no need to reply |
439 | m_log.Error(e); | ||
275 | } | 440 | } |
276 | } | 441 | catch (Exception e) |
277 | else | ||
278 | { | ||
279 | m_threadPool.QueueWorkItem(x => | ||
280 | { | 442 | { |
443 | <<<<<<< HEAD | ||
444 | m_log.Error(e); | ||
445 | } | ||
446 | |||
447 | return null; | ||
448 | }, null); | ||
449 | } | ||
450 | } | ||
451 | else | ||
452 | { | ||
453 | if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms) | ||
454 | { | ||
455 | ResponsesProcessed++; | ||
456 | req.DoHTTPGruntWork( | ||
457 | m_server, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id)); | ||
458 | } | ||
459 | else | ||
460 | { | ||
461 | ReQueueEvent(req); | ||
462 | ======= | ||
281 | try | 463 | try |
282 | { | 464 | { |
283 | req.DoHTTPGruntWork(m_server, responsedata); | 465 | req.DoHTTPGruntWork(m_server, responsedata); |
@@ -304,12 +486,13 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
304 | { | 486 | { |
305 | ReQueueEvent(req); | 487 | ReQueueEvent(req); |
306 | } | 488 | } |
489 | >>>>>>> avn/ubitvar | ||
307 | } | 490 | } |
308 | } | 491 | } |
309 | catch (Exception e) | 492 | } |
310 | { | 493 | catch (Exception e) |
311 | m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); | 494 | { |
312 | } | 495 | m_log.ErrorFormat("Exception in poll service thread: " + e.ToString()); |
313 | } | 496 | } |
314 | } | 497 | } |
315 | } | 498 | } |
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs index f409667..63335bd 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.8.0.*")] | 32 | [assembly: AssemblyVersion("0.8.2.*")] |
33 | 33 | ||
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 83c9848..ad69cd2 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs | |||
@@ -77,25 +77,24 @@ 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 | } | ||
91 | |||
92 | int length = (int)buffer.Length; | ||
93 | request.ContentLength = length; | ||
94 | 94 | ||
95 | Stream requestStream = request.GetRequestStream(); | 95 | using (Stream requestStream = request.GetRequestStream()) |
96 | requestStream.Write(buffer.ToArray(), 0, length); | 96 | requestStream.Write(buffer.ToArray(), 0, length); |
97 | buffer.Close(); | 97 | } |
98 | requestStream.Close(); | ||
99 | 98 | ||
100 | TResponse deserial = default(TResponse); | 99 | TResponse deserial = default(TResponse); |
101 | using (WebResponse resp = request.GetResponse()) | 100 | using (WebResponse resp = request.GetResponse()) |
@@ -133,25 +132,25 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
133 | request.ContentType = "text/xml"; | 132 | request.ContentType = "text/xml"; |
134 | request.Timeout = 10000; | 133 | request.Timeout = 10000; |
135 | 134 | ||
136 | MemoryStream buffer = new MemoryStream(); | 135 | using (MemoryStream buffer = new MemoryStream()) |
136 | { | ||
137 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
138 | settings.Encoding = Encoding.UTF8; | ||
139 | |||
140 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
141 | { | ||
142 | XmlSerializer serializer = new XmlSerializer(type); | ||
143 | serializer.Serialize(writer, sobj); | ||
144 | writer.Flush(); | ||
145 | } | ||
137 | 146 | ||
138 | XmlWriterSettings settings = new XmlWriterSettings(); | 147 | int length = (int)buffer.Length; |
139 | settings.Encoding = Encoding.UTF8; | 148 | request.ContentLength = length; |
140 | 149 | ||
141 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | 150 | using (Stream requestStream = request.GetRequestStream()) |
142 | { | 151 | requestStream.Write(buffer.ToArray(), 0, length); |
143 | XmlSerializer serializer = new XmlSerializer(type); | ||
144 | serializer.Serialize(writer, sobj); | ||
145 | writer.Flush(); | ||
146 | } | 152 | } |
147 | buffer.Close(); | ||
148 | |||
149 | int length = (int)buffer.Length; | ||
150 | request.ContentLength = length; | ||
151 | 153 | ||
152 | Stream requestStream = request.GetRequestStream(); | ||
153 | requestStream.Write(buffer.ToArray(), 0, length); | ||
154 | requestStream.Close(); | ||
155 | // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); | 154 | // IAsyncResult result = request.BeginGetResponse(AsyncCallback, request); |
156 | request.BeginGetResponse(AsyncCallback, request); | 155 | request.BeginGetResponse(AsyncCallback, request); |
157 | } | 156 | } |
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 7108314..35177f4 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; |
@@ -279,6 +280,29 @@ namespace OpenSim.Framework.Servers | |||
279 | "debug threadpool status", | 280 | "debug threadpool status", |
280 | "Show current debug threadpool parameters.", | 281 | "Show current debug threadpool parameters.", |
281 | HandleDebugThreadpoolStatus); | 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 | |||
301 | m_console.Commands.AddCommand( | ||
302 | "Debug", false, "show threadpool calls complete", | ||
303 | "show threadpool calls complete", | ||
304 | "Show details about threadpool calls that have been completed.", | ||
305 | HandleShowThreadpoolCallsComplete); | ||
282 | 306 | ||
283 | m_console.Commands.AddCommand( | 307 | m_console.Commands.AddCommand( |
284 | "Debug", false, "force gc", | 308 | "Debug", false, "force gc", |
@@ -343,6 +367,57 @@ namespace OpenSim.Framework.Servers | |||
343 | Notice("serialosdreq is now {0}", setSerializeOsdRequests); | 367 | Notice("serialosdreq is now {0}", setSerializeOsdRequests); |
344 | } | 368 | } |
345 | 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 | |||
346 | private void HandleDebugThreadpoolStatus(string module, string[] args) | 421 | private void HandleDebugThreadpoolStatus(string module, string[] args) |
347 | { | 422 | { |
348 | int workerThreads, iocpThreads; | 423 | int workerThreads, iocpThreads; |
@@ -432,6 +507,33 @@ namespace OpenSim.Framework.Servers | |||
432 | } | 507 | } |
433 | } | 508 | } |
434 | 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); | ||
535 | } | ||
536 | |||
435 | private void HandleForceGc(string module, string[] args) | 537 | private void HandleForceGc(string module, string[] args) |
436 | { | 538 | { |
437 | Notice("Manually invoking runtime garbage collection"); | 539 | Notice("Manually invoking runtime garbage collection"); |
diff --git a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs index deae45c..e13551c 100644 --- a/OpenSim/Framework/Servers/Tests/OSHttpTests.cs +++ b/OpenSim/Framework/Servers/Tests/OSHttpTests.cs | |||
@@ -41,6 +41,9 @@ namespace OpenSim.Framework.Servers.Tests | |||
41 | { | 41 | { |
42 | [TestFixture] | 42 | [TestFixture] |
43 | public class OSHttpTests : OpenSimTestCase | 43 | public class OSHttpTests : OpenSimTestCase |
44 | <<<<<<< HEAD | ||
45 | { | ||
46 | ======= | ||
44 | { | 47 | { |
45 | // we need an IHttpClientContext for our tests | 48 | // we need an IHttpClientContext for our tests |
46 | public class TestHttpClientContext: IHttpClientContext | 49 | public class TestHttpClientContext: IHttpClientContext |
@@ -362,6 +365,7 @@ namespace OpenSim.Framework.Servers.Tests | |||
362 | } | 365 | } |
363 | 366 | ||
364 | 367 | ||
368 | >>>>>>> avn/ubitvar | ||
365 | public OSHttpRequest req0; | 369 | public OSHttpRequest req0; |
366 | public OSHttpRequest req1; | 370 | public OSHttpRequest req1; |
367 | 371 | ||
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/Framework/ServiceAuth/CompoundAuthentication.cs b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs new file mode 100644 index 0000000..a49952c --- /dev/null +++ b/OpenSim/Framework/ServiceAuth/CompoundAuthentication.cs | |||
@@ -0,0 +1,82 @@ | |||
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.Linq; | ||
32 | using System.Net; | ||
33 | |||
34 | namespace OpenSim.Framework.ServiceAuth | ||
35 | { | ||
36 | public class CompoundAuthentication : IServiceAuth | ||
37 | { | ||
38 | public string Name { get { return "Compound"; } } | ||
39 | |||
40 | private List<IServiceAuth> m_authentications = new List<IServiceAuth>(); | ||
41 | |||
42 | public int Count { get { return m_authentications.Count; } } | ||
43 | |||
44 | public List<IServiceAuth> GetAuthentors() | ||
45 | { | ||
46 | return new List<IServiceAuth>(m_authentications); | ||
47 | } | ||
48 | |||
49 | public void AddAuthenticator(IServiceAuth auth) | ||
50 | { | ||
51 | m_authentications.Add(auth); | ||
52 | } | ||
53 | |||
54 | public void RemoveAuthenticator(IServiceAuth auth) | ||
55 | { | ||
56 | m_authentications.Remove(auth); | ||
57 | } | ||
58 | |||
59 | public void AddAuthorization(NameValueCollection headers) | ||
60 | { | ||
61 | foreach (IServiceAuth auth in m_authentications) | ||
62 | auth.AddAuthorization(headers); | ||
63 | } | ||
64 | |||
65 | public bool Authenticate(string data) | ||
66 | { | ||
67 | return m_authentications.TrueForAll(a => a.Authenticate(data)); | ||
68 | } | ||
69 | |||
70 | public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) | ||
71 | { | ||
72 | foreach (IServiceAuth auth in m_authentications) | ||
73 | { | ||
74 | if (!auth.Authenticate(requestHeaders, d, out statusCode)) | ||
75 | return false; | ||
76 | } | ||
77 | |||
78 | statusCode = HttpStatusCode.OK; | ||
79 | return true; | ||
80 | } | ||
81 | } | ||
82 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs index 10bc88a..e0c413b 100644 --- a/OpenSim/Framework/Configuration/HTTP/RemoteConfigSettings.cs +++ b/OpenSim/Framework/ServiceAuth/DisallowLlHttpRequest.cs | |||
@@ -26,38 +26,34 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Specialized; | ||
30 | using System.Net; | ||
29 | 31 | ||
30 | namespace OpenSim.Framework.Configuration.HTTP | 32 | namespace OpenSim.Framework.ServiceAuth |
31 | { | 33 | { |
32 | public class RemoteConfigSettings | 34 | public class DisallowLlHttpRequest : IServiceAuth |
33 | { | 35 | { |
34 | private ConfigurationMember configMember; | 36 | public string Name { get { return "DisallowllHTTPRequest"; } } |
35 | 37 | ||
36 | public string baseConfigURL = String.Empty; | 38 | public void AddAuthorization(NameValueCollection headers) {} |
37 | 39 | ||
38 | public RemoteConfigSettings(string filename) | 40 | public bool Authenticate(string data) |
39 | { | 41 | { |
40 | configMember = | 42 | return false; |
41 | new ConfigurationMember(filename, "REMOTE CONFIG SETTINGS", loadConfigurationOptions, | ||
42 | handleIncomingConfiguration,true); | ||
43 | configMember.forceConfigurationPluginLibrary("OpenSim.Framework.Configuration.XML.dll"); | ||
44 | configMember.performConfigurationRetrieve(); | ||
45 | } | 43 | } |
46 | 44 | ||
47 | public void loadConfigurationOptions() | 45 | public bool Authenticate(NameValueCollection requestHeaders, AddHeaderDelegate d, out HttpStatusCode statusCode) |
48 | { | 46 | { |
49 | configMember.addConfigurationOption("base_config_url", | 47 | // Console.WriteLine("DisallowLlHttpRequest"); |
50 | ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, | ||
51 | "URL Containing Configuration Files", "http://localhost/", false); | ||
52 | } | ||
53 | 48 | ||
54 | public bool handleIncomingConfiguration(string configuration_key, object configuration_result) | 49 | if (requestHeaders["X-SecondLife-Shard"] != null) |
55 | { | ||
56 | if (configuration_key == "base_config_url") | ||
57 | { | 50 | { |
58 | baseConfigURL = (string) configuration_result; | 51 | statusCode = HttpStatusCode.Forbidden; |
52 | return false; | ||
59 | } | 53 | } |
54 | |||
55 | statusCode = HttpStatusCode.OK; | ||
60 | return true; | 56 | return true; |
61 | } | 57 | } |
62 | } | 58 | } |
63 | } | 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/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/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 3b7f252..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++) |
@@ -299,7 +290,7 @@ namespace OpenSim.Framework.Tests | |||
299 | uint z1 = 22; | 290 | uint z1 = 22; |
300 | ulong regionHandle2; | 291 | ulong regionHandle2; |
301 | uint x2, y2, z2; | 292 | uint x2, y2, z2; |
302 | UUID fakeParcelID1, fakeParcelID2, uuid; | 293 | UUID fakeParcelID1, uuid; |
303 | 294 | ||
304 | ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8); | 295 | ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8); |
305 | Assert.AreEqual(var64Bit, bigInt64, | 296 | Assert.AreEqual(var64Bit, bigInt64, |
diff --git a/OpenSim/Framework/ThreadSafeRandom.cs b/OpenSim/Framework/ThreadSafeRandom.cs new file mode 100644 index 0000000..58853e6 --- /dev/null +++ b/OpenSim/Framework/ThreadSafeRandom.cs | |||
@@ -0,0 +1,72 @@ | |||
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 | ||
31 | { | ||
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 | ||
37 | { | ||
38 | public ThreadSafeRandom() : base() {} | ||
39 | |||
40 | public ThreadSafeRandom(int seed): base (seed) {} | ||
41 | |||
42 | public override int Next() | ||
43 | { | ||
44 | lock (this) | ||
45 | return base.Next(); | ||
46 | } | ||
47 | |||
48 | public override int Next(int maxValue) | ||
49 | { | ||
50 | lock (this) | ||
51 | return base.Next(maxValue); | ||
52 | } | ||
53 | |||
54 | public override int Next(int minValue, int maxValue) | ||
55 | { | ||
56 | lock (this) | ||
57 | return base.Next(minValue, maxValue); | ||
58 | } | ||
59 | |||
60 | public override void NextBytes(byte[] buffer) | ||
61 | { | ||
62 | lock (this) | ||
63 | base.NextBytes(buffer); | ||
64 | } | ||
65 | |||
66 | public override double NextDouble() | ||
67 | { | ||
68 | lock (this) | ||
69 | return base.NextDouble(); | ||
70 | } | ||
71 | } | ||
72 | } \ No newline at end of file | ||
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 f7069a5..61d8fe5 100644 --- a/OpenSim/Framework/UserProfileData.cs +++ b/OpenSim/Framework/UserProfileData.cs | |||
@@ -160,7 +160,11 @@ namespace OpenSim.Framework | |||
160 | public virtual ulong HomeRegion | 160 | public virtual ulong HomeRegion |
161 | { | 161 | { |
162 | get | 162 | get |
163 | <<<<<<< HEAD | ||
164 | { | ||
165 | ======= | ||
163 | { | 166 | { |
167 | >>>>>>> avn/ubitvar | ||
164 | return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY)); | 168 | return Util.RegionWorldLocToHandle(Util.RegionToWorldLoc(m_homeRegionX), Util.RegionToWorldLoc(m_homeRegionY)); |
165 | // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); | 169 | // return Utils.UIntsToLong( m_homeRegionX * (uint)Constants.RegionSize, m_homeRegionY * (uint)Constants.RegionSize); |
166 | } | 170 | } |
diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs index 6133591..944a492 100644 --- a/OpenSim/Framework/UserProfiles.cs +++ b/OpenSim/Framework/UserProfiles.cs | |||
@@ -77,9 +77,10 @@ namespace OpenSim.Framework | |||
77 | public string Desc = string.Empty; | 77 | public string Desc = string.Empty; |
78 | public UUID ParcelId = UUID.Zero; | 78 | public UUID ParcelId = UUID.Zero; |
79 | public UUID SnapshotId = UUID.Zero; | 79 | public UUID SnapshotId = UUID.Zero; |
80 | public string User = string.Empty; | 80 | public string ParcelName = string.Empty; |
81 | public string SimName = string.Empty; | 81 | public string SimName = string.Empty; |
82 | public string GlobalPos = "<0,0,0>"; | 82 | public string GlobalPos = "<0,0,0>"; |
83 | public string Gatekeeper = string.Empty; | ||
83 | public int SortOrder = 0; | 84 | public int SortOrder = 0; |
84 | public bool Enabled = false; | 85 | public bool Enabled = false; |
85 | } | 86 | } |
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5f4ab06..eb3526a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -51,6 +51,9 @@ using Nwc.XmlRpc; | |||
51 | using OpenMetaverse; | 51 | using OpenMetaverse; |
52 | using OpenMetaverse.StructuredData; | 52 | using OpenMetaverse.StructuredData; |
53 | using Amib.Threading; | 53 | using Amib.Threading; |
54 | using System.Collections.Concurrent; | ||
55 | using System.Collections.Specialized; | ||
56 | using System.Web; | ||
54 | 57 | ||
55 | namespace OpenSim.Framework | 58 | namespace OpenSim.Framework |
56 | { | 59 | { |
@@ -76,7 +79,7 @@ namespace OpenSim.Framework | |||
76 | // All does not contain Export, which is special and must be | 79 | // All does not contain Export, which is special and must be |
77 | // explicitly given | 80 | // explicitly given |
78 | All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) | 81 | All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) |
79 | } | 82 | } |
80 | 83 | ||
81 | /// <summary> | 84 | /// <summary> |
82 | /// The method used by Util.FireAndForget for asynchronously firing events | 85 | /// The method used by Util.FireAndForget for asynchronously firing events |
@@ -125,8 +128,26 @@ namespace OpenSim.Framework | |||
125 | { | 128 | { |
126 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 129 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
127 | 130 | ||
131 | /// <summary> | ||
132 | /// Log-level for the thread pool: | ||
133 | /// 0 = no logging | ||
134 | /// 1 = only first line of stack trace; don't log common threads | ||
135 | /// 2 = full stack trace; don't log common threads | ||
136 | /// 3 = full stack trace, including common threads | ||
137 | /// </summary> | ||
138 | public static int LogThreadPool { get; set; } | ||
139 | public static bool LogOverloads { get; set; } | ||
140 | |||
141 | public static readonly int MAX_THREADPOOL_LEVEL = 3; | ||
142 | |||
143 | static Util() | ||
144 | { | ||
145 | LogThreadPool = 0; | ||
146 | LogOverloads = true; | ||
147 | } | ||
148 | |||
128 | private static uint nextXferID = 5000; | 149 | private static uint nextXferID = 5000; |
129 | private static Random randomClass = new Random(); | 150 | private static Random randomClass = new ThreadSafeRandom(); |
130 | 151 | ||
131 | // Get a list of invalid file characters (OS dependent) | 152 | // Get a list of invalid file characters (OS dependent) |
132 | private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; | 153 | private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; |
@@ -138,6 +159,9 @@ namespace OpenSim.Framework | |||
138 | /// </summary> | 159 | /// </summary> |
139 | private static SmartThreadPool m_ThreadPool; | 160 | private static SmartThreadPool m_ThreadPool; |
140 | 161 | ||
162 | // Watchdog timer that aborts threads that have timed-out | ||
163 | private static Timer m_threadPoolWatchdog; | ||
164 | |||
141 | // 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. | 165 | // 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. |
142 | public static readonly DateTime UnixEpoch = | 166 | public static readonly DateTime UnixEpoch = |
143 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); | 167 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); |
@@ -403,6 +427,22 @@ namespace OpenSim.Framework | |||
403 | return x; | 427 | return x; |
404 | } | 428 | } |
405 | 429 | ||
430 | /// <summary> | ||
431 | /// Check if any of the values in a Vector3 are NaN or Infinity | ||
432 | /// </summary> | ||
433 | /// <param name="v">Vector3 to check</param> | ||
434 | /// <returns></returns> | ||
435 | public static bool IsNanOrInfinity(Vector3 v) | ||
436 | { | ||
437 | if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z)) | ||
438 | return true; | ||
439 | |||
440 | if (float.IsInfinity(v.X) || float.IsInfinity(v.Y) || float.IsNaN(v.Z)) | ||
441 | return true; | ||
442 | |||
443 | return false; | ||
444 | } | ||
445 | |||
406 | // Inclusive, within range test (true if equal to the endpoints) | 446 | // Inclusive, within range test (true if equal to the endpoints) |
407 | public static bool InRange<T>(T x, T min, T max) | 447 | public static bool InRange<T>(T x, T min, T max) |
408 | where T : IComparable<T> | 448 | where T : IComparable<T> |
@@ -492,6 +532,19 @@ namespace OpenSim.Framework | |||
492 | return sb.ToString(); | 532 | return sb.ToString(); |
493 | } | 533 | } |
494 | 534 | ||
535 | public static byte[] DocToBytes(XmlDocument doc) | ||
536 | { | ||
537 | using (MemoryStream ms = new MemoryStream()) | ||
538 | using (XmlTextWriter xw = new XmlTextWriter(ms, null)) | ||
539 | { | ||
540 | xw.Formatting = Formatting.Indented; | ||
541 | doc.WriteTo(xw); | ||
542 | xw.Flush(); | ||
543 | |||
544 | return ms.ToArray(); | ||
545 | } | ||
546 | } | ||
547 | |||
495 | /// <summary> | 548 | /// <summary> |
496 | /// Is the platform Windows? | 549 | /// Is the platform Windows? |
497 | /// </summary> | 550 | /// </summary> |
@@ -508,6 +561,11 @@ namespace OpenSim.Framework | |||
508 | 561 | ||
509 | public static bool LoadArchSpecificWindowsDll(string libraryName) | 562 | public static bool LoadArchSpecificWindowsDll(string libraryName) |
510 | { | 563 | { |
564 | return LoadArchSpecificWindowsDll(libraryName, string.Empty); | ||
565 | } | ||
566 | |||
567 | public static bool LoadArchSpecificWindowsDll(string libraryName, string path) | ||
568 | { | ||
511 | // We do this so that OpenSimulator on Windows loads the correct native library depending on whether | 569 | // We do this so that OpenSimulator on Windows loads the correct native library depending on whether |
512 | // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports | 570 | // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports |
513 | // will find it already loaded later on. | 571 | // will find it already loaded later on. |
@@ -517,9 +575,9 @@ namespace OpenSim.Framework | |||
517 | string nativeLibraryPath; | 575 | string nativeLibraryPath; |
518 | 576 | ||
519 | if (Util.Is64BitProcess()) | 577 | if (Util.Is64BitProcess()) |
520 | nativeLibraryPath = "lib64/" + libraryName; | 578 | nativeLibraryPath = Path.Combine(Path.Combine(path, "lib64"), libraryName); |
521 | else | 579 | else |
522 | nativeLibraryPath = "lib32/" + libraryName; | 580 | nativeLibraryPath = Path.Combine(Path.Combine(path, "lib32"), libraryName); |
523 | 581 | ||
524 | m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); | 582 | m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); |
525 | 583 | ||
@@ -874,6 +932,54 @@ namespace OpenSim.Framework | |||
874 | } | 932 | } |
875 | 933 | ||
876 | /// <summary> | 934 | /// <summary> |
935 | /// Parses a foreign asset ID. | ||
936 | /// </summary> | ||
937 | /// <param name="id">A possibly-foreign asset ID: http://grid.example.com:8002/00000000-0000-0000-0000-000000000000 </param> | ||
938 | /// <param name="url">The URL: http://grid.example.com:8002</param> | ||
939 | /// <param name="assetID">The asset ID: 00000000-0000-0000-0000-000000000000. Returned even if 'id' isn't foreign.</param> | ||
940 | /// <returns>True: this is a foreign asset ID; False: it isn't</returns> | ||
941 | public static bool ParseForeignAssetID(string id, out string url, out string assetID) | ||
942 | { | ||
943 | url = String.Empty; | ||
944 | assetID = String.Empty; | ||
945 | |||
946 | UUID uuid; | ||
947 | if (UUID.TryParse(id, out uuid)) | ||
948 | { | ||
949 | assetID = uuid.ToString(); | ||
950 | return false; | ||
951 | } | ||
952 | |||
953 | if ((id.Length == 0) || (id[0] != 'h' && id[0] != 'H')) | ||
954 | return false; | ||
955 | |||
956 | Uri assetUri; | ||
957 | if (!Uri.TryCreate(id, UriKind.Absolute, out assetUri) || assetUri.Scheme != Uri.UriSchemeHttp) | ||
958 | return false; | ||
959 | |||
960 | // Simian | ||
961 | if (assetUri.Query != string.Empty) | ||
962 | { | ||
963 | NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query); | ||
964 | assetID = qscoll["id"]; | ||
965 | if (assetID != null) | ||
966 | url = id.Replace(assetID, ""); // Malformed again, as simian expects | ||
967 | else | ||
968 | url = id; // !!! best effort | ||
969 | } | ||
970 | else // robust | ||
971 | { | ||
972 | url = "http://" + assetUri.Authority; | ||
973 | assetID = assetUri.LocalPath.Trim(new char[] { '/' }); | ||
974 | } | ||
975 | |||
976 | if (!UUID.TryParse(assetID, out uuid)) | ||
977 | return false; | ||
978 | |||
979 | return true; | ||
980 | } | ||
981 | |||
982 | /// <summary> | ||
877 | /// Removes all invalid path chars (OS dependent) | 983 | /// Removes all invalid path chars (OS dependent) |
878 | /// </summary> | 984 | /// </summary> |
879 | /// <param name="path">path</param> | 985 | /// <param name="path">path</param> |
@@ -974,11 +1080,12 @@ namespace OpenSim.Framework | |||
974 | } | 1080 | } |
975 | 1081 | ||
976 | #region Nini (config) related Methods | 1082 | #region Nini (config) related Methods |
1083 | |||
977 | public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) | 1084 | public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) |
978 | { | 1085 | { |
979 | if (!File.Exists(fileName)) | 1086 | if (!File.Exists(fileName)) |
980 | { | 1087 | { |
981 | //create new file | 1088 | // create new file |
982 | } | 1089 | } |
983 | XmlConfigSource config = new XmlConfigSource(fileName); | 1090 | XmlConfigSource config = new XmlConfigSource(fileName); |
984 | AddDataRowToConfig(config, row); | 1091 | AddDataRowToConfig(config, row); |
@@ -1067,6 +1174,148 @@ namespace OpenSim.Framework | |||
1067 | return (T)val; | 1174 | return (T)val; |
1068 | } | 1175 | } |
1069 | 1176 | ||
1177 | public static void MergeEnvironmentToConfig(IConfigSource ConfigSource) | ||
1178 | { | ||
1179 | IConfig enVars = ConfigSource.Configs["Environment"]; | ||
1180 | // if section does not exist then user isn't expecting them, so don't bother. | ||
1181 | if( enVars != null ) | ||
1182 | { | ||
1183 | // load the values from the environment | ||
1184 | EnvConfigSource envConfigSource = new EnvConfigSource(); | ||
1185 | // add the requested keys | ||
1186 | string[] env_keys = enVars.GetKeys(); | ||
1187 | foreach ( string key in env_keys ) | ||
1188 | { | ||
1189 | envConfigSource.AddEnv(key, string.Empty); | ||
1190 | } | ||
1191 | // load the values from environment | ||
1192 | envConfigSource.LoadEnv(); | ||
1193 | // add them in to the master | ||
1194 | ConfigSource.Merge(envConfigSource); | ||
1195 | ConfigSource.ExpandKeyValues(); | ||
1196 | } | ||
1197 | } | ||
1198 | |||
1199 | public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass) | ||
1200 | { | ||
1201 | Type settingsType = settingsClass.GetType(); | ||
1202 | |||
1203 | FieldInfo[] fieldInfos = settingsType.GetFields(); | ||
1204 | foreach (FieldInfo fieldInfo in fieldInfos) | ||
1205 | { | ||
1206 | if (!fieldInfo.IsStatic) | ||
1207 | { | ||
1208 | if (fieldInfo.FieldType == typeof(System.String)) | ||
1209 | { | ||
1210 | fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); | ||
1211 | } | ||
1212 | else if (fieldInfo.FieldType == typeof(System.Boolean)) | ||
1213 | { | ||
1214 | fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); | ||
1215 | } | ||
1216 | else if (fieldInfo.FieldType == typeof(System.Int32)) | ||
1217 | { | ||
1218 | fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); | ||
1219 | } | ||
1220 | else if (fieldInfo.FieldType == typeof(System.Single)) | ||
1221 | { | ||
1222 | fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); | ||
1223 | } | ||
1224 | else if (fieldInfo.FieldType == typeof(System.UInt32)) | ||
1225 | { | ||
1226 | fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); | ||
1227 | } | ||
1228 | } | ||
1229 | } | ||
1230 | |||
1231 | PropertyInfo[] propertyInfos = settingsType.GetProperties(); | ||
1232 | foreach (PropertyInfo propInfo in propertyInfos) | ||
1233 | { | ||
1234 | if ((propInfo.CanRead) && (propInfo.CanWrite)) | ||
1235 | { | ||
1236 | if (propInfo.PropertyType == typeof(System.String)) | ||
1237 | { | ||
1238 | propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); | ||
1239 | } | ||
1240 | else if (propInfo.PropertyType == typeof(System.Boolean)) | ||
1241 | { | ||
1242 | propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); | ||
1243 | } | ||
1244 | else if (propInfo.PropertyType == typeof(System.Int32)) | ||
1245 | { | ||
1246 | propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); | ||
1247 | } | ||
1248 | else if (propInfo.PropertyType == typeof(System.Single)) | ||
1249 | { | ||
1250 | propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); | ||
1251 | } | ||
1252 | if (propInfo.PropertyType == typeof(System.UInt32)) | ||
1253 | { | ||
1254 | propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); | ||
1255 | } | ||
1256 | } | ||
1257 | } | ||
1258 | |||
1259 | return settingsClass; | ||
1260 | } | ||
1261 | |||
1262 | /// <summary> | ||
1263 | /// Reads a configuration file, configFile, merging it with the main configuration, config. | ||
1264 | /// If the file doesn't exist, it copies a given exampleConfigFile onto configFile, and then | ||
1265 | /// merges it. | ||
1266 | /// </summary> | ||
1267 | /// <param name="config">The main configuration data</param> | ||
1268 | /// <param name="configFileName">The name of a configuration file in ConfigDirectory variable, no path</param> | ||
1269 | /// <param name="exampleConfigFile">Full path to an example configuration file</param> | ||
1270 | /// <param name="configFilePath">Full path ConfigDirectory/configFileName</param> | ||
1271 | /// <param name="created">True if the file was created in ConfigDirectory, false if it existed</param> | ||
1272 | /// <returns>True if success</returns> | ||
1273 | public static bool MergeConfigurationFile(IConfigSource config, string configFileName, string exampleConfigFile, out string configFilePath, out bool created) | ||
1274 | { | ||
1275 | created = false; | ||
1276 | configFilePath = string.Empty; | ||
1277 | |||
1278 | IConfig cnf = config.Configs["Startup"]; | ||
1279 | if (cnf == null) | ||
1280 | { | ||
1281 | m_log.WarnFormat("[UTILS]: Startup section doesn't exist"); | ||
1282 | return false; | ||
1283 | } | ||
1284 | |||
1285 | string configDirectory = cnf.GetString("ConfigDirectory", "."); | ||
1286 | string configFile = Path.Combine(configDirectory, configFileName); | ||
1287 | |||
1288 | if (!File.Exists(configFile) && !string.IsNullOrEmpty(exampleConfigFile)) | ||
1289 | { | ||
1290 | // We need to copy the example onto it | ||
1291 | |||
1292 | if (!Directory.Exists(configDirectory)) | ||
1293 | Directory.CreateDirectory(configDirectory); | ||
1294 | |||
1295 | try | ||
1296 | { | ||
1297 | File.Copy(exampleConfigFile, configFile); | ||
1298 | created = true; | ||
1299 | } | ||
1300 | catch (Exception e) | ||
1301 | { | ||
1302 | m_log.WarnFormat("[UTILS]: Exception copying configuration file {0} to {1}: {2}", configFile, exampleConfigFile, e.Message); | ||
1303 | return false; | ||
1304 | } | ||
1305 | } | ||
1306 | |||
1307 | if (File.Exists(configFile)) | ||
1308 | { | ||
1309 | // Merge | ||
1310 | config.Merge(new IniConfigSource(configFile)); | ||
1311 | config.ExpandKeyValues(); | ||
1312 | configFilePath = configFile; | ||
1313 | return true; | ||
1314 | } | ||
1315 | else | ||
1316 | return false; | ||
1317 | } | ||
1318 | |||
1070 | #endregion | 1319 | #endregion |
1071 | 1320 | ||
1072 | public static float Clip(float x, float min, float max) | 1321 | public static float Clip(float x, float min, float max) |
@@ -1514,6 +1763,46 @@ namespace OpenSim.Framework | |||
1514 | return result; | 1763 | return result; |
1515 | } | 1764 | } |
1516 | 1765 | ||
1766 | public static void BinaryToASCII(char[] chars) | ||
1767 | { | ||
1768 | for (int i = 0; i < chars.Length; i++) | ||
1769 | { | ||
1770 | char ch = chars[i]; | ||
1771 | if (ch < 32 || ch > 127) | ||
1772 | chars[i] = '.'; | ||
1773 | } | ||
1774 | } | ||
1775 | |||
1776 | public static string BinaryToASCII(string src) | ||
1777 | { | ||
1778 | char[] chars = src.ToCharArray(); | ||
1779 | BinaryToASCII(chars); | ||
1780 | return new String(chars); | ||
1781 | } | ||
1782 | |||
1783 | /// <summary> | ||
1784 | /// Reads a known number of bytes from a stream. | ||
1785 | /// Throws EndOfStreamException if the stream doesn't contain enough data. | ||
1786 | /// </summary> | ||
1787 | /// <param name="stream">The stream to read data from</param> | ||
1788 | /// <param name="data">The array to write bytes into. The array | ||
1789 | /// will be completely filled from the stream, so an appropriate | ||
1790 | /// size must be given.</param> | ||
1791 | public static void ReadStream(Stream stream, byte[] data) | ||
1792 | { | ||
1793 | int offset = 0; | ||
1794 | int remaining = data.Length; | ||
1795 | |||
1796 | while (remaining > 0) | ||
1797 | { | ||
1798 | int read = stream.Read(data, offset, remaining); | ||
1799 | if (read <= 0) | ||
1800 | throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining)); | ||
1801 | remaining -= read; | ||
1802 | offset += read; | ||
1803 | } | ||
1804 | } | ||
1805 | |||
1517 | public static Guid GetHashGuid(string data, string salt) | 1806 | public static Guid GetHashGuid(string data, string salt) |
1518 | { | 1807 | { |
1519 | byte[] hash = ComputeMD5Hash(data + salt, Encoding.Default); | 1808 | byte[] hash = ComputeMD5Hash(data + salt, Encoding.Default); |
@@ -1774,6 +2063,30 @@ namespace OpenSim.Framework | |||
1774 | } | 2063 | } |
1775 | 2064 | ||
1776 | /// <summary> | 2065 | /// <summary> |
2066 | /// Pretty format the hashtable contents to a single line. | ||
2067 | /// </summary> | ||
2068 | /// <remarks> | ||
2069 | /// Used for debugging output. | ||
2070 | /// </remarks> | ||
2071 | /// <param name='ht'></param> | ||
2072 | public static string PrettyFormatToSingleLine(Hashtable ht) | ||
2073 | { | ||
2074 | StringBuilder sb = new StringBuilder(); | ||
2075 | |||
2076 | int i = 0; | ||
2077 | |||
2078 | foreach (string key in ht.Keys) | ||
2079 | { | ||
2080 | sb.AppendFormat("{0}:{1}", key, ht[key]); | ||
2081 | |||
2082 | if (++i < ht.Count) | ||
2083 | sb.AppendFormat(", "); | ||
2084 | } | ||
2085 | |||
2086 | return sb.ToString(); | ||
2087 | } | ||
2088 | |||
2089 | /// <summary> | ||
1777 | /// Used to trigger an early library load on Windows systems. | 2090 | /// Used to trigger an early library load on Windows systems. |
1778 | /// </summary> | 2091 | /// </summary> |
1779 | /// <remarks> | 2092 | /// <remarks> |
@@ -1852,10 +2165,15 @@ namespace OpenSim.Framework | |||
1852 | { | 2165 | { |
1853 | if (maxThreads < 2) | 2166 | if (maxThreads < 2) |
1854 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); | 2167 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); |
2168 | |||
1855 | if (minThreads > maxThreads || minThreads < 2) | 2169 | if (minThreads > maxThreads || minThreads < 2) |
1856 | throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); | 2170 | throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); |
2171 | |||
1857 | if (m_ThreadPool != null) | 2172 | if (m_ThreadPool != null) |
1858 | throw new InvalidOperationException("SmartThreadPool is already initialized"); | 2173 | { |
2174 | m_log.Warn("SmartThreadPool is already initialized. Ignoring request."); | ||
2175 | return; | ||
2176 | } | ||
1859 | 2177 | ||
1860 | STPStartInfo startInfo = new STPStartInfo(); | 2178 | STPStartInfo startInfo = new STPStartInfo(); |
1861 | startInfo.ThreadPoolName = "Util"; | 2179 | startInfo.ThreadPoolName = "Util"; |
@@ -1864,6 +2182,7 @@ namespace OpenSim.Framework | |||
1864 | startInfo.MinWorkerThreads = minThreads; | 2182 | startInfo.MinWorkerThreads = minThreads; |
1865 | 2183 | ||
1866 | m_ThreadPool = new SmartThreadPool(startInfo); | 2184 | m_ThreadPool = new SmartThreadPool(startInfo); |
2185 | m_threadPoolWatchdog = new Timer(ThreadPoolWatchdog, null, 0, 1000); | ||
1867 | } | 2186 | } |
1868 | 2187 | ||
1869 | public static int FireAndForgetCount() | 2188 | public static int FireAndForgetCount() |
@@ -1886,15 +2205,179 @@ namespace OpenSim.Framework | |||
1886 | throw new NotImplementedException(); | 2205 | throw new NotImplementedException(); |
1887 | } | 2206 | } |
1888 | } | 2207 | } |
2208 | |||
2209 | /// <summary> | ||
2210 | /// Additional information about threads in the main thread pool. Used to time how long the | ||
2211 | /// thread has been running, and abort it if it has timed-out. | ||
2212 | /// </summary> | ||
2213 | private class ThreadInfo | ||
2214 | { | ||
2215 | public long ThreadFuncNum { get; set; } | ||
2216 | public string StackTrace { get; set; } | ||
2217 | private string context; | ||
2218 | public bool LogThread { get; set; } | ||
2219 | |||
2220 | public IWorkItemResult WorkItem { get; set; } | ||
2221 | public Thread Thread { get; set; } | ||
2222 | public bool Running { get; set; } | ||
2223 | public bool Aborted { get; set; } | ||
2224 | private int started; | ||
2225 | |||
2226 | public ThreadInfo(long threadFuncNum, string context) | ||
2227 | { | ||
2228 | ThreadFuncNum = threadFuncNum; | ||
2229 | this.context = context; | ||
2230 | LogThread = false; | ||
2231 | Thread = null; | ||
2232 | Running = false; | ||
2233 | Aborted = false; | ||
2234 | } | ||
2235 | |||
2236 | public void Started() | ||
2237 | { | ||
2238 | Thread = Thread.CurrentThread; | ||
2239 | started = EnvironmentTickCount(); | ||
2240 | Running = true; | ||
2241 | } | ||
2242 | |||
2243 | public void Ended() | ||
2244 | { | ||
2245 | Running = false; | ||
2246 | } | ||
2247 | |||
2248 | public int Elapsed() | ||
2249 | { | ||
2250 | return EnvironmentTickCountSubtract(started); | ||
2251 | } | ||
2252 | |||
2253 | public void Abort() | ||
2254 | { | ||
2255 | Aborted = true; | ||
2256 | WorkItem.Cancel(true); | ||
2257 | } | ||
2258 | |||
2259 | /// <summary> | ||
2260 | /// Returns the thread's stack trace. | ||
2261 | /// </summary> | ||
2262 | /// <remarks> | ||
2263 | /// May return one of two stack traces. First, tries to get the thread's active stack | ||
2264 | /// trace. But this can fail, so as a fallback this method will return the stack | ||
2265 | /// trace that was active when the task was queued. | ||
2266 | /// </remarks> | ||
2267 | public string GetStackTrace() | ||
2268 | { | ||
2269 | string ret = (context == null) ? "" : ("(" + context + ") "); | ||
2270 | |||
2271 | StackTrace activeStackTrace = Util.GetStackTrace(Thread); | ||
2272 | if (activeStackTrace != null) | ||
2273 | ret += activeStackTrace.ToString(); | ||
2274 | else if (StackTrace != null) | ||
2275 | ret += "(Stack trace when queued) " + StackTrace; | ||
2276 | // else, no stack trace available | ||
2277 | |||
2278 | return ret; | ||
2279 | } | ||
2280 | } | ||
2281 | |||
2282 | private static long nextThreadFuncNum = 0; | ||
2283 | private static long numQueuedThreadFuncs = 0; | ||
2284 | private static long numRunningThreadFuncs = 0; | ||
2285 | private static long numTotalThreadFuncsCalled = 0; | ||
2286 | private static Int32 threadFuncOverloadMode = 0; | ||
2287 | |||
2288 | public static long TotalQueuedFireAndForgetCalls { get { return numQueuedThreadFuncs; } } | ||
2289 | public static long TotalRunningFireAndForgetCalls { get { return numRunningThreadFuncs; } } | ||
2290 | |||
2291 | // Maps (ThreadFunc number -> Thread) | ||
2292 | private static ConcurrentDictionary<long, ThreadInfo> activeThreads = new ConcurrentDictionary<long, ThreadInfo>(); | ||
2293 | |||
2294 | private static readonly int THREAD_TIMEOUT = 10 * 60 * 1000; // 10 minutes | ||
2295 | |||
2296 | /// <summary> | ||
2297 | /// Finds threads in the main thread pool that have timed-out, and aborts them. | ||
2298 | /// </summary> | ||
2299 | private static void ThreadPoolWatchdog(object state) | ||
2300 | { | ||
2301 | foreach (KeyValuePair<long, ThreadInfo> entry in activeThreads) | ||
2302 | { | ||
2303 | ThreadInfo t = entry.Value; | ||
2304 | if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT)) | ||
2305 | { | ||
2306 | m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace()); | ||
2307 | t.Abort(); | ||
2308 | |||
2309 | ThreadInfo dummy; | ||
2310 | activeThreads.TryRemove(entry.Key, out dummy); | ||
2311 | |||
2312 | // It's possible that the thread won't abort. To make sure the thread pool isn't | ||
2313 | // depleted, increase the pool size. | ||
2314 | m_ThreadPool.MaxThreads++; | ||
2315 | } | ||
2316 | } | ||
2317 | } | ||
2318 | |||
2319 | public static long TotalFireAndForgetCallsMade { get { return numTotalThreadFuncsCalled; } } | ||
2320 | |||
2321 | public static Dictionary<string, int> GetFireAndForgetCallsMade() | ||
2322 | { | ||
2323 | return new Dictionary<string, int>(m_fireAndForgetCallsMade); | ||
2324 | } | ||
2325 | |||
2326 | private static Dictionary<string, int> m_fireAndForgetCallsMade = new Dictionary<string, int>(); | ||
2327 | |||
2328 | public static Dictionary<string, int> GetFireAndForgetCallsInProgress() | ||
2329 | { | ||
2330 | return new Dictionary<string, int>(m_fireAndForgetCallsInProgress); | ||
2331 | } | ||
2332 | |||
2333 | private static Dictionary<string, int> m_fireAndForgetCallsInProgress = new Dictionary<string, int>(); | ||
2334 | |||
2335 | public static void FireAndForget(System.Threading.WaitCallback callback) | ||
2336 | { | ||
2337 | FireAndForget(callback, null, null); | ||
2338 | } | ||
1889 | 2339 | ||
1890 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj) | 2340 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj) |
1891 | { | 2341 | { |
2342 | FireAndForget(callback, obj, null); | ||
2343 | } | ||
2344 | |||
2345 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) | ||
2346 | { | ||
2347 | Interlocked.Increment(ref numTotalThreadFuncsCalled); | ||
2348 | |||
2349 | if (context != null) | ||
2350 | { | ||
2351 | if (!m_fireAndForgetCallsMade.ContainsKey(context)) | ||
2352 | m_fireAndForgetCallsMade[context] = 1; | ||
2353 | else | ||
2354 | m_fireAndForgetCallsMade[context]++; | ||
2355 | |||
2356 | if (!m_fireAndForgetCallsInProgress.ContainsKey(context)) | ||
2357 | m_fireAndForgetCallsInProgress[context] = 1; | ||
2358 | else | ||
2359 | m_fireAndForgetCallsInProgress[context]++; | ||
2360 | } | ||
2361 | |||
1892 | WaitCallback realCallback; | 2362 | WaitCallback realCallback; |
1893 | 2363 | ||
2364 | bool loggingEnabled = LogThreadPool > 0; | ||
2365 | |||
2366 | long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); | ||
2367 | ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context); | ||
2368 | |||
1894 | if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) | 2369 | if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) |
1895 | { | 2370 | { |
1896 | // If we're running regression tests, then we want any exceptions to rise up to the test code. | 2371 | // If we're running regression tests, then we want any exceptions to rise up to the test code. |
1897 | realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; | 2372 | realCallback = |
2373 | o => | ||
2374 | { | ||
2375 | Culture.SetCurrentCulture(); | ||
2376 | callback(o); | ||
2377 | |||
2378 | if (context != null) | ||
2379 | m_fireAndForgetCallsInProgress[context]--; | ||
2380 | }; | ||
1898 | } | 2381 | } |
1899 | else | 2382 | else |
1900 | { | 2383 | { |
@@ -1903,51 +2386,267 @@ namespace OpenSim.Framework | |||
1903 | // for decimals places but is read by a culture that treats commas as number seperators. | 2386 | // for decimals places but is read by a culture that treats commas as number seperators. |
1904 | realCallback = o => | 2387 | realCallback = o => |
1905 | { | 2388 | { |
1906 | Culture.SetCurrentCulture(); | 2389 | long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs); |
2390 | long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs); | ||
2391 | threadInfo.Started(); | ||
2392 | activeThreads[threadFuncNum] = threadInfo; | ||
1907 | 2393 | ||
1908 | try | 2394 | try |
1909 | { | 2395 | { |
2396 | if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) | ||
2397 | m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1); | ||
2398 | |||
2399 | Culture.SetCurrentCulture(); | ||
2400 | |||
1910 | callback(o); | 2401 | callback(o); |
1911 | } | 2402 | } |
2403 | catch (ThreadAbortException e) | ||
2404 | { | ||
2405 | m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e); | ||
2406 | } | ||
1912 | catch (Exception e) | 2407 | catch (Exception e) |
1913 | { | 2408 | { |
1914 | m_log.ErrorFormat( | 2409 | m_log.Error(string.Format("[UTIL]: Util STP threadfunc {0} terminated with error ", threadFuncNum), e); |
1915 | "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", | 2410 | } |
1916 | e.Message, e.StackTrace); | 2411 | finally |
2412 | { | ||
2413 | Interlocked.Decrement(ref numRunningThreadFuncs); | ||
2414 | threadInfo.Ended(); | ||
2415 | ThreadInfo dummy; | ||
2416 | activeThreads.TryRemove(threadFuncNum, out dummy); | ||
2417 | if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) | ||
2418 | m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); | ||
2419 | |||
2420 | if (context != null) | ||
2421 | m_fireAndForgetCallsInProgress[context]--; | ||
1917 | } | 2422 | } |
1918 | }; | 2423 | }; |
1919 | } | 2424 | } |
1920 | 2425 | ||
1921 | switch (FireAndForgetMethod) | 2426 | long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs); |
2427 | try | ||
1922 | { | 2428 | { |
1923 | case FireAndForgetMethod.RegressionTest: | 2429 | long numRunning = numRunningThreadFuncs; |
1924 | case FireAndForgetMethod.None: | 2430 | |
1925 | realCallback.Invoke(obj); | 2431 | if (m_ThreadPool != null && LogOverloads) |
1926 | break; | 2432 | { |
1927 | case FireAndForgetMethod.UnsafeQueueUserWorkItem: | 2433 | if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads)) |
1928 | ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); | 2434 | { |
1929 | break; | 2435 | if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0) |
1930 | case FireAndForgetMethod.QueueUserWorkItem: | 2436 | m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning); |
1931 | ThreadPool.QueueUserWorkItem(realCallback, obj); | 2437 | } |
1932 | break; | 2438 | else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads * 2) / 3)) |
1933 | case FireAndForgetMethod.BeginInvoke: | 2439 | { |
1934 | FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; | 2440 | if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1) |
1935 | wrapper.FireAndForget(realCallback, obj); | 2441 | m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning); |
1936 | break; | 2442 | } |
1937 | case FireAndForgetMethod.SmartThreadPool: | 2443 | } |
1938 | if (m_ThreadPool == null) | 2444 | |
1939 | InitThreadPool(2, 15); | 2445 | if (loggingEnabled || (threadFuncOverloadMode == 1)) |
1940 | m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); | 2446 | { |
1941 | break; | 2447 | string full, partial; |
1942 | case FireAndForgetMethod.Thread: | 2448 | GetFireAndForgetStackTrace(out full, out partial); |
1943 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); | 2449 | threadInfo.StackTrace = full; |
1944 | thread.Start(obj); | 2450 | threadInfo.LogThread = ShouldLogThread(partial); |
1945 | break; | 2451 | |
1946 | default: | 2452 | if (threadInfo.LogThread) |
1947 | throw new NotImplementedException(); | 2453 | { |
2454 | m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", | ||
2455 | threadFuncNum, numQueued, numRunningThreadFuncs, | ||
2456 | (context == null) ? "" : ("(" + context + ") "), | ||
2457 | (LogThreadPool >= 2) ? full : partial); | ||
2458 | } | ||
2459 | } | ||
2460 | else | ||
2461 | { | ||
2462 | // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either. | ||
2463 | // Those log lines aren't useful when we don't know which function is running in the thread. | ||
2464 | threadInfo.LogThread = false; | ||
2465 | } | ||
2466 | |||
2467 | switch (FireAndForgetMethod) | ||
2468 | { | ||
2469 | case FireAndForgetMethod.RegressionTest: | ||
2470 | case FireAndForgetMethod.None: | ||
2471 | realCallback.Invoke(obj); | ||
2472 | break; | ||
2473 | case FireAndForgetMethod.UnsafeQueueUserWorkItem: | ||
2474 | ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); | ||
2475 | break; | ||
2476 | case FireAndForgetMethod.QueueUserWorkItem: | ||
2477 | ThreadPool.QueueUserWorkItem(realCallback, obj); | ||
2478 | break; | ||
2479 | case FireAndForgetMethod.BeginInvoke: | ||
2480 | FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; | ||
2481 | wrapper.FireAndForget(realCallback, obj); | ||
2482 | break; | ||
2483 | case FireAndForgetMethod.SmartThreadPool: | ||
2484 | if (m_ThreadPool == null) | ||
2485 | InitThreadPool(2, 15); | ||
2486 | threadInfo.WorkItem = m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); | ||
2487 | break; | ||
2488 | case FireAndForgetMethod.Thread: | ||
2489 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); | ||
2490 | thread.Start(obj); | ||
2491 | break; | ||
2492 | default: | ||
2493 | throw new NotImplementedException(); | ||
2494 | } | ||
2495 | } | ||
2496 | catch (Exception) | ||
2497 | { | ||
2498 | Interlocked.Decrement(ref numQueuedThreadFuncs); | ||
2499 | ThreadInfo dummy; | ||
2500 | activeThreads.TryRemove(threadFuncNum, out dummy); | ||
2501 | throw; | ||
2502 | } | ||
2503 | } | ||
2504 | |||
2505 | /// <summary> | ||
2506 | /// Returns whether the thread should be logged. Some very common threads aren't logged, | ||
2507 | /// to avoid filling up the log. | ||
2508 | /// </summary> | ||
2509 | /// <param name="stackTrace">A partial stack trace of where the thread was queued</param> | ||
2510 | /// <returns>Whether to log this thread</returns> | ||
2511 | private static bool ShouldLogThread(string stackTrace) | ||
2512 | { | ||
2513 | if (LogThreadPool < 3) | ||
2514 | { | ||
2515 | if (stackTrace.Contains("BeginFireQueueEmpty")) | ||
2516 | return false; | ||
2517 | } | ||
2518 | |||
2519 | return true; | ||
2520 | } | ||
2521 | |||
2522 | /// <summary> | ||
2523 | /// Returns a stack trace for a thread added using FireAndForget(). | ||
2524 | /// </summary> | ||
2525 | /// <param name="full">Will contain the full stack trace</param> | ||
2526 | /// <param name="partial">Will contain only the first frame of the stack trace</param> | ||
2527 | private static void GetFireAndForgetStackTrace(out string full, out string partial) | ||
2528 | { | ||
2529 | string src = Environment.StackTrace; | ||
2530 | string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); | ||
2531 | |||
2532 | StringBuilder dest = new StringBuilder(src.Length); | ||
2533 | |||
2534 | bool started = false; | ||
2535 | bool first = true; | ||
2536 | partial = ""; | ||
2537 | |||
2538 | for (int i = 0; i < lines.Length; i++) | ||
2539 | { | ||
2540 | string line = lines[i]; | ||
2541 | |||
2542 | if (!started) | ||
2543 | { | ||
2544 | // Skip the initial stack frames, because they're of no interest for debugging | ||
2545 | if (line.Contains("StackTrace") || line.Contains("FireAndForget")) | ||
2546 | continue; | ||
2547 | started = true; | ||
2548 | } | ||
2549 | |||
2550 | if (first) | ||
2551 | { | ||
2552 | line = line.TrimStart(); | ||
2553 | first = false; | ||
2554 | partial = line; | ||
2555 | } | ||
2556 | |||
2557 | bool last = (i == lines.Length - 1); | ||
2558 | if (last) | ||
2559 | dest.Append(line); | ||
2560 | else | ||
2561 | dest.AppendLine(line); | ||
1948 | } | 2562 | } |
2563 | |||
2564 | full = dest.ToString(); | ||
1949 | } | 2565 | } |
1950 | 2566 | ||
2567 | #pragma warning disable 0618 | ||
2568 | /// <summary> | ||
2569 | /// Return the stack trace of a different thread. | ||
2570 | /// </summary> | ||
2571 | /// <remarks> | ||
2572 | /// This is complicated because the thread needs to be paused in order to get its stack | ||
2573 | /// trace. And pausing another thread can cause a deadlock. This method attempts to | ||
2574 | /// avoid deadlock by using a short timeout (200ms), after which it gives up and | ||
2575 | /// returns 'null' instead of the stack trace. | ||
2576 | /// | ||
2577 | /// Take from: http://stackoverflow.com/a/14935378 | ||
2578 | /// | ||
2579 | /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691 | ||
2580 | /// | ||
2581 | /// </remarks> | ||
2582 | /// <returns>The stack trace, or null if failed to get it</returns> | ||
2583 | private static StackTrace GetStackTrace(Thread targetThread) | ||
2584 | { | ||
2585 | if (IsPlatformMono) | ||
2586 | { | ||
2587 | // This doesn't work in Mono | ||
2588 | return null; | ||
2589 | } | ||
2590 | |||
2591 | ManualResetEventSlim fallbackThreadReady = new ManualResetEventSlim(); | ||
2592 | ManualResetEventSlim exitedSafely = new ManualResetEventSlim(); | ||
2593 | |||
2594 | try | ||
2595 | { | ||
2596 | new Thread(delegate() | ||
2597 | { | ||
2598 | fallbackThreadReady.Set(); | ||
2599 | while (!exitedSafely.Wait(200)) | ||
2600 | { | ||
2601 | try | ||
2602 | { | ||
2603 | targetThread.Resume(); | ||
2604 | } | ||
2605 | catch (Exception) | ||
2606 | { | ||
2607 | // Whatever happens, do never stop to resume the main-thread regularly until the main-thread has exited safely. | ||
2608 | } | ||
2609 | } | ||
2610 | }).Start(); | ||
2611 | |||
2612 | fallbackThreadReady.Wait(); | ||
2613 | // From here, you have about 200ms to get the stack-trace | ||
2614 | |||
2615 | targetThread.Suspend(); | ||
2616 | |||
2617 | StackTrace trace = null; | ||
2618 | try | ||
2619 | { | ||
2620 | trace = new StackTrace(targetThread, true); | ||
2621 | } | ||
2622 | catch (ThreadStateException) | ||
2623 | { | ||
2624 | //failed to get stack trace, since the fallback-thread resumed the thread | ||
2625 | //possible reasons: | ||
2626 | //1.) This thread was just too slow | ||
2627 | //2.) A deadlock ocurred | ||
2628 | //Automatic retry seems too risky here, so just return null. | ||
2629 | } | ||
2630 | |||
2631 | try | ||
2632 | { | ||
2633 | targetThread.Resume(); | ||
2634 | } | ||
2635 | catch (ThreadStateException) | ||
2636 | { | ||
2637 | // Thread is running again already | ||
2638 | } | ||
2639 | |||
2640 | return trace; | ||
2641 | } | ||
2642 | finally | ||
2643 | { | ||
2644 | // Signal the fallack-thread to stop | ||
2645 | exitedSafely.Set(); | ||
2646 | } | ||
2647 | } | ||
2648 | #pragma warning restore 0618 | ||
2649 | |||
1951 | /// <summary> | 2650 | /// <summary> |
1952 | /// Get information about the current state of the smart thread pool. | 2651 | /// Get information about the current state of the smart thread pool. |
1953 | /// </summary> | 2652 | /// </summary> |
@@ -2032,6 +2731,60 @@ namespace OpenSim.Framework | |||
2032 | } | 2731 | } |
2033 | 2732 | ||
2034 | /// <summary> | 2733 | /// <summary> |
2734 | /// Formats a duration (given in milliseconds). | ||
2735 | /// </summary> | ||
2736 | public static string FormatDuration(int ms) | ||
2737 | { | ||
2738 | TimeSpan span = new TimeSpan(ms * TimeSpan.TicksPerMillisecond); | ||
2739 | |||
2740 | string str = ""; | ||
2741 | string suffix = null; | ||
2742 | |||
2743 | int hours = (int)span.TotalHours; | ||
2744 | if (hours > 0) | ||
2745 | { | ||
2746 | str += hours.ToString(str.Length == 0 ? "0" : "00"); | ||
2747 | suffix = "hours"; | ||
2748 | } | ||
2749 | |||
2750 | if ((hours > 0) || (span.Minutes > 0)) | ||
2751 | { | ||
2752 | if (str.Length > 0) | ||
2753 | str += ":"; | ||
2754 | str += span.Minutes.ToString(str.Length == 0 ? "0" : "00"); | ||
2755 | if (suffix == null) | ||
2756 | suffix = "min"; | ||
2757 | } | ||
2758 | |||
2759 | if ((hours > 0) || (span.Minutes > 0) || (span.Seconds > 0)) | ||
2760 | { | ||
2761 | if (str.Length > 0) | ||
2762 | str += ":"; | ||
2763 | str += span.Seconds.ToString(str.Length == 0 ? "0" : "00"); | ||
2764 | if (suffix == null) | ||
2765 | suffix = "sec"; | ||
2766 | } | ||
2767 | |||
2768 | if (suffix == null) | ||
2769 | suffix = "ms"; | ||
2770 | |||
2771 | if (span.TotalMinutes < 1) | ||
2772 | { | ||
2773 | int ms1 = span.Milliseconds; | ||
2774 | if (str.Length > 0) | ||
2775 | { | ||
2776 | ms1 /= 100; | ||
2777 | str += "."; | ||
2778 | } | ||
2779 | str += ms1.ToString("0"); | ||
2780 | } | ||
2781 | |||
2782 | str += " " + suffix; | ||
2783 | |||
2784 | return str; | ||
2785 | } | ||
2786 | |||
2787 | /// <summary> | ||
2035 | /// Prints the call stack at any given point. Useful for debugging. | 2788 | /// Prints the call stack at any given point. Useful for debugging. |
2036 | /// </summary> | 2789 | /// </summary> |
2037 | public static void PrintCallStack() | 2790 | public static void PrintCallStack() |
@@ -2098,7 +2851,7 @@ namespace OpenSim.Framework | |||
2098 | } | 2851 | } |
2099 | 2852 | ||
2100 | #region Xml Serialization Utilities | 2853 | #region Xml Serialization Utilities |
2101 | public static bool ReadBoolean(XmlTextReader reader) | 2854 | public static bool ReadBoolean(XmlReader reader) |
2102 | { | 2855 | { |
2103 | // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. | 2856 | // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. |
2104 | reader.ReadStartElement(); | 2857 | reader.ReadStartElement(); |
@@ -2109,7 +2862,7 @@ namespace OpenSim.Framework | |||
2109 | return result; | 2862 | return result; |
2110 | } | 2863 | } |
2111 | 2864 | ||
2112 | public static UUID ReadUUID(XmlTextReader reader, string name) | 2865 | public static UUID ReadUUID(XmlReader reader, string name) |
2113 | { | 2866 | { |
2114 | UUID id; | 2867 | UUID id; |
2115 | string idStr; | 2868 | string idStr; |
@@ -2128,7 +2881,7 @@ namespace OpenSim.Framework | |||
2128 | return id; | 2881 | return id; |
2129 | } | 2882 | } |
2130 | 2883 | ||
2131 | public static Vector3 ReadVector(XmlTextReader reader, string name) | 2884 | public static Vector3 ReadVector(XmlReader reader, string name) |
2132 | { | 2885 | { |
2133 | Vector3 vec; | 2886 | Vector3 vec; |
2134 | 2887 | ||
@@ -2141,7 +2894,7 @@ namespace OpenSim.Framework | |||
2141 | return vec; | 2894 | return vec; |
2142 | } | 2895 | } |
2143 | 2896 | ||
2144 | public static Quaternion ReadQuaternion(XmlTextReader reader, string name) | 2897 | public static Quaternion ReadQuaternion(XmlReader reader, string name) |
2145 | { | 2898 | { |
2146 | Quaternion quat = new Quaternion(); | 2899 | Quaternion quat = new Quaternion(); |
2147 | 2900 | ||
@@ -2170,7 +2923,7 @@ namespace OpenSim.Framework | |||
2170 | return quat; | 2923 | return quat; |
2171 | } | 2924 | } |
2172 | 2925 | ||
2173 | public static T ReadEnum<T>(XmlTextReader reader, string name) | 2926 | public static T ReadEnum<T>(XmlReader reader, string name) |
2174 | { | 2927 | { |
2175 | string value = reader.ReadElementContentAsString(name, String.Empty); | 2928 | string value = reader.ReadElementContentAsString(name, String.Empty); |
2176 | // !!!!! to deal with flags without commas | 2929 | // !!!!! to deal with flags without commas |
@@ -2182,7 +2935,9 @@ namespace OpenSim.Framework | |||
2182 | #endregion | 2935 | #endregion |
2183 | 2936 | ||
2184 | #region Universal User Identifiers | 2937 | #region Universal User Identifiers |
2185 | /// <summary> | 2938 | |
2939 | /// <summary> | ||
2940 | /// Attempts to parse a UUI into its components: UUID, name and URL. | ||
2186 | /// </summary> | 2941 | /// </summary> |
2187 | /// <param name="value">uuid[;endpoint[;first last[;secret]]]</param> | 2942 | /// <param name="value">uuid[;endpoint[;first last[;secret]]]</param> |
2188 | /// <param name="uuid">the uuid part</param> | 2943 | /// <param name="uuid">the uuid part</param> |
@@ -2218,6 +2973,27 @@ namespace OpenSim.Framework | |||
2218 | } | 2973 | } |
2219 | 2974 | ||
2220 | /// <summary> | 2975 | /// <summary> |
2976 | /// For foreign avatars, extracts their original name and Server URL from their First Name and Last Name. | ||
2977 | /// </summary> | ||
2978 | public static bool ParseForeignAvatarName(string firstname, string lastname, | ||
2979 | out string realFirstName, out string realLastName, out string serverURI) | ||
2980 | { | ||
2981 | realFirstName = realLastName = serverURI = string.Empty; | ||
2982 | |||
2983 | if (!lastname.Contains("@")) | ||
2984 | return false; | ||
2985 | |||
2986 | if (!firstname.Contains(".")) | ||
2987 | return false; | ||
2988 | |||
2989 | realFirstName = firstname.Split('.')[0]; | ||
2990 | realLastName = firstname.Split('.')[1]; | ||
2991 | serverURI = new Uri("http://" + lastname.Replace("@", "")).ToString(); | ||
2992 | |||
2993 | return true; | ||
2994 | } | ||
2995 | |||
2996 | /// <summary> | ||
2221 | /// Produces a universal (HG) system-facing identifier given the information | 2997 | /// Produces a universal (HG) system-facing identifier given the information |
2222 | /// </summary> | 2998 | /// </summary> |
2223 | /// <param name="acircuit"></param> | 2999 | /// <param name="acircuit"></param> |
@@ -2250,10 +3026,15 @@ namespace OpenSim.Framework | |||
2250 | { | 3026 | { |
2251 | string[] parts = firstName.Split(new char[] { '.' }); | 3027 | string[] parts = firstName.Split(new char[] { '.' }); |
2252 | if (parts.Length == 2) | 3028 | if (parts.Length == 2) |
2253 | return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; | 3029 | return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]); |
2254 | } | 3030 | } |
2255 | return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; | 3031 | |
3032 | return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName); | ||
3033 | } | ||
2256 | 3034 | ||
3035 | private static string CalcUniversalIdentifier(UUID id, string agentsURI, string name) | ||
3036 | { | ||
3037 | return id.ToString() + ";" + agentsURI + ";" + name; | ||
2257 | } | 3038 | } |
2258 | 3039 | ||
2259 | /// <summary> | 3040 | /// <summary> |
@@ -2288,6 +3069,48 @@ namespace OpenSim.Framework | |||
2288 | { | 3069 | { |
2289 | return str.Replace("_", "\\_").Replace("%", "\\%"); | 3070 | return str.Replace("_", "\\_").Replace("%", "\\%"); |
2290 | } | 3071 | } |
3072 | |||
3073 | /// <summary> | ||
3074 | /// Returns the name of the user's viewer. | ||
3075 | /// </summary> | ||
3076 | /// <remarks> | ||
3077 | /// This method handles two ways that viewers specify their name: | ||
3078 | /// 1. Viewer = "Firestorm-Release 4.4.2.34167", Channel = "(don't care)" -> "Firestorm-Release 4.4.2.34167" | ||
3079 | /// 2. Viewer = "4.5.1.38838", Channel = "Firestorm-Beta" -> "Firestorm-Beta 4.5.1.38838" | ||
3080 | /// </remarks> | ||
3081 | public static string GetViewerName(AgentCircuitData agent) | ||
3082 | { | ||
3083 | string name = agent.Viewer; | ||
3084 | if (name == null) | ||
3085 | name = ""; | ||
3086 | else | ||
3087 | name = name.Trim(); | ||
3088 | |||
3089 | // Check if 'Viewer' is just a version number. If it's *not*, then we | ||
3090 | // assume that it contains the real viewer name, and we return it. | ||
3091 | foreach (char c in name) | ||
3092 | { | ||
3093 | if (Char.IsLetter(c)) | ||
3094 | return name; | ||
3095 | } | ||
3096 | |||
3097 | // The 'Viewer' string contains just a version number. If there's anything in | ||
3098 | // 'Channel' then assume that it's the viewer name. | ||
3099 | if ((agent.Channel != null) && (agent.Channel.Length > 0)) | ||
3100 | name = agent.Channel.Trim() + " " + name; | ||
3101 | |||
3102 | return name; | ||
3103 | } | ||
3104 | |||
3105 | public static void LogFailedXML(string message, string xml) | ||
3106 | { | ||
3107 | int length = xml.Length; | ||
3108 | if (length > 2000) | ||
3109 | xml = xml.Substring(0, 2000) + "..."; | ||
3110 | |||
3111 | m_log.ErrorFormat("{0} Failed XML ({1} bytes) = {2}", message, length, xml); | ||
3112 | } | ||
3113 | |||
2291 | } | 3114 | } |
2292 | 3115 | ||
2293 | public class DoubleQueue<T> where T:class | 3116 | public class DoubleQueue<T> where T:class |
@@ -2304,7 +3127,11 @@ namespace OpenSim.Framework | |||
2304 | 3127 | ||
2305 | public virtual int Count | 3128 | public virtual int Count |
2306 | { | 3129 | { |
2307 | get { return m_highQueue.Count + m_lowQueue.Count; } | 3130 | get |
3131 | { | ||
3132 | lock (m_syncRoot) | ||
3133 | return m_highQueue.Count + m_lowQueue.Count; | ||
3134 | } | ||
2308 | } | 3135 | } |
2309 | 3136 | ||
2310 | public virtual void Enqueue(T data) | 3137 | public virtual void Enqueue(T data) |
@@ -2397,4 +3224,55 @@ namespace OpenSim.Framework | |||
2397 | } | 3224 | } |
2398 | } | 3225 | } |
2399 | } | 3226 | } |
3227 | |||
3228 | public class BetterRandom | ||
3229 | { | ||
3230 | private const int BufferSize = 1024; // must be a multiple of 4 | ||
3231 | private byte[] RandomBuffer; | ||
3232 | private int BufferOffset; | ||
3233 | private RNGCryptoServiceProvider rng; | ||
3234 | public BetterRandom() | ||
3235 | { | ||
3236 | RandomBuffer = new byte[BufferSize]; | ||
3237 | rng = new RNGCryptoServiceProvider(); | ||
3238 | BufferOffset = RandomBuffer.Length; | ||
3239 | } | ||
3240 | private void FillBuffer() | ||
3241 | { | ||
3242 | rng.GetBytes(RandomBuffer); | ||
3243 | BufferOffset = 0; | ||
3244 | } | ||
3245 | public int Next() | ||
3246 | { | ||
3247 | if (BufferOffset >= RandomBuffer.Length) | ||
3248 | { | ||
3249 | FillBuffer(); | ||
3250 | } | ||
3251 | int val = BitConverter.ToInt32(RandomBuffer, BufferOffset) & 0x7fffffff; | ||
3252 | BufferOffset += sizeof(int); | ||
3253 | return val; | ||
3254 | } | ||
3255 | public int Next(int maxValue) | ||
3256 | { | ||
3257 | return Next() % maxValue; | ||
3258 | } | ||
3259 | public int Next(int minValue, int maxValue) | ||
3260 | { | ||
3261 | if (maxValue < minValue) | ||
3262 | { | ||
3263 | throw new ArgumentOutOfRangeException("maxValue must be greater than or equal to minValue"); | ||
3264 | } | ||
3265 | int range = maxValue - minValue; | ||
3266 | return minValue + Next(range); | ||
3267 | } | ||
3268 | public double NextDouble() | ||
3269 | { | ||
3270 | int val = Next(); | ||
3271 | return (double)val / int.MaxValue; | ||
3272 | } | ||
3273 | public void GetBytes(byte[] buff) | ||
3274 | { | ||
3275 | rng.GetBytes(buff); | ||
3276 | } | ||
3277 | } | ||
2400 | } | 3278 | } |
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/VersionInfo.cs index 33b1366..ea99444 100644 --- a/OpenSim/Framework/Servers/VersionInfo.cs +++ b/OpenSim/Framework/VersionInfo.cs | |||
@@ -29,7 +29,11 @@ namespace OpenSim | |||
29 | { | 29 | { |
30 | public class VersionInfo | 30 | public class VersionInfo |
31 | { | 31 | { |
32 | <<<<<<< HEAD:OpenSim/Framework/VersionInfo.cs | ||
33 | public const string VersionNumber = "0.8.2.0"; | ||
34 | ======= | ||
32 | private const string VERSION_NUMBER = "0.8.0CM"; | 35 | private const string VERSION_NUMBER = "0.8.0CM"; |
36 | >>>>>>> avn/ubitvar:OpenSim/Framework/Servers/VersionInfo.cs | ||
33 | private const Flavour VERSION_FLAVOUR = Flavour.Dev; | 37 | private const Flavour VERSION_FLAVOUR = Flavour.Dev; |
34 | 38 | ||
35 | public enum Flavour | 39 | public enum Flavour |
@@ -38,6 +42,7 @@ namespace OpenSim | |||
38 | Dev, | 42 | Dev, |
39 | RC1, | 43 | RC1, |
40 | RC2, | 44 | RC2, |
45 | RC3, | ||
41 | Release, | 46 | Release, |
42 | Post_Fixes, | 47 | Post_Fixes, |
43 | Extended | 48 | Extended |
@@ -45,7 +50,7 @@ namespace OpenSim | |||
45 | 50 | ||
46 | public static string Version | 51 | public static string Version |
47 | { | 52 | { |
48 | get { return GetVersionString(VERSION_NUMBER, VERSION_FLAVOUR); } | 53 | get { return GetVersionString(VersionNumber, VERSION_FLAVOUR); } |
49 | } | 54 | } |
50 | 55 | ||
51 | public static string GetVersionString(string versionNumber, Flavour flavour) | 56 | public static string GetVersionString(string versionNumber, Flavour flavour) |
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 3625a1f..94b5230 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,7 @@ 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; } |
68 | 73 | ||
69 | /// <summary> | 74 | /// <summary> |
70 | /// Control where OSD requests should be serialized per endpoint. | 75 | /// Control where OSD requests should be serialized per endpoint. |
@@ -89,8 +94,9 @@ namespace OpenSim.Framework | |||
89 | /// <remarks> | 94 | /// <remarks> |
90 | /// 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 |
91 | /// 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. | ||
92 | /// </remarks> | 98 | /// </remarks> |
93 | public const int MaxRequestDiagLength = 100; | 99 | public const int MaxRequestDiagLength = 200; |
94 | 100 | ||
95 | /// <summary> | 101 | /// <summary> |
96 | /// Dictionary of end points | 102 | /// Dictionary of end points |
@@ -125,88 +131,112 @@ namespace OpenSim.Framework | |||
125 | /// </summary> | 131 | /// </summary> |
126 | public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout) | 132 | public static OSDMap PutToServiceCompressed(string url, OSDMap data, int timeout) |
127 | { | 133 | { |
128 | return ServiceOSDRequest(url,data, "PUT", timeout, true); | 134 | return ServiceOSDRequest(url,data, "PUT", timeout, true, false); |
129 | } | 135 | } |
130 | 136 | ||
131 | public static OSDMap PutToService(string url, OSDMap data, int timeout) | 137 | public static OSDMap PutToService(string url, OSDMap data, int timeout) |
132 | { | 138 | { |
133 | return ServiceOSDRequest(url,data, "PUT", timeout, false); | 139 | return ServiceOSDRequest(url,data, "PUT", timeout, false, false); |
134 | } | 140 | } |
135 | 141 | ||
136 | public static OSDMap PostToService(string url, OSDMap data, int timeout) | 142 | public static OSDMap PostToService(string url, OSDMap data, int timeout, bool rpc) |
137 | { | 143 | { |
138 | return ServiceOSDRequest(url, data, "POST", timeout, false); | 144 | return ServiceOSDRequest(url, data, "POST", timeout, false, rpc); |
139 | } | 145 | } |
140 | 146 | ||
141 | public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout) | 147 | public static OSDMap PostToServiceCompressed(string url, OSDMap data, int timeout) |
142 | { | 148 | { |
143 | return ServiceOSDRequest(url, data, "POST", timeout, true); | 149 | return ServiceOSDRequest(url, data, "POST", timeout, true, false); |
144 | } | 150 | } |
145 | 151 | ||
146 | public static OSDMap GetFromService(string url, int timeout) | 152 | public static OSDMap GetFromService(string url, int timeout) |
147 | { | 153 | { |
148 | return ServiceOSDRequest(url, null, "GET", timeout, false); | 154 | return ServiceOSDRequest(url, null, "GET", timeout, false, false); |
149 | } | 155 | } |
150 | 156 | ||
151 | 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) |
152 | { | 158 | { |
153 | if (SerializeOSDRequestsPerEndpoint) | 159 | if (SerializeOSDRequestsPerEndpoint) |
154 | { | 160 | { |
155 | lock (EndPointLock(url)) | 161 | lock (EndPointLock(url)) |
156 | { | 162 | { |
157 | return ServiceOSDRequestWorker(url, data, method, timeout, compressed); | 163 | return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc); |
158 | } | 164 | } |
159 | } | 165 | } |
160 | else | 166 | else |
161 | { | 167 | { |
162 | return ServiceOSDRequestWorker(url, data, method, timeout, compressed); | 168 | return ServiceOSDRequestWorker(url, data, method, timeout, compressed, rpc); |
163 | } | 169 | } |
164 | } | 170 | } |
165 | 171 | ||
166 | public static void LogOutgoingDetail(Stream outputStream) | 172 | public static void LogOutgoingDetail(Stream outputStream) |
167 | { | 173 | { |
168 | using (StreamReader reader = new StreamReader(Util.Copy(outputStream), Encoding.UTF8)) | 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)) | ||
169 | { | 181 | { |
170 | string output; | 182 | string output; |
171 | 183 | ||
172 | if (DebugLevel == 5) | 184 | if (DebugLevel == 5) |
173 | { | 185 | { |
174 | const int sampleLength = 80; | 186 | char[] chars = new char[WebUtil.MaxRequestDiagLength + 1]; // +1 so we know to add "..." only if needed |
175 | char[] sampleChars = new char[sampleLength]; | 187 | int len = reader.Read(chars, 0, WebUtil.MaxRequestDiagLength + 1); |
176 | reader.Read(sampleChars, 0, sampleLength); | 188 | output = new string(chars, 0, len); |
177 | output = new string(sampleChars); | ||
178 | } | 189 | } |
179 | else | 190 | else |
180 | { | 191 | { |
181 | output = reader.ReadToEnd(); | 192 | output = reader.ReadToEnd(); |
182 | } | 193 | } |
183 | 194 | ||
184 | LogOutgoingDetail(output); | 195 | LogOutgoingDetail(context, output); |
185 | } | 196 | } |
186 | } | 197 | } |
187 | 198 | ||
188 | public static void LogOutgoingDetail(string output) | 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) | ||
189 | { | 205 | { |
190 | if (DebugLevel == 5) | 206 | if (DebugLevel == 5) |
191 | { | 207 | { |
208 | <<<<<<< HEAD | ||
209 | if (output.Length > MaxRequestDiagLength) | ||
210 | output = output.Substring(0, MaxRequestDiagLength) + "..."; | ||
211 | ======= | ||
192 | int len = output.Length; | 212 | int len = output.Length; |
193 | if(len > 80) | 213 | if(len > 80) |
194 | len = 80; | 214 | len = 80; |
195 | output = output.Substring(0, len); | 215 | output = output.Substring(0, len); |
196 | output = output + "..."; | 216 | output = output + "..."; |
217 | >>>>>>> avn/ubitvar | ||
197 | } | 218 | } |
198 | 219 | ||
199 | m_log.DebugFormat("[WEB UTIL]: {0}", output.Replace("\n", @"\n")); | 220 | m_log.DebugFormat("[LOGHTTP]: {0}{1}", context, Util.BinaryToASCII(output)); |
221 | } | ||
222 | |||
223 | public static void LogResponseDetail(int reqnum, Stream inputStream) | ||
224 | { | ||
225 | LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), inputStream); | ||
200 | } | 226 | } |
201 | 227 | ||
202 | private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) | 228 | public static void LogResponseDetail(int reqnum, string input) |
229 | { | ||
230 | LogOutgoingDetail(string.Format("RESPONSE {0}: ", reqnum), input); | ||
231 | } | ||
232 | |||
233 | private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed, bool rpc) | ||
203 | { | 234 | { |
204 | int reqnum = RequestNumber++; | 235 | int reqnum = RequestNumber++; |
205 | 236 | ||
206 | if (DebugLevel >= 3) | 237 | if (DebugLevel >= 3) |
207 | m_log.DebugFormat( | 238 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} JSON-RPC {1} to {2}", |
208 | "[WEB UTIL]: HTTP OUT {0} ServiceOSD {1} {2} (timeout {3}, compressed {4})", | 239 | reqnum, method, url); |
209 | reqnum, method, url, timeout, compressed); | ||
210 | 240 | ||
211 | string errorMessage = "unknown error"; | 241 | string errorMessage = "unknown error"; |
212 | int tickstart = Util.EnvironmentTickCount(); | 242 | int tickstart = Util.EnvironmentTickCount(); |
@@ -234,21 +264,24 @@ namespace OpenSim.Framework | |||
234 | tickJsondata = Util.EnvironmentTickCountSubtract(tickstart); | 264 | tickJsondata = Util.EnvironmentTickCountSubtract(tickstart); |
235 | 265 | ||
236 | if (DebugLevel >= 5) | 266 | if (DebugLevel >= 5) |
237 | LogOutgoingDetail(strBuffer); | 267 | LogOutgoingDetail("SEND", reqnum, strBuffer); |
238 | 268 | ||
239 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); | 269 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); |
240 | 270 | ||
271 | request.ContentType = rpc ? "application/json-rpc" : "application/json"; | ||
272 | |||
241 | if (compressed) | 273 | if (compressed) |
242 | { | 274 | { |
243 | request.ContentType = "application/x-gzip"; | 275 | request.Headers["X-Content-Encoding"] = "gzip"; // can't set "Content-Encoding" because old OpenSims fail if they get an unrecognized Content-Encoding |
276 | |||
244 | using (MemoryStream ms = new MemoryStream()) | 277 | using (MemoryStream ms = new MemoryStream()) |
245 | { | 278 | { |
246 | using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress)) | 279 | using (GZipStream comp = new GZipStream(ms, CompressionMode.Compress, true)) |
247 | { | 280 | { |
248 | comp.Write(buffer, 0, buffer.Length); | 281 | comp.Write(buffer, 0, buffer.Length); |
249 | // We need to close the gzip stream before we write it anywhere | 282 | // We need to close the gzip stream before we write it anywhere |
250 | // because apparently something important related to gzip compression | 283 | // because apparently something important related to gzip compression |
251 | // gets written on the strteam upon Dispose() | 284 | // gets written on the stream upon Dispose() |
252 | } | 285 | } |
253 | byte[] buf = ms.ToArray(); | 286 | byte[] buf = ms.ToArray(); |
254 | 287 | ||
@@ -262,12 +295,15 @@ namespace OpenSim.Framework | |||
262 | } | 295 | } |
263 | else | 296 | else |
264 | { | 297 | { |
298 | <<<<<<< HEAD | ||
299 | ======= | ||
265 | tickcompressdata = tickJsondata; | 300 | tickcompressdata = tickJsondata; |
266 | compsize = buffer.Length; | 301 | compsize = buffer.Length; |
267 | request.ContentType = "application/json"; | 302 | request.ContentType = "application/json"; |
303 | >>>>>>> avn/ubitvar | ||
268 | request.ContentLength = buffer.Length; //Count bytes to send | 304 | request.ContentLength = buffer.Length; //Count bytes to send |
269 | using (Stream requestStream = request.GetRequestStream()) | 305 | using (Stream requestStream = request.GetRequestStream()) |
270 | requestStream.Write(buffer, 0, buffer.Length); //Send it | 306 | requestStream.Write(buffer, 0, buffer.Length); //Send it |
271 | } | 307 | } |
272 | } | 308 | } |
273 | 309 | ||
@@ -279,10 +315,20 @@ namespace OpenSim.Framework | |||
279 | { | 315 | { |
280 | using (Stream responseStream = response.GetResponseStream()) | 316 | using (Stream responseStream = response.GetResponseStream()) |
281 | { | 317 | { |
318 | <<<<<<< HEAD | ||
319 | using (StreamReader reader = new StreamReader(responseStream)) | ||
320 | { | ||
321 | string responseStr = reader.ReadToEnd(); | ||
322 | if (WebUtil.DebugLevel >= 5) | ||
323 | WebUtil.LogResponseDetail(reqnum, responseStr); | ||
324 | return CanonicalizeResults(responseStr); | ||
325 | } | ||
326 | ======= | ||
282 | string responseStr = null; | 327 | string responseStr = null; |
283 | responseStr = responseStream.GetStreamString(); | 328 | responseStr = responseStream.GetStreamString(); |
284 | //m_log.DebugFormat("[WEB UTIL]: <{0}> response is <{1}>",reqnum,responseStr); | 329 | //m_log.DebugFormat("[WEB UTIL]: <{0}> response is <{1}>",reqnum,responseStr); |
285 | return CanonicalizeResults(responseStr); | 330 | return CanonicalizeResults(responseStr); |
331 | >>>>>>> avn/ubitvar | ||
286 | } | 332 | } |
287 | } | 333 | } |
288 | } | 334 | } |
@@ -304,7 +350,12 @@ namespace OpenSim.Framework | |||
304 | { | 350 | { |
305 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | 351 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); |
306 | if (tickdiff > LongCallTime) | 352 | if (tickdiff > LongCallTime) |
353 | { | ||
307 | m_log.InfoFormat( | 354 | m_log.InfoFormat( |
355 | <<<<<<< HEAD | ||
356 | "[LOGHTTP]: Slow JSON-RPC request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", | ||
357 | reqnum, method, url, tickdiff, tickdata, | ||
358 | ======= | ||
308 | "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing({5} at Json; {6} at comp), {7} bytes ({8} uncomp): {9}", | 359 | "[WEB UTIL]: Slow ServiceOSD request {0} {1} {2} took {3}ms, {4}ms writing({5} at Json; {6} at comp), {7} bytes ({8} uncomp): {9}", |
309 | reqnum, | 360 | reqnum, |
310 | method, | 361 | method, |
@@ -315,17 +366,20 @@ namespace OpenSim.Framework | |||
315 | tickcompressdata, | 366 | tickcompressdata, |
316 | compsize, | 367 | compsize, |
317 | strBuffer != null ? strBuffer.Length : 0, | 368 | strBuffer != null ? strBuffer.Length : 0, |
369 | >>>>>>> avn/ubitvar | ||
318 | strBuffer != null | 370 | strBuffer != null |
319 | ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) | 371 | ? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer) |
320 | : ""); | 372 | : ""); |
373 | } | ||
321 | else if (DebugLevel >= 4) | 374 | else if (DebugLevel >= 4) |
322 | m_log.DebugFormat( | 375 | { |
323 | "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", | 376 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", |
324 | reqnum, tickdiff, tickdata); | 377 | reqnum, tickdiff, tickdata); |
378 | } | ||
325 | } | 379 | } |
326 | 380 | ||
327 | m_log.DebugFormat( | 381 | m_log.DebugFormat( |
328 | "[WEB UTIL]: ServiceOSD request {0} {1} {2} FAILED: {3}", reqnum, url, method, errorMessage); | 382 | "[LOGHTTP]: JSON-RPC request {0} {1} to {2} FAILED: {3}", reqnum, method, url, errorMessage); |
329 | 383 | ||
330 | return ErrorResponseMap(errorMessage); | 384 | return ErrorResponseMap(errorMessage); |
331 | } | 385 | } |
@@ -403,9 +457,8 @@ namespace OpenSim.Framework | |||
403 | string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; | 457 | string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; |
404 | 458 | ||
405 | if (DebugLevel >= 3) | 459 | if (DebugLevel >= 3) |
406 | m_log.DebugFormat( | 460 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} ServiceForm '{1}' to {2}", |
407 | "[WEB UTIL]: HTTP OUT {0} ServiceForm {1} {2} (timeout {3})", | 461 | reqnum, method, url); |
408 | reqnum, method, url, timeout); | ||
409 | 462 | ||
410 | string errorMessage = "unknown error"; | 463 | string errorMessage = "unknown error"; |
411 | int tickstart = Util.EnvironmentTickCount(); | 464 | int tickstart = Util.EnvironmentTickCount(); |
@@ -427,7 +480,7 @@ namespace OpenSim.Framework | |||
427 | queryString = BuildQueryString(data); | 480 | queryString = BuildQueryString(data); |
428 | 481 | ||
429 | if (DebugLevel >= 5) | 482 | if (DebugLevel >= 5) |
430 | LogOutgoingDetail(queryString); | 483 | LogOutgoingDetail("SEND", reqnum, queryString); |
431 | 484 | ||
432 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); | 485 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); |
433 | 486 | ||
@@ -445,12 +498,16 @@ namespace OpenSim.Framework | |||
445 | { | 498 | { |
446 | using (Stream responseStream = response.GetResponseStream()) | 499 | using (Stream responseStream = response.GetResponseStream()) |
447 | { | 500 | { |
448 | string responseStr = null; | 501 | using (StreamReader reader = new StreamReader(responseStream)) |
502 | { | ||
503 | string responseStr = reader.ReadToEnd(); | ||
504 | if (WebUtil.DebugLevel >= 5) | ||
505 | WebUtil.LogResponseDetail(reqnum, responseStr); | ||
506 | OSD responseOSD = OSDParser.Deserialize(responseStr); | ||
449 | 507 | ||
450 | responseStr = responseStream.GetStreamString(); | 508 | if (responseOSD.Type == OSDType.Map) |
451 | OSD responseOSD = OSDParser.Deserialize(responseStr); | 509 | return (OSDMap)responseOSD; |
452 | if (responseOSD.Type == OSDType.Map) | 510 | } |
453 | return (OSDMap)responseOSD; | ||
454 | } | 511 | } |
455 | } | 512 | } |
456 | } | 513 | } |
@@ -471,23 +528,22 @@ namespace OpenSim.Framework | |||
471 | { | 528 | { |
472 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | 529 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); |
473 | if (tickdiff > LongCallTime) | 530 | if (tickdiff > LongCallTime) |
531 | { | ||
474 | m_log.InfoFormat( | 532 | m_log.InfoFormat( |
475 | "[WEB UTIL]: Slow ServiceForm request {0} {1} {2} took {3}ms, {4}ms writing, {5}", | 533 | "[LOGHTTP]: Slow ServiceForm request {0} '{1}' to {2} took {3}ms, {4}ms writing, {5}", |
476 | reqnum, | 534 | reqnum, method, url, tickdiff, tickdata, |
477 | method, | ||
478 | url, | ||
479 | tickdiff, | ||
480 | tickdata, | ||
481 | queryString != null | 535 | queryString != null |
482 | ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString | 536 | ? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString |
483 | : ""); | 537 | : ""); |
538 | } | ||
484 | else if (DebugLevel >= 4) | 539 | else if (DebugLevel >= 4) |
485 | m_log.DebugFormat( | 540 | { |
486 | "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", | 541 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", |
487 | reqnum, tickdiff, tickdata); | 542 | reqnum, tickdiff, tickdata); |
543 | } | ||
488 | } | 544 | } |
489 | 545 | ||
490 | m_log.WarnFormat("[WEB UTIL]: ServiceForm request {0} {1} {2} failed: {2}", reqnum, method, url, errorMessage); | 546 | m_log.WarnFormat("[LOGHTTP]: ServiceForm request {0} '{1}' to {2} failed: {3}", reqnum, method, url, errorMessage); |
491 | 547 | ||
492 | return ErrorResponseMap(errorMessage); | 548 | return ErrorResponseMap(errorMessage); |
493 | } | 549 | } |
@@ -664,38 +720,6 @@ namespace OpenSim.Framework | |||
664 | return totalCopiedBytes; | 720 | return totalCopiedBytes; |
665 | } | 721 | } |
666 | 722 | ||
667 | /// <summary> | ||
668 | /// Converts an entire stream to a string, regardless of current stream | ||
669 | /// position | ||
670 | /// </summary> | ||
671 | /// <param name="stream">The stream to convert to a string</param> | ||
672 | /// <returns></returns> | ||
673 | /// <remarks>When this method is done, the stream position will be | ||
674 | /// reset to its previous position before this method was called</remarks> | ||
675 | public static string GetStreamString(this Stream stream) | ||
676 | { | ||
677 | string value = null; | ||
678 | |||
679 | if (stream != null && stream.CanRead) | ||
680 | { | ||
681 | long rewindPos = -1; | ||
682 | |||
683 | if (stream.CanSeek) | ||
684 | { | ||
685 | rewindPos = stream.Position; | ||
686 | stream.Seek(0, SeekOrigin.Begin); | ||
687 | } | ||
688 | |||
689 | StreamReader reader = new StreamReader(stream); | ||
690 | value = reader.ReadToEnd(); | ||
691 | |||
692 | if (rewindPos >= 0) | ||
693 | stream.Seek(rewindPos, SeekOrigin.Begin); | ||
694 | } | ||
695 | |||
696 | return value; | ||
697 | } | ||
698 | |||
699 | #endregion Stream | 723 | #endregion Stream |
700 | 724 | ||
701 | public class QBasedComparer : IComparer | 725 | public class QBasedComparer : IComparer |
@@ -796,11 +820,17 @@ namespace OpenSim.Framework | |||
796 | string requestUrl, TRequest obj, Action<TResponse> action, | 820 | string requestUrl, TRequest obj, Action<TResponse> action, |
797 | int maxConnections) | 821 | int maxConnections) |
798 | { | 822 | { |
823 | MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, action, maxConnections, null); | ||
824 | } | ||
825 | |||
826 | public static void MakeRequest<TRequest, TResponse>(string verb, | ||
827 | string requestUrl, TRequest obj, Action<TResponse> action, | ||
828 | int maxConnections, IServiceAuth auth) | ||
829 | { | ||
799 | int reqnum = WebUtil.RequestNumber++; | 830 | int reqnum = WebUtil.RequestNumber++; |
800 | 831 | ||
801 | if (WebUtil.DebugLevel >= 3) | 832 | if (WebUtil.DebugLevel >= 3) |
802 | m_log.DebugFormat( | 833 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} AsynchronousRequestObject {1} to {2}", |
803 | "[WEB UTIL]: HTTP OUT {0} AsynchronousRequestObject {1} {2}", | ||
804 | reqnum, verb, requestUrl); | 834 | reqnum, verb, requestUrl); |
805 | 835 | ||
806 | int tickstart = Util.EnvironmentTickCount(); | 836 | int tickstart = Util.EnvironmentTickCount(); |
@@ -811,125 +841,170 @@ namespace OpenSim.Framework | |||
811 | 841 | ||
812 | WebRequest request = WebRequest.Create(requestUrl); | 842 | WebRequest request = WebRequest.Create(requestUrl); |
813 | HttpWebRequest ht = (HttpWebRequest)request; | 843 | HttpWebRequest ht = (HttpWebRequest)request; |
844 | |||
845 | if (auth != null) | ||
846 | auth.AddAuthorization(ht.Headers); | ||
847 | |||
814 | if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) | 848 | if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) |
815 | ht.ServicePoint.ConnectionLimit = maxConnections; | 849 | ht.ServicePoint.ConnectionLimit = maxConnections; |
816 | 850 | ||
817 | WebResponse response = null; | ||
818 | TResponse deserial = default(TResponse); | 851 | TResponse deserial = default(TResponse); |
819 | XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); | ||
820 | 852 | ||
821 | request.Method = verb; | 853 | request.Method = verb; |
854 | |||
822 | MemoryStream buffer = null; | 855 | MemoryStream buffer = null; |
823 | 856 | ||
824 | if (verb == "POST") | 857 | try |
825 | { | 858 | { |
826 | request.ContentType = "text/xml"; | 859 | if (verb == "POST") |
827 | |||
828 | buffer = new MemoryStream(); | ||
829 | |||
830 | XmlWriterSettings settings = new XmlWriterSettings(); | ||
831 | settings.Encoding = Encoding.UTF8; | ||
832 | |||
833 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
834 | { | 860 | { |
835 | XmlSerializer serializer = new XmlSerializer(type); | 861 | request.ContentType = "text/xml"; |
836 | serializer.Serialize(writer, obj); | ||
837 | writer.Flush(); | ||
838 | } | ||
839 | 862 | ||
840 | int length = (int)buffer.Length; | 863 | buffer = new MemoryStream(); |
841 | request.ContentLength = length; | ||
842 | 864 | ||
843 | if (WebUtil.DebugLevel >= 5) | 865 | XmlWriterSettings settings = new XmlWriterSettings(); |
844 | WebUtil.LogOutgoingDetail(buffer); | 866 | settings.Encoding = Encoding.UTF8; |
845 | 867 | ||
846 | request.BeginGetRequestStream(delegate(IAsyncResult res) | 868 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) |
847 | { | 869 | { |
848 | Stream requestStream = request.EndGetRequestStream(res); | 870 | XmlSerializer serializer = new XmlSerializer(type); |
871 | serializer.Serialize(writer, obj); | ||
872 | writer.Flush(); | ||
873 | } | ||
874 | |||
875 | int length = (int)buffer.Length; | ||
876 | request.ContentLength = length; | ||
877 | byte[] data = buffer.ToArray(); | ||
849 | 878 | ||
850 | requestStream.Write(buffer.ToArray(), 0, length); | 879 | <<<<<<< HEAD |
851 | requestStream.Close(); | 880 | if (WebUtil.DebugLevel >= 5) |
881 | WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); | ||
852 | 882 | ||
883 | request.BeginGetRequestStream(delegate(IAsyncResult res) | ||
884 | ======= | ||
853 | // capture how much time was spent writing | 885 | // capture how much time was spent writing |
854 | // useless in this async | 886 | // useless in this async |
855 | // tickdata = Util.EnvironmentTickCountSubtract(tickstart); | 887 | // tickdata = Util.EnvironmentTickCountSubtract(tickstart); |
856 | request.BeginGetResponse(delegate(IAsyncResult ar) | 888 | request.BeginGetResponse(delegate(IAsyncResult ar) |
889 | >>>>>>> avn/ubitvar | ||
857 | { | 890 | { |
858 | response = request.EndGetResponse(ar); | 891 | using (Stream requestStream = request.EndGetRequestStream(res)) |
859 | Stream respStream = null; | 892 | requestStream.Write(data, 0, length); |
860 | try | 893 | |
861 | { | 894 | // capture how much time was spent writing |
862 | respStream = response.GetResponseStream(); | 895 | tickdata = Util.EnvironmentTickCountSubtract(tickstart); |
863 | deserial = (TResponse)deserializer.Deserialize( | 896 | |
864 | respStream); | 897 | request.BeginGetResponse(delegate(IAsyncResult ar) |
865 | } | ||
866 | catch (System.InvalidOperationException) | ||
867 | { | ||
868 | } | ||
869 | finally | ||
870 | { | 898 | { |
899 | <<<<<<< HEAD | ||
900 | using (WebResponse response = request.EndGetResponse(ar)) | ||
901 | { | ||
902 | try | ||
903 | { | ||
904 | using (Stream respStream = response.GetResponseStream()) | ||
905 | { | ||
906 | deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>( | ||
907 | reqnum, respStream, response.ContentLength); | ||
908 | } | ||
909 | } | ||
910 | catch (System.InvalidOperationException) | ||
911 | { | ||
912 | } | ||
913 | } | ||
914 | ======= | ||
871 | // Let's not close this | 915 | // Let's not close this |
872 | // yes do close it | 916 | // yes do close it |
873 | buffer.Close(); | 917 | buffer.Close(); |
874 | respStream.Close(); | 918 | respStream.Close(); |
875 | response.Close(); | 919 | response.Close(); |
876 | } | 920 | } |
921 | >>>>>>> avn/ubitvar | ||
877 | 922 | ||
878 | action(deserial); | 923 | action(deserial); |
879 | 924 | ||
925 | }, null); | ||
880 | }, null); | 926 | }, null); |
881 | }, null); | 927 | } |
882 | } | 928 | else |
883 | else | ||
884 | { | ||
885 | request.BeginGetResponse(delegate(IAsyncResult res2) | ||
886 | { | 929 | { |
887 | try | 930 | request.BeginGetResponse(delegate(IAsyncResult res2) |
888 | { | 931 | { |
889 | // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't | ||
890 | // documented in MSDN | ||
891 | response = request.EndGetResponse(res2); | ||
892 | |||
893 | Stream respStream = null; | ||
894 | try | 932 | try |
895 | { | 933 | { |
896 | respStream = response.GetResponseStream(); | 934 | // If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't |
897 | deserial = (TResponse)deserializer.Deserialize(respStream); | 935 | // documented in MSDN |
898 | } | 936 | using (WebResponse response = request.EndGetResponse(res2)) |
899 | catch (System.InvalidOperationException) | 937 | { |
900 | { | 938 | try |
901 | } | 939 | { |
902 | finally | 940 | using (Stream respStream = response.GetResponseStream()) |
903 | { | 941 | { |
904 | respStream.Close(); | 942 | deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>( |
905 | response.Close(); | 943 | reqnum, respStream, response.ContentLength); |
944 | } | ||
945 | } | ||
946 | catch (System.InvalidOperationException) | ||
947 | { | ||
948 | } | ||
949 | } | ||
906 | } | 950 | } |
907 | } | 951 | catch (WebException e) |
908 | catch (WebException e) | ||
909 | { | ||
910 | if (e.Status == WebExceptionStatus.ProtocolError) | ||
911 | { | 952 | { |
912 | if (e.Response is HttpWebResponse) | 953 | if (e.Status == WebExceptionStatus.ProtocolError) |
913 | { | 954 | { |
914 | using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response) | 955 | if (e.Response is HttpWebResponse) |
915 | { | 956 | { |
916 | if (httpResponse.StatusCode != HttpStatusCode.NotFound) | 957 | using (HttpWebResponse httpResponse = (HttpWebResponse)e.Response) |
917 | { | 958 | { |
918 | // We don't appear to be handling any other status codes, so log these feailures to that | 959 | if (httpResponse.StatusCode != HttpStatusCode.NotFound) |
919 | // people don't spend unnecessary hours hunting phantom bugs. | 960 | { |
920 | m_log.DebugFormat( | 961 | // We don't appear to be handling any other status codes, so log these feailures to that |
921 | "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", | 962 | // people don't spend unnecessary hours hunting phantom bugs. |
922 | verb, requestUrl, httpResponse.StatusCode); | 963 | m_log.DebugFormat( |
964 | "[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}", | ||
965 | verb, requestUrl, httpResponse.StatusCode); | ||
966 | } | ||
923 | } | 967 | } |
924 | } | 968 | } |
925 | } | 969 | } |
970 | else | ||
971 | { | ||
972 | m_log.ErrorFormat( | ||
973 | "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", | ||
974 | verb, requestUrl, e.Status, e.Message); | ||
975 | } | ||
926 | } | 976 | } |
927 | else | 977 | catch (Exception e) |
978 | { | ||
979 | m_log.ErrorFormat( | ||
980 | "[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}", | ||
981 | verb, requestUrl, e.Message, e.StackTrace); | ||
982 | } | ||
983 | <<<<<<< HEAD | ||
984 | |||
985 | // m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString()); | ||
986 | |||
987 | try | ||
988 | { | ||
989 | action(deserial); | ||
990 | } | ||
991 | catch (Exception e) | ||
928 | { | 992 | { |
929 | m_log.ErrorFormat( | 993 | m_log.ErrorFormat( |
930 | "[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", | 994 | "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}", |
931 | verb, requestUrl, e.Status, e.Message); | 995 | verb, requestUrl, e.Message, e.StackTrace); |
932 | } | 996 | } |
997 | |||
998 | }, null); | ||
999 | } | ||
1000 | |||
1001 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | ||
1002 | if (tickdiff > WebUtil.LongCallTime) | ||
1003 | { | ||
1004 | string originalRequest = null; | ||
1005 | |||
1006 | if (buffer != null) | ||
1007 | ======= | ||
933 | } | 1008 | } |
934 | catch (Exception e) | 1009 | catch (Exception e) |
935 | { | 1010 | { |
@@ -944,28 +1019,39 @@ namespace OpenSim.Framework | |||
944 | action(deserial); | 1019 | action(deserial); |
945 | } | 1020 | } |
946 | catch (Exception e) | 1021 | catch (Exception e) |
1022 | >>>>>>> avn/ubitvar | ||
947 | { | 1023 | { |
948 | m_log.ErrorFormat( | 1024 | originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); |
949 | "[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}", | ||
950 | verb, requestUrl, e.Message, e.StackTrace); | ||
951 | } | ||
952 | |||
953 | }, null); | ||
954 | } | ||
955 | 1025 | ||
1026 | <<<<<<< HEAD | ||
1027 | if (originalRequest.Length > WebUtil.MaxRequestDiagLength) | ||
1028 | originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); | ||
1029 | } | ||
1030 | ======= | ||
956 | tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | 1031 | tickdiff = Util.EnvironmentTickCountSubtract(tickstart); |
957 | if (tickdiff > WebUtil.LongCallTime) | 1032 | if (tickdiff > WebUtil.LongCallTime) |
958 | { | 1033 | { |
959 | /* | 1034 | /* |
960 | string originalRequest = null; | 1035 | string originalRequest = null; |
1036 | >>>>>>> avn/ubitvar | ||
961 | 1037 | ||
962 | if (buffer != null) | 1038 | m_log.InfoFormat( |
1039 | "[LOGHTTP]: Slow AsynchronousRequestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", | ||
1040 | reqnum, verb, requestUrl, tickdiff, tickdata, | ||
1041 | originalRequest); | ||
1042 | } | ||
1043 | else if (WebUtil.DebugLevel >= 4) | ||
963 | { | 1044 | { |
964 | originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); | 1045 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", |
965 | 1046 | reqnum, tickdiff, tickdata); | |
966 | if (originalRequest.Length > WebUtil.MaxRequestDiagLength) | ||
967 | originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); | ||
968 | } | 1047 | } |
1048 | <<<<<<< HEAD | ||
1049 | } | ||
1050 | finally | ||
1051 | { | ||
1052 | if (buffer != null) | ||
1053 | buffer.Dispose(); | ||
1054 | ======= | ||
969 | 1055 | ||
970 | m_log.InfoFormat( | 1056 | m_log.InfoFormat( |
971 | "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", | 1057 | "[ASYNC REQUEST]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", |
@@ -988,6 +1074,7 @@ namespace OpenSim.Framework | |||
988 | m_log.DebugFormat( | 1074 | m_log.DebugFormat( |
989 | "[WEB UTIL]: HTTP OUT {0} took {1}ms", | 1075 | "[WEB UTIL]: HTTP OUT {0} took {1}ms", |
990 | reqnum, tickdiff); | 1076 | reqnum, tickdiff); |
1077 | >>>>>>> avn/ubitvar | ||
991 | } | 1078 | } |
992 | } | 1079 | } |
993 | } | 1080 | } |
@@ -1007,13 +1094,12 @@ namespace OpenSim.Framework | |||
1007 | /// | 1094 | /// |
1008 | /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting | 1095 | /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting |
1009 | /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> | 1096 | /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> |
1010 | public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs) | 1097 | public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs, IServiceAuth auth) |
1011 | { | 1098 | { |
1012 | int reqnum = WebUtil.RequestNumber++; | 1099 | int reqnum = WebUtil.RequestNumber++; |
1013 | 1100 | ||
1014 | if (WebUtil.DebugLevel >= 3) | 1101 | if (WebUtil.DebugLevel >= 3) |
1015 | m_log.DebugFormat( | 1102 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestForms {1} to {2}", |
1016 | "[WEB UTIL]: HTTP OUT {0} SynchronousRestForms {1} {2}", | ||
1017 | reqnum, verb, requestUrl); | 1103 | reqnum, verb, requestUrl); |
1018 | 1104 | ||
1019 | int tickstart = Util.EnvironmentTickCount(); | 1105 | int tickstart = Util.EnvironmentTickCount(); |
@@ -1023,6 +1109,10 @@ namespace OpenSim.Framework | |||
1023 | request.Method = verb; | 1109 | request.Method = verb; |
1024 | if (timeoutsecs > 0) | 1110 | if (timeoutsecs > 0) |
1025 | request.Timeout = timeoutsecs * 1000; | 1111 | request.Timeout = timeoutsecs * 1000; |
1112 | |||
1113 | if (auth != null) | ||
1114 | auth.AddAuthorization(request.Headers); | ||
1115 | |||
1026 | string respstring = String.Empty; | 1116 | string respstring = String.Empty; |
1027 | 1117 | ||
1028 | int tickset = Util.EnvironmentTickCountSubtract(tickstart); | 1118 | int tickset = Util.EnvironmentTickCountSubtract(tickstart); |
@@ -1044,23 +1134,30 @@ namespace OpenSim.Framework | |||
1044 | 1134 | ||
1045 | length = (int)obj.Length; | 1135 | length = (int)obj.Length; |
1046 | request.ContentLength = length; | 1136 | request.ContentLength = length; |
1137 | byte[] data = buffer.ToArray(); | ||
1047 | 1138 | ||
1139 | <<<<<<< HEAD | ||
1140 | if (WebUtil.DebugLevel >= 5) | ||
1141 | WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); | ||
1142 | ======= | ||
1143 | >>>>>>> avn/ubitvar | ||
1048 | 1144 | ||
1049 | Stream requestStream = null; | 1145 | Stream requestStream = null; |
1050 | try | 1146 | try |
1051 | { | 1147 | { |
1052 | requestStream = request.GetRequestStream(); | 1148 | requestStream = request.GetRequestStream(); |
1053 | requestStream.Write(buffer.ToArray(), 0, length); | 1149 | requestStream.Write(data, 0, length); |
1054 | } | 1150 | } |
1055 | catch (Exception e) | 1151 | catch (Exception e) |
1056 | { | 1152 | { |
1057 | m_log.DebugFormat( | 1153 | m_log.InfoFormat("[FORMS]: Error sending request to {0}: {1}. Request: {2}", requestUrl, e.Message, |
1058 | "[FORMS]: exception occured {0} {1}: {2}{3}", verb, requestUrl, e.Message, e.StackTrace); | 1154 | obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); |
1155 | throw e; | ||
1059 | } | 1156 | } |
1060 | finally | 1157 | finally |
1061 | { | 1158 | { |
1062 | if (requestStream != null) | 1159 | if (requestStream != null) |
1063 | requestStream.Close(); | 1160 | requestStream.Dispose(); |
1064 | 1161 | ||
1065 | // capture how much time was spent writing | 1162 | // capture how much time was spent writing |
1066 | tickdata = Util.EnvironmentTickCountSubtract(tickstart); | 1163 | tickdata = Util.EnvironmentTickCountSubtract(tickstart); |
@@ -1073,37 +1170,28 @@ namespace OpenSim.Framework | |||
1073 | { | 1170 | { |
1074 | if (resp.ContentLength != 0) | 1171 | if (resp.ContentLength != 0) |
1075 | { | 1172 | { |
1076 | Stream respStream = null; | 1173 | using (Stream respStream = resp.GetResponseStream()) |
1077 | try | 1174 | using (StreamReader reader = new StreamReader(respStream)) |
1078 | { | 1175 | respstring = reader.ReadToEnd(); |
1079 | using (respStream = resp.GetResponseStream()) | ||
1080 | using (StreamReader reader = new StreamReader(respStream)) | ||
1081 | respstring = reader.ReadToEnd(); | ||
1082 | } | ||
1083 | catch (Exception e) | ||
1084 | { | ||
1085 | m_log.DebugFormat( | ||
1086 | "[FORMS]: Exception occured on receiving {0} {1}: {2}{3}", | ||
1087 | verb, requestUrl, e.Message, e.StackTrace); | ||
1088 | } | ||
1089 | finally | ||
1090 | { | ||
1091 | if (respStream != null) | ||
1092 | respStream.Close(); | ||
1093 | } | ||
1094 | } | 1176 | } |
1095 | } | 1177 | } |
1096 | } | 1178 | } |
1097 | catch (System.InvalidOperationException) | 1179 | catch (Exception e) |
1098 | { | 1180 | { |
1099 | // This is what happens when there is invalid XML | 1181 | m_log.InfoFormat("[FORMS]: Error receiving response from {0}: {1}. Request: {2}", requestUrl, e.Message, |
1100 | m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving {0} {1}", verb, requestUrl); | 1182 | obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); |
1183 | throw e; | ||
1101 | } | 1184 | } |
1102 | } | 1185 | } |
1103 | 1186 | ||
1104 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | 1187 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); |
1105 | if (tickdiff > WebUtil.LongCallTime) | 1188 | if (tickdiff > WebUtil.LongCallTime) |
1189 | { | ||
1106 | m_log.InfoFormat( | 1190 | m_log.InfoFormat( |
1191 | <<<<<<< HEAD | ||
1192 | "[LOGHTTP]: Slow SynchronousRestForms request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", | ||
1193 | reqnum, verb, requestUrl, tickdiff, tickdata, | ||
1194 | ======= | ||
1107 | "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", | 1195 | "[FORMS]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", |
1108 | reqnum, | 1196 | reqnum, |
1109 | verb, | 1197 | verb, |
@@ -1111,19 +1199,35 @@ namespace OpenSim.Framework | |||
1111 | tickdiff, | 1199 | tickdiff, |
1112 | tickset, | 1200 | tickset, |
1113 | tickdata, | 1201 | tickdata, |
1202 | >>>>>>> avn/ubitvar | ||
1114 | obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); | 1203 | obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj); |
1204 | } | ||
1115 | else if (WebUtil.DebugLevel >= 4) | 1205 | else if (WebUtil.DebugLevel >= 4) |
1116 | m_log.DebugFormat( | 1206 | { |
1117 | "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", | 1207 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", |
1118 | reqnum, tickdiff, tickdata); | 1208 | reqnum, tickdiff, tickdata); |
1209 | } | ||
1210 | |||
1211 | if (WebUtil.DebugLevel >= 5) | ||
1212 | WebUtil.LogResponseDetail(reqnum, respstring); | ||
1119 | 1213 | ||
1120 | return respstring; | 1214 | return respstring; |
1121 | } | 1215 | } |
1122 | 1216 | ||
1217 | public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs) | ||
1218 | { | ||
1219 | return MakeRequest(verb, requestUrl, obj, timeoutsecs, null); | ||
1220 | } | ||
1221 | |||
1123 | public static string MakeRequest(string verb, string requestUrl, string obj) | 1222 | public static string MakeRequest(string verb, string requestUrl, string obj) |
1124 | { | 1223 | { |
1125 | return MakeRequest(verb, requestUrl, obj, -1); | 1224 | return MakeRequest(verb, requestUrl, obj, -1); |
1126 | } | 1225 | } |
1226 | |||
1227 | public static string MakeRequest(string verb, string requestUrl, string obj, IServiceAuth auth) | ||
1228 | { | ||
1229 | return MakeRequest(verb, requestUrl, obj, -1, auth); | ||
1230 | } | ||
1127 | } | 1231 | } |
1128 | 1232 | ||
1129 | public class SynchronousRestObjectRequester | 1233 | public class SynchronousRestObjectRequester |
@@ -1137,28 +1241,80 @@ namespace OpenSim.Framework | |||
1137 | /// </summary> | 1241 | /// </summary> |
1138 | /// <param name="verb"></param> | 1242 | /// <param name="verb"></param> |
1139 | /// <param name="requestUrl"></param> | 1243 | /// <param name="requestUrl"></param> |
1140 | /// <param name="obj"> </param> | 1244 | /// <param name="obj"></param> |
1141 | /// <returns></returns> | 1245 | /// <returns> |
1142 | /// | 1246 | /// The response. If there was an internal exception, then the default(TResponse) is returned. |
1143 | /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting | 1247 | /// </returns> |
1144 | /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> | ||
1145 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) | 1248 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj) |
1146 | { | 1249 | { |
1147 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0); | 1250 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0); |
1148 | } | 1251 | } |
1149 | 1252 | ||
1253 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, IServiceAuth auth) | ||
1254 | { | ||
1255 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0, auth); | ||
1256 | } | ||
1257 | /// <summary> | ||
1258 | /// Perform a synchronous REST request. | ||
1259 | /// </summary> | ||
1260 | /// <param name="verb"></param> | ||
1261 | /// <param name="requestUrl"></param> | ||
1262 | /// <param name="obj"></param> | ||
1263 | /// <param name="pTimeout"> | ||
1264 | /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) | ||
1265 | /// </param> | ||
1266 | /// <returns> | ||
1267 | /// The response. If there was an internal exception or the request timed out, | ||
1268 | /// then the default(TResponse) is returned. | ||
1269 | /// </returns> | ||
1150 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout) | 1270 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout) |
1151 | { | 1271 | { |
1152 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0); | 1272 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0); |
1153 | } | 1273 | } |
1154 | 1274 | ||
1275 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth) | ||
1276 | { | ||
1277 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0, auth); | ||
1278 | } | ||
1279 | |||
1280 | /// Perform a synchronous REST request. | ||
1281 | /// </summary> | ||
1282 | /// <param name="verb"></param> | ||
1283 | /// <param name="requestUrl"></param> | ||
1284 | /// <param name="obj"></param> | ||
1285 | /// <param name="pTimeout"> | ||
1286 | /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) | ||
1287 | /// </param> | ||
1288 | /// <param name="maxConnections"></param> | ||
1289 | /// <returns> | ||
1290 | /// The response. If there was an internal exception or the request timed out, | ||
1291 | /// then the default(TResponse) is returned. | ||
1292 | /// </returns> | ||
1155 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) | 1293 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections) |
1156 | { | 1294 | { |
1295 | return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, maxConnections, null); | ||
1296 | } | ||
1297 | |||
1298 | /// <summary> | ||
1299 | /// Perform a synchronous REST request. | ||
1300 | /// </summary> | ||
1301 | /// <param name="verb"></param> | ||
1302 | /// <param name="requestUrl"></param> | ||
1303 | /// <param name="obj"></param> | ||
1304 | /// <param name="pTimeout"> | ||
1305 | /// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds) | ||
1306 | /// </param> | ||
1307 | /// <param name="maxConnections"></param> | ||
1308 | /// <returns> | ||
1309 | /// The response. If there was an internal exception or the request timed out, | ||
1310 | /// then the default(TResponse) is returned. | ||
1311 | /// </returns> | ||
1312 | public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections, IServiceAuth auth) | ||
1313 | { | ||
1157 | int reqnum = WebUtil.RequestNumber++; | 1314 | int reqnum = WebUtil.RequestNumber++; |
1158 | 1315 | ||
1159 | if (WebUtil.DebugLevel >= 3) | 1316 | if (WebUtil.DebugLevel >= 3) |
1160 | m_log.DebugFormat( | 1317 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SynchronousRestObject {1} to {2}", |
1161 | "[WEB UTIL]: HTTP OUT {0} SynchronousRestObject {1} {2}", | ||
1162 | reqnum, verb, requestUrl); | 1318 | reqnum, verb, requestUrl); |
1163 | 1319 | ||
1164 | int tickstart = Util.EnvironmentTickCount(); | 1320 | int tickstart = Util.EnvironmentTickCount(); |
@@ -1169,6 +1325,13 @@ namespace OpenSim.Framework | |||
1169 | 1325 | ||
1170 | WebRequest request = WebRequest.Create(requestUrl); | 1326 | WebRequest request = WebRequest.Create(requestUrl); |
1171 | HttpWebRequest ht = (HttpWebRequest)request; | 1327 | HttpWebRequest ht = (HttpWebRequest)request; |
1328 | |||
1329 | if (auth != null) | ||
1330 | auth.AddAuthorization(ht.Headers); | ||
1331 | |||
1332 | if (pTimeout != 0) | ||
1333 | ht.Timeout = pTimeout; | ||
1334 | |||
1172 | if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) | 1335 | if (maxConnections > 0 && ht.ServicePoint.ConnectionLimit < maxConnections) |
1173 | ht.ServicePoint.ConnectionLimit = maxConnections; | 1336 | ht.ServicePoint.ConnectionLimit = maxConnections; |
1174 | 1337 | ||
@@ -1177,15 +1340,25 @@ namespace OpenSim.Framework | |||
1177 | request.Timeout = pTimeout * 1000; | 1340 | request.Timeout = pTimeout * 1000; |
1178 | MemoryStream buffer = null; | 1341 | MemoryStream buffer = null; |
1179 | 1342 | ||
1180 | if ((verb == "POST") || (verb == "PUT")) | 1343 | try |
1181 | { | 1344 | { |
1182 | request.ContentType = "text/xml"; | 1345 | if ((verb == "POST") || (verb == "PUT")) |
1346 | { | ||
1347 | request.ContentType = "text/xml"; | ||
1183 | 1348 | ||
1184 | buffer = new MemoryStream(); | 1349 | buffer = new MemoryStream(); |
1185 | 1350 | ||
1186 | XmlWriterSettings settings = new XmlWriterSettings(); | 1351 | XmlWriterSettings settings = new XmlWriterSettings(); |
1187 | settings.Encoding = Encoding.UTF8; | 1352 | settings.Encoding = Encoding.UTF8; |
1188 | 1353 | ||
1354 | <<<<<<< HEAD | ||
1355 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | ||
1356 | { | ||
1357 | XmlSerializer serializer = new XmlSerializer(type); | ||
1358 | serializer.Serialize(writer, obj); | ||
1359 | writer.Flush(); | ||
1360 | } | ||
1361 | ======= | ||
1189 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) | 1362 | using (XmlWriter writer = XmlWriter.Create(buffer, settings)) |
1190 | { | 1363 | { |
1191 | XmlSerializer serializer = new XmlSerializer(type); | 1364 | XmlSerializer serializer = new XmlSerializer(type); |
@@ -1194,110 +1367,227 @@ namespace OpenSim.Framework | |||
1194 | if (WebUtil.DebugLevel >= 5) | 1367 | if (WebUtil.DebugLevel >= 5) |
1195 | WebUtil.LogOutgoingDetail(buffer); | 1368 | WebUtil.LogOutgoingDetail(buffer); |
1196 | } | 1369 | } |
1370 | >>>>>>> avn/ubitvar | ||
1371 | |||
1372 | int length = (int)buffer.Length; | ||
1373 | request.ContentLength = length; | ||
1374 | byte[] data = buffer.ToArray(); | ||
1375 | |||
1376 | <<<<<<< HEAD | ||
1377 | if (WebUtil.DebugLevel >= 5) | ||
1378 | WebUtil.LogOutgoingDetail("SEND", reqnum, System.Text.Encoding.UTF8.GetString(data)); | ||
1379 | |||
1380 | try | ||
1381 | { | ||
1382 | using (Stream requestStream = request.GetRequestStream()) | ||
1383 | requestStream.Write(data, 0, length); | ||
1384 | } | ||
1385 | catch (Exception e) | ||
1386 | { | ||
1387 | m_log.DebugFormat( | ||
1388 | "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", | ||
1389 | verb, requestUrl, e.Message, e.StackTrace); | ||
1197 | 1390 | ||
1198 | int length = (int)buffer.Length; | 1391 | return deserial; |
1199 | request.ContentLength = length; | 1392 | } |
1393 | finally | ||
1394 | { | ||
1395 | // capture how much time was spent writing | ||
1396 | tickdata = Util.EnvironmentTickCountSubtract(tickstart); | ||
1397 | } | ||
1398 | } | ||
1200 | 1399 | ||
1400 | ======= | ||
1201 | Stream requestStream = null; | 1401 | Stream requestStream = null; |
1402 | >>>>>>> avn/ubitvar | ||
1202 | try | 1403 | try |
1203 | { | 1404 | { |
1204 | requestStream = request.GetRequestStream(); | 1405 | using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse()) |
1205 | requestStream.Write(buffer.ToArray(), 0, length); | 1406 | { |
1407 | if (resp.ContentLength != 0) | ||
1408 | { | ||
1409 | using (Stream respStream = resp.GetResponseStream()) | ||
1410 | { | ||
1411 | deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>( | ||
1412 | reqnum, respStream, resp.ContentLength); | ||
1413 | } | ||
1414 | } | ||
1415 | else | ||
1416 | { | ||
1417 | m_log.DebugFormat( | ||
1418 | "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", | ||
1419 | verb, requestUrl); | ||
1420 | } | ||
1421 | } | ||
1206 | } | 1422 | } |
1207 | catch (Exception e) | 1423 | catch (WebException e) |
1424 | { | ||
1425 | using (HttpWebResponse hwr = (HttpWebResponse)e.Response) | ||
1426 | { | ||
1427 | if (hwr != null) | ||
1428 | { | ||
1429 | if (hwr.StatusCode == HttpStatusCode.NotFound) | ||
1430 | return deserial; | ||
1431 | if (hwr.StatusCode == HttpStatusCode.Unauthorized) | ||
1432 | { | ||
1433 | m_log.Error(string.Format( | ||
1434 | "[SynchronousRestObjectRequester]: Web request {0} requires authentication ", | ||
1435 | requestUrl)); | ||
1436 | return deserial; | ||
1437 | } | ||
1438 | } | ||
1439 | else | ||
1440 | m_log.Error(string.Format( | ||
1441 | "[SynchronousRestObjectRequester]: WebException for {0} {1} {2} ", | ||
1442 | verb, requestUrl, typeof(TResponse).ToString()), e); | ||
1443 | } | ||
1444 | } | ||
1445 | catch (System.InvalidOperationException) | ||
1208 | { | 1446 | { |
1447 | // This is what happens when there is invalid XML | ||
1209 | m_log.DebugFormat( | 1448 | m_log.DebugFormat( |
1210 | "[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}", | 1449 | "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}", |
1211 | verb, requestUrl, e.Message, e.StackTrace); | 1450 | verb, requestUrl, typeof(TResponse).ToString()); |
1212 | |||
1213 | return deserial; | ||
1214 | } | 1451 | } |
1215 | finally | 1452 | catch (Exception e) |
1216 | { | 1453 | { |
1217 | if (requestStream != null) | 1454 | m_log.Debug(string.Format( |
1218 | requestStream.Close(); | 1455 | "[SynchronousRestObjectRequester]: Exception on response from {0} {1} ", |
1219 | 1456 | verb, requestUrl), e); | |
1220 | // capture how much time was spent writing | ||
1221 | tickdata = Util.EnvironmentTickCountSubtract(tickstart); | ||
1222 | } | 1457 | } |
1223 | } | ||
1224 | 1458 | ||
1225 | try | 1459 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); |
1226 | { | 1460 | if (tickdiff > WebUtil.LongCallTime) |
1227 | using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse()) | ||
1228 | { | 1461 | { |
1229 | if (resp.ContentLength != 0) | 1462 | string originalRequest = null; |
1230 | { | 1463 | |
1231 | using (Stream respStream = resp.GetResponseStream()) | 1464 | if (buffer != null) |
1232 | { | ||
1233 | XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); | ||
1234 | deserial = (TResponse)deserializer.Deserialize(respStream); | ||
1235 | } | ||
1236 | } | ||
1237 | else | ||
1238 | { | 1465 | { |
1239 | m_log.DebugFormat( | 1466 | originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); |
1240 | "[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", | 1467 | |
1241 | verb, requestUrl); | 1468 | if (originalRequest.Length > WebUtil.MaxRequestDiagLength) |
1469 | originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); | ||
1242 | } | 1470 | } |
1471 | |||
1472 | m_log.InfoFormat( | ||
1473 | "[LOGHTTP]: Slow SynchronousRestObject request {0} {1} to {2} took {3}ms, {4}ms writing, {5}", | ||
1474 | reqnum, verb, requestUrl, tickdiff, tickdata, | ||
1475 | originalRequest); | ||
1243 | } | 1476 | } |
1244 | } | 1477 | else if (WebUtil.DebugLevel >= 4) |
1245 | catch (WebException e) | ||
1246 | { | ||
1247 | using (HttpWebResponse hwr = (HttpWebResponse)e.Response) | ||
1248 | { | 1478 | { |
1249 | if (hwr != null && hwr.StatusCode == HttpStatusCode.NotFound) | 1479 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms, {2}ms writing", |
1250 | return deserial; | 1480 | reqnum, tickdiff, tickdata); |
1251 | else | ||
1252 | m_log.ErrorFormat( | ||
1253 | "[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}", | ||
1254 | verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace); | ||
1255 | } | 1481 | } |
1256 | } | 1482 | } |
1257 | catch (System.InvalidOperationException) | 1483 | finally |
1258 | { | 1484 | { |
1259 | // This is what happens when there is invalid XML | 1485 | if (buffer != null) |
1260 | m_log.DebugFormat( | 1486 | buffer.Dispose(); |
1261 | "[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}", | ||
1262 | verb, requestUrl, typeof(TResponse).ToString()); | ||
1263 | } | 1487 | } |
1264 | catch (Exception e) | 1488 | |
1489 | return deserial; | ||
1490 | } | ||
1491 | |||
1492 | |||
1493 | public static class XMLResponseHelper | ||
1494 | { | ||
1495 | public static TResponse LogAndDeserialize<TRequest, TResponse>(int reqnum, Stream respStream, long contentLength) | ||
1265 | { | 1496 | { |
1266 | m_log.DebugFormat( | 1497 | XmlSerializer deserializer = new XmlSerializer(typeof(TResponse)); |
1267 | "[SynchronousRestObjectRequester]: Exception on response from {0} {1}: {2}{3}", | 1498 | |
1268 | verb, requestUrl, e.Message, e.StackTrace); | 1499 | if (WebUtil.DebugLevel >= 5) |
1500 | { | ||
1501 | byte[] data = new byte[contentLength]; | ||
1502 | Util.ReadStream(respStream, data); | ||
1503 | |||
1504 | WebUtil.LogResponseDetail(reqnum, System.Text.Encoding.UTF8.GetString(data)); | ||
1505 | |||
1506 | using (MemoryStream temp = new MemoryStream(data)) | ||
1507 | return (TResponse)deserializer.Deserialize(temp); | ||
1508 | } | ||
1509 | else | ||
1510 | { | ||
1511 | return (TResponse)deserializer.Deserialize(respStream); | ||
1512 | } | ||
1269 | } | 1513 | } |
1514 | } | ||
1515 | } | ||
1270 | 1516 | ||
1271 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | 1517 | |
1272 | if (tickdiff > WebUtil.LongCallTime) | 1518 | public static class XMLRPCRequester |
1519 | { | ||
1520 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
1521 | |||
1522 | public static Hashtable SendRequest(Hashtable ReqParams, string method, string url) | ||
1523 | { | ||
1524 | int reqnum = WebUtil.RequestNumber++; | ||
1525 | |||
1526 | if (WebUtil.DebugLevel >= 3) | ||
1527 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} XML-RPC '{1}' to {2}", | ||
1528 | reqnum, method, url); | ||
1529 | |||
1530 | int tickstart = Util.EnvironmentTickCount(); | ||
1531 | string responseStr = null; | ||
1532 | |||
1533 | try | ||
1273 | { | 1534 | { |
1274 | string originalRequest = null; | 1535 | ArrayList SendParams = new ArrayList(); |
1536 | SendParams.Add(ReqParams); | ||
1275 | 1537 | ||
1276 | if (buffer != null) | 1538 | XmlRpcRequest Req = new XmlRpcRequest(method, SendParams); |
1539 | |||
1540 | if (WebUtil.DebugLevel >= 5) | ||
1277 | { | 1541 | { |
1278 | originalRequest = Encoding.UTF8.GetString(buffer.ToArray()); | 1542 | string str = Req.ToString(); |
1543 | str = XElement.Parse(str).ToString(SaveOptions.DisableFormatting); | ||
1544 | WebUtil.LogOutgoingDetail("SEND", reqnum, str); | ||
1545 | } | ||
1279 | 1546 | ||
1280 | if (originalRequest.Length > WebUtil.MaxRequestDiagLength) | 1547 | XmlRpcResponse Resp = Req.Send(url, 30000); |
1281 | originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength); | 1548 | |
1549 | try | ||
1550 | { | ||
1551 | responseStr = Resp.ToString(); | ||
1552 | responseStr = XElement.Parse(responseStr).ToString(SaveOptions.DisableFormatting); | ||
1553 | |||
1554 | if (WebUtil.DebugLevel >= 5) | ||
1555 | WebUtil.LogResponseDetail(reqnum, responseStr); | ||
1556 | } | ||
1557 | catch (Exception e) | ||
1558 | { | ||
1559 | m_log.Error("Error parsing XML-RPC response", e); | ||
1560 | } | ||
1561 | |||
1562 | if (Resp.IsFault) | ||
1563 | { | ||
1564 | m_log.DebugFormat( | ||
1565 | "[LOGHTTP]: XML-RPC request {0} '{1}' to {2} FAILED: FaultCode={3}, FaultMessage={4}", | ||
1566 | reqnum, method, url, Resp.FaultCode, Resp.FaultString); | ||
1567 | return null; | ||
1282 | } | 1568 | } |
1283 | 1569 | ||
1284 | m_log.InfoFormat( | 1570 | Hashtable RespData = (Hashtable)Resp.Value; |
1285 | "[SynchronousRestObjectRequester]: Slow request {0} {1} {2} took {3}ms, {4}ms writing, {5}", | 1571 | return RespData; |
1286 | reqnum, | ||
1287 | verb, | ||
1288 | requestUrl, | ||
1289 | tickdiff, | ||
1290 | tickdata, | ||
1291 | originalRequest); | ||
1292 | } | 1572 | } |
1293 | else if (WebUtil.DebugLevel >= 4) | 1573 | finally |
1294 | { | 1574 | { |
1295 | m_log.DebugFormat( | 1575 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); |
1296 | "[WEB UTIL]: HTTP OUT {0} took {1}ms, {2}ms writing", | 1576 | if (tickdiff > WebUtil.LongCallTime) |
1297 | reqnum, tickdiff, tickdata); | 1577 | { |
1578 | m_log.InfoFormat( | ||
1579 | "[LOGHTTP]: Slow XML-RPC request {0} '{1}' to {2} took {3}ms, {4}", | ||
1580 | reqnum, method, url, tickdiff, | ||
1581 | responseStr != null | ||
1582 | ? (responseStr.Length > WebUtil.MaxRequestDiagLength ? responseStr.Remove(WebUtil.MaxRequestDiagLength) : responseStr) | ||
1583 | : ""); | ||
1584 | } | ||
1585 | else if (WebUtil.DebugLevel >= 4) | ||
1586 | { | ||
1587 | m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms", reqnum, tickdiff); | ||
1588 | } | ||
1298 | } | 1589 | } |
1299 | |||
1300 | return deserial; | ||
1301 | } | 1590 | } |
1591 | |||
1302 | } | 1592 | } |
1303 | } \ No newline at end of file | 1593 | } |