diff options
Diffstat (limited to 'OpenSim/Framework')
82 files changed, 4118 insertions, 663 deletions
diff --git a/OpenSim/Framework/AgentCircuitData.cs b/OpenSim/Framework/AgentCircuitData.cs index ffcc584..f2fe494 100644 --- a/OpenSim/Framework/AgentCircuitData.cs +++ b/OpenSim/Framework/AgentCircuitData.cs | |||
@@ -128,7 +128,31 @@ namespace OpenSim.Framework | |||
128 | /// <summary> | 128 | /// <summary> |
129 | /// Viewer's version string as reported by the viewer at login | 129 | /// Viewer's version string as reported by the viewer at login |
130 | /// </summary> | 130 | /// </summary> |
131 | public string Viewer; | 131 | private string m_viewerInternal; |
132 | |||
133 | /// <summary> | ||
134 | /// Viewer's version string | ||
135 | /// </summary> | ||
136 | public string Viewer | ||
137 | { | ||
138 | set { m_viewerInternal = value; } | ||
139 | |||
140 | // Try to return consistent viewer string taking into account | ||
141 | // that viewers have chaagned how version is reported | ||
142 | // See http://opensimulator.org/mantis/view.php?id=6851 | ||
143 | get | ||
144 | { | ||
145 | // Old style version string contains viewer name followed by a space followed by a version number | ||
146 | if (m_viewerInternal == null || m_viewerInternal.Contains(" ")) | ||
147 | { | ||
148 | return m_viewerInternal; | ||
149 | } | ||
150 | else // New style version contains no spaces, just version number | ||
151 | { | ||
152 | return Channel + " " + m_viewerInternal; | ||
153 | } | ||
154 | } | ||
155 | } | ||
132 | 156 | ||
133 | /// <summary> | 157 | /// <summary> |
134 | /// The channel strinf sent by the viewer at login | 158 | /// The channel strinf sent by the viewer at login |
diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs index 232f5a1..3425505 100644 --- a/OpenSim/Framework/Animation.cs +++ b/OpenSim/Framework/Animation.cs | |||
@@ -120,5 +120,24 @@ namespace OpenSim.Framework | |||
120 | sequenceNum = args["seq_num"].AsInteger(); | 120 | sequenceNum = args["seq_num"].AsInteger(); |
121 | } | 121 | } |
122 | 122 | ||
123 | public override bool Equals(object obj) | ||
124 | { | ||
125 | Animation other = obj as Animation; | ||
126 | if (other != null) | ||
127 | { | ||
128 | return (other.AnimID.Equals(this.AnimID) | ||
129 | && other.SequenceNum == this.SequenceNum | ||
130 | && other.ObjectID.Equals(this.ObjectID) ); | ||
131 | } | ||
132 | return base.Equals(obj); | ||
133 | } | ||
134 | |||
135 | public override string ToString() | ||
136 | { | ||
137 | return "AnimID=" + AnimID.ToString() | ||
138 | + "/seq=" + SequenceNum.ToString() | ||
139 | + "/objID=" + ObjectID.ToString(); | ||
140 | } | ||
141 | |||
123 | } | 142 | } |
124 | } | 143 | } |
diff --git a/OpenSim/Framework/AssemblyInfo.cs b/OpenSim/Framework/AssemblyInfo.cs index d6b4e6a..287b988 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.7.6.*")] | 62 | [assembly : AssemblyVersion("0.8.0.*")] |
diff --git a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs index feffa26..11fece3 100644 --- a/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/AssetLoader/Filesystem/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/BasicDOSProtector.cs b/OpenSim/Framework/BasicDOSProtector.cs new file mode 100644 index 0000000..89bfa94 --- /dev/null +++ b/OpenSim/Framework/BasicDOSProtector.cs | |||
@@ -0,0 +1,275 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | |||
32 | namespace OpenSim.Framework | ||
33 | { | ||
34 | |||
35 | public class BasicDOSProtector | ||
36 | { | ||
37 | public enum ThrottleAction | ||
38 | { | ||
39 | DoThrottledMethod, | ||
40 | DoThrow | ||
41 | } | ||
42 | private readonly CircularBuffer<int> _generalRequestTimes; // General request checker | ||
43 | private readonly BasicDosProtectorOptions _options; | ||
44 | private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker | ||
45 | private readonly Dictionary<string, int> _tempBlocked; // blocked list | ||
46 | private readonly Dictionary<string, int> _sessions; | ||
47 | private readonly System.Timers.Timer _forgetTimer; // Cleanup timer | ||
48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim(); | ||
50 | private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim(); | ||
51 | public BasicDOSProtector(BasicDosProtectorOptions options) | ||
52 | { | ||
53 | _generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true); | ||
54 | _generalRequestTimes.Put(0); | ||
55 | _options = options; | ||
56 | _deeperInspection = new Dictionary<string, CircularBuffer<int>>(); | ||
57 | _tempBlocked = new Dictionary<string, int>(); | ||
58 | _sessions = new Dictionary<string, int>(); | ||
59 | _forgetTimer = new System.Timers.Timer(); | ||
60 | _forgetTimer.Elapsed += delegate | ||
61 | { | ||
62 | _forgetTimer.Enabled = false; | ||
63 | |||
64 | List<string> removes = new List<string>(); | ||
65 | _blockLockSlim.EnterReadLock(); | ||
66 | foreach (string str in _tempBlocked.Keys) | ||
67 | { | ||
68 | if ( | ||
69 | Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), | ||
70 | _tempBlocked[str]) > 0) | ||
71 | removes.Add(str); | ||
72 | } | ||
73 | _blockLockSlim.ExitReadLock(); | ||
74 | lock (_deeperInspection) | ||
75 | { | ||
76 | _blockLockSlim.EnterWriteLock(); | ||
77 | for (int i = 0; i < removes.Count; i++) | ||
78 | { | ||
79 | _tempBlocked.Remove(removes[i]); | ||
80 | _deeperInspection.Remove(removes[i]); | ||
81 | _sessions.Remove(removes[i]); | ||
82 | } | ||
83 | _blockLockSlim.ExitWriteLock(); | ||
84 | } | ||
85 | foreach (string str in removes) | ||
86 | { | ||
87 | m_log.InfoFormat("[{0}] client: {1} is no longer blocked.", | ||
88 | _options.ReportingName, str); | ||
89 | } | ||
90 | _blockLockSlim.EnterReadLock(); | ||
91 | if (_tempBlocked.Count > 0) | ||
92 | _forgetTimer.Enabled = true; | ||
93 | _blockLockSlim.ExitReadLock(); | ||
94 | }; | ||
95 | |||
96 | _forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds; | ||
97 | } | ||
98 | |||
99 | /// <summary> | ||
100 | /// Given a string Key, Returns if that context is blocked | ||
101 | /// </summary> | ||
102 | /// <param name="key">A Key identifying the context</param> | ||
103 | /// <returns>bool Yes or No, True or False for blocked</returns> | ||
104 | public bool IsBlocked(string key) | ||
105 | { | ||
106 | bool ret = false; | ||
107 | _blockLockSlim.EnterReadLock(); | ||
108 | ret = _tempBlocked.ContainsKey(key); | ||
109 | _blockLockSlim.ExitReadLock(); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | /// <summary> | ||
114 | /// Process the velocity of this context | ||
115 | /// </summary> | ||
116 | /// <param name="key"></param> | ||
117 | /// <param name="endpoint"></param> | ||
118 | /// <returns></returns> | ||
119 | public bool Process(string key, string endpoint) | ||
120 | { | ||
121 | if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1) | ||
122 | return true; | ||
123 | |||
124 | string clientstring = key; | ||
125 | |||
126 | _blockLockSlim.EnterReadLock(); | ||
127 | if (_tempBlocked.ContainsKey(clientstring)) | ||
128 | { | ||
129 | _blockLockSlim.ExitReadLock(); | ||
130 | |||
131 | if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) | ||
132 | return false; | ||
133 | else | ||
134 | throw new System.Security.SecurityException("Throttled"); | ||
135 | } | ||
136 | |||
137 | _blockLockSlim.ExitReadLock(); | ||
138 | |||
139 | lock (_generalRequestTimes) | ||
140 | _generalRequestTimes.Put(Util.EnvironmentTickCount()); | ||
141 | |||
142 | if (_options.MaxConcurrentSessions > 0) | ||
143 | { | ||
144 | int sessionscount = 0; | ||
145 | |||
146 | _sessionLockSlim.EnterReadLock(); | ||
147 | if (_sessions.ContainsKey(key)) | ||
148 | sessionscount = _sessions[key]; | ||
149 | _sessionLockSlim.ExitReadLock(); | ||
150 | |||
151 | if (sessionscount > _options.MaxConcurrentSessions) | ||
152 | { | ||
153 | // Add to blocking and cleanup methods | ||
154 | lock (_deeperInspection) | ||
155 | { | ||
156 | _blockLockSlim.EnterWriteLock(); | ||
157 | if (!_tempBlocked.ContainsKey(clientstring)) | ||
158 | { | ||
159 | _tempBlocked.Add(clientstring, | ||
160 | Util.EnvironmentTickCount() + | ||
161 | (int) _options.ForgetTimeSpan.TotalMilliseconds); | ||
162 | _forgetTimer.Enabled = true; | ||
163 | m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds based on concurrency, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); | ||
164 | |||
165 | } | ||
166 | else | ||
167 | _tempBlocked[clientstring] = Util.EnvironmentTickCount() + | ||
168 | (int) _options.ForgetTimeSpan.TotalMilliseconds; | ||
169 | _blockLockSlim.ExitWriteLock(); | ||
170 | |||
171 | } | ||
172 | |||
173 | |||
174 | } | ||
175 | else | ||
176 | ProcessConcurrency(key, endpoint); | ||
177 | } | ||
178 | if (_generalRequestTimes.Size == _generalRequestTimes.Capacity && | ||
179 | (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) < | ||
180 | _options.RequestTimeSpan.TotalMilliseconds)) | ||
181 | { | ||
182 | //Trigger deeper inspection | ||
183 | if (DeeperInspection(key, endpoint)) | ||
184 | return true; | ||
185 | if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod) | ||
186 | return false; | ||
187 | else | ||
188 | throw new System.Security.SecurityException("Throttled"); | ||
189 | } | ||
190 | return true; | ||
191 | } | ||
192 | private void ProcessConcurrency(string key, string endpoint) | ||
193 | { | ||
194 | _sessionLockSlim.EnterWriteLock(); | ||
195 | if (_sessions.ContainsKey(key)) | ||
196 | _sessions[key] = _sessions[key] + 1; | ||
197 | else | ||
198 | _sessions.Add(key,1); | ||
199 | _sessionLockSlim.ExitWriteLock(); | ||
200 | } | ||
201 | public void ProcessEnd(string key, string endpoint) | ||
202 | { | ||
203 | _sessionLockSlim.EnterWriteLock(); | ||
204 | if (_sessions.ContainsKey(key)) | ||
205 | { | ||
206 | _sessions[key]--; | ||
207 | if (_sessions[key] <= 0) | ||
208 | _sessions.Remove(key); | ||
209 | } | ||
210 | else | ||
211 | _sessions.Add(key, 1); | ||
212 | |||
213 | _sessionLockSlim.ExitWriteLock(); | ||
214 | } | ||
215 | |||
216 | /// <summary> | ||
217 | /// At this point, the rate limiting code needs to track 'per user' velocity. | ||
218 | /// </summary> | ||
219 | /// <param name="key">Context Key, string representing a rate limiting context</param> | ||
220 | /// <param name="endpoint"></param> | ||
221 | /// <returns></returns> | ||
222 | private bool DeeperInspection(string key, string endpoint) | ||
223 | { | ||
224 | lock (_deeperInspection) | ||
225 | { | ||
226 | string clientstring = key; | ||
227 | |||
228 | |||
229 | if (_deeperInspection.ContainsKey(clientstring)) | ||
230 | { | ||
231 | _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); | ||
232 | if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity && | ||
233 | (Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) < | ||
234 | _options.RequestTimeSpan.TotalMilliseconds)) | ||
235 | { | ||
236 | //Looks like we're over the limit | ||
237 | _blockLockSlim.EnterWriteLock(); | ||
238 | if (!_tempBlocked.ContainsKey(clientstring)) | ||
239 | _tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds); | ||
240 | else | ||
241 | _tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds; | ||
242 | _blockLockSlim.ExitWriteLock(); | ||
243 | |||
244 | m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint); | ||
245 | |||
246 | return false; | ||
247 | } | ||
248 | //else | ||
249 | // return true; | ||
250 | } | ||
251 | else | ||
252 | { | ||
253 | _deeperInspection.Add(clientstring, new CircularBuffer<int>(_options.MaxRequestsInTimeframe + 1, true)); | ||
254 | _deeperInspection[clientstring].Put(Util.EnvironmentTickCount()); | ||
255 | _forgetTimer.Enabled = true; | ||
256 | } | ||
257 | |||
258 | } | ||
259 | return true; | ||
260 | } | ||
261 | |||
262 | } | ||
263 | |||
264 | |||
265 | public class BasicDosProtectorOptions | ||
266 | { | ||
267 | public int MaxRequestsInTimeframe; | ||
268 | public TimeSpan RequestTimeSpan; | ||
269 | public TimeSpan ForgetTimeSpan; | ||
270 | public bool AllowXForwardedFor; | ||
271 | public string ReportingName = "BASICDOSPROTECTOR"; | ||
272 | public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod; | ||
273 | public int MaxConcurrentSessions; | ||
274 | } | ||
275 | } | ||
diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs index 3658161..3e90fac 100644 --- a/OpenSim/Framework/BlockingQueue.cs +++ b/OpenSim/Framework/BlockingQueue.cs | |||
@@ -58,7 +58,7 @@ namespace OpenSim.Framework | |||
58 | { | 58 | { |
59 | lock (m_queueSync) | 59 | lock (m_queueSync) |
60 | { | 60 | { |
61 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | 61 | while (m_queue.Count < 1 && m_pqueue.Count < 1) |
62 | { | 62 | { |
63 | Monitor.Wait(m_queueSync); | 63 | Monitor.Wait(m_queueSync); |
64 | } | 64 | } |
@@ -76,9 +76,10 @@ namespace OpenSim.Framework | |||
76 | { | 76 | { |
77 | lock (m_queueSync) | 77 | lock (m_queueSync) |
78 | { | 78 | { |
79 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | 79 | bool success = true; |
80 | while (m_queue.Count < 1 && m_pqueue.Count < 1 && success) | ||
80 | { | 81 | { |
81 | Monitor.Wait(m_queueSync, msTimeout); | 82 | success = Monitor.Wait(m_queueSync, msTimeout); |
82 | } | 83 | } |
83 | 84 | ||
84 | if (m_pqueue.Count > 0) | 85 | if (m_pqueue.Count > 0) |
@@ -89,8 +90,17 @@ namespace OpenSim.Framework | |||
89 | } | 90 | } |
90 | } | 91 | } |
91 | 92 | ||
93 | /// <summary> | ||
94 | /// Indicate whether this queue contains the given item. | ||
95 | /// </summary> | ||
96 | /// <remarks> | ||
97 | /// This method is not thread-safe. Do not rely on the result without consistent external locking. | ||
98 | /// </remarks> | ||
92 | public bool Contains(T item) | 99 | public bool Contains(T item) |
93 | { | 100 | { |
101 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | ||
102 | return false; | ||
103 | |||
94 | lock (m_queueSync) | 104 | lock (m_queueSync) |
95 | { | 105 | { |
96 | if (m_pqueue.Contains(item)) | 106 | if (m_pqueue.Contains(item)) |
@@ -99,16 +109,28 @@ namespace OpenSim.Framework | |||
99 | } | 109 | } |
100 | } | 110 | } |
101 | 111 | ||
112 | /// <summary> | ||
113 | /// Return a count of the number of requests on this queue. | ||
114 | /// </summary> | ||
115 | /// <remarks> | ||
116 | /// This method is not thread-safe. Do not rely on the result without consistent external locking. | ||
117 | /// </remarks> | ||
102 | public int Count() | 118 | public int Count() |
103 | { | 119 | { |
104 | lock (m_queueSync) | 120 | return m_queue.Count + m_pqueue.Count; |
105 | { | ||
106 | return m_queue.Count+m_pqueue.Count; | ||
107 | } | ||
108 | } | 121 | } |
109 | 122 | ||
123 | /// <summary> | ||
124 | /// Return the array of items on this queue. | ||
125 | /// </summary> | ||
126 | /// <remarks> | ||
127 | /// This method is not thread-safe. Do not rely on the result without consistent external locking. | ||
128 | /// </remarks> | ||
110 | public T[] GetQueueArray() | 129 | public T[] GetQueueArray() |
111 | { | 130 | { |
131 | if (m_queue.Count < 1 && m_pqueue.Count < 1) | ||
132 | return new T[0]; | ||
133 | |||
112 | lock (m_queueSync) | 134 | lock (m_queueSync) |
113 | { | 135 | { |
114 | return m_queue.ToArray(); | 136 | return m_queue.ToArray(); |
diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs new file mode 100644 index 0000000..239fc56 --- /dev/null +++ b/OpenSim/Framework/CachedTextureEventArg.cs | |||
@@ -0,0 +1,46 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Text; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Framework | ||
33 | { | ||
34 | public class CachedTextureRequestArg | ||
35 | { | ||
36 | public int BakedTextureIndex; | ||
37 | public UUID WearableHashID; | ||
38 | } | ||
39 | |||
40 | public class CachedTextureResponseArg | ||
41 | { | ||
42 | public int BakedTextureIndex; | ||
43 | public UUID BakedTextureID; | ||
44 | public String HostName; | ||
45 | } | ||
46 | } | ||
diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs index 8c32734..2a8e67d 100644 --- a/OpenSim/Framework/ChildAgentDataUpdate.cs +++ b/OpenSim/Framework/ChildAgentDataUpdate.cs | |||
@@ -171,9 +171,10 @@ namespace OpenSim.Framework | |||
171 | /// Soon to be decommissioned | 171 | /// Soon to be decommissioned |
172 | /// </summary> | 172 | /// </summary> |
173 | /// <param name="cAgent"></param> | 173 | /// <param name="cAgent"></param> |
174 | public void CopyFrom(ChildAgentDataUpdate cAgent) | 174 | public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid) |
175 | { | 175 | { |
176 | AgentID = new UUID(cAgent.AgentID); | 176 | AgentID = new UUID(cAgent.AgentID); |
177 | SessionID = sid; | ||
177 | 178 | ||
178 | // next: ??? | 179 | // next: ??? |
179 | Size = new Vector3(); | 180 | Size = new Vector3(); |
@@ -291,7 +292,13 @@ namespace OpenSim.Framework | |||
291 | public Vector3 AtAxis; | 292 | public Vector3 AtAxis; |
292 | public Vector3 LeftAxis; | 293 | public Vector3 LeftAxis; |
293 | public Vector3 UpAxis; | 294 | public Vector3 UpAxis; |
294 | public bool ChangedGrid; | 295 | |
296 | /// <summary> | ||
297 | /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the | ||
298 | /// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after | ||
299 | /// establishing the connection triggered by it's receipt of a TeleportFinish EQ message). | ||
300 | /// </summary> | ||
301 | public bool SenderWantsToWaitForRoot; | ||
295 | 302 | ||
296 | public float Far; | 303 | public float Far; |
297 | public float Aspect; | 304 | public float Aspect; |
@@ -362,8 +369,9 @@ namespace OpenSim.Framework | |||
362 | args["left_axis"] = OSD.FromString(LeftAxis.ToString()); | 369 | args["left_axis"] = OSD.FromString(LeftAxis.ToString()); |
363 | args["up_axis"] = OSD.FromString(UpAxis.ToString()); | 370 | args["up_axis"] = OSD.FromString(UpAxis.ToString()); |
364 | 371 | ||
365 | 372 | //backwards compatibility | |
366 | args["changed_grid"] = OSD.FromBoolean(ChangedGrid); | 373 | args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot); |
374 | args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot); | ||
367 | args["far"] = OSD.FromReal(Far); | 375 | args["far"] = OSD.FromReal(Far); |
368 | args["aspect"] = OSD.FromReal(Aspect); | 376 | args["aspect"] = OSD.FromReal(Aspect); |
369 | 377 | ||
@@ -536,8 +544,8 @@ namespace OpenSim.Framework | |||
536 | if (args["up_axis"] != null) | 544 | if (args["up_axis"] != null) |
537 | Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); | 545 | Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); |
538 | 546 | ||
539 | if (args["changed_grid"] != null) | 547 | if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null) |
540 | ChangedGrid = args["changed_grid"].AsBoolean(); | 548 | SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean(); |
541 | 549 | ||
542 | if (args["far"] != null) | 550 | if (args["far"] != null) |
543 | Far = (float)(args["far"].AsReal()); | 551 | Far = (float)(args["far"].AsReal()); |
diff --git a/OpenSim/Framework/CircularBuffer.cs b/OpenSim/Framework/CircularBuffer.cs new file mode 100644 index 0000000..e919337 --- /dev/null +++ b/OpenSim/Framework/CircularBuffer.cs | |||
@@ -0,0 +1,312 @@ | |||
1 | /* | ||
2 | Copyright (c) 2012, Alex Regueiro | ||
3 | All rights reserved. | ||
4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the | ||
5 | following conditions are met: | ||
6 | |||
7 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
8 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer | ||
9 | in the documentation and/or other materials provided with the distribution. | ||
10 | |||
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, | ||
12 | BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
13 | IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | ||
14 | OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, | ||
15 | OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
16 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
17 | POSSIBILITY OF SUCH DAMAGE. | ||
18 | */ | ||
19 | using System; | ||
20 | using System.Collections; | ||
21 | using System.Collections.Generic; | ||
22 | using System.Threading; | ||
23 | |||
24 | namespace OpenSim.Framework | ||
25 | { | ||
26 | public class CircularBuffer<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable | ||
27 | { | ||
28 | private int capacity; | ||
29 | private int size; | ||
30 | private int head; | ||
31 | private int tail; | ||
32 | private T[] buffer; | ||
33 | |||
34 | [NonSerialized()] | ||
35 | private object syncRoot; | ||
36 | |||
37 | public CircularBuffer(int capacity) | ||
38 | : this(capacity, false) | ||
39 | { | ||
40 | } | ||
41 | |||
42 | public CircularBuffer(int capacity, bool allowOverflow) | ||
43 | { | ||
44 | if (capacity < 0) | ||
45 | throw new ArgumentException("Needs to have at least 1","capacity"); | ||
46 | |||
47 | this.capacity = capacity; | ||
48 | size = 0; | ||
49 | head = 0; | ||
50 | tail = 0; | ||
51 | buffer = new T[capacity]; | ||
52 | AllowOverflow = allowOverflow; | ||
53 | } | ||
54 | |||
55 | public bool AllowOverflow | ||
56 | { | ||
57 | get; | ||
58 | set; | ||
59 | } | ||
60 | |||
61 | public int Capacity | ||
62 | { | ||
63 | get { return capacity; } | ||
64 | set | ||
65 | { | ||
66 | if (value == capacity) | ||
67 | return; | ||
68 | |||
69 | if (value < size) | ||
70 | throw new ArgumentOutOfRangeException("value","Capacity is too small."); | ||
71 | |||
72 | var dst = new T[value]; | ||
73 | if (size > 0) | ||
74 | CopyTo(dst); | ||
75 | buffer = dst; | ||
76 | |||
77 | capacity = value; | ||
78 | } | ||
79 | } | ||
80 | |||
81 | public int Size | ||
82 | { | ||
83 | get { return size; } | ||
84 | } | ||
85 | |||
86 | public bool Contains(T item) | ||
87 | { | ||
88 | int bufferIndex = head; | ||
89 | var comparer = EqualityComparer<T>.Default; | ||
90 | for (int i = 0; i < size; i++, bufferIndex++) | ||
91 | { | ||
92 | if (bufferIndex == capacity) | ||
93 | bufferIndex = 0; | ||
94 | |||
95 | if (item == null && buffer[bufferIndex] == null) | ||
96 | return true; | ||
97 | else if ((buffer[bufferIndex] != null) && | ||
98 | comparer.Equals(buffer[bufferIndex], item)) | ||
99 | return true; | ||
100 | } | ||
101 | |||
102 | return false; | ||
103 | } | ||
104 | |||
105 | public void Clear() | ||
106 | { | ||
107 | size = 0; | ||
108 | head = 0; | ||
109 | tail = 0; | ||
110 | } | ||
111 | |||
112 | public int Put(T[] src) | ||
113 | { | ||
114 | return Put(src, 0, src.Length); | ||
115 | } | ||
116 | |||
117 | public int Put(T[] src, int offset, int count) | ||
118 | { | ||
119 | if (!AllowOverflow && count > capacity - size) | ||
120 | throw new InvalidOperationException("Buffer Overflow"); | ||
121 | |||
122 | int srcIndex = offset; | ||
123 | for (int i = 0; i < count; i++, tail++, srcIndex++) | ||
124 | { | ||
125 | if (tail == capacity) | ||
126 | tail = 0; | ||
127 | buffer[tail] = src[srcIndex]; | ||
128 | } | ||
129 | size = Math.Min(size + count, capacity); | ||
130 | return count; | ||
131 | } | ||
132 | |||
133 | public void Put(T item) | ||
134 | { | ||
135 | if (!AllowOverflow && size == capacity) | ||
136 | throw new InvalidOperationException("Buffer Overflow"); | ||
137 | |||
138 | buffer[tail] = item; | ||
139 | if (++tail == capacity) | ||
140 | tail = 0; | ||
141 | size++; | ||
142 | } | ||
143 | |||
144 | public void Skip(int count) | ||
145 | { | ||
146 | head += count; | ||
147 | if (head >= capacity) | ||
148 | head -= capacity; | ||
149 | } | ||
150 | |||
151 | public T[] Get(int count) | ||
152 | { | ||
153 | var dst = new T[count]; | ||
154 | Get(dst); | ||
155 | return dst; | ||
156 | } | ||
157 | |||
158 | public int Get(T[] dst) | ||
159 | { | ||
160 | return Get(dst, 0, dst.Length); | ||
161 | } | ||
162 | |||
163 | public int Get(T[] dst, int offset, int count) | ||
164 | { | ||
165 | int realCount = Math.Min(count, size); | ||
166 | int dstIndex = offset; | ||
167 | for (int i = 0; i < realCount; i++, head++, dstIndex++) | ||
168 | { | ||
169 | if (head == capacity) | ||
170 | head = 0; | ||
171 | dst[dstIndex] = buffer[head]; | ||
172 | } | ||
173 | size -= realCount; | ||
174 | return realCount; | ||
175 | } | ||
176 | |||
177 | public T Get() | ||
178 | { | ||
179 | if (size == 0) | ||
180 | throw new InvalidOperationException("Buffer Empty"); | ||
181 | |||
182 | var item = buffer[head]; | ||
183 | if (++head == capacity) | ||
184 | head = 0; | ||
185 | size--; | ||
186 | return item; | ||
187 | } | ||
188 | |||
189 | public void CopyTo(T[] array) | ||
190 | { | ||
191 | CopyTo(array, 0); | ||
192 | } | ||
193 | |||
194 | public void CopyTo(T[] array, int arrayIndex) | ||
195 | { | ||
196 | CopyTo(0, array, arrayIndex, size); | ||
197 | } | ||
198 | |||
199 | public void CopyTo(int index, T[] array, int arrayIndex, int count) | ||
200 | { | ||
201 | if (count > size) | ||
202 | throw new ArgumentOutOfRangeException("count", "Count Too Large"); | ||
203 | |||
204 | int bufferIndex = head; | ||
205 | for (int i = 0; i < count; i++, bufferIndex++, arrayIndex++) | ||
206 | { | ||
207 | if (bufferIndex == capacity) | ||
208 | bufferIndex = 0; | ||
209 | array[arrayIndex] = buffer[bufferIndex]; | ||
210 | } | ||
211 | } | ||
212 | |||
213 | public IEnumerator<T> GetEnumerator() | ||
214 | { | ||
215 | int bufferIndex = head; | ||
216 | for (int i = 0; i < size; i++, bufferIndex++) | ||
217 | { | ||
218 | if (bufferIndex == capacity) | ||
219 | bufferIndex = 0; | ||
220 | |||
221 | yield return buffer[bufferIndex]; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | public T[] GetBuffer() | ||
226 | { | ||
227 | return buffer; | ||
228 | } | ||
229 | |||
230 | public T[] ToArray() | ||
231 | { | ||
232 | var dst = new T[size]; | ||
233 | CopyTo(dst); | ||
234 | return dst; | ||
235 | } | ||
236 | |||
237 | #region ICollection<T> Members | ||
238 | |||
239 | int ICollection<T>.Count | ||
240 | { | ||
241 | get { return Size; } | ||
242 | } | ||
243 | |||
244 | bool ICollection<T>.IsReadOnly | ||
245 | { | ||
246 | get { return false; } | ||
247 | } | ||
248 | |||
249 | void ICollection<T>.Add(T item) | ||
250 | { | ||
251 | Put(item); | ||
252 | } | ||
253 | |||
254 | bool ICollection<T>.Remove(T item) | ||
255 | { | ||
256 | if (size == 0) | ||
257 | return false; | ||
258 | |||
259 | Get(); | ||
260 | return true; | ||
261 | } | ||
262 | |||
263 | #endregion | ||
264 | |||
265 | #region IEnumerable<T> Members | ||
266 | |||
267 | IEnumerator<T> IEnumerable<T>.GetEnumerator() | ||
268 | { | ||
269 | return GetEnumerator(); | ||
270 | } | ||
271 | |||
272 | #endregion | ||
273 | |||
274 | #region ICollection Members | ||
275 | |||
276 | int ICollection.Count | ||
277 | { | ||
278 | get { return Size; } | ||
279 | } | ||
280 | |||
281 | bool ICollection.IsSynchronized | ||
282 | { | ||
283 | get { return false; } | ||
284 | } | ||
285 | |||
286 | object ICollection.SyncRoot | ||
287 | { | ||
288 | get | ||
289 | { | ||
290 | if (syncRoot == null) | ||
291 | Interlocked.CompareExchange(ref syncRoot, new object(), null); | ||
292 | return syncRoot; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | void ICollection.CopyTo(Array array, int arrayIndex) | ||
297 | { | ||
298 | CopyTo((T[])array, arrayIndex); | ||
299 | } | ||
300 | |||
301 | #endregion | ||
302 | |||
303 | #region IEnumerable Members | ||
304 | |||
305 | IEnumerator IEnumerable.GetEnumerator() | ||
306 | { | ||
307 | return (IEnumerator)GetEnumerator(); | ||
308 | } | ||
309 | |||
310 | #endregion | ||
311 | } | ||
312 | } | ||
diff --git a/OpenSim/Framework/ClientInfo.cs b/OpenSim/Framework/ClientInfo.cs index 62acb70..9021315 100644 --- a/OpenSim/Framework/ClientInfo.cs +++ b/OpenSim/Framework/ClientInfo.cs | |||
@@ -33,12 +33,13 @@ namespace OpenSim.Framework | |||
33 | { | 33 | { |
34 | public class ClientInfo | 34 | public class ClientInfo |
35 | { | 35 | { |
36 | public AgentCircuitData agentcircuit; | 36 | public readonly DateTime StartedTime = DateTime.Now; |
37 | public AgentCircuitData agentcircuit = null; | ||
37 | 38 | ||
38 | public Dictionary<uint, byte[]> needAck; | 39 | public Dictionary<uint, byte[]> needAck; |
39 | 40 | ||
40 | public List<byte[]> out_packets; | 41 | public List<byte[]> out_packets = new List<byte[]>(); |
41 | public Dictionary<uint, uint> pendingAcks; | 42 | public Dictionary<uint, uint> pendingAcks = new Dictionary<uint,uint>(); |
42 | public EndPoint proxyEP; | 43 | public EndPoint proxyEP; |
43 | 44 | ||
44 | public uint sequence; | 45 | public uint sequence; |
@@ -53,5 +54,9 @@ namespace OpenSim.Framework | |||
53 | public int assetThrottle; | 54 | public int assetThrottle; |
54 | public int textureThrottle; | 55 | public int textureThrottle; |
55 | public int totalThrottle; | 56 | public int totalThrottle; |
57 | |||
58 | public Dictionary<string, int> SyncRequests = new Dictionary<string,int>(); | ||
59 | public Dictionary<string, int> AsyncRequests = new Dictionary<string,int>(); | ||
60 | public Dictionary<string, int> GenericRequests = new Dictionary<string,int>(); | ||
56 | } | 61 | } |
57 | } | 62 | } |
diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs index df8eb52..09611fa 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.7.6.*")] | 64 | [assembly : AssemblyVersion("0.8.0.*")] |
65 | 65 | ||
diff --git a/OpenSim/Framework/ConfigSettings.cs b/OpenSim/Framework/ConfigSettings.cs index 002a371..108a3e4 100644 --- a/OpenSim/Framework/ConfigSettings.cs +++ b/OpenSim/Framework/ConfigSettings.cs | |||
@@ -31,7 +31,6 @@ namespace OpenSim.Framework | |||
31 | { | 31 | { |
32 | public string PhysicsEngine { get; set; } | 32 | public string PhysicsEngine { get; set; } |
33 | public string MeshEngineName { get; set; } | 33 | public string MeshEngineName { get; set; } |
34 | public string StorageDll { get; set; } | ||
35 | public string ClientstackDll { get; set; } | 34 | public string ClientstackDll { get; set; } |
36 | public string LibrariesXMLFile { get; set; } | 35 | public string LibrariesXMLFile { get; set; } |
37 | 36 | ||
diff --git a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs index 3ef9682..05a2e0e 100644 --- a/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Configuration/HTTP/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs index cbdffeb..d928a94 100644 --- a/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Configuration/XML/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs b/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs index 43162fc..3152a7d 100644 --- a/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs +++ b/OpenSim/Framework/Configuration/XML/XmlConfiguration.cs | |||
@@ -121,7 +121,7 @@ namespace OpenSim.Framework.Configuration.XML | |||
121 | 121 | ||
122 | public void Commit() | 122 | public void Commit() |
123 | { | 123 | { |
124 | if (fileName == null || fileName == String.Empty) | 124 | if (string.IsNullOrEmpty(fileName)) |
125 | return; | 125 | return; |
126 | 126 | ||
127 | if (!Directory.Exists(Util.configDir())) | 127 | if (!Directory.Exists(Util.configDir())) |
diff --git a/OpenSim/Framework/Console/AssemblyInfo.cs b/OpenSim/Framework/Console/AssemblyInfo.cs index c618454..ba59025 100644 --- a/OpenSim/Framework/Console/AssemblyInfo.cs +++ b/OpenSim/Framework/Console/AssemblyInfo.cs | |||
@@ -55,4 +55,4 @@ using System.Runtime.InteropServices; | |||
55 | // You can specify all values by your own or you can build default build and revision | 55 | // You can specify all values by your own or you can build default build and revision |
56 | // numbers with the '*' character (the default): | 56 | // numbers with the '*' character (the default): |
57 | 57 | ||
58 | [assembly : AssemblyVersion("0.7.6.*")] | 58 | [assembly : AssemblyVersion("0.8.0.*")] |
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs index 97a86a8..794bfaf 100644 --- a/OpenSim/Framework/Console/ConsoleUtil.cs +++ b/OpenSim/Framework/Console/ConsoleUtil.cs | |||
@@ -156,12 +156,32 @@ namespace OpenSim.Framework.Console | |||
156 | } | 156 | } |
157 | 157 | ||
158 | /// <summary> | 158 | /// <summary> |
159 | /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 | 159 | /// Convert a console integer to an int, automatically complaining if a console is given. |
160 | /// </summary> | 160 | /// </summary> |
161 | /// <param name='console'>Can be null if no console is available.</param> | 161 | /// <param name='console'>Can be null if no console is available.</param> |
162 | /// <param name='rawConsoleVector'>/param> | 162 | /// <param name='rawConsoleVector'>/param> |
163 | /// <param name='vector'></param> | 163 | /// <param name='vector'></param> |
164 | /// <returns></returns> | 164 | /// <returns></returns> |
165 | public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b) | ||
166 | { | ||
167 | if (!bool.TryParse(rawConsoleString, out b)) | ||
168 | { | ||
169 | if (console != null) | ||
170 | console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString); | ||
171 | |||
172 | return false; | ||
173 | } | ||
174 | |||
175 | return true; | ||
176 | } | ||
177 | |||
178 | /// <summary> | ||
179 | /// Convert a console integer to an int, automatically complaining if a console is given. | ||
180 | /// </summary> | ||
181 | /// <param name='console'>Can be null if no console is available.</param> | ||
182 | /// <param name='rawConsoleInt'>/param> | ||
183 | /// <param name='i'></param> | ||
184 | /// <returns></returns> | ||
165 | public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i) | 185 | public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i) |
166 | { | 186 | { |
167 | if (!int.TryParse(rawConsoleInt, out i)) | 187 | if (!int.TryParse(rawConsoleInt, out i)) |
@@ -174,6 +194,31 @@ namespace OpenSim.Framework.Console | |||
174 | 194 | ||
175 | return true; | 195 | return true; |
176 | } | 196 | } |
197 | |||
198 | /// <summary> | ||
199 | /// Convert a console integer to a natural int, 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='rawConsoleInt'>/param> | ||
203 | /// <param name='i'></param> | ||
204 | /// <returns></returns> | ||
205 | public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i) | ||
206 | { | ||
207 | if (TryParseConsoleInt(console, rawConsoleInt, out i)) | ||
208 | { | ||
209 | if (i < 0) | ||
210 | { | ||
211 | if (console != null) | ||
212 | console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt); | ||
213 | |||
214 | return false; | ||
215 | } | ||
216 | |||
217 | return true; | ||
218 | } | ||
219 | |||
220 | return false; | ||
221 | } | ||
177 | 222 | ||
178 | /// <summary> | 223 | /// <summary> |
179 | /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 | 224 | /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 |
diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs index d41481f..a967db6 100644 --- a/OpenSim/Framework/Console/LocalConsole.cs +++ b/OpenSim/Framework/Console/LocalConsole.cs | |||
@@ -426,6 +426,21 @@ namespace OpenSim.Framework.Console | |||
426 | System.Console.Write("{0}", prompt); | 426 | System.Console.Write("{0}", prompt); |
427 | 427 | ||
428 | break; | 428 | break; |
429 | case ConsoleKey.Delete: | ||
430 | if (m_cursorXPosition == m_commandLine.Length) | ||
431 | break; | ||
432 | |||
433 | m_commandLine.Remove(m_cursorXPosition, 1); | ||
434 | |||
435 | SetCursorLeft(0); | ||
436 | m_cursorYPosition = SetCursorTop(m_cursorYPosition); | ||
437 | |||
438 | if (m_echo) | ||
439 | System.Console.Write("{0}{1} ", prompt, m_commandLine); | ||
440 | else | ||
441 | System.Console.Write("{0}", prompt); | ||
442 | |||
443 | break; | ||
429 | case ConsoleKey.End: | 444 | case ConsoleKey.End: |
430 | m_cursorXPosition = m_commandLine.Length; | 445 | m_cursorXPosition = m_commandLine.Length; |
431 | break; | 446 | break; |
diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs index 3e3c2b3..8ad7b0d 100644 --- a/OpenSim/Framework/Console/RemoteConsole.cs +++ b/OpenSim/Framework/Console/RemoteConsole.cs | |||
@@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console | |||
234 | string uri = "/ReadResponses/" + sessionID.ToString() + "/"; | 234 | string uri = "/ReadResponses/" + sessionID.ToString() + "/"; |
235 | 235 | ||
236 | m_Server.AddPollServiceHTTPHandler( | 236 | m_Server.AddPollServiceHTTPHandler( |
237 | uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout | 237 | uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout |
238 | 238 | ||
239 | XmlDocument xmldoc = new XmlDocument(); | 239 | XmlDocument xmldoc = new XmlDocument(); |
240 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, | 240 | XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, |
diff --git a/OpenSim/Framework/Constants.cs b/OpenSim/Framework/Constants.cs index a2eb5ee..3ba264c 100644 --- a/OpenSim/Framework/Constants.cs +++ b/OpenSim/Framework/Constants.cs | |||
@@ -30,9 +30,18 @@ namespace OpenSim.Framework | |||
30 | { | 30 | { |
31 | public class Constants | 31 | public class Constants |
32 | { | 32 | { |
33 | // 'RegionSize' is the legacy region size. | ||
34 | // DO NOT USE THIS FOR ANY NEW CODE. Use Scene.RegionInfo.RegionSize[XYZ] as a region might not | ||
35 | // be the legacy region size. | ||
33 | public const uint RegionSize = 256; | 36 | public const uint RegionSize = 256; |
34 | public const uint RegionHeight = 4096; | 37 | public const uint RegionHeight = 4096; |
35 | public const byte TerrainPatchSize = 16; | 38 | // This could be a parameters but, really, a region of greater than this is pretty unmanageable |
39 | public const uint MaximumRegionSize = 8192; | ||
40 | |||
41 | // Since terrain is stored in 16x16 heights, regions must be a multiple of this number and that is the minimum | ||
42 | public const int MinRegionSize = 16; | ||
43 | public const int TerrainPatchSize = 16; | ||
44 | |||
36 | public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; | 45 | public const string DefaultTexture = "89556747-24cb-43ed-920b-47caed15465f"; |
37 | 46 | ||
38 | public enum EstateAccessCodex : uint | 47 | public enum EstateAccessCodex : uint |
diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs index df4a6bc..4995a92 100644 --- a/OpenSim/Framework/DAMap.cs +++ b/OpenSim/Framework/DAMap.cs | |||
@@ -29,10 +29,12 @@ using System; | |||
29 | using System.Collections; | 29 | using System.Collections; |
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Reflection; | ||
32 | using System.Text; | 33 | using System.Text; |
33 | using System.Xml; | 34 | using System.Xml; |
34 | using System.Xml.Schema; | 35 | using System.Xml.Schema; |
35 | using System.Xml.Serialization; | 36 | using System.Xml.Serialization; |
37 | using log4net; | ||
36 | using OpenMetaverse; | 38 | using OpenMetaverse; |
37 | using OpenMetaverse.StructuredData; | 39 | using OpenMetaverse.StructuredData; |
38 | 40 | ||
@@ -48,13 +50,20 @@ namespace OpenSim.Framework | |||
48 | /// within their data store. However, avoid storing large amounts of data because that | 50 | /// within their data store. However, avoid storing large amounts of data because that |
49 | /// would slow down database access. | 51 | /// would slow down database access. |
50 | /// </remarks> | 52 | /// </remarks> |
51 | public class DAMap : IDictionary<string, OSDMap>, IXmlSerializable | 53 | public class DAMap : IXmlSerializable |
52 | { | 54 | { |
53 | private static readonly int MIN_STORE_NAME_LENGTH = 4; | 55 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
54 | 56 | ||
55 | protected OSDMap m_map; | 57 | private static readonly int MIN_NAMESPACE_LENGTH = 4; |
56 | 58 | ||
57 | public DAMap() { m_map = new OSDMap(); } | 59 | private OSDMap m_map = new OSDMap(); |
60 | |||
61 | // WARNING: this is temporary for experimentation only, it will be removed!!!! | ||
62 | public OSDMap TopLevelMap | ||
63 | { | ||
64 | get { return m_map; } | ||
65 | set { m_map = value; } | ||
66 | } | ||
58 | 67 | ||
59 | public XmlSchema GetSchema() { return null; } | 68 | public XmlSchema GetSchema() { return null; } |
60 | 69 | ||
@@ -64,39 +73,34 @@ namespace OpenSim.Framework | |||
64 | map.ReadXml(rawXml); | 73 | map.ReadXml(rawXml); |
65 | return map; | 74 | return map; |
66 | } | 75 | } |
67 | 76 | ||
77 | public void ReadXml(XmlReader reader) | ||
78 | { | ||
79 | ReadXml(reader.ReadInnerXml()); | ||
80 | } | ||
81 | |||
68 | public void ReadXml(string rawXml) | 82 | public void ReadXml(string rawXml) |
69 | { | 83 | { |
70 | // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml); | 84 | // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml); |
71 | 85 | ||
72 | lock (this) | 86 | lock (this) |
87 | { | ||
73 | m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); | 88 | m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); |
89 | SanitiseMap(this); | ||
90 | } | ||
74 | } | 91 | } |
75 | 92 | ||
76 | // WARNING: this is temporary for experimentation only, it will be removed!!!! | 93 | public void WriteXml(XmlWriter writer) |
77 | public OSDMap TopLevelMap | ||
78 | { | 94 | { |
79 | get { return m_map; } | 95 | writer.WriteRaw(ToXml()); |
80 | set { m_map = value; } | ||
81 | } | 96 | } |
82 | |||
83 | 97 | ||
84 | public void ReadXml(XmlReader reader) | ||
85 | { | ||
86 | ReadXml(reader.ReadInnerXml()); | ||
87 | } | ||
88 | |||
89 | public string ToXml() | 98 | public string ToXml() |
90 | { | 99 | { |
91 | lock (this) | 100 | lock (this) |
92 | return OSDParser.SerializeLLSDXmlString(m_map); | 101 | return OSDParser.SerializeLLSDXmlString(m_map); |
93 | } | 102 | } |
94 | 103 | ||
95 | public void WriteXml(XmlWriter writer) | ||
96 | { | ||
97 | writer.WriteRaw(ToXml()); | ||
98 | } | ||
99 | |||
100 | public void CopyFrom(DAMap other) | 104 | public void CopyFrom(DAMap other) |
101 | { | 105 | { |
102 | // Deep copy | 106 | // Deep copy |
@@ -104,7 +108,7 @@ namespace OpenSim.Framework | |||
104 | string data = null; | 108 | string data = null; |
105 | lock (other) | 109 | lock (other) |
106 | { | 110 | { |
107 | if (other.Count > 0) | 111 | if (other.CountNamespaces > 0) |
108 | { | 112 | { |
109 | data = OSDParser.SerializeLLSDXmlString(other.m_map); | 113 | data = OSDParser.SerializeLLSDXmlString(other.m_map); |
110 | } | 114 | } |
@@ -120,59 +124,132 @@ namespace OpenSim.Framework | |||
120 | } | 124 | } |
121 | 125 | ||
122 | /// <summary> | 126 | /// <summary> |
123 | /// Returns the number of data stores. | 127 | /// Sanitise the map to remove any namespaces or stores that are not OSDMap. |
124 | /// </summary> | 128 | /// </summary> |
125 | public int Count { get { lock (this) { return m_map.Count; } } } | 129 | /// <param name='map'> |
126 | 130 | /// </param> | |
127 | public bool IsReadOnly { get { return false; } } | 131 | public static void SanitiseMap(DAMap daMap) |
128 | 132 | { | |
133 | List<string> keysToRemove = null; | ||
134 | |||
135 | OSDMap namespacesMap = daMap.m_map; | ||
136 | |||
137 | foreach (string key in namespacesMap.Keys) | ||
138 | { | ||
139 | // Console.WriteLine("Processing ns {0}", key); | ||
140 | if (!(namespacesMap[key] is OSDMap)) | ||
141 | { | ||
142 | if (keysToRemove == null) | ||
143 | keysToRemove = new List<string>(); | ||
144 | |||
145 | keysToRemove.Add(key); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | if (keysToRemove != null) | ||
150 | { | ||
151 | foreach (string key in keysToRemove) | ||
152 | { | ||
153 | // Console.WriteLine ("Removing bad ns {0}", key); | ||
154 | namespacesMap.Remove(key); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | foreach (OSD nsOsd in namespacesMap.Values) | ||
159 | { | ||
160 | OSDMap nsOsdMap = (OSDMap)nsOsd; | ||
161 | keysToRemove = null; | ||
162 | |||
163 | foreach (string key in nsOsdMap.Keys) | ||
164 | { | ||
165 | if (!(nsOsdMap[key] is OSDMap)) | ||
166 | { | ||
167 | if (keysToRemove == null) | ||
168 | keysToRemove = new List<string>(); | ||
169 | |||
170 | keysToRemove.Add(key); | ||
171 | } | ||
172 | } | ||
173 | |||
174 | if (keysToRemove != null) | ||
175 | foreach (string key in keysToRemove) | ||
176 | nsOsdMap.Remove(key); | ||
177 | } | ||
178 | } | ||
179 | |||
129 | /// <summary> | 180 | /// <summary> |
130 | /// Returns the names of the data stores. | 181 | /// Get the number of namespaces |
131 | /// </summary> | 182 | /// </summary> |
132 | public ICollection<string> Keys { get { lock (this) { return m_map.Keys; } } } | 183 | public int CountNamespaces { get { lock (this) { return m_map.Count; } } } |
133 | 184 | ||
134 | /// <summary> | 185 | /// <summary> |
135 | /// Returns all the data stores. | 186 | /// Get the number of stores. |
136 | /// </summary> | 187 | /// </summary> |
137 | public ICollection<OSDMap> Values | 188 | public int CountStores |
138 | { | 189 | { |
139 | get | 190 | get |
140 | { | 191 | { |
192 | int count = 0; | ||
193 | |||
141 | lock (this) | 194 | lock (this) |
142 | { | 195 | { |
143 | List<OSDMap> stores = new List<OSDMap>(m_map.Count); | 196 | foreach (OSD osdNamespace in m_map) |
144 | foreach (OSD llsd in m_map.Values) | 197 | { |
145 | stores.Add((OSDMap)llsd); | 198 | count += ((OSDMap)osdNamespace).Count; |
146 | return stores; | 199 | } |
147 | } | 200 | } |
201 | |||
202 | return count; | ||
148 | } | 203 | } |
149 | } | 204 | } |
150 | 205 | ||
151 | /// <summary> | 206 | /// <summary> |
152 | /// Gets or sets one data store. | 207 | /// Retrieve a Dynamic Attribute store |
153 | /// </summary> | 208 | /// </summary> |
154 | /// <param name="key">Store name</param> | 209 | /// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param> |
155 | /// <returns></returns> | 210 | /// <param name="storeName">name of the store within the namespace</param> |
156 | public OSDMap this[string key] | 211 | /// <returns>an OSDMap representing the stored data, or null if not found</returns> |
157 | { | 212 | public OSDMap GetStore(string ns, string storeName) |
158 | get | 213 | { |
159 | { | 214 | OSD namespaceOsd; |
160 | OSD llsd; | 215 | |
161 | 216 | lock (this) | |
162 | lock (this) | 217 | { |
218 | if (m_map.TryGetValue(ns, out namespaceOsd)) | ||
163 | { | 219 | { |
164 | if (m_map.TryGetValue(key, out llsd)) | 220 | OSD store; |
165 | return (OSDMap)llsd; | 221 | |
166 | else | 222 | if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store)) |
167 | return null; | 223 | return (OSDMap)store; |
168 | } | 224 | } |
169 | } | 225 | } |
170 | 226 | ||
171 | set | 227 | return null; |
228 | } | ||
229 | |||
230 | /// <summary> | ||
231 | /// Saves a Dynamic attribute store | ||
232 | /// </summary> | ||
233 | /// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param> | ||
234 | /// <param name="storeName">name of the store within the namespace</param> | ||
235 | /// <param name="store">an OSDMap representing the data to store</param> | ||
236 | public void SetStore(string ns, string storeName, OSDMap store) | ||
237 | { | ||
238 | ValidateNamespace(ns); | ||
239 | OSDMap nsMap; | ||
240 | |||
241 | lock (this) | ||
172 | { | 242 | { |
173 | ValidateKey(key); | 243 | if (!m_map.ContainsKey(ns)) |
174 | lock (this) | 244 | { |
175 | m_map[key] = value; | 245 | nsMap = new OSDMap(); |
246 | m_map[ns] = nsMap; | ||
247 | } | ||
248 | |||
249 | nsMap = (OSDMap)m_map[ns]; | ||
250 | |||
251 | // m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName); | ||
252 | nsMap[storeName] = store; | ||
176 | } | 253 | } |
177 | } | 254 | } |
178 | 255 | ||
@@ -180,54 +257,46 @@ namespace OpenSim.Framework | |||
180 | /// Validate the key used for storing separate data stores. | 257 | /// Validate the key used for storing separate data stores. |
181 | /// </summary> | 258 | /// </summary> |
182 | /// <param name='key'></param> | 259 | /// <param name='key'></param> |
183 | public static void ValidateKey(string key) | 260 | public static void ValidateNamespace(string ns) |
184 | { | 261 | { |
185 | if (key.Length < MIN_STORE_NAME_LENGTH) | 262 | if (ns.Length < MIN_NAMESPACE_LENGTH) |
186 | throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH); | 263 | throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH); |
187 | } | 264 | } |
188 | 265 | ||
189 | public bool ContainsKey(string key) | 266 | public bool ContainsStore(string ns, string storeName) |
190 | { | 267 | { |
191 | lock (this) | 268 | OSD namespaceOsd; |
192 | return m_map.ContainsKey(key); | ||
193 | } | ||
194 | 269 | ||
195 | public void Add(string key, OSDMap store) | ||
196 | { | ||
197 | ValidateKey(key); | ||
198 | lock (this) | ||
199 | m_map.Add(key, store); | ||
200 | } | ||
201 | |||
202 | public void Add(KeyValuePair<string, OSDMap> kvp) | ||
203 | { | ||
204 | ValidateKey(kvp.Key); | ||
205 | lock (this) | 270 | lock (this) |
206 | m_map.Add(kvp.Key, kvp.Value); | 271 | { |
207 | } | 272 | if (m_map.TryGetValue(ns, out namespaceOsd)) |
273 | { | ||
274 | return ((OSDMap)namespaceOsd).ContainsKey(storeName); | ||
275 | } | ||
276 | } | ||
208 | 277 | ||
209 | public bool Remove(string key) | 278 | return false; |
210 | { | 279 | } |
211 | lock (this) | ||
212 | return m_map.Remove(key); | ||
213 | } | ||
214 | 280 | ||
215 | public bool TryGetValue(string key, out OSDMap store) | 281 | public bool TryGetStore(string ns, string storeName, out OSDMap store) |
216 | { | 282 | { |
283 | OSD namespaceOsd; | ||
284 | |||
217 | lock (this) | 285 | lock (this) |
218 | { | 286 | { |
219 | OSD llsd; | 287 | if (m_map.TryGetValue(ns, out namespaceOsd)) |
220 | if (m_map.TryGetValue(key, out llsd)) | ||
221 | { | ||
222 | store = (OSDMap)llsd; | ||
223 | return true; | ||
224 | } | ||
225 | else | ||
226 | { | 288 | { |
227 | store = null; | 289 | OSD storeOsd; |
228 | return false; | 290 | |
291 | bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd); | ||
292 | store = (OSDMap)storeOsd; | ||
293 | |||
294 | return result; | ||
229 | } | 295 | } |
230 | } | 296 | } |
297 | |||
298 | store = null; | ||
299 | return false; | ||
231 | } | 300 | } |
232 | 301 | ||
233 | public void Clear() | 302 | public void Clear() |
@@ -235,39 +304,25 @@ namespace OpenSim.Framework | |||
235 | lock (this) | 304 | lock (this) |
236 | m_map.Clear(); | 305 | m_map.Clear(); |
237 | } | 306 | } |
238 | |||
239 | public bool Contains(KeyValuePair<string, OSDMap> kvp) | ||
240 | { | ||
241 | lock (this) | ||
242 | return m_map.ContainsKey(kvp.Key); | ||
243 | } | ||
244 | |||
245 | public void CopyTo(KeyValuePair<string, OSDMap>[] array, int index) | ||
246 | { | ||
247 | throw new NotImplementedException(); | ||
248 | } | ||
249 | 307 | ||
250 | public bool Remove(KeyValuePair<string, OSDMap> kvp) | 308 | public bool RemoveStore(string ns, string storeName) |
251 | { | 309 | { |
252 | lock (this) | 310 | OSD namespaceOsd; |
253 | return m_map.Remove(kvp.Key); | ||
254 | } | ||
255 | 311 | ||
256 | public System.Collections.IDictionaryEnumerator GetEnumerator() | ||
257 | { | ||
258 | lock (this) | 312 | lock (this) |
259 | return m_map.GetEnumerator(); | 313 | { |
260 | } | 314 | if (m_map.TryGetValue(ns, out namespaceOsd)) |
315 | { | ||
316 | OSDMap namespaceOsdMap = (OSDMap)namespaceOsd; | ||
317 | namespaceOsdMap.Remove(storeName); | ||
261 | 318 | ||
262 | IEnumerator<KeyValuePair<string, OSDMap>> IEnumerable<KeyValuePair<string, OSDMap>>.GetEnumerator() | 319 | // Don't keep empty namespaces around |
263 | { | 320 | if (namespaceOsdMap.Count <= 0) |
264 | return null; | 321 | m_map.Remove(ns); |
265 | } | 322 | } |
323 | } | ||
266 | 324 | ||
267 | IEnumerator IEnumerable.GetEnumerator() | 325 | return false; |
268 | { | 326 | } |
269 | lock (this) | ||
270 | return m_map.GetEnumerator(); | ||
271 | } | ||
272 | } | 327 | } |
273 | } \ No newline at end of file | 328 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs index 755e129..f5b650b 100644 --- a/OpenSim/Framework/DOMap.cs +++ b/OpenSim/Framework/DOMap.cs | |||
@@ -42,22 +42,22 @@ namespace OpenSim.Framework | |||
42 | /// This class stores and retrieves dynamic objects. | 42 | /// This class stores and retrieves dynamic objects. |
43 | /// </summary> | 43 | /// </summary> |
44 | /// <remarks> | 44 | /// <remarks> |
45 | /// Experimental - DO NOT USE. | 45 | /// Experimental - DO NOT USE. Does not yet have namespace support. |
46 | /// </remarks> | 46 | /// </remarks> |
47 | public class DOMap | 47 | public class DOMap |
48 | { | 48 | { |
49 | private IDictionary<string, object> m_map; | 49 | private IDictionary<string, object> m_map; |
50 | 50 | ||
51 | public void Add(string key, object dynObj) | 51 | public void Add(string ns, string objName, object dynObj) |
52 | { | 52 | { |
53 | DAMap.ValidateKey(key); | 53 | DAMap.ValidateNamespace(ns); |
54 | 54 | ||
55 | lock (this) | 55 | lock (this) |
56 | { | 56 | { |
57 | if (m_map == null) | 57 | if (m_map == null) |
58 | m_map = new Dictionary<string, object>(); | 58 | m_map = new Dictionary<string, object>(); |
59 | 59 | ||
60 | m_map.Add(key, dynObj); | 60 | m_map.Add(objName, dynObj); |
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs index e03750b..5ddbd61 100644 --- a/OpenSim/Framework/EstateSettings.cs +++ b/OpenSim/Framework/EstateSettings.cs | |||
@@ -430,6 +430,5 @@ namespace OpenSim.Framework | |||
430 | { | 430 | { |
431 | return l_EstateGroups.Contains(groupID); | 431 | return l_EstateGroups.Contains(groupID); |
432 | } | 432 | } |
433 | |||
434 | } | 433 | } |
435 | } | 434 | } |
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index ad3471a..22cc79d 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs | |||
@@ -65,6 +65,7 @@ namespace OpenSim.Framework | |||
65 | public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); | 65 | public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); |
66 | 66 | ||
67 | public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems); | 67 | public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems); |
68 | public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List<CachedTextureRequestArg> cachedTextureRequest); | ||
68 | 69 | ||
69 | public delegate void StartAnim(IClientAPI remoteClient, UUID animID); | 70 | public delegate void StartAnim(IClientAPI remoteClient, UUID animID); |
70 | 71 | ||
@@ -789,6 +790,7 @@ namespace OpenSim.Framework | |||
789 | event EstateChangeInfo OnEstateChangeInfo; | 790 | event EstateChangeInfo OnEstateChangeInfo; |
790 | event EstateManageTelehub OnEstateManageTelehub; | 791 | event EstateManageTelehub OnEstateManageTelehub; |
791 | // [Obsolete("LLClientView Specific.")] | 792 | // [Obsolete("LLClientView Specific.")] |
793 | event CachedTextureRequest OnCachedTextureRequest; | ||
792 | event SetAppearance OnSetAppearance; | 794 | event SetAppearance OnSetAppearance; |
793 | // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] | 795 | // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] |
794 | event AvatarNowWearing OnAvatarNowWearing; | 796 | event AvatarNowWearing OnAvatarNowWearing; |
@@ -832,6 +834,8 @@ namespace OpenSim.Framework | |||
832 | /// </remarks> | 834 | /// </remarks> |
833 | event UpdateAgent OnAgentUpdate; | 835 | event UpdateAgent OnAgentUpdate; |
834 | 836 | ||
837 | event UpdateAgent OnAgentCameraUpdate; | ||
838 | |||
835 | event AgentRequestSit OnAgentRequestSit; | 839 | event AgentRequestSit OnAgentRequestSit; |
836 | event AgentSit OnAgentSit; | 840 | event AgentSit OnAgentSit; |
837 | event AvatarPickerRequest OnAvatarPickerRequest; | 841 | event AvatarPickerRequest OnAvatarPickerRequest; |
@@ -1100,14 +1104,15 @@ namespace OpenSim.Framework | |||
1100 | /// <param name="textureEntry"></param> | 1104 | /// <param name="textureEntry"></param> |
1101 | void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); | 1105 | void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); |
1102 | 1106 | ||
1107 | void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures); | ||
1108 | |||
1103 | void SendStartPingCheck(byte seq); | 1109 | void SendStartPingCheck(byte seq); |
1104 | 1110 | ||
1105 | /// <summary> | 1111 | /// <summary> |
1106 | /// Tell the client that an object has been deleted | 1112 | /// Tell the client that an object has been deleted |
1107 | /// </summary> | 1113 | /// </summary> |
1108 | /// <param name="regionHandle"></param> | ||
1109 | /// <param name="localID"></param> | 1114 | /// <param name="localID"></param> |
1110 | void SendKillObject(ulong regionHandle, List<uint> localID); | 1115 | void SendKillObject(List<uint> localID); |
1111 | 1116 | ||
1112 | void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); | 1117 | void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); |
1113 | void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); | 1118 | void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); |
@@ -1486,7 +1491,7 @@ namespace OpenSim.Framework | |||
1486 | void SendChangeUserRights(UUID agentID, UUID friendID, int rights); | 1491 | void SendChangeUserRights(UUID agentID, UUID friendID, int rights); |
1487 | void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); | 1492 | void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); |
1488 | 1493 | ||
1489 | void StopFlying(ISceneEntity presence); | 1494 | void SendAgentTerseUpdate(ISceneEntity presence); |
1490 | 1495 | ||
1491 | void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); | 1496 | void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); |
1492 | } | 1497 | } |
diff --git a/OpenSim/Framework/IImprovedAssetCache.cs b/OpenSim/Framework/IImprovedAssetCache.cs index a0b8b55..a853e90 100644 --- a/OpenSim/Framework/IImprovedAssetCache.cs +++ b/OpenSim/Framework/IImprovedAssetCache.cs | |||
@@ -31,10 +31,34 @@ namespace OpenSim.Framework | |||
31 | { | 31 | { |
32 | public interface IImprovedAssetCache | 32 | public interface IImprovedAssetCache |
33 | { | 33 | { |
34 | /// <summary> | ||
35 | /// Cache the specified asset. | ||
36 | /// </summary> | ||
37 | /// <param name='asset'></param> | ||
34 | void Cache(AssetBase asset); | 38 | void Cache(AssetBase asset); |
39 | |||
40 | /// <summary> | ||
41 | /// Get an asset by its id. | ||
42 | /// </summary> | ||
43 | /// <param name='id'></param> | ||
44 | /// <returns>null if the asset does not exist.</returns> | ||
35 | AssetBase Get(string id); | 45 | AssetBase Get(string id); |
46 | |||
47 | /// <summary> | ||
48 | /// Check whether an asset with the specified id exists in the cache. | ||
49 | /// </summary> | ||
50 | /// <param name='id'></param> | ||
36 | bool Check(string id); | 51 | bool Check(string id); |
52 | |||
53 | /// <summary> | ||
54 | /// Expire an asset from the cache. | ||
55 | /// </summary> | ||
56 | /// <param name='id'></param> | ||
37 | void Expire(string id); | 57 | void Expire(string id); |
58 | |||
59 | /// <summary> | ||
60 | /// Clear the cache. | ||
61 | /// </summary> | ||
38 | void Clear(); | 62 | void Clear(); |
39 | } | 63 | } |
40 | } | 64 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs new file mode 100644 index 0000000..b88e103 --- /dev/null +++ b/OpenSim/Framework/IPeople.cs | |||
@@ -0,0 +1,47 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Framework | ||
33 | { | ||
34 | public class UserData | ||
35 | { | ||
36 | public UUID Id { get; set; } | ||
37 | public string FirstName { get; set; } | ||
38 | public string LastName { get; set; } | ||
39 | public string HomeURL { get; set; } | ||
40 | public Dictionary<string, object> ServerURLs { get; set; } | ||
41 | } | ||
42 | |||
43 | public interface IPeople | ||
44 | { | ||
45 | List<UserData> GetUserData(string query, int page_size, int page_number); | ||
46 | } | ||
47 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs index 87ec99e..e1b6d1e 100644 --- a/OpenSim/Framework/IScene.cs +++ b/OpenSim/Framework/IScene.cs | |||
@@ -86,24 +86,26 @@ namespace OpenSim.Framework | |||
86 | event restart OnRestart; | 86 | event restart OnRestart; |
87 | 87 | ||
88 | /// <summary> | 88 | /// <summary> |
89 | /// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent | 89 | /// Add a new agent with an attached client. All agents except initial login clients will starts off as a child agent |
90 | /// - the later agent crossing will promote it to a root agent. | 90 | /// - the later agent crossing will promote it to a root agent. |
91 | /// </summary> | 91 | /// </summary> |
92 | /// <param name="client"></param> | 92 | /// <param name="client"></param> |
93 | /// <param name="type">The type of agent to add.</param> | 93 | /// <param name="type">The type of agent to add.</param> |
94 | /// <returns> | 94 | /// <returns> |
95 | /// The scene agent if the new client was added or if an agent that already existed.</returns> | 95 | /// The scene agent if the new client was added or if an agent that already existed.</returns> |
96 | ISceneAgent AddNewClient(IClientAPI client, PresenceType type); | 96 | ISceneAgent AddNewAgent(IClientAPI client, PresenceType type); |
97 | 97 | ||
98 | /// <summary> | 98 | /// <summary> |
99 | /// Remove the given client from the scene. | 99 | /// Tell a single agent to disconnect from the region. |
100 | /// </summary> | 100 | /// </summary> |
101 | /// <param name="agentID"></param> | 101 | /// <param name="agentID"></param> |
102 | /// <param name="closeChildAgents">Close the neighbour child agents associated with this client.</param> | 102 | /// <param name="force"> |
103 | void RemoveClient(UUID agentID, bool closeChildAgents); | 103 | /// Force the agent to close even if it might be in the middle of some other operation. You do not want to |
104 | /// force unless you are absolutely sure that the agent is dead and a normal close is not working. | ||
105 | /// </param> | ||
106 | bool CloseAgent(UUID agentID, bool force); | ||
104 | 107 | ||
105 | void Restart(); | 108 | void Restart(); |
106 | //RegionInfo OtherRegionUp(RegionInfo thisRegion); | ||
107 | 109 | ||
108 | string GetSimulatorVersion(); | 110 | string GetSimulatorVersion(); |
109 | 111 | ||
@@ -136,5 +138,10 @@ namespace OpenSim.Framework | |||
136 | ISceneObject DeserializeObject(string representation); | 138 | ISceneObject DeserializeObject(string representation); |
137 | 139 | ||
138 | bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); | 140 | bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); |
141 | |||
142 | /// <summary> | ||
143 | /// Start the scene and associated scripts within it. | ||
144 | /// </summary> | ||
145 | void Start(); | ||
139 | } | 146 | } |
140 | } | 147 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/InventoryItemBase.cs b/OpenSim/Framework/InventoryItemBase.cs index 3d45e76..558dfd0 100644 --- a/OpenSim/Framework/InventoryItemBase.cs +++ b/OpenSim/Framework/InventoryItemBase.cs | |||
@@ -122,7 +122,7 @@ namespace OpenSim.Framework | |||
122 | { | 122 | { |
123 | get | 123 | get |
124 | { | 124 | { |
125 | if (m_creatorData != null && m_creatorData != string.Empty) | 125 | if (!string.IsNullOrEmpty(m_creatorData)) |
126 | return m_creatorId + ';' + m_creatorData; | 126 | return m_creatorId + ';' + m_creatorData; |
127 | else | 127 | else |
128 | return m_creatorId; | 128 | return m_creatorId; |
diff --git a/OpenSim/Framework/Location.cs b/OpenSim/Framework/Location.cs index 9504e03..0b88834 100644 --- a/OpenSim/Framework/Location.cs +++ b/OpenSim/Framework/Location.cs | |||
@@ -33,10 +33,10 @@ namespace OpenSim.Framework | |||
33 | [Serializable] | 33 | [Serializable] |
34 | public class Location : ICloneable | 34 | public class Location : ICloneable |
35 | { | 35 | { |
36 | private readonly int m_x; | 36 | private readonly uint m_x; |
37 | private readonly int m_y; | 37 | private readonly uint m_y; |
38 | 38 | ||
39 | public Location(int x, int y) | 39 | public Location(uint x, uint y) |
40 | { | 40 | { |
41 | m_x = x; | 41 | m_x = x; |
42 | m_y = y; | 42 | m_y = y; |
@@ -44,21 +44,21 @@ namespace OpenSim.Framework | |||
44 | 44 | ||
45 | public Location(ulong regionHandle) | 45 | public Location(ulong regionHandle) |
46 | { | 46 | { |
47 | m_x = (int) regionHandle; | 47 | m_x = (uint)(regionHandle >> 32); |
48 | m_y = (int) (regionHandle >> 32); | 48 | m_y = (uint)(regionHandle & (ulong)uint.MaxValue); |
49 | } | 49 | } |
50 | 50 | ||
51 | public ulong RegionHandle | 51 | public ulong RegionHandle |
52 | { | 52 | { |
53 | get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); } | 53 | get { return Utils.UIntsToLong(m_x, m_y); } |
54 | } | 54 | } |
55 | 55 | ||
56 | public int X | 56 | public uint X |
57 | { | 57 | { |
58 | get { return m_x; } | 58 | get { return m_x; } |
59 | } | 59 | } |
60 | 60 | ||
61 | public int Y | 61 | public uint Y |
62 | { | 62 | { |
63 | get { return m_y; } | 63 | get { return m_y; } |
64 | } | 64 | } |
diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs index 23dba09..96536e8 100644 --- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs +++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -44,16 +44,16 @@ namespace OpenSim.Framework.Monitoring | |||
44 | sb.Append("MEMORY STATISTICS"); | 44 | sb.Append("MEMORY STATISTICS"); |
45 | sb.Append(Environment.NewLine); | 45 | sb.Append(Environment.NewLine); |
46 | sb.AppendFormat( | 46 | sb.AppendFormat( |
47 | "Allocated to OpenSim objects: {0} MB\n", | 47 | "Heap allocated to OpenSim : {0} MB\n", |
48 | Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); | 48 | Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); |
49 | 49 | ||
50 | sb.AppendFormat( | 50 | sb.AppendFormat( |
51 | "OpenSim last object memory churn : {0} MB/s\n", | 51 | "Last heap allocation rate : {0} MB/s\n", |
52 | Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3)); | 52 | Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); |
53 | 53 | ||
54 | sb.AppendFormat( | 54 | sb.AppendFormat( |
55 | "OpenSim average object memory churn : {0} MB/s\n", | 55 | "Average heap allocation rate: {0} MB/s\n", |
56 | Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3)); | 56 | Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3)); |
57 | 57 | ||
58 | Process myprocess = Process.GetCurrentProcess(); | 58 | Process myprocess = Process.GetCurrentProcess(); |
59 | if (!myprocess.HasExited) | 59 | if (!myprocess.HasExited) |
diff --git a/OpenSim/Framework/Monitoring/Checks/Check.cs b/OpenSim/Framework/Monitoring/Checks/Check.cs new file mode 100644 index 0000000..594386a --- /dev/null +++ b/OpenSim/Framework/Monitoring/Checks/Check.cs | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Text; | ||
30 | |||
31 | namespace OpenSim.Framework.Monitoring | ||
32 | { | ||
33 | public class Check | ||
34 | { | ||
35 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
36 | |||
37 | public static readonly char[] DisallowedShortNameCharacters = { '.' }; | ||
38 | |||
39 | /// <summary> | ||
40 | /// Category of this stat (e.g. cache, scene, etc). | ||
41 | /// </summary> | ||
42 | public string Category { get; private set; } | ||
43 | |||
44 | /// <summary> | ||
45 | /// Containing name for this stat. | ||
46 | /// FIXME: In the case of a scene, this is currently the scene name (though this leaves | ||
47 | /// us with a to-be-resolved problem of non-unique region names). | ||
48 | /// </summary> | ||
49 | /// <value> | ||
50 | /// The container. | ||
51 | /// </value> | ||
52 | public string Container { get; private set; } | ||
53 | |||
54 | /// <summary> | ||
55 | /// Action used to check whether alert should go off. | ||
56 | /// </summary> | ||
57 | /// <remarks> | ||
58 | /// Should return true if check passes. False otherwise. | ||
59 | /// </remarks> | ||
60 | public Func<Check, bool> CheckFunc { get; private set; } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Message from the last failure, if any. If there is no message or no failure then will be null. | ||
64 | /// </summary> | ||
65 | /// <remarks> | ||
66 | /// Should be set by the CheckFunc when applicable. | ||
67 | /// </remarks> | ||
68 | public string LastFailureMessage { get; set; } | ||
69 | |||
70 | public StatVerbosity Verbosity { get; private set; } | ||
71 | public string ShortName { get; private set; } | ||
72 | public string Name { get; private set; } | ||
73 | public string Description { get; private set; } | ||
74 | |||
75 | public Check( | ||
76 | string shortName, | ||
77 | string name, | ||
78 | string description, | ||
79 | string category, | ||
80 | string container, | ||
81 | Func<Check, bool> checkFunc, | ||
82 | StatVerbosity verbosity) | ||
83 | { | ||
84 | if (ChecksManager.SubCommands.Contains(category)) | ||
85 | throw new Exception( | ||
86 | string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category)); | ||
87 | |||
88 | foreach (char c in DisallowedShortNameCharacters) | ||
89 | { | ||
90 | if (shortName.IndexOf(c) != -1) | ||
91 | throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c)); | ||
92 | } | ||
93 | |||
94 | ShortName = shortName; | ||
95 | Name = name; | ||
96 | Description = description; | ||
97 | Category = category; | ||
98 | Container = container; | ||
99 | CheckFunc = checkFunc; | ||
100 | Verbosity = verbosity; | ||
101 | } | ||
102 | |||
103 | public bool CheckIt() | ||
104 | { | ||
105 | return CheckFunc(this); | ||
106 | } | ||
107 | |||
108 | public virtual string ToConsoleString() | ||
109 | { | ||
110 | return string.Format( | ||
111 | "{0}.{1}.{2} - {3}", | ||
112 | Category, | ||
113 | Container, | ||
114 | ShortName, | ||
115 | Description); | ||
116 | } | ||
117 | } | ||
118 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Monitoring/ChecksManager.cs b/OpenSim/Framework/Monitoring/ChecksManager.cs new file mode 100644 index 0000000..e4a7f8c --- /dev/null +++ b/OpenSim/Framework/Monitoring/ChecksManager.cs | |||
@@ -0,0 +1,262 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
32 | using System.Text; | ||
33 | using log4net; | ||
34 | |||
35 | namespace OpenSim.Framework.Monitoring | ||
36 | { | ||
37 | /// <summary> | ||
38 | /// Static class used to register/deregister checks on runtime conditions. | ||
39 | /// </summary> | ||
40 | public static class ChecksManager | ||
41 | { | ||
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
43 | |||
44 | // Subcommand used to list other stats. | ||
45 | public const string ListSubCommand = "list"; | ||
46 | |||
47 | // All subcommands | ||
48 | public static HashSet<string> SubCommands = new HashSet<string> { ListSubCommand }; | ||
49 | |||
50 | /// <summary> | ||
51 | /// Checks categorized by category/container/shortname | ||
52 | /// </summary> | ||
53 | /// <remarks> | ||
54 | /// Do not add or remove directly from this dictionary. | ||
55 | /// </remarks> | ||
56 | public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>> RegisteredChecks | ||
57 | = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>>(); | ||
58 | |||
59 | public static void RegisterConsoleCommands(ICommandConsole console) | ||
60 | { | ||
61 | console.Commands.AddCommand( | ||
62 | "General", | ||
63 | false, | ||
64 | "show checks", | ||
65 | "show checks", | ||
66 | "Show checks configured for this server", | ||
67 | "If no argument is specified then info on all checks will be shown.\n" | ||
68 | + "'list' argument will show check categories.\n" | ||
69 | + "THIS FACILITY IS EXPERIMENTAL", | ||
70 | HandleShowchecksCommand); | ||
71 | } | ||
72 | |||
73 | public static void HandleShowchecksCommand(string module, string[] cmd) | ||
74 | { | ||
75 | ICommandConsole con = MainConsole.Instance; | ||
76 | |||
77 | if (cmd.Length > 2) | ||
78 | { | ||
79 | foreach (string name in cmd.Skip(2)) | ||
80 | { | ||
81 | string[] components = name.Split('.'); | ||
82 | |||
83 | string categoryName = components[0]; | ||
84 | // string containerName = components.Length > 1 ? components[1] : null; | ||
85 | |||
86 | if (categoryName == ListSubCommand) | ||
87 | { | ||
88 | con.Output("check categories available are:"); | ||
89 | |||
90 | foreach (string category in RegisteredChecks.Keys) | ||
91 | con.OutputFormat(" {0}", category); | ||
92 | } | ||
93 | // else | ||
94 | // { | ||
95 | // SortedDictionary<string, SortedDictionary<string, Check>> category; | ||
96 | // if (!Registeredchecks.TryGetValue(categoryName, out category)) | ||
97 | // { | ||
98 | // con.OutputFormat("No such category as {0}", categoryName); | ||
99 | // } | ||
100 | // else | ||
101 | // { | ||
102 | // if (String.IsNullOrEmpty(containerName)) | ||
103 | // { | ||
104 | // OutputConfiguredToConsole(con, category); | ||
105 | // } | ||
106 | // else | ||
107 | // { | ||
108 | // SortedDictionary<string, Check> container; | ||
109 | // if (category.TryGetValue(containerName, out container)) | ||
110 | // { | ||
111 | // OutputContainerChecksToConsole(con, container); | ||
112 | // } | ||
113 | // else | ||
114 | // { | ||
115 | // con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); | ||
116 | // } | ||
117 | // } | ||
118 | // } | ||
119 | // } | ||
120 | } | ||
121 | } | ||
122 | else | ||
123 | { | ||
124 | OutputAllChecksToConsole(con); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /// <summary> | ||
129 | /// Registers a statistic. | ||
130 | /// </summary> | ||
131 | /// <param name='stat'></param> | ||
132 | /// <returns></returns> | ||
133 | public static bool RegisterCheck(Check check) | ||
134 | { | ||
135 | SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory; | ||
136 | SortedDictionary<string, Check> container = null, newContainer; | ||
137 | |||
138 | lock (RegisteredChecks) | ||
139 | { | ||
140 | // Check name is not unique across category/container/shortname key. | ||
141 | // XXX: For now just return false. This is to avoid problems in regression tests where all tests | ||
142 | // in a class are run in the same instance of the VM. | ||
143 | if (TryGetCheckParents(check, out category, out container)) | ||
144 | return false; | ||
145 | |||
146 | // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. | ||
147 | // This means that we don't need to lock or copy them on iteration, which will be a much more | ||
148 | // common operation after startup. | ||
149 | if (container != null) | ||
150 | newContainer = new SortedDictionary<string, Check>(container); | ||
151 | else | ||
152 | newContainer = new SortedDictionary<string, Check>(); | ||
153 | |||
154 | if (category != null) | ||
155 | newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category); | ||
156 | else | ||
157 | newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(); | ||
158 | |||
159 | newContainer[check.ShortName] = check; | ||
160 | newCategory[check.Container] = newContainer; | ||
161 | RegisteredChecks[check.Category] = newCategory; | ||
162 | } | ||
163 | |||
164 | return true; | ||
165 | } | ||
166 | |||
167 | /// <summary> | ||
168 | /// Deregister an check | ||
169 | /// </summary>> | ||
170 | /// <param name='stat'></param> | ||
171 | /// <returns></returns> | ||
172 | public static bool DeregisterCheck(Check check) | ||
173 | { | ||
174 | SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory; | ||
175 | SortedDictionary<string, Check> container = null, newContainer; | ||
176 | |||
177 | lock (RegisteredChecks) | ||
178 | { | ||
179 | if (!TryGetCheckParents(check, out category, out container)) | ||
180 | return false; | ||
181 | |||
182 | newContainer = new SortedDictionary<string, Check>(container); | ||
183 | newContainer.Remove(check.ShortName); | ||
184 | |||
185 | newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category); | ||
186 | newCategory.Remove(check.Container); | ||
187 | |||
188 | newCategory[check.Container] = newContainer; | ||
189 | RegisteredChecks[check.Category] = newCategory; | ||
190 | |||
191 | return true; | ||
192 | } | ||
193 | } | ||
194 | |||
195 | public static bool TryGetCheckParents( | ||
196 | Check check, | ||
197 | out SortedDictionary<string, SortedDictionary<string, Check>> category, | ||
198 | out SortedDictionary<string, Check> container) | ||
199 | { | ||
200 | category = null; | ||
201 | container = null; | ||
202 | |||
203 | lock (RegisteredChecks) | ||
204 | { | ||
205 | if (RegisteredChecks.TryGetValue(check.Category, out category)) | ||
206 | { | ||
207 | if (category.TryGetValue(check.Container, out container)) | ||
208 | { | ||
209 | if (container.ContainsKey(check.ShortName)) | ||
210 | return true; | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | |||
215 | return false; | ||
216 | } | ||
217 | |||
218 | public static void CheckChecks() | ||
219 | { | ||
220 | lock (RegisteredChecks) | ||
221 | { | ||
222 | foreach (SortedDictionary<string, SortedDictionary<string, Check>> category in RegisteredChecks.Values) | ||
223 | { | ||
224 | foreach (SortedDictionary<string, Check> container in category.Values) | ||
225 | { | ||
226 | foreach (Check check in container.Values) | ||
227 | { | ||
228 | if (!check.CheckIt()) | ||
229 | m_log.WarnFormat( | ||
230 | "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | |||
237 | private static void OutputAllChecksToConsole(ICommandConsole con) | ||
238 | { | ||
239 | foreach (var category in RegisteredChecks.Values) | ||
240 | { | ||
241 | OutputCategoryChecksToConsole(con, category); | ||
242 | } | ||
243 | } | ||
244 | |||
245 | private static void OutputCategoryChecksToConsole( | ||
246 | ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Check>> category) | ||
247 | { | ||
248 | foreach (var container in category.Values) | ||
249 | { | ||
250 | OutputContainerChecksToConsole(con, container); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary<string, Check> container) | ||
255 | { | ||
256 | foreach (Check check in container.Values) | ||
257 | { | ||
258 | con.Output(check.ToConsoleString()); | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs index c6010cd..c474622 100644 --- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs +++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs | |||
@@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring | |||
60 | private static bool m_enabled; | 60 | private static bool m_enabled; |
61 | 61 | ||
62 | /// <summary> | 62 | /// <summary> |
63 | /// Last memory churn in bytes per millisecond. | 63 | /// Average heap allocation rate in bytes per millisecond. |
64 | /// </summary> | 64 | /// </summary> |
65 | public static double AverageMemoryChurn | 65 | public static double AverageHeapAllocationRate |
66 | { | 66 | { |
67 | get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } | 67 | get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } |
68 | } | 68 | } |
69 | 69 | ||
70 | /// <summary> | 70 | /// <summary> |
71 | /// Average memory churn in bytes per millisecond. | 71 | /// Last heap allocation in bytes |
72 | /// </summary> | 72 | /// </summary> |
73 | public static double LastMemoryChurn | 73 | public static double LastHeapAllocationRate |
74 | { | 74 | { |
75 | get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } | 75 | get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } |
76 | } | 76 | } |
diff --git a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs index 36678bb..07971bf 100644 --- a/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Monitoring/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs new file mode 100644 index 0000000..ac0f0bc --- /dev/null +++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs | |||
@@ -0,0 +1,349 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Diagnostics; | ||
31 | using System.Linq; | ||
32 | using System.Net.NetworkInformation; | ||
33 | using System.Text; | ||
34 | using System.Threading; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using OpenMetaverse.StructuredData; | ||
38 | using OpenSim.Framework; | ||
39 | |||
40 | namespace OpenSim.Framework.Monitoring | ||
41 | { | ||
42 | public class ServerStatsCollector | ||
43 | { | ||
44 | private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); | ||
45 | private readonly string LogHeader = "[SERVER STATS]"; | ||
46 | |||
47 | public bool Enabled = false; | ||
48 | private static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>(); | ||
49 | |||
50 | public readonly string CategoryServer = "server"; | ||
51 | |||
52 | public readonly string ContainerThreadpool = "threadpool"; | ||
53 | public readonly string ContainerProcessor = "processor"; | ||
54 | public readonly string ContainerMemory = "memory"; | ||
55 | public readonly string ContainerNetwork = "network"; | ||
56 | public readonly string ContainerProcess = "process"; | ||
57 | |||
58 | public string NetworkInterfaceTypes = "Ethernet"; | ||
59 | |||
60 | readonly int performanceCounterSampleInterval = 500; | ||
61 | // int lastperformanceCounterSampleTime = 0; | ||
62 | |||
63 | private class PerfCounterControl | ||
64 | { | ||
65 | public PerformanceCounter perfCounter; | ||
66 | public int lastFetch; | ||
67 | public string name; | ||
68 | public PerfCounterControl(PerformanceCounter pPc) | ||
69 | : this(pPc, String.Empty) | ||
70 | { | ||
71 | } | ||
72 | public PerfCounterControl(PerformanceCounter pPc, string pName) | ||
73 | { | ||
74 | perfCounter = pPc; | ||
75 | lastFetch = 0; | ||
76 | name = pName; | ||
77 | } | ||
78 | } | ||
79 | |||
80 | PerfCounterControl processorPercentPerfCounter = null; | ||
81 | |||
82 | // IRegionModuleBase.Initialize | ||
83 | public void Initialise(IConfigSource source) | ||
84 | { | ||
85 | IConfig cfg = source.Configs["Monitoring"]; | ||
86 | |||
87 | if (cfg != null) | ||
88 | Enabled = cfg.GetBoolean("ServerStatsEnabled", true); | ||
89 | |||
90 | if (Enabled) | ||
91 | { | ||
92 | NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet"); | ||
93 | } | ||
94 | } | ||
95 | |||
96 | public void Start() | ||
97 | { | ||
98 | if (RegisteredStats.Count == 0) | ||
99 | RegisterServerStats(); | ||
100 | } | ||
101 | |||
102 | public void Close() | ||
103 | { | ||
104 | if (RegisteredStats.Count > 0) | ||
105 | { | ||
106 | foreach (Stat stat in RegisteredStats.Values) | ||
107 | { | ||
108 | StatsManager.DeregisterStat(stat); | ||
109 | stat.Dispose(); | ||
110 | } | ||
111 | RegisteredStats.Clear(); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act) | ||
116 | { | ||
117 | MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None); | ||
118 | } | ||
119 | |||
120 | private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act, MeasuresOfInterest moi) | ||
121 | { | ||
122 | string desc = pDesc; | ||
123 | if (desc == null) | ||
124 | desc = pName; | ||
125 | Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug); | ||
126 | StatsManager.RegisterStat(stat); | ||
127 | RegisteredStats.Add(pName, stat); | ||
128 | } | ||
129 | |||
130 | public void RegisterServerStats() | ||
131 | { | ||
132 | // lastperformanceCounterSampleTime = Util.EnvironmentTickCount(); | ||
133 | PerformanceCounter tempPC; | ||
134 | Stat tempStat; | ||
135 | string tempName; | ||
136 | |||
137 | try | ||
138 | { | ||
139 | tempName = "CPUPercent"; | ||
140 | tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total"); | ||
141 | 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. | ||
143 | tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor, | ||
144 | StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); }, | ||
145 | StatVerbosity.Info); | ||
146 | StatsManager.RegisterStat(tempStat); | ||
147 | RegisteredStats.Add(tempName, tempStat); | ||
148 | |||
149 | MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor, | ||
150 | (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; }); | ||
151 | |||
152 | MakeStat("UserProcessorTime", null, "sec", ContainerProcessor, | ||
153 | (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; }); | ||
154 | |||
155 | MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor, | ||
156 | (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; }); | ||
157 | |||
158 | MakeStat("Threads", null, "threads", ContainerProcessor, | ||
159 | (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; }); | ||
160 | } | ||
161 | catch (Exception e) | ||
162 | { | ||
163 | m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e); | ||
164 | } | ||
165 | |||
166 | MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool, | ||
167 | s => | ||
168 | { | ||
169 | int workerThreads, iocpThreads; | ||
170 | ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); | ||
171 | s.Value = workerThreads; | ||
172 | }); | ||
173 | |||
174 | MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool, | ||
175 | s => | ||
176 | { | ||
177 | int workerThreads, iocpThreads; | ||
178 | ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); | ||
179 | s.Value = iocpThreads; | ||
180 | }); | ||
181 | |||
182 | if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null) | ||
183 | { | ||
184 | MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads); | ||
185 | MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads); | ||
186 | MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems); | ||
187 | MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads); | ||
188 | MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads); | ||
189 | MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks); | ||
190 | } | ||
191 | |||
192 | MakeStat( | ||
193 | "HTTPRequestsMade", | ||
194 | "Number of outbound HTTP requests made", | ||
195 | "requests", | ||
196 | ContainerNetwork, | ||
197 | s => s.Value = WebUtil.RequestNumber, | ||
198 | MeasuresOfInterest.AverageChangeOverTime); | ||
199 | |||
200 | try | ||
201 | { | ||
202 | List<string> okInterfaceTypes = new List<string>(NetworkInterfaceTypes.Split(',')); | ||
203 | |||
204 | IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces(); | ||
205 | foreach (NetworkInterface nic in nics) | ||
206 | { | ||
207 | if (nic.OperationalStatus != OperationalStatus.Up) | ||
208 | continue; | ||
209 | |||
210 | string nicInterfaceType = nic.NetworkInterfaceType.ToString(); | ||
211 | if (!okInterfaceTypes.Contains(nicInterfaceType)) | ||
212 | { | ||
213 | m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.", | ||
214 | LogHeader, nic.Name, nicInterfaceType); | ||
215 | m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}", | ||
216 | LogHeader, NetworkInterfaceTypes); | ||
217 | continue; | ||
218 | } | ||
219 | |||
220 | if (nic.Supports(NetworkInterfaceComponent.IPv4)) | ||
221 | { | ||
222 | IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics(); | ||
223 | if (nicStats != null) | ||
224 | { | ||
225 | MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork, | ||
226 | (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); }); | ||
227 | MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork, | ||
228 | (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); }); | ||
229 | MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork, | ||
230 | (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); }); | ||
231 | } | ||
232 | } | ||
233 | // TODO: add IPv6 (it may actually happen someday) | ||
234 | } | ||
235 | } | ||
236 | catch (Exception e) | ||
237 | { | ||
238 | m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e); | ||
239 | } | ||
240 | |||
241 | MakeStat("ProcessMemory", null, "MB", ContainerMemory, | ||
242 | (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); }); | ||
243 | MakeStat("HeapMemory", null, "MB", ContainerMemory, | ||
244 | (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); }); | ||
245 | MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory, | ||
246 | (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); | ||
247 | MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory, | ||
248 | (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); }); | ||
249 | } | ||
250 | |||
251 | // Notes on performance counters: | ||
252 | // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx | ||
253 | // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c | ||
254 | // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters | ||
255 | private delegate double PerfCounterNextValue(); | ||
256 | private void GetNextValue(Stat stat, PerfCounterControl perfControl) | ||
257 | { | ||
258 | GetNextValue(stat, perfControl, 1.0); | ||
259 | } | ||
260 | private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor) | ||
261 | { | ||
262 | if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval) | ||
263 | { | ||
264 | if (perfControl != null && perfControl.perfCounter != null) | ||
265 | { | ||
266 | try | ||
267 | { | ||
268 | // Kludge for factor to run double duty. If -1, subtract the value from one | ||
269 | if (factor == -1) | ||
270 | stat.Value = 1 - perfControl.perfCounter.NextValue(); | ||
271 | else | ||
272 | stat.Value = perfControl.perfCounter.NextValue() / factor; | ||
273 | } | ||
274 | catch (Exception e) | ||
275 | { | ||
276 | m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e); | ||
277 | } | ||
278 | perfControl.lastFetch = Util.EnvironmentTickCount(); | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | // Lookup the nic that goes with this stat and set the value by using a fetch action. | ||
284 | // Not sure about closure with delegates inside delegates. | ||
285 | private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat); | ||
286 | private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor) | ||
287 | { | ||
288 | // Get the one nic that has the name of this stat | ||
289 | IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().Where( | ||
290 | (network) => network.Name == stat.Description); | ||
291 | try | ||
292 | { | ||
293 | foreach (NetworkInterface nic in nics) | ||
294 | { | ||
295 | IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics(); | ||
296 | if (intrStats != null) | ||
297 | { | ||
298 | double newVal = Math.Round(getter(intrStats) / factor, 3); | ||
299 | stat.Value = newVal; | ||
300 | } | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | catch | ||
305 | { | ||
306 | // There are times interfaces go away so we just won't update the stat for this | ||
307 | m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description); | ||
308 | } | ||
309 | } | ||
310 | } | ||
311 | |||
312 | public class ServerStatsAggregator : Stat | ||
313 | { | ||
314 | public ServerStatsAggregator( | ||
315 | string shortName, | ||
316 | string name, | ||
317 | string description, | ||
318 | string unitName, | ||
319 | string category, | ||
320 | string container | ||
321 | ) | ||
322 | : base( | ||
323 | shortName, | ||
324 | name, | ||
325 | description, | ||
326 | unitName, | ||
327 | category, | ||
328 | container, | ||
329 | StatType.Push, | ||
330 | MeasuresOfInterest.None, | ||
331 | null, | ||
332 | StatVerbosity.Info) | ||
333 | { | ||
334 | } | ||
335 | public override string ToConsoleString() | ||
336 | { | ||
337 | StringBuilder sb = new StringBuilder(); | ||
338 | |||
339 | return sb.ToString(); | ||
340 | } | ||
341 | |||
342 | public override OSDMap ToOSDMap() | ||
343 | { | ||
344 | OSDMap ret = new OSDMap(); | ||
345 | |||
346 | return ret; | ||
347 | } | ||
348 | } | ||
349 | } | ||
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs index 6a68322..f6f458d 100644 --- 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.Linq; | ||
30 | using System.Text; | 31 | using System.Text; |
31 | using OpenMetaverse; | 32 | using OpenMetaverse; |
32 | using OpenMetaverse.StructuredData; | 33 | using OpenMetaverse.StructuredData; |
@@ -39,8 +40,6 @@ namespace OpenSim.Framework.Monitoring | |||
39 | /// </summary> | 40 | /// </summary> |
40 | public class SimExtraStatsCollector : BaseStatsCollector | 41 | public class SimExtraStatsCollector : BaseStatsCollector |
41 | { | 42 | { |
42 | private long abnormalClientThreadTerminations; | ||
43 | |||
44 | // private long assetsInCache; | 43 | // private long assetsInCache; |
45 | // private long texturesInCache; | 44 | // private long texturesInCache; |
46 | // private long assetCacheMemoryUsage; | 45 | // private long assetCacheMemoryUsage; |
@@ -73,11 +72,6 @@ namespace OpenSim.Framework.Monitoring | |||
73 | private volatile float activeScripts; | 72 | private volatile float activeScripts; |
74 | private volatile float scriptLinesPerSecond; | 73 | private volatile float scriptLinesPerSecond; |
75 | 74 | ||
76 | /// <summary> | ||
77 | /// Number of times that a client thread terminated because of an exception | ||
78 | /// </summary> | ||
79 | public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } } | ||
80 | |||
81 | // /// <summary> | 75 | // /// <summary> |
82 | // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the | 76 | // /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the |
83 | // /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these | 77 | // /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these |
@@ -166,11 +160,6 @@ namespace OpenSim.Framework.Monitoring | |||
166 | private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors | 160 | private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors |
167 | = new Dictionary<UUID, PacketQueueStatsCollector>(); | 161 | = new Dictionary<UUID, PacketQueueStatsCollector>(); |
168 | 162 | ||
169 | public void AddAbnormalClientThreadTermination() | ||
170 | { | ||
171 | abnormalClientThreadTerminations++; | ||
172 | } | ||
173 | |||
174 | // public void AddAsset(AssetBase asset) | 163 | // public void AddAsset(AssetBase asset) |
175 | // { | 164 | // { |
176 | // assetsInCache++; | 165 | // assetsInCache++; |
@@ -324,10 +313,12 @@ Asset service request failures: {3}" + Environment.NewLine, | |||
324 | sb.Append(Environment.NewLine); | 313 | sb.Append(Environment.NewLine); |
325 | sb.Append("CONNECTION STATISTICS"); | 314 | sb.Append("CONNECTION STATISTICS"); |
326 | sb.Append(Environment.NewLine); | 315 | sb.Append(Environment.NewLine); |
327 | sb.Append( | 316 | |
328 | string.Format( | 317 | List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives"); |
329 | "Abnormal client thread terminations: {0}" + Environment.NewLine, | 318 | |
330 | abnormalClientThreadTerminations)); | 319 | sb.AppendFormat( |
320 | "Client logouts due to no data receive timeout: {0}\n\n", | ||
321 | stats != null ? stats.Sum(s => s.Value).ToString() : "unknown"); | ||
331 | 322 | ||
332 | // sb.Append(Environment.NewLine); | 323 | // sb.Append(Environment.NewLine); |
333 | // sb.Append("INVENTORY STATISTICS"); | 324 | // sb.Append("INVENTORY STATISTICS"); |
@@ -338,7 +329,7 @@ Asset service request failures: {3}" + Environment.NewLine, | |||
338 | // InventoryServiceRetrievalFailures)); | 329 | // InventoryServiceRetrievalFailures)); |
339 | 330 | ||
340 | sb.Append(Environment.NewLine); | 331 | sb.Append(Environment.NewLine); |
341 | sb.Append("FRAME STATISTICS"); | 332 | sb.Append("SAMPLE FRAME STATISTICS"); |
342 | sb.Append(Environment.NewLine); | 333 | sb.Append(Environment.NewLine); |
343 | sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); | 334 | sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); |
344 | sb.Append(Environment.NewLine); | 335 | sb.Append(Environment.NewLine); |
diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs index caea30d..318cf1c 100755 --- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs | |||
@@ -34,142 +34,6 @@ using OpenMetaverse.StructuredData; | |||
34 | 34 | ||
35 | namespace OpenSim.Framework.Monitoring | 35 | namespace OpenSim.Framework.Monitoring |
36 | { | 36 | { |
37 | // Create a time histogram of events. The histogram is built in a wrap-around | ||
38 | // array of equally distributed buckets. | ||
39 | // For instance, a minute long histogram of second sized buckets would be: | ||
40 | // new EventHistogram(60, 1000) | ||
41 | public class EventHistogram | ||
42 | { | ||
43 | private int m_timeBase; | ||
44 | private int m_numBuckets; | ||
45 | private int m_bucketMilliseconds; | ||
46 | private int m_lastBucket; | ||
47 | private int m_totalHistogramMilliseconds; | ||
48 | private long[] m_histogram; | ||
49 | private object histoLock = new object(); | ||
50 | |||
51 | public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) | ||
52 | { | ||
53 | m_numBuckets = numberOfBuckets; | ||
54 | m_bucketMilliseconds = millisecondsPerBucket; | ||
55 | m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; | ||
56 | |||
57 | m_histogram = new long[m_numBuckets]; | ||
58 | Zero(); | ||
59 | m_lastBucket = 0; | ||
60 | m_timeBase = Util.EnvironmentTickCount(); | ||
61 | } | ||
62 | |||
63 | public void Event() | ||
64 | { | ||
65 | this.Event(1); | ||
66 | } | ||
67 | |||
68 | // Record an event at time 'now' in the histogram. | ||
69 | public void Event(int cnt) | ||
70 | { | ||
71 | lock (histoLock) | ||
72 | { | ||
73 | // The time as displaced from the base of the histogram | ||
74 | int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); | ||
75 | |||
76 | // If more than the total time of the histogram, we just start over | ||
77 | if (bucketTime > m_totalHistogramMilliseconds) | ||
78 | { | ||
79 | Zero(); | ||
80 | m_lastBucket = 0; | ||
81 | m_timeBase = Util.EnvironmentTickCount(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | // To which bucket should we add this event? | ||
86 | int bucket = bucketTime / m_bucketMilliseconds; | ||
87 | |||
88 | // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. | ||
89 | while (bucket != m_lastBucket) | ||
90 | { | ||
91 | // Zero from just after the last bucket to the new bucket or the end | ||
92 | for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) | ||
93 | { | ||
94 | m_histogram[jj] = 0; | ||
95 | } | ||
96 | m_lastBucket = bucket; | ||
97 | // If the new bucket is off the end, wrap around to the beginning | ||
98 | if (bucket > m_numBuckets) | ||
99 | { | ||
100 | bucket -= m_numBuckets; | ||
101 | m_lastBucket = 0; | ||
102 | m_histogram[m_lastBucket] = 0; | ||
103 | m_timeBase += m_totalHistogramMilliseconds; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | m_histogram[m_lastBucket] += cnt; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // Get a copy of the current histogram | ||
112 | public long[] GetHistogram() | ||
113 | { | ||
114 | long[] ret = new long[m_numBuckets]; | ||
115 | lock (histoLock) | ||
116 | { | ||
117 | int indx = m_lastBucket + 1; | ||
118 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
119 | { | ||
120 | if (indx >= m_numBuckets) | ||
121 | indx = 0; | ||
122 | ret[ii] = m_histogram[indx]; | ||
123 | } | ||
124 | } | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | public OSDMap GetHistogramAsOSDMap() | ||
129 | { | ||
130 | OSDMap ret = new OSDMap(); | ||
131 | |||
132 | ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); | ||
133 | ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); | ||
134 | ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); | ||
135 | |||
136 | // Compute a number for the first bucket in the histogram. | ||
137 | // This will allow readers to know how this histogram relates to any previously read histogram. | ||
138 | int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; | ||
139 | ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); | ||
140 | |||
141 | ret.Add("Values", GetHistogramAsOSDArray()); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | // Get a copy of the current histogram | ||
146 | public OSDArray GetHistogramAsOSDArray() | ||
147 | { | ||
148 | OSDArray ret = new OSDArray(m_numBuckets); | ||
149 | lock (histoLock) | ||
150 | { | ||
151 | int indx = m_lastBucket + 1; | ||
152 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
153 | { | ||
154 | if (indx >= m_numBuckets) | ||
155 | indx = 0; | ||
156 | ret[ii] = OSD.FromLong(m_histogram[indx]); | ||
157 | } | ||
158 | } | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | // Zero out the histogram | ||
163 | public void Zero() | ||
164 | { | ||
165 | lock (histoLock) | ||
166 | { | ||
167 | for (int ii = 0; ii < m_numBuckets; ii++) | ||
168 | m_histogram[ii] = 0; | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | // A statistic that wraps a counter. | 37 | // A statistic that wraps a counter. |
174 | // Built this way mostly so histograms and history can be created. | 38 | // Built this way mostly so histograms and history can be created. |
175 | public class CounterStat : Stat | 39 | public class CounterStat : Stat |
@@ -224,5 +88,32 @@ public class CounterStat : Stat | |||
224 | } | 88 | } |
225 | } | 89 | } |
226 | } | 90 | } |
91 | |||
92 | // CounterStat is a basic stat plus histograms | ||
93 | public override OSDMap ToOSDMap() | ||
94 | { | ||
95 | // Get the foundational instance | ||
96 | OSDMap map = base.ToOSDMap(); | ||
97 | |||
98 | map["StatType"] = "CounterStat"; | ||
99 | |||
100 | // If there are any histograms, add a new field that is an array of histograms as OSDMaps | ||
101 | if (m_histograms.Count > 0) | ||
102 | { | ||
103 | lock (counterLock) | ||
104 | { | ||
105 | if (m_histograms.Count > 0) | ||
106 | { | ||
107 | OSDArray histos = new OSDArray(); | ||
108 | foreach (EventHistogram histo in m_histograms.Values) | ||
109 | { | ||
110 | histos.Add(histo.GetHistogramAsOSDMap()); | ||
111 | } | ||
112 | map.Add("Histograms", histos); | ||
113 | } | ||
114 | } | ||
115 | } | ||
116 | return map; | ||
117 | } | ||
227 | } | 118 | } |
228 | } | 119 | } |
diff --git a/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs new file mode 100755 index 0000000..f51f322 --- /dev/null +++ b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs | |||
@@ -0,0 +1,173 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Linq; | ||
31 | using System.Text; | ||
32 | |||
33 | using OpenMetaverse.StructuredData; | ||
34 | |||
35 | namespace OpenSim.Framework.Monitoring | ||
36 | { | ||
37 | // Create a time histogram of events. The histogram is built in a wrap-around | ||
38 | // array of equally distributed buckets. | ||
39 | // For instance, a minute long histogram of second sized buckets would be: | ||
40 | // new EventHistogram(60, 1000) | ||
41 | public class EventHistogram | ||
42 | { | ||
43 | private int m_timeBase; | ||
44 | private int m_numBuckets; | ||
45 | private int m_bucketMilliseconds; | ||
46 | private int m_lastBucket; | ||
47 | private int m_totalHistogramMilliseconds; | ||
48 | private long[] m_histogram; | ||
49 | private object histoLock = new object(); | ||
50 | |||
51 | public EventHistogram(int numberOfBuckets, int millisecondsPerBucket) | ||
52 | { | ||
53 | m_numBuckets = numberOfBuckets; | ||
54 | m_bucketMilliseconds = millisecondsPerBucket; | ||
55 | m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds; | ||
56 | |||
57 | m_histogram = new long[m_numBuckets]; | ||
58 | Zero(); | ||
59 | m_lastBucket = 0; | ||
60 | m_timeBase = Util.EnvironmentTickCount(); | ||
61 | } | ||
62 | |||
63 | public void Event() | ||
64 | { | ||
65 | this.Event(1); | ||
66 | } | ||
67 | |||
68 | // Record an event at time 'now' in the histogram. | ||
69 | public void Event(int cnt) | ||
70 | { | ||
71 | lock (histoLock) | ||
72 | { | ||
73 | // The time as displaced from the base of the histogram | ||
74 | int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase); | ||
75 | |||
76 | // If more than the total time of the histogram, we just start over | ||
77 | if (bucketTime > m_totalHistogramMilliseconds) | ||
78 | { | ||
79 | Zero(); | ||
80 | m_lastBucket = 0; | ||
81 | m_timeBase = Util.EnvironmentTickCount(); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | // To which bucket should we add this event? | ||
86 | int bucket = bucketTime / m_bucketMilliseconds; | ||
87 | |||
88 | // Advance m_lastBucket to the new bucket. Zero any buckets skipped over. | ||
89 | while (bucket != m_lastBucket) | ||
90 | { | ||
91 | // Zero from just after the last bucket to the new bucket or the end | ||
92 | for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++) | ||
93 | { | ||
94 | m_histogram[jj] = 0; | ||
95 | } | ||
96 | m_lastBucket = bucket; | ||
97 | // If the new bucket is off the end, wrap around to the beginning | ||
98 | if (bucket > m_numBuckets) | ||
99 | { | ||
100 | bucket -= m_numBuckets; | ||
101 | m_lastBucket = 0; | ||
102 | m_histogram[m_lastBucket] = 0; | ||
103 | m_timeBase += m_totalHistogramMilliseconds; | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | m_histogram[m_lastBucket] += cnt; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | // Get a copy of the current histogram | ||
112 | public long[] GetHistogram() | ||
113 | { | ||
114 | long[] ret = new long[m_numBuckets]; | ||
115 | lock (histoLock) | ||
116 | { | ||
117 | int indx = m_lastBucket + 1; | ||
118 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
119 | { | ||
120 | if (indx >= m_numBuckets) | ||
121 | indx = 0; | ||
122 | ret[ii] = m_histogram[indx]; | ||
123 | } | ||
124 | } | ||
125 | return ret; | ||
126 | } | ||
127 | |||
128 | public OSDMap GetHistogramAsOSDMap() | ||
129 | { | ||
130 | OSDMap ret = new OSDMap(); | ||
131 | |||
132 | ret.Add("Buckets", OSD.FromInteger(m_numBuckets)); | ||
133 | ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds)); | ||
134 | ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds)); | ||
135 | |||
136 | // Compute a number for the first bucket in the histogram. | ||
137 | // This will allow readers to know how this histogram relates to any previously read histogram. | ||
138 | int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1; | ||
139 | ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum)); | ||
140 | |||
141 | ret.Add("Values", GetHistogramAsOSDArray()); | ||
142 | |||
143 | return ret; | ||
144 | } | ||
145 | // Get a copy of the current histogram | ||
146 | public OSDArray GetHistogramAsOSDArray() | ||
147 | { | ||
148 | OSDArray ret = new OSDArray(m_numBuckets); | ||
149 | lock (histoLock) | ||
150 | { | ||
151 | int indx = m_lastBucket + 1; | ||
152 | for (int ii = 0; ii < m_numBuckets; ii++, indx++) | ||
153 | { | ||
154 | if (indx >= m_numBuckets) | ||
155 | indx = 0; | ||
156 | ret[ii] = OSD.FromLong(m_histogram[indx]); | ||
157 | } | ||
158 | } | ||
159 | return ret; | ||
160 | } | ||
161 | |||
162 | // Zero out the histogram | ||
163 | public void Zero() | ||
164 | { | ||
165 | lock (histoLock) | ||
166 | { | ||
167 | for (int ii = 0; ii < m_numBuckets; ii++) | ||
168 | m_histogram[ii] = 0; | ||
169 | } | ||
170 | } | ||
171 | } | ||
172 | |||
173 | } | ||
diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs index 60bed55..55ddf06 100644 --- a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs +++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs | |||
@@ -29,6 +29,8 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | 31 | ||
32 | using OpenMetaverse.StructuredData; | ||
33 | |||
32 | namespace OpenSim.Framework.Monitoring | 34 | namespace OpenSim.Framework.Monitoring |
33 | { | 35 | { |
34 | public class PercentageStat : Stat | 36 | public class PercentageStat : Stat |
@@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring | |||
84 | 86 | ||
85 | return sb.ToString(); | 87 | return sb.ToString(); |
86 | } | 88 | } |
89 | |||
90 | // PercentageStat is a basic stat plus percent calc | ||
91 | public override OSDMap ToOSDMap() | ||
92 | { | ||
93 | // Get the foundational instance | ||
94 | OSDMap map = base.ToOSDMap(); | ||
95 | |||
96 | map["StatType"] = "PercentageStat"; | ||
97 | |||
98 | map.Add("Antecedent", OSD.FromLong(Antecedent)); | ||
99 | map.Add("Consequent", OSD.FromLong(Consequent)); | ||
100 | |||
101 | return map; | ||
102 | } | ||
87 | } | 103 | } |
88 | } \ No newline at end of file | 104 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs index 2e7665f..e095801 100644 --- a/OpenSim/Framework/Monitoring/Stats/Stat.cs +++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs | |||
@@ -27,8 +27,10 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Linq; | ||
31 | using System.Reflection; | ||
30 | using System.Text; | 32 | using System.Text; |
31 | 33 | using log4net; | |
32 | using OpenMetaverse.StructuredData; | 34 | using OpenMetaverse.StructuredData; |
33 | 35 | ||
34 | namespace OpenSim.Framework.Monitoring | 36 | namespace OpenSim.Framework.Monitoring |
@@ -38,6 +40,10 @@ namespace OpenSim.Framework.Monitoring | |||
38 | /// </summary> | 40 | /// </summary> |
39 | public class Stat : IDisposable | 41 | public class Stat : IDisposable |
40 | { | 42 | { |
43 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
44 | |||
45 | public static readonly char[] DisallowedShortNameCharacters = { '.' }; | ||
46 | |||
41 | /// <summary> | 47 | /// <summary> |
42 | /// Category of this stat (e.g. cache, scene, etc). | 48 | /// Category of this stat (e.g. cache, scene, etc). |
43 | /// </summary> | 49 | /// </summary> |
@@ -95,7 +101,7 @@ namespace OpenSim.Framework.Monitoring | |||
95 | /// <remarks> | 101 | /// <remarks> |
96 | /// Will be null if no measures of interest require samples. | 102 | /// Will be null if no measures of interest require samples. |
97 | /// </remarks> | 103 | /// </remarks> |
98 | private static Queue<double> m_samples; | 104 | private Queue<double> m_samples; |
99 | 105 | ||
100 | /// <summary> | 106 | /// <summary> |
101 | /// Maximum number of statistical samples. | 107 | /// Maximum number of statistical samples. |
@@ -162,6 +168,12 @@ namespace OpenSim.Framework.Monitoring | |||
162 | throw new Exception( | 168 | throw new Exception( |
163 | string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); | 169 | string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); |
164 | 170 | ||
171 | foreach (char c in DisallowedShortNameCharacters) | ||
172 | { | ||
173 | if (shortName.IndexOf(c) != -1) | ||
174 | throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c)); | ||
175 | } | ||
176 | |||
165 | ShortName = shortName; | 177 | ShortName = shortName; |
166 | Name = name; | 178 | Name = name; |
167 | Description = description; | 179 | Description = description; |
@@ -204,6 +216,8 @@ namespace OpenSim.Framework.Monitoring | |||
204 | if (m_samples.Count >= m_maxSamples) | 216 | if (m_samples.Count >= m_maxSamples) |
205 | m_samples.Dequeue(); | 217 | m_samples.Dequeue(); |
206 | 218 | ||
219 | // m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name); | ||
220 | |||
207 | m_samples.Enqueue(newValue); | 221 | m_samples.Enqueue(newValue); |
208 | } | 222 | } |
209 | } | 223 | } |
@@ -211,7 +225,13 @@ namespace OpenSim.Framework.Monitoring | |||
211 | public virtual string ToConsoleString() | 225 | public virtual string ToConsoleString() |
212 | { | 226 | { |
213 | StringBuilder sb = new StringBuilder(); | 227 | StringBuilder sb = new StringBuilder(); |
214 | sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName); | 228 | sb.AppendFormat( |
229 | "{0}.{1}.{2} : {3}{4}", | ||
230 | Category, | ||
231 | Container, | ||
232 | ShortName, | ||
233 | Value, | ||
234 | string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName)); | ||
215 | 235 | ||
216 | AppendMeasuresOfInterest(sb); | 236 | AppendMeasuresOfInterest(sb); |
217 | 237 | ||
@@ -221,6 +241,8 @@ namespace OpenSim.Framework.Monitoring | |||
221 | public virtual OSDMap ToOSDMap() | 241 | public virtual OSDMap ToOSDMap() |
222 | { | 242 | { |
223 | OSDMap ret = new OSDMap(); | 243 | OSDMap ret = new OSDMap(); |
244 | ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat | ||
245 | |||
224 | ret.Add("Category", OSD.FromString(Category)); | 246 | ret.Add("Category", OSD.FromString(Category)); |
225 | ret.Add("Container", OSD.FromString(Container)); | 247 | ret.Add("Container", OSD.FromString(Container)); |
226 | ret.Add("ShortName", OSD.FromString(ShortName)); | 248 | ret.Add("ShortName", OSD.FromString(ShortName)); |
@@ -229,31 +251,74 @@ namespace OpenSim.Framework.Monitoring | |||
229 | ret.Add("UnitName", OSD.FromString(UnitName)); | 251 | ret.Add("UnitName", OSD.FromString(UnitName)); |
230 | ret.Add("Value", OSD.FromReal(Value)); | 252 | ret.Add("Value", OSD.FromReal(Value)); |
231 | 253 | ||
254 | double lastChangeOverTime, averageChangeOverTime; | ||
255 | if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) | ||
256 | { | ||
257 | ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime)); | ||
258 | ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime)); | ||
259 | } | ||
260 | |||
232 | return ret; | 261 | return ret; |
233 | } | 262 | } |
234 | 263 | ||
235 | protected void AppendMeasuresOfInterest(StringBuilder sb) | 264 | // Compute the averages over time and return same. |
265 | // Return 'true' if averages were actually computed. 'false' if no average info. | ||
266 | public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime) | ||
236 | { | 267 | { |
237 | if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) | 268 | bool ret = false; |
238 | == MeasuresOfInterest.AverageChangeOverTime) | 269 | lastChangeOverTime = 0; |
270 | averageChangeOverTime = 0; | ||
271 | |||
272 | if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime) | ||
239 | { | 273 | { |
240 | double totalChange = 0; | 274 | double totalChange = 0; |
275 | double? penultimateSample = null; | ||
241 | double? lastSample = null; | 276 | double? lastSample = null; |
242 | 277 | ||
243 | lock (m_samples) | 278 | lock (m_samples) |
244 | { | 279 | { |
280 | // m_log.DebugFormat( | ||
281 | // "[STAT]: Samples for {0} are {1}", | ||
282 | // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray())); | ||
283 | |||
245 | foreach (double s in m_samples) | 284 | foreach (double s in m_samples) |
246 | { | 285 | { |
247 | if (lastSample != null) | 286 | if (lastSample != null) |
248 | totalChange += s - (double)lastSample; | 287 | totalChange += s - (double)lastSample; |
249 | 288 | ||
289 | penultimateSample = lastSample; | ||
250 | lastSample = s; | 290 | lastSample = s; |
251 | } | 291 | } |
252 | } | 292 | } |
253 | 293 | ||
294 | if (lastSample != null && penultimateSample != null) | ||
295 | { | ||
296 | lastChangeOverTime | ||
297 | = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); | ||
298 | } | ||
299 | |||
254 | int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; | 300 | int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; |
255 | 301 | ||
256 | sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); | 302 | averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000); |
303 | ret = true; | ||
304 | } | ||
305 | |||
306 | return ret; | ||
307 | } | ||
308 | |||
309 | protected void AppendMeasuresOfInterest(StringBuilder sb) | ||
310 | { | ||
311 | double lastChangeOverTime = 0; | ||
312 | double averageChangeOverTime = 0; | ||
313 | |||
314 | if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime)) | ||
315 | { | ||
316 | sb.AppendFormat( | ||
317 | ", {0:0.##}{1}/s, {2:0.##}{3}/s", | ||
318 | lastChangeOverTime, | ||
319 | string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName), | ||
320 | averageChangeOverTime, | ||
321 | string.IsNullOrEmpty(UnitName) ? "" : string.Format(" {0}", UnitName)); | ||
257 | } | 322 | } |
258 | } | 323 | } |
259 | } | 324 | } |
diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs new file mode 100644 index 0000000..1e4fa11 --- /dev/null +++ b/OpenSim/Framework/Monitoring/StatsLogger.cs | |||
@@ -0,0 +1,108 @@ | |||
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.Timers; | ||
31 | using log4net; | ||
32 | |||
33 | namespace OpenSim.Framework.Monitoring | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Provides a means to continuously log stats for debugging purposes. | ||
37 | /// </summary> | ||
38 | public static class StatsLogger | ||
39 | { | ||
40 | private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger"); | ||
41 | |||
42 | private static Timer m_loggingTimer; | ||
43 | private static int m_statsLogIntervalMs = 5000; | ||
44 | |||
45 | public static void RegisterConsoleCommands(ICommandConsole console) | ||
46 | { | ||
47 | console.Commands.AddCommand( | ||
48 | "Debug", | ||
49 | false, | ||
50 | "debug stats record", | ||
51 | "debug stats record start|stop", | ||
52 | "Control whether stats are being regularly recorded to a separate file.", | ||
53 | "For debug purposes. Experimental.", | ||
54 | HandleStatsRecordCommand); | ||
55 | } | ||
56 | |||
57 | public static void HandleStatsRecordCommand(string module, string[] cmd) | ||
58 | { | ||
59 | ICommandConsole con = MainConsole.Instance; | ||
60 | |||
61 | if (cmd.Length != 4) | ||
62 | { | ||
63 | con.Output("Usage: debug stats record start|stop"); | ||
64 | return; | ||
65 | } | ||
66 | |||
67 | if (cmd[3] == "start") | ||
68 | { | ||
69 | Start(); | ||
70 | con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs); | ||
71 | } | ||
72 | else if (cmd[3] == "stop") | ||
73 | { | ||
74 | Stop(); | ||
75 | con.Output("Stopped recording stats to file."); | ||
76 | } | ||
77 | } | ||
78 | |||
79 | public static void Start() | ||
80 | { | ||
81 | if (m_loggingTimer != null) | ||
82 | Stop(); | ||
83 | |||
84 | m_loggingTimer = new Timer(m_statsLogIntervalMs); | ||
85 | m_loggingTimer.AutoReset = false; | ||
86 | m_loggingTimer.Elapsed += Log; | ||
87 | m_loggingTimer.Start(); | ||
88 | } | ||
89 | |||
90 | public static void Stop() | ||
91 | { | ||
92 | if (m_loggingTimer != null) | ||
93 | { | ||
94 | m_loggingTimer.Stop(); | ||
95 | } | ||
96 | } | ||
97 | |||
98 | private static void Log(object sender, ElapsedEventArgs e) | ||
99 | { | ||
100 | m_statsLog.InfoFormat("*** STATS REPORT AT {0} ***", DateTime.Now); | ||
101 | |||
102 | foreach (string report in StatsManager.GetAllStatsReports()) | ||
103 | m_statsLog.Info(report); | ||
104 | |||
105 | m_loggingTimer.Start(); | ||
106 | } | ||
107 | } | ||
108 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs index 24db6d4..05ee4c5 100644 --- a/OpenSim/Framework/Monitoring/StatsManager.cs +++ b/OpenSim/Framework/Monitoring/StatsManager.cs | |||
@@ -26,15 +26,20 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Linq; | ||
30 | using System.Text; | 32 | using System.Text; |
31 | 33 | ||
34 | using OpenSim.Framework; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | |||
32 | namespace OpenSim.Framework.Monitoring | 37 | namespace OpenSim.Framework.Monitoring |
33 | { | 38 | { |
34 | /// <summary> | 39 | /// <summary> |
35 | /// Singleton used to provide access to statistics reporters | 40 | /// Static class used to register/deregister/fetch statistics |
36 | /// </summary> | 41 | /// </summary> |
37 | public class StatsManager | 42 | public static class StatsManager |
38 | { | 43 | { |
39 | // Subcommand used to list other stats. | 44 | // Subcommand used to list other stats. |
40 | public const string AllSubCommand = "all"; | 45 | public const string AllSubCommand = "all"; |
@@ -54,13 +59,13 @@ namespace OpenSim.Framework.Monitoring | |||
54 | public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats | 59 | public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats |
55 | = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>(); | 60 | = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>(); |
56 | 61 | ||
57 | private static AssetStatsCollector assetStats; | 62 | // private static AssetStatsCollector assetStats; |
58 | private static UserStatsCollector userStats; | 63 | // private static UserStatsCollector userStats; |
59 | private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); | 64 | // private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); |
60 | 65 | ||
61 | public static AssetStatsCollector AssetStats { get { return assetStats; } } | 66 | // public static AssetStatsCollector AssetStats { get { return assetStats; } } |
62 | public static UserStatsCollector UserStats { get { return userStats; } } | 67 | // public static UserStatsCollector UserStats { get { return userStats; } } |
63 | public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } | 68 | public static SimExtraStatsCollector SimExtraStats { get; set; } |
64 | 69 | ||
65 | public static void RegisterConsoleCommands(ICommandConsole console) | 70 | public static void RegisterConsoleCommands(ICommandConsole console) |
66 | { | 71 | { |
@@ -68,14 +73,18 @@ namespace OpenSim.Framework.Monitoring | |||
68 | "General", | 73 | "General", |
69 | false, | 74 | false, |
70 | "show stats", | 75 | "show stats", |
71 | "show stats [list|all|<category>]", | 76 | "show stats [list|all|(<category>[.<container>])+", |
72 | "Show statistical information for this server", | 77 | "Show statistical information for this server", |
73 | "If no final argument is specified then legacy statistics information is currently shown.\n" | 78 | "If no final argument is specified then legacy statistics information is currently shown.\n" |
74 | + "If list is specified then statistic categories are shown.\n" | 79 | + "'list' argument will show statistic categories.\n" |
75 | + "If all is specified then all registered statistics are shown.\n" | 80 | + "'all' will show all statistics.\n" |
76 | + "If a category name is specified then only statistics from that category are shown.\n" | 81 | + "A <category> name will show statistics from that category.\n" |
82 | + "A <category>.<container> name will show statistics from that category in that container.\n" | ||
83 | + "More than one name can be given separated by spaces.\n" | ||
77 | + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", | 84 | + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", |
78 | HandleShowStatsCommand); | 85 | HandleShowStatsCommand); |
86 | |||
87 | StatsLogger.RegisterConsoleCommands(console); | ||
79 | } | 88 | } |
80 | 89 | ||
81 | public static void HandleShowStatsCommand(string module, string[] cmd) | 90 | public static void HandleShowStatsCommand(string module, string[] cmd) |
@@ -84,43 +93,47 @@ namespace OpenSim.Framework.Monitoring | |||
84 | 93 | ||
85 | if (cmd.Length > 2) | 94 | if (cmd.Length > 2) |
86 | { | 95 | { |
87 | var categoryName = cmd[2]; | 96 | foreach (string name in cmd.Skip(2)) |
88 | var containerName = cmd.Length > 3 ? cmd[3] : String.Empty; | ||
89 | |||
90 | if (categoryName == AllSubCommand) | ||
91 | { | 97 | { |
92 | foreach (var category in RegisteredStats.Values) | 98 | string[] components = name.Split('.'); |
99 | |||
100 | string categoryName = components[0]; | ||
101 | string containerName = components.Length > 1 ? components[1] : null; | ||
102 | |||
103 | if (categoryName == AllSubCommand) | ||
93 | { | 104 | { |
94 | OutputCategoryStatsToConsole(con, category); | 105 | OutputAllStatsToConsole(con); |
95 | } | 106 | } |
96 | } | 107 | else if (categoryName == ListSubCommand) |
97 | else if (categoryName == ListSubCommand) | ||
98 | { | ||
99 | con.Output("Statistic categories available are:"); | ||
100 | foreach (string category in RegisteredStats.Keys) | ||
101 | con.OutputFormat(" {0}", category); | ||
102 | } | ||
103 | else | ||
104 | { | ||
105 | SortedDictionary<string, SortedDictionary<string, Stat>> category; | ||
106 | if (!RegisteredStats.TryGetValue(categoryName, out category)) | ||
107 | { | 108 | { |
108 | con.OutputFormat("No such category as {0}", categoryName); | 109 | con.Output("Statistic categories available are:"); |
110 | foreach (string category in RegisteredStats.Keys) | ||
111 | con.OutputFormat(" {0}", category); | ||
109 | } | 112 | } |
110 | else | 113 | else |
111 | { | 114 | { |
112 | if (String.IsNullOrEmpty(containerName)) | 115 | SortedDictionary<string, SortedDictionary<string, Stat>> category; |
113 | OutputCategoryStatsToConsole(con, category); | 116 | if (!RegisteredStats.TryGetValue(categoryName, out category)) |
117 | { | ||
118 | con.OutputFormat("No such category as {0}", categoryName); | ||
119 | } | ||
114 | else | 120 | else |
115 | { | 121 | { |
116 | SortedDictionary<string, Stat> container; | 122 | if (String.IsNullOrEmpty(containerName)) |
117 | if (category.TryGetValue(containerName, out container)) | ||
118 | { | 123 | { |
119 | OutputContainerStatsToConsole(con, container); | 124 | OutputCategoryStatsToConsole(con, category); |
120 | } | 125 | } |
121 | else | 126 | else |
122 | { | 127 | { |
123 | con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); | 128 | SortedDictionary<string, Stat> container; |
129 | if (category.TryGetValue(containerName, out container)) | ||
130 | { | ||
131 | OutputContainerStatsToConsole(con, container); | ||
132 | } | ||
133 | else | ||
134 | { | ||
135 | con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); | ||
136 | } | ||
124 | } | 137 | } |
125 | } | 138 | } |
126 | } | 139 | } |
@@ -129,51 +142,187 @@ namespace OpenSim.Framework.Monitoring | |||
129 | else | 142 | else |
130 | { | 143 | { |
131 | // Legacy | 144 | // Legacy |
132 | con.Output(SimExtraStats.Report()); | 145 | if (SimExtraStats != null) |
146 | con.Output(SimExtraStats.Report()); | ||
147 | else | ||
148 | OutputAllStatsToConsole(con); | ||
133 | } | 149 | } |
134 | } | 150 | } |
135 | 151 | ||
152 | public static List<string> GetAllStatsReports() | ||
153 | { | ||
154 | List<string> reports = new List<string>(); | ||
155 | |||
156 | foreach (var category in RegisteredStats.Values) | ||
157 | reports.AddRange(GetCategoryStatsReports(category)); | ||
158 | |||
159 | return reports; | ||
160 | } | ||
161 | |||
162 | private static void OutputAllStatsToConsole(ICommandConsole con) | ||
163 | { | ||
164 | foreach (string report in GetAllStatsReports()) | ||
165 | con.Output(report); | ||
166 | } | ||
167 | |||
168 | private static List<string> GetCategoryStatsReports( | ||
169 | SortedDictionary<string, SortedDictionary<string, Stat>> category) | ||
170 | { | ||
171 | List<string> reports = new List<string>(); | ||
172 | |||
173 | foreach (var container in category.Values) | ||
174 | reports.AddRange(GetContainerStatsReports(container)); | ||
175 | |||
176 | return reports; | ||
177 | } | ||
178 | |||
136 | private static void OutputCategoryStatsToConsole( | 179 | private static void OutputCategoryStatsToConsole( |
137 | ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category) | 180 | ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category) |
138 | { | 181 | { |
139 | foreach (var container in category.Values) | 182 | foreach (string report in GetCategoryStatsReports(category)) |
140 | { | 183 | con.Output(report); |
141 | OutputContainerStatsToConsole(con, container); | ||
142 | } | ||
143 | } | 184 | } |
144 | 185 | ||
145 | private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary<string, Stat> container) | 186 | private static List<string> GetContainerStatsReports(SortedDictionary<string, Stat> container) |
146 | { | 187 | { |
188 | List<string> reports = new List<string>(); | ||
189 | |||
147 | foreach (Stat stat in container.Values) | 190 | foreach (Stat stat in container.Values) |
148 | { | 191 | reports.Add(stat.ToConsoleString()); |
149 | con.Output(stat.ToConsoleString()); | 192 | |
150 | } | 193 | return reports; |
151 | } | 194 | } |
152 | 195 | ||
153 | /// <summary> | 196 | private static void OutputContainerStatsToConsole( |
154 | /// Start collecting statistics related to assets. | 197 | ICommandConsole con, SortedDictionary<string, Stat> container) |
155 | /// Should only be called once. | 198 | { |
156 | /// </summary> | 199 | foreach (string report in GetContainerStatsReports(container)) |
157 | public static AssetStatsCollector StartCollectingAssetStats() | 200 | con.Output(report); |
201 | } | ||
202 | |||
203 | // Creates an OSDMap of the format: | ||
204 | // { categoryName: { | ||
205 | // containerName: { | ||
206 | // statName: { | ||
207 | // "Name": name, | ||
208 | // "ShortName": shortName, | ||
209 | // ... | ||
210 | // }, | ||
211 | // statName: { | ||
212 | // "Name": name, | ||
213 | // "ShortName": shortName, | ||
214 | // ... | ||
215 | // }, | ||
216 | // ... | ||
217 | // }, | ||
218 | // containerName: { | ||
219 | // ... | ||
220 | // }, | ||
221 | // ... | ||
222 | // }, | ||
223 | // categoryName: { | ||
224 | // ... | ||
225 | // }, | ||
226 | // ... | ||
227 | // } | ||
228 | // The passed in parameters will filter the categories, containers and stats returned. If any of the | ||
229 | // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned. | ||
230 | // Case matters. | ||
231 | public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName) | ||
158 | { | 232 | { |
159 | assetStats = new AssetStatsCollector(); | 233 | OSDMap map = new OSDMap(); |
234 | |||
235 | foreach (string catName in RegisteredStats.Keys) | ||
236 | { | ||
237 | // Do this category if null spec, "all" subcommand or category name matches passed parameter. | ||
238 | // Skip category if none of the above. | ||
239 | if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName)) | ||
240 | continue; | ||
160 | 241 | ||
161 | return assetStats; | 242 | OSDMap contMap = new OSDMap(); |
243 | foreach (string contName in RegisteredStats[catName].Keys) | ||
244 | { | ||
245 | if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName)) | ||
246 | continue; | ||
247 | |||
248 | OSDMap statMap = new OSDMap(); | ||
249 | |||
250 | SortedDictionary<string, Stat> theStats = RegisteredStats[catName][contName]; | ||
251 | foreach (string statName in theStats.Keys) | ||
252 | { | ||
253 | if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName)) | ||
254 | continue; | ||
255 | |||
256 | statMap.Add(statName, theStats[statName].ToOSDMap()); | ||
257 | } | ||
258 | |||
259 | contMap.Add(contName, statMap); | ||
260 | } | ||
261 | map.Add(catName, contMap); | ||
262 | } | ||
263 | |||
264 | return map; | ||
162 | } | 265 | } |
163 | 266 | ||
164 | /// <summary> | 267 | public static Hashtable HandleStatsRequest(Hashtable request) |
165 | /// Start collecting statistics related to users. | ||
166 | /// Should only be called once. | ||
167 | /// </summary> | ||
168 | public static UserStatsCollector StartCollectingUserStats() | ||
169 | { | 268 | { |
170 | userStats = new UserStatsCollector(); | 269 | Hashtable responsedata = new Hashtable(); |
270 | // string regpath = request["uri"].ToString(); | ||
271 | int response_code = 200; | ||
272 | string contenttype = "text/json"; | ||
273 | |||
274 | string pCategoryName = StatsManager.AllSubCommand; | ||
275 | string pContainerName = StatsManager.AllSubCommand; | ||
276 | string pStatName = StatsManager.AllSubCommand; | ||
277 | |||
278 | if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString(); | ||
279 | if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString(); | ||
280 | if (request.ContainsKey("stat")) pStatName = request["cat"].ToString(); | ||
281 | |||
282 | string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString(); | ||
283 | |||
284 | // If requestor wants it as a callback function, build response as a function rather than just the JSON string. | ||
285 | if (request.ContainsKey("callback")) | ||
286 | { | ||
287 | strOut = request["callback"].ToString() + "(" + strOut + ");"; | ||
288 | } | ||
171 | 289 | ||
172 | return userStats; | 290 | // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}", |
291 | // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut); | ||
292 | |||
293 | responsedata["int_response_code"] = response_code; | ||
294 | responsedata["content_type"] = contenttype; | ||
295 | responsedata["keepalive"] = false; | ||
296 | responsedata["str_response_string"] = strOut; | ||
297 | responsedata["access_control_allow_origin"] = "*"; | ||
298 | |||
299 | return responsedata; | ||
173 | } | 300 | } |
174 | 301 | ||
302 | // /// <summary> | ||
303 | // /// Start collecting statistics related to assets. | ||
304 | // /// Should only be called once. | ||
305 | // /// </summary> | ||
306 | // public static AssetStatsCollector StartCollectingAssetStats() | ||
307 | // { | ||
308 | // assetStats = new AssetStatsCollector(); | ||
309 | // | ||
310 | // return assetStats; | ||
311 | // } | ||
312 | // | ||
313 | // /// <summary> | ||
314 | // /// Start collecting statistics related to users. | ||
315 | // /// Should only be called once. | ||
316 | // /// </summary> | ||
317 | // public static UserStatsCollector StartCollectingUserStats() | ||
318 | // { | ||
319 | // userStats = new UserStatsCollector(); | ||
320 | // | ||
321 | // return userStats; | ||
322 | // } | ||
323 | |||
175 | /// <summary> | 324 | /// <summary> |
176 | /// Registers a statistic. | 325 | /// Register a statistic. |
177 | /// </summary> | 326 | /// </summary> |
178 | /// <param name='stat'></param> | 327 | /// <param name='stat'></param> |
179 | /// <returns></returns> | 328 | /// <returns></returns> |
@@ -187,7 +336,7 @@ namespace OpenSim.Framework.Monitoring | |||
187 | // Stat name is not unique across category/container/shortname key. | 336 | // Stat name is not unique across category/container/shortname key. |
188 | // XXX: For now just return false. This is to avoid problems in regression tests where all tests | 337 | // XXX: For now just return false. This is to avoid problems in regression tests where all tests |
189 | // in a class are run in the same instance of the VM. | 338 | // in a class are run in the same instance of the VM. |
190 | if (TryGetStat(stat, out category, out container)) | 339 | if (TryGetStatParents(stat, out category, out container)) |
191 | return false; | 340 | return false; |
192 | 341 | ||
193 | // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. | 342 | // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. |
@@ -223,7 +372,7 @@ namespace OpenSim.Framework.Monitoring | |||
223 | 372 | ||
224 | lock (RegisteredStats) | 373 | lock (RegisteredStats) |
225 | { | 374 | { |
226 | if (!TryGetStat(stat, out category, out container)) | 375 | if (!TryGetStatParents(stat, out category, out container)) |
227 | return false; | 376 | return false; |
228 | 377 | ||
229 | newContainer = new SortedDictionary<string, Stat>(container); | 378 | newContainer = new SortedDictionary<string, Stat>(container); |
@@ -239,12 +388,67 @@ namespace OpenSim.Framework.Monitoring | |||
239 | } | 388 | } |
240 | } | 389 | } |
241 | 390 | ||
242 | public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats) | 391 | public static bool TryGetStat(string category, string container, string statShortName, out Stat stat) |
243 | { | 392 | { |
244 | return RegisteredStats.TryGetValue(category, out stats); | 393 | stat = null; |
394 | SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats; | ||
395 | |||
396 | lock (RegisteredStats) | ||
397 | { | ||
398 | if (!TryGetStatsForCategory(category, out categoryStats)) | ||
399 | return false; | ||
400 | |||
401 | SortedDictionary<string, Stat> containerStats; | ||
402 | |||
403 | if (!categoryStats.TryGetValue(container, out containerStats)) | ||
404 | return false; | ||
405 | |||
406 | return containerStats.TryGetValue(statShortName, out stat); | ||
407 | } | ||
408 | } | ||
409 | |||
410 | public static bool TryGetStatsForCategory( | ||
411 | string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats) | ||
412 | { | ||
413 | lock (RegisteredStats) | ||
414 | return RegisteredStats.TryGetValue(category, out stats); | ||
415 | } | ||
416 | |||
417 | /// <summary> | ||
418 | /// Get the same stat for each container in a given category. | ||
419 | /// </summary> | ||
420 | /// <returns> | ||
421 | /// The stats if there were any to fetch. Otherwise null. | ||
422 | /// </returns> | ||
423 | /// <param name='category'></param> | ||
424 | /// <param name='statShortName'></param> | ||
425 | public static List<Stat> GetStatsFromEachContainer(string category, string statShortName) | ||
426 | { | ||
427 | SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats; | ||
428 | |||
429 | lock (RegisteredStats) | ||
430 | { | ||
431 | if (!RegisteredStats.TryGetValue(category, out categoryStats)) | ||
432 | return null; | ||
433 | |||
434 | List<Stat> stats = null; | ||
435 | |||
436 | foreach (SortedDictionary<string, Stat> containerStats in categoryStats.Values) | ||
437 | { | ||
438 | if (containerStats.ContainsKey(statShortName)) | ||
439 | { | ||
440 | if (stats == null) | ||
441 | stats = new List<Stat>(); | ||
442 | |||
443 | stats.Add(containerStats[statShortName]); | ||
444 | } | ||
445 | } | ||
446 | |||
447 | return stats; | ||
448 | } | ||
245 | } | 449 | } |
246 | 450 | ||
247 | public static bool TryGetStat( | 451 | public static bool TryGetStatParents( |
248 | Stat stat, | 452 | Stat stat, |
249 | out SortedDictionary<string, SortedDictionary<string, Stat>> category, | 453 | out SortedDictionary<string, SortedDictionary<string, Stat>> category, |
250 | out SortedDictionary<string, Stat> container) | 454 | out SortedDictionary<string, Stat> container) |
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs index 69d2db5..32724ec 100644 --- a/OpenSim/Framework/Monitoring/Watchdog.cs +++ b/OpenSim/Framework/Monitoring/Watchdog.cs | |||
@@ -380,6 +380,7 @@ namespace OpenSim.Framework.Monitoring | |||
380 | if (MemoryWatchdog.Enabled) | 380 | if (MemoryWatchdog.Enabled) |
381 | MemoryWatchdog.Update(); | 381 | MemoryWatchdog.Update(); |
382 | 382 | ||
383 | ChecksManager.CheckChecks(); | ||
383 | StatsManager.RecordStats(); | 384 | StatsManager.RecordStats(); |
384 | 385 | ||
385 | m_watchdogTimer.Start(); | 386 | m_watchdogTimer.Start(); |
diff --git a/OpenSim/Framework/PermissionsUtil.cs b/OpenSim/Framework/PermissionsUtil.cs new file mode 100644 index 0000000..d785a78 --- /dev/null +++ b/OpenSim/Framework/PermissionsUtil.cs | |||
@@ -0,0 +1,87 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
32 | using log4net; | ||
33 | |||
34 | namespace OpenSim.Framework | ||
35 | { | ||
36 | public static class PermissionsUtil | ||
37 | { | ||
38 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
39 | |||
40 | /// <summary> | ||
41 | /// Logs permissions flags. Useful when debugging permission problems. | ||
42 | /// </summary> | ||
43 | /// <param name="message"></param> | ||
44 | public static void LogPermissions(String name, String message, uint basePerm, uint curPerm, uint nextPerm) | ||
45 | { | ||
46 | m_log.DebugFormat("Permissions of \"{0}\" at \"{1}\": Base {2} ({3:X4}), Current {4} ({5:X4}), NextOwner {6} ({7:X4})", | ||
47 | name, message, | ||
48 | PermissionsToString(basePerm), basePerm, PermissionsToString(curPerm), curPerm, PermissionsToString(nextPerm), nextPerm); | ||
49 | } | ||
50 | |||
51 | /// <summary> | ||
52 | /// Converts a permissions bit-mask to a string (e.g., "MCT"). | ||
53 | /// </summary> | ||
54 | private static string PermissionsToString(uint perms) | ||
55 | { | ||
56 | string str = ""; | ||
57 | if ((perms & (int)PermissionMask.Modify) != 0) | ||
58 | str += "M"; | ||
59 | if ((perms & (int)PermissionMask.Copy) != 0) | ||
60 | str += "C"; | ||
61 | if ((perms & (int)PermissionMask.Transfer) != 0) | ||
62 | str += "T"; | ||
63 | if (str == "") | ||
64 | str = "."; | ||
65 | return str; | ||
66 | } | ||
67 | |||
68 | /// <summary> | ||
69 | /// Applies an object's folded permissions to its regular permissions. | ||
70 | /// </summary> | ||
71 | /// <param name="foldedPerms">The folded permissions. Only the lowest 7 bits are examined.</param> | ||
72 | /// <param name="mainPerms">The permissions variable to modify.</param> | ||
73 | public static void ApplyFoldedPermissions(uint foldedPerms, ref uint mainPerms) | ||
74 | { | ||
75 | if ((foldedPerms & 7) == 0) | ||
76 | return; // assume that if the folded permissions are 0 then this means that they weren't actually recorded | ||
77 | |||
78 | if ((foldedPerms & ((uint)PermissionMask.Copy >> 13)) == 0) | ||
79 | mainPerms &= ~(uint)PermissionMask.Copy; | ||
80 | if ((foldedPerms & ((uint)PermissionMask.Transfer >> 13)) == 0) | ||
81 | mainPerms &= ~(uint)PermissionMask.Transfer; | ||
82 | if ((foldedPerms & ((uint)PermissionMask.Modify >> 13)) == 0) | ||
83 | mainPerms &= ~(uint)PermissionMask.Modify; | ||
84 | } | ||
85 | |||
86 | } | ||
87 | } | ||
diff --git a/OpenSim/Framework/PrimitiveBaseShape.cs b/OpenSim/Framework/PrimitiveBaseShape.cs index df928dc..6a12a45 100644 --- a/OpenSim/Framework/PrimitiveBaseShape.cs +++ b/OpenSim/Framework/PrimitiveBaseShape.cs | |||
@@ -105,6 +105,7 @@ namespace OpenSim.Framework | |||
105 | private ushort _profileHollow; | 105 | private ushort _profileHollow; |
106 | private Vector3 _scale; | 106 | private Vector3 _scale; |
107 | private byte _state; | 107 | private byte _state; |
108 | private byte _lastattach; | ||
108 | private ProfileShape _profileShape; | 109 | private ProfileShape _profileShape; |
109 | private HollowShape _hollowShape; | 110 | private HollowShape _hollowShape; |
110 | 111 | ||
@@ -207,6 +208,7 @@ namespace OpenSim.Framework | |||
207 | PCode = (byte)prim.PrimData.PCode; | 208 | PCode = (byte)prim.PrimData.PCode; |
208 | 209 | ||
209 | State = prim.PrimData.State; | 210 | State = prim.PrimData.State; |
211 | LastAttachPoint = prim.PrimData.State; | ||
210 | PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); | 212 | PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin); |
211 | PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd); | 213 | PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd); |
212 | PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX); | 214 | PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX); |
@@ -583,6 +585,15 @@ namespace OpenSim.Framework | |||
583 | } | 585 | } |
584 | } | 586 | } |
585 | 587 | ||
588 | public byte LastAttachPoint { | ||
589 | get { | ||
590 | return _lastattach; | ||
591 | } | ||
592 | set { | ||
593 | _lastattach = value; | ||
594 | } | ||
595 | } | ||
596 | |||
586 | public ProfileShape ProfileShape { | 597 | public ProfileShape ProfileShape { |
587 | get { | 598 | get { |
588 | return _profileShape; | 599 | return _profileShape; |
diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs index a3089b0..7c6569e 100644 --- a/OpenSim/Framework/RegionFlags.cs +++ b/OpenSim/Framework/RegionFlags.cs | |||
@@ -48,6 +48,7 @@ namespace OpenSim.Framework | |||
48 | NoMove = 64, // Don't allow moving this region | 48 | NoMove = 64, // Don't allow moving this region |
49 | Reservation = 128, // This is an inactive reservation | 49 | Reservation = 128, // This is an inactive reservation |
50 | Authenticate = 256, // Require authentication | 50 | Authenticate = 256, // Require authentication |
51 | Hyperlink = 512 // Record represents a HG link | 51 | Hyperlink = 512, // Record represents a HG link |
52 | DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only. | ||
52 | } | 53 | } |
53 | } \ No newline at end of file | 54 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 24ec181..ae2ff63 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs | |||
@@ -100,6 +100,7 @@ namespace OpenSim.Framework | |||
100 | public class RegionInfo | 100 | public class RegionInfo |
101 | { | 101 | { |
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 | 104 | ||
104 | public bool commFailTF = false; | 105 | public bool commFailTF = false; |
105 | public ConfigurationMember configMember; | 106 | public ConfigurationMember configMember; |
@@ -139,16 +140,20 @@ namespace OpenSim.Framework | |||
139 | public bool m_allow_alternate_ports; | 140 | public bool m_allow_alternate_ports; |
140 | protected string m_externalHostName; | 141 | protected string m_externalHostName; |
141 | protected IPEndPoint m_internalEndPoint; | 142 | protected IPEndPoint m_internalEndPoint; |
142 | protected uint? m_regionLocX; | ||
143 | protected uint? m_regionLocY; | ||
144 | protected uint m_remotingPort; | 143 | protected uint m_remotingPort; |
145 | public UUID RegionID = UUID.Zero; | 144 | public UUID RegionID = UUID.Zero; |
146 | public string RemotingAddress; | 145 | public string RemotingAddress; |
147 | public UUID ScopeID = UUID.Zero; | 146 | public UUID ScopeID = UUID.Zero; |
148 | private UUID m_maptileStaticUUID = UUID.Zero; | 147 | private UUID m_maptileStaticUUID = UUID.Zero; |
149 | 148 | ||
150 | private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); | 149 | public uint WorldLocX = 0; |
150 | public uint WorldLocY = 0; | ||
151 | public uint WorldLocZ = 0; | ||
152 | public uint RegionSizeX = Constants.RegionSize; | ||
153 | public uint RegionSizeY = Constants.RegionSize; | ||
154 | public uint RegionSizeZ = Constants.RegionHeight; | ||
151 | 155 | ||
156 | private Dictionary<String, String> m_otherSettings = new Dictionary<string, string>(); | ||
152 | 157 | ||
153 | // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. | 158 | // Apparently, we're applying the same estatesettings regardless of whether it's local or remote. |
154 | 159 | ||
@@ -233,11 +238,12 @@ namespace OpenSim.Framework | |||
233 | m_serverURI = string.Empty; | 238 | m_serverURI = string.Empty; |
234 | } | 239 | } |
235 | 240 | ||
236 | public RegionInfo(uint regionLocX, uint regionLocY, IPEndPoint internalEndPoint, string externalUri) | 241 | public RegionInfo(uint legacyRegionLocX, uint legacyRegionLocY, IPEndPoint internalEndPoint, string externalUri) |
237 | { | 242 | { |
238 | m_regionLocX = regionLocX; | 243 | RegionLocX = legacyRegionLocX; |
239 | m_regionLocY = regionLocY; | 244 | RegionLocY = legacyRegionLocY; |
240 | 245 | RegionSizeX = Constants.RegionSize; | |
246 | RegionSizeY = Constants.RegionSize; | ||
241 | m_internalEndPoint = internalEndPoint; | 247 | m_internalEndPoint = internalEndPoint; |
242 | m_externalHostName = externalUri; | 248 | m_externalHostName = externalUri; |
243 | m_serverURI = string.Empty; | 249 | m_serverURI = string.Empty; |
@@ -451,25 +457,42 @@ namespace OpenSim.Framework | |||
451 | 457 | ||
452 | /// <summary> | 458 | /// <summary> |
453 | /// The x co-ordinate of this region in map tiles (e.g. 1000). | 459 | /// The x co-ordinate of this region in map tiles (e.g. 1000). |
460 | /// Coordinate is scaled as world coordinates divided by the legacy region size | ||
461 | /// and is thus is the number of legacy regions. | ||
454 | /// </summary> | 462 | /// </summary> |
455 | public uint RegionLocX | 463 | public uint RegionLocX |
456 | { | 464 | { |
457 | get { return m_regionLocX.Value; } | 465 | get { return WorldLocX / Constants.RegionSize; } |
458 | set { m_regionLocX = value; } | 466 | set { WorldLocX = value * Constants.RegionSize; } |
459 | } | 467 | } |
460 | 468 | ||
461 | /// <summary> | 469 | /// <summary> |
462 | /// The y co-ordinate of this region in map tiles (e.g. 1000). | 470 | /// The y co-ordinate of this region in map tiles (e.g. 1000). |
471 | /// Coordinate is scaled as world coordinates divided by the legacy region size | ||
472 | /// and is thus is the number of legacy regions. | ||
463 | /// </summary> | 473 | /// </summary> |
464 | public uint RegionLocY | 474 | public uint RegionLocY |
465 | { | 475 | { |
466 | get { return m_regionLocY.Value; } | 476 | get { return WorldLocY / Constants.RegionSize; } |
467 | set { m_regionLocY = value; } | 477 | set { WorldLocY = value * Constants.RegionSize; } |
468 | } | 478 | } |
469 | 479 | ||
480 | public void SetDefaultRegionSize() | ||
481 | { | ||
482 | WorldLocX = 0; | ||
483 | WorldLocY = 0; | ||
484 | WorldLocZ = 0; | ||
485 | RegionSizeX = Constants.RegionSize; | ||
486 | RegionSizeY = Constants.RegionSize; | ||
487 | RegionSizeZ = Constants.RegionHeight; | ||
488 | } | ||
489 | |||
490 | // A unique region handle is created from the region's world coordinates. | ||
491 | // This cannot be changed because some code expects to receive the region handle and then | ||
492 | // compute the region coordinates from it. | ||
470 | public ulong RegionHandle | 493 | public ulong RegionHandle |
471 | { | 494 | { |
472 | get { return Util.UIntsToLong((RegionLocX * (uint) Constants.RegionSize), (RegionLocY * (uint) Constants.RegionSize)); } | 495 | get { return Util.UIntsToLong(WorldLocX, WorldLocY); } |
473 | } | 496 | } |
474 | 497 | ||
475 | public void SetEndPoint(string ipaddr, int port) | 498 | public void SetEndPoint(string ipaddr, int port) |
@@ -576,8 +599,25 @@ namespace OpenSim.Framework | |||
576 | 599 | ||
577 | string[] locationElements = location.Split(new char[] {','}); | 600 | string[] locationElements = location.Split(new char[] {','}); |
578 | 601 | ||
579 | m_regionLocX = Convert.ToUInt32(locationElements[0]); | 602 | RegionLocX = Convert.ToUInt32(locationElements[0]); |
580 | m_regionLocY = Convert.ToUInt32(locationElements[1]); | 603 | RegionLocY = Convert.ToUInt32(locationElements[1]); |
604 | |||
605 | // Region size | ||
606 | // Default to legacy region size if not specified. | ||
607 | allKeys.Remove("SizeX"); | ||
608 | string configSizeX = config.GetString("SizeX", Constants.RegionSize.ToString()); | ||
609 | config.Set("SizeX", configSizeX); | ||
610 | RegionSizeX = Convert.ToUInt32(configSizeX); | ||
611 | allKeys.Remove("SizeY"); | ||
612 | string configSizeY = config.GetString("SizeY", Constants.RegionSize.ToString()); | ||
613 | config.Set("SizeY", configSizeX); | ||
614 | RegionSizeY = Convert.ToUInt32(configSizeY); | ||
615 | allKeys.Remove("SizeZ"); | ||
616 | string configSizeZ = config.GetString("SizeZ", Constants.RegionHeight.ToString()); | ||
617 | config.Set("SizeZ", configSizeX); | ||
618 | RegionSizeZ = Convert.ToUInt32(configSizeZ); | ||
619 | |||
620 | DoRegionSizeSanityChecks(); | ||
581 | 621 | ||
582 | // InternalAddress | 622 | // InternalAddress |
583 | // | 623 | // |
@@ -697,6 +737,57 @@ namespace OpenSim.Framework | |||
697 | } | 737 | } |
698 | } | 738 | } |
699 | 739 | ||
740 | // Make sure user specified region sizes are sane. | ||
741 | // Must be multiples of legacy region size (256). | ||
742 | private void DoRegionSizeSanityChecks() | ||
743 | { | ||
744 | if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) | ||
745 | { | ||
746 | // Doing non-legacy region sizes. | ||
747 | // Enforce region size to be multiples of the legacy region size (256) | ||
748 | uint partial = RegionSizeX % Constants.RegionSize; | ||
749 | if (partial != 0) | ||
750 | { | ||
751 | RegionSizeX -= partial; | ||
752 | if (RegionSizeX == 0) | ||
753 | RegionSizeX = Constants.RegionSize; | ||
754 | m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeX={3} instead of specified {4}", | ||
755 | LogHeader, Constants.RegionSize, m_regionName, RegionSizeX, RegionSizeX + partial); | ||
756 | } | ||
757 | partial = RegionSizeY % Constants.RegionSize; | ||
758 | if (partial != 0) | ||
759 | { | ||
760 | RegionSizeY -= partial; | ||
761 | if (RegionSizeY == 0) | ||
762 | RegionSizeY = Constants.RegionSize; | ||
763 | m_log.ErrorFormat("{0} Region size must be multiple of {1}. Enforcing {2}.RegionSizeY={3} instead of specified {4}", | ||
764 | LogHeader, Constants.RegionSize, m_regionName, RegionSizeY, RegionSizeY + partial); | ||
765 | } | ||
766 | |||
767 | // Because of things in the viewer, regions MUST be square. | ||
768 | // Remove this check when viewers have been updated. | ||
769 | if (RegionSizeX != RegionSizeY) | ||
770 | { | ||
771 | uint minSize = Math.Min(RegionSizeX, RegionSizeY); | ||
772 | RegionSizeX = minSize; | ||
773 | RegionSizeY = minSize; | ||
774 | m_log.ErrorFormat("{0} Regions must be square until viewers are updated. Forcing region {1} size to <{2},{3}>", | ||
775 | LogHeader, m_regionName, RegionSizeX, RegionSizeY); | ||
776 | } | ||
777 | |||
778 | // There is a practical limit to region size. | ||
779 | if (RegionSizeX > Constants.MaximumRegionSize || RegionSizeY > Constants.MaximumRegionSize) | ||
780 | { | ||
781 | RegionSizeX = Util.Clamp<uint>(RegionSizeX, Constants.RegionSize, Constants.MaximumRegionSize); | ||
782 | RegionSizeY = Util.Clamp<uint>(RegionSizeY, Constants.RegionSize, Constants.MaximumRegionSize); | ||
783 | m_log.ErrorFormat("{0} Region dimensions must be less than {1}. Clamping {2}'s size to <{3},{4}>", | ||
784 | LogHeader, Constants.MaximumRegionSize, m_regionName, RegionSizeX, RegionSizeY); | ||
785 | } | ||
786 | |||
787 | m_log.InfoFormat("{0} Region {1} size set to <{2},{3}>", LogHeader, m_regionName, RegionSizeX, RegionSizeY); | ||
788 | } | ||
789 | } | ||
790 | |||
700 | private void WriteNiniConfig(IConfigSource source) | 791 | private void WriteNiniConfig(IConfigSource source) |
701 | { | 792 | { |
702 | IConfig config = source.Configs[RegionName]; | 793 | IConfig config = source.Configs[RegionName]; |
@@ -708,11 +799,17 @@ namespace OpenSim.Framework | |||
708 | 799 | ||
709 | config.Set("RegionUUID", RegionID.ToString()); | 800 | config.Set("RegionUUID", RegionID.ToString()); |
710 | 801 | ||
711 | string location = String.Format("{0},{1}", m_regionLocX, m_regionLocY); | 802 | string location = String.Format("{0},{1}", RegionLocX, RegionLocY); |
712 | config.Set("Location", location); | 803 | config.Set("Location", location); |
713 | 804 | ||
714 | if (DataStore != String.Empty) | 805 | if (DataStore != String.Empty) |
715 | config.Set("Datastore", DataStore); | 806 | config.Set("Datastore", DataStore); |
807 | if (RegionSizeX != Constants.RegionSize || RegionSizeY != Constants.RegionSize) | ||
808 | { | ||
809 | config.Set("SizeX", RegionSizeX); | ||
810 | config.Set("SizeY", RegionSizeY); | ||
811 | config.Set("SizeZ", RegionSizeZ); | ||
812 | } | ||
716 | 813 | ||
717 | config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); | 814 | config.Set("InternalAddress", m_internalEndPoint.Address.ToString()); |
718 | config.Set("InternalPort", m_internalEndPoint.Port); | 815 | config.Set("InternalPort", m_internalEndPoint.Port); |
@@ -796,10 +893,18 @@ namespace OpenSim.Framework | |||
796 | RegionID.ToString(), true); | 893 | RegionID.ToString(), true); |
797 | configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, | 894 | configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, |
798 | "Region Name", RegionName, true); | 895 | "Region Name", RegionName, true); |
896 | |||
799 | configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | 897 | configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, |
800 | "Grid Location (X Axis)", m_regionLocX.ToString(), true); | 898 | "Grid Location (X Axis)", RegionLocX.ToString(), true); |
801 | configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | 899 | configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, |
802 | "Grid Location (Y Axis)", m_regionLocY.ToString(), true); | 900 | "Grid Location (Y Axis)", RegionLocY.ToString(), true); |
901 | configMember.addConfigurationOption("sim_size_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | ||
902 | "Size of region in X dimension", RegionSizeX.ToString(), true); | ||
903 | configMember.addConfigurationOption("sim_size_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | ||
904 | "Size of region in Y dimension", RegionSizeY.ToString(), true); | ||
905 | configMember.addConfigurationOption("sim_size_z", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | ||
906 | "Size of region in Z dimension", RegionSizeZ.ToString(), true); | ||
907 | |||
803 | //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false); | 908 | //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false); |
804 | configMember.addConfigurationOption("internal_ip_address", | 909 | configMember.addConfigurationOption("internal_ip_address", |
805 | ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS, | 910 | ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS, |
@@ -862,10 +967,18 @@ namespace OpenSim.Framework | |||
862 | UUID.Random().ToString(), true); | 967 | UUID.Random().ToString(), true); |
863 | configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, | 968 | configMember.addConfigurationOption("sim_name", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, |
864 | "Region Name", "OpenSim Test", false); | 969 | "Region Name", "OpenSim Test", false); |
970 | |||
865 | configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | 971 | configMember.addConfigurationOption("sim_location_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, |
866 | "Grid Location (X Axis)", "1000", false); | 972 | "Grid Location (X Axis)", "1000", false); |
867 | configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | 973 | configMember.addConfigurationOption("sim_location_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, |
868 | "Grid Location (Y Axis)", "1000", false); | 974 | "Grid Location (Y Axis)", "1000", false); |
975 | configMember.addConfigurationOption("sim_size_x", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | ||
976 | "Size of region in X dimension", Constants.RegionSize.ToString(), false); | ||
977 | configMember.addConfigurationOption("sim_size_y", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | ||
978 | "Size of region in Y dimension", Constants.RegionSize.ToString(), false); | ||
979 | configMember.addConfigurationOption("sim_size_z", ConfigurationOption.ConfigurationTypes.TYPE_UINT32, | ||
980 | "Size of region in Z dimension", Constants.RegionHeight.ToString(), false); | ||
981 | |||
869 | //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false); | 982 | //m_configMember.addConfigurationOption("datastore", ConfigurationOption.ConfigurationTypes.TYPE_STRING_NOT_EMPTY, "Filename for local storage", "OpenSim.db", false); |
870 | configMember.addConfigurationOption("internal_ip_address", | 983 | configMember.addConfigurationOption("internal_ip_address", |
871 | ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS, | 984 | ConfigurationOption.ConfigurationTypes.TYPE_IP_ADDRESS, |
@@ -923,10 +1036,19 @@ namespace OpenSim.Framework | |||
923 | RegionName = (string) configuration_result; | 1036 | RegionName = (string) configuration_result; |
924 | break; | 1037 | break; |
925 | case "sim_location_x": | 1038 | case "sim_location_x": |
926 | m_regionLocX = (uint) configuration_result; | 1039 | RegionLocX = (uint) configuration_result; |
927 | break; | 1040 | break; |
928 | case "sim_location_y": | 1041 | case "sim_location_y": |
929 | m_regionLocY = (uint) configuration_result; | 1042 | RegionLocY = (uint) configuration_result; |
1043 | break; | ||
1044 | case "sim_size_x": | ||
1045 | RegionSizeX = (uint) configuration_result; | ||
1046 | break; | ||
1047 | case "sim_size_y": | ||
1048 | RegionSizeY = (uint) configuration_result; | ||
1049 | break; | ||
1050 | case "sim_size_z": | ||
1051 | RegionSizeZ = (uint) configuration_result; | ||
930 | break; | 1052 | break; |
931 | case "datastore": | 1053 | case "datastore": |
932 | DataStore = (string) configuration_result; | 1054 | DataStore = (string) configuration_result; |
@@ -1010,8 +1132,13 @@ namespace OpenSim.Framework | |||
1010 | args["external_host_name"] = OSD.FromString(ExternalHostName); | 1132 | args["external_host_name"] = OSD.FromString(ExternalHostName); |
1011 | args["http_port"] = OSD.FromString(HttpPort.ToString()); | 1133 | args["http_port"] = OSD.FromString(HttpPort.ToString()); |
1012 | args["server_uri"] = OSD.FromString(ServerURI); | 1134 | args["server_uri"] = OSD.FromString(ServerURI); |
1135 | |||
1013 | args["region_xloc"] = OSD.FromString(RegionLocX.ToString()); | 1136 | args["region_xloc"] = OSD.FromString(RegionLocX.ToString()); |
1014 | args["region_yloc"] = OSD.FromString(RegionLocY.ToString()); | 1137 | args["region_yloc"] = OSD.FromString(RegionLocY.ToString()); |
1138 | args["region_size_x"] = OSD.FromString(RegionSizeX.ToString()); | ||
1139 | args["region_size_y"] = OSD.FromString(RegionSizeY.ToString()); | ||
1140 | args["region_size_z"] = OSD.FromString(RegionSizeZ.ToString()); | ||
1141 | |||
1015 | args["internal_ep_address"] = OSD.FromString(InternalEndPoint.Address.ToString()); | 1142 | args["internal_ep_address"] = OSD.FromString(InternalEndPoint.Address.ToString()); |
1016 | args["internal_ep_port"] = OSD.FromString(InternalEndPoint.Port.ToString()); | 1143 | args["internal_ep_port"] = OSD.FromString(InternalEndPoint.Port.ToString()); |
1017 | if ((RemotingAddress != null) && !RemotingAddress.Equals("")) | 1144 | if ((RemotingAddress != null) && !RemotingAddress.Equals("")) |
@@ -1050,6 +1177,13 @@ namespace OpenSim.Framework | |||
1050 | UInt32.TryParse(args["region_yloc"].AsString(), out locy); | 1177 | UInt32.TryParse(args["region_yloc"].AsString(), out locy); |
1051 | RegionLocY = locy; | 1178 | RegionLocY = locy; |
1052 | } | 1179 | } |
1180 | if (args.ContainsKey("region_size_x")) | ||
1181 | RegionSizeX = (uint)args["region_size_x"].AsInteger(); | ||
1182 | if (args.ContainsKey("region_size_y")) | ||
1183 | RegionSizeY = (uint)args["region_size_y"].AsInteger(); | ||
1184 | if (args.ContainsKey("region_size_z")) | ||
1185 | RegionSizeZ = (uint)args["region_size_z"].AsInteger(); | ||
1186 | |||
1053 | IPAddress ip_addr = null; | 1187 | IPAddress ip_addr = null; |
1054 | if (args["internal_ep_address"] != null) | 1188 | if (args["internal_ep_address"] != null) |
1055 | { | 1189 | { |
diff --git a/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Filesystem/Properties/AssemblyInfo.cs index d4806f1..563bcb9 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.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs b/OpenSim/Framework/RegionLoader/Web/Properties/AssemblyInfo.cs index 1541a5b..ab36f10 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.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/RegionSettings.cs b/OpenSim/Framework/RegionSettings.cs index 47a2780..dec01ea 100644 --- a/OpenSim/Framework/RegionSettings.cs +++ b/OpenSim/Framework/RegionSettings.cs | |||
@@ -200,7 +200,7 @@ namespace OpenSim.Framework | |||
200 | set { m_ObjectBonus = value; } | 200 | set { m_ObjectBonus = value; } |
201 | } | 201 | } |
202 | 202 | ||
203 | private int m_Maturity = 1; | 203 | private int m_Maturity = 0; |
204 | 204 | ||
205 | public int Maturity | 205 | public int Maturity |
206 | { | 206 | { |
@@ -504,21 +504,14 @@ namespace OpenSim.Framework | |||
504 | set { m_TelehubEnabled = value; } | 504 | set { m_TelehubEnabled = value; } |
505 | } | 505 | } |
506 | 506 | ||
507 | // Connected Telehub object | 507 | /// <summary> |
508 | private UUID m_TelehubObject = UUID.Zero; | 508 | /// Connected Telehub object |
509 | public UUID TelehubObject | 509 | /// </summary> |
510 | { | 510 | public UUID TelehubObject { get; set; } |
511 | get | ||
512 | { | ||
513 | return m_TelehubObject; | ||
514 | } | ||
515 | set | ||
516 | { | ||
517 | m_TelehubObject = value; | ||
518 | } | ||
519 | } | ||
520 | 511 | ||
521 | // Our Connected Telehub's SpawnPoints | 512 | /// <summary> |
513 | /// Our connected Telehub's SpawnPoints | ||
514 | /// </summary> | ||
522 | public List<SpawnPoint> l_SpawnPoints = new List<SpawnPoint>(); | 515 | public List<SpawnPoint> l_SpawnPoints = new List<SpawnPoint>(); |
523 | 516 | ||
524 | // Add a SpawnPoint | 517 | // Add a SpawnPoint |
@@ -549,4 +542,4 @@ namespace OpenSim.Framework | |||
549 | l_SpawnPoints.Clear(); | 542 | l_SpawnPoints.Clear(); |
550 | } | 543 | } |
551 | } | 544 | } |
552 | } \ No newline at end of file | 545 | } |
diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index 537de7a..9249105 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs | |||
@@ -39,8 +39,32 @@ namespace OpenSim.Framework | |||
39 | { | 39 | { |
40 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 40 | // private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
41 | 41 | ||
42 | /// <summary> | ||
43 | /// Asset types used only in OpenSim. | ||
44 | /// To avoid clashing with the code numbers used in Second Life, use only negative numbers here. | ||
45 | /// </summary> | ||
46 | public enum OpenSimAssetType : sbyte | ||
47 | { | ||
48 | Material = -2 | ||
49 | } | ||
50 | |||
51 | |||
42 | #region SL / file extension / content-type conversions | 52 | #region SL / file extension / content-type conversions |
43 | 53 | ||
54 | /// <summary> | ||
55 | /// Returns the Enum entry corresponding to the given code, regardless of whether it belongs | ||
56 | /// to the AssetType or OpenSimAssetType enums. | ||
57 | /// </summary> | ||
58 | public static object AssetTypeFromCode(sbyte assetType) | ||
59 | { | ||
60 | if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) | ||
61 | return (OpenMetaverse.AssetType)assetType; | ||
62 | else if (Enum.IsDefined(typeof(OpenSimAssetType), assetType)) | ||
63 | return (OpenSimAssetType)assetType; | ||
64 | else | ||
65 | return OpenMetaverse.AssetType.Unknown; | ||
66 | } | ||
67 | |||
44 | private class TypeMapping | 68 | private class TypeMapping |
45 | { | 69 | { |
46 | private sbyte assetType; | 70 | private sbyte assetType; |
@@ -56,12 +80,7 @@ namespace OpenSim.Framework | |||
56 | 80 | ||
57 | public object AssetType | 81 | public object AssetType |
58 | { | 82 | { |
59 | get { | 83 | get { return AssetTypeFromCode(assetType); } |
60 | if (Enum.IsDefined(typeof(OpenMetaverse.AssetType), assetType)) | ||
61 | return (OpenMetaverse.AssetType)assetType; | ||
62 | else | ||
63 | return OpenMetaverse.AssetType.Unknown; | ||
64 | } | ||
65 | } | 84 | } |
66 | 85 | ||
67 | public InventoryType InventoryType | 86 | public InventoryType InventoryType |
@@ -102,6 +121,11 @@ namespace OpenSim.Framework | |||
102 | : this((sbyte)assetType, inventoryType, contentType, null, extension) | 121 | : this((sbyte)assetType, inventoryType, contentType, null, extension) |
103 | { | 122 | { |
104 | } | 123 | } |
124 | |||
125 | public TypeMapping(OpenSimAssetType assetType, InventoryType inventoryType, string contentType, string extension) | ||
126 | : this((sbyte)assetType, inventoryType, contentType, null, extension) | ||
127 | { | ||
128 | } | ||
105 | } | 129 | } |
106 | 130 | ||
107 | /// <summary> | 131 | /// <summary> |
@@ -142,7 +166,9 @@ namespace OpenSim.Framework | |||
142 | new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), | 166 | new TypeMapping(AssetType.CurrentOutfitFolder, InventoryType.Unknown, "application/vnd.ll.currentoutfitfolder", "currentoutfitfolder"), |
143 | new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), | 167 | new TypeMapping(AssetType.OutfitFolder, InventoryType.Unknown, "application/vnd.ll.outfitfolder", "outfitfolder"), |
144 | new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), | 168 | new TypeMapping(AssetType.MyOutfitsFolder, InventoryType.Unknown, "application/vnd.ll.myoutfitsfolder", "myoutfitsfolder"), |
145 | new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm") | 169 | new TypeMapping(AssetType.Mesh, InventoryType.Mesh, "application/vnd.ll.mesh", "llm"), |
170 | |||
171 | new TypeMapping(OpenSimAssetType.Material, InventoryType.Unknown, "application/llsd+xml", "material") | ||
146 | }; | 172 | }; |
147 | 173 | ||
148 | private static Dictionary<sbyte, string> asset2Content; | 174 | private static Dictionary<sbyte, string> asset2Content; |
@@ -247,12 +273,18 @@ namespace OpenSim.Framework | |||
247 | /// <returns></returns> | 273 | /// <returns></returns> |
248 | public static List<string> ParseNotecardToList(string rawInput) | 274 | public static List<string> ParseNotecardToList(string rawInput) |
249 | { | 275 | { |
250 | string[] input = rawInput.Replace("\r", "").Split('\n'); | 276 | string[] input; |
251 | int idx = 0; | 277 | int idx = 0; |
252 | int level = 0; | 278 | int level = 0; |
253 | List<string> output = new List<string>(); | 279 | List<string> output = new List<string>(); |
254 | string[] words; | 280 | string[] words; |
255 | 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 | |||
256 | while (idx < input.Length) | 288 | while (idx < input.Length) |
257 | { | 289 | { |
258 | if (input[idx] == "{") | 290 | if (input[idx] == "{") |
@@ -287,24 +319,18 @@ namespace OpenSim.Framework | |||
287 | break; | 319 | break; |
288 | if (words[0] == "Text") | 320 | if (words[0] == "Text") |
289 | { | 321 | { |
290 | int len = int.Parse(words[2]); | 322 | idx++; //Now points to first line of notecard text |
291 | idx++; | ||
292 | 323 | ||
293 | int count = -1; | 324 | //Number of lines in notecard. |
325 | int lines = input.Length - idx; | ||
326 | int line = 0; | ||
294 | 327 | ||
295 | while (count < len && idx < input.Length) | 328 | while (line < lines) |
296 | { | 329 | { |
297 | // int l = input[idx].Length; | 330 | // m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", input[idx]); |
298 | string ln = input[idx]; | 331 | output.Add(input[idx]); |
299 | |||
300 | int need = len-count-1; | ||
301 | if (ln.Length > need) | ||
302 | ln = ln.Substring(0, need); | ||
303 | |||
304 | // m_log.DebugFormat("[PARSE NOTECARD]: Adding line {0}", ln); | ||
305 | output.Add(ln); | ||
306 | count += ln.Length + 1; | ||
307 | idx++; | 332 | idx++; |
333 | line++; | ||
308 | } | 334 | } |
309 | 335 | ||
310 | return output; | 336 | return output; |
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs index 0c12787..73ebfae 100644 --- a/OpenSim/Framework/Serialization/ArchiveConstants.cs +++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs | |||
@@ -29,6 +29,7 @@ using System; | |||
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | 30 | using System.Text; |
31 | using OpenMetaverse; | 31 | using OpenMetaverse; |
32 | using OpenSimAssetType = OpenSim.Framework.SLUtil.OpenSimAssetType; | ||
32 | 33 | ||
33 | namespace OpenSim.Framework.Serialization | 34 | namespace OpenSim.Framework.Serialization |
34 | { | 35 | { |
@@ -128,6 +129,7 @@ namespace OpenSim.Framework.Serialization | |||
128 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; | 129 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.Texture] = ASSET_EXTENSION_SEPARATOR + "texture.jp2"; |
129 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; | 130 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TextureTGA] = ASSET_EXTENSION_SEPARATOR + "texture.tga"; |
130 | ASSET_TYPE_TO_EXTENSION[(sbyte)AssetType.TrashFolder] = ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"; // Not sure if we'll ever see this | 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 | ||
131 | 133 | ||
132 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation; | 134 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "animation.bvh"] = (sbyte)AssetType.Animation; |
133 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart; | 135 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "bodypart.txt"] = (sbyte)AssetType.Bodypart; |
@@ -152,6 +154,7 @@ namespace OpenSim.Framework.Serialization | |||
152 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture; | 154 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.jp2"] = (sbyte)AssetType.Texture; |
153 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA; | 155 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "texture.tga"] = (sbyte)AssetType.TextureTGA; |
154 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; | 156 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "trashfolder.txt"] = (sbyte)AssetType.TrashFolder; |
157 | EXTENSION_TO_ASSET_TYPE[ASSET_EXTENSION_SEPARATOR + "material.xml"] = (sbyte)OpenSimAssetType.Material; | ||
155 | } | 158 | } |
156 | 159 | ||
157 | public static string CreateOarLandDataPath(LandData ld) | 160 | public static string CreateOarLandDataPath(LandData ld) |
diff --git a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs index 88f9581..f2a6b8b 100644 --- a/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs +++ b/OpenSim/Framework/Serialization/External/UserInventoryItemSerializer.cs | |||
@@ -277,7 +277,7 @@ namespace OpenSim.Framework.Serialization.External | |||
277 | writer.WriteStartElement("GroupOwned"); | 277 | writer.WriteStartElement("GroupOwned"); |
278 | writer.WriteString(inventoryItem.GroupOwned.ToString()); | 278 | writer.WriteString(inventoryItem.GroupOwned.ToString()); |
279 | writer.WriteEndElement(); | 279 | writer.WriteEndElement(); |
280 | if (options.ContainsKey("creators") && inventoryItem.CreatorData != null && inventoryItem.CreatorData != string.Empty) | 280 | if (options.ContainsKey("creators") && !string.IsNullOrEmpty(inventoryItem.CreatorData)) |
281 | writer.WriteElementString("CreatorData", inventoryItem.CreatorData); | 281 | writer.WriteElementString("CreatorData", inventoryItem.CreatorData); |
282 | else if (options.ContainsKey("home")) | 282 | else if (options.ContainsKey("home")) |
283 | { | 283 | { |
diff --git a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs index a8dff93..3f04148 100644 --- a/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Serialization/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 6c04c69..cbd34a2 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs | |||
@@ -86,26 +86,23 @@ namespace OpenSim.Framework.Servers | |||
86 | /// </summary> | 86 | /// </summary> |
87 | protected virtual void StartupSpecific() | 87 | protected virtual void StartupSpecific() |
88 | { | 88 | { |
89 | if (m_console == null) | 89 | StatsManager.SimExtraStats = new SimExtraStatsCollector(); |
90 | return; | ||
91 | |||
92 | RegisterCommonCommands(); | 90 | RegisterCommonCommands(); |
93 | 91 | RegisterCommonComponents(Config); | |
94 | m_console.Commands.AddCommand("General", false, "quit", | 92 | } |
95 | "quit", | 93 | |
96 | "Quit the application", HandleQuit); | 94 | protected override void ShutdownSpecific() |
95 | { | ||
96 | m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); | ||
97 | |||
98 | RemovePIDFile(); | ||
97 | 99 | ||
98 | m_console.Commands.AddCommand("General", false, "shutdown", | 100 | base.ShutdownSpecific(); |
99 | "shutdown", | 101 | |
100 | "Quit the application", HandleQuit); | 102 | Environment.Exit(0); |
101 | } | 103 | } |
102 | 104 | ||
103 | /// <summary> | 105 | /// <summary> |
104 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
105 | /// </summary> | ||
106 | public virtual void ShutdownSpecific() {} | ||
107 | |||
108 | /// <summary> | ||
109 | /// Provides a list of help topics that are available. Overriding classes should append their topics to the | 106 | /// Provides a list of help topics that are available. Overriding classes should append their topics to the |
110 | /// information returned when the base method is called. | 107 | /// information returned when the base method is called. |
111 | /// </summary> | 108 | /// </summary> |
@@ -148,30 +145,13 @@ namespace OpenSim.Framework.Servers | |||
148 | 145 | ||
149 | TimeSpan timeTaken = DateTime.Now - m_startuptime; | 146 | TimeSpan timeTaken = DateTime.Now - m_startuptime; |
150 | 147 | ||
151 | m_log.InfoFormat( | 148 | MainConsole.Instance.OutputFormat( |
152 | "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.", | 149 | "PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED. Non-script portion of startup took {0}m {1}s.", |
153 | timeTaken.Minutes, timeTaken.Seconds); | 150 | timeTaken.Minutes, timeTaken.Seconds); |
154 | } | 151 | } |
155 | 152 | ||
156 | /// <summary> | 153 | public string osSecret |
157 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
158 | /// </summary> | ||
159 | public virtual void Shutdown() | ||
160 | { | 154 | { |
161 | ShutdownSpecific(); | ||
162 | |||
163 | m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting..."); | ||
164 | RemovePIDFile(); | ||
165 | |||
166 | Environment.Exit(0); | ||
167 | } | ||
168 | |||
169 | private void HandleQuit(string module, string[] args) | ||
170 | { | ||
171 | Shutdown(); | ||
172 | } | ||
173 | |||
174 | public string osSecret { | ||
175 | // Secret uuid for the simulator | 155 | // Secret uuid for the simulator |
176 | get { return m_osSecret; } | 156 | get { return m_osSecret; } |
177 | } | 157 | } |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs index 97035e3..7841f47 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs | |||
@@ -54,7 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 54 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); | 55 | private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); |
56 | 56 | ||
57 | |||
58 | /// <summary> | 57 | /// <summary> |
59 | /// This is a pending websocket request before it got an sucessful upgrade response. | 58 | /// This is a pending websocket request before it got an sucessful upgrade response. |
60 | /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to | 59 | /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to |
@@ -81,6 +80,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
81 | /// </remarks> | 80 | /// </remarks> |
82 | public int RequestNumber { get; private set; } | 81 | public int RequestNumber { get; private set; } |
83 | 82 | ||
83 | /// <summary> | ||
84 | /// Statistic for holding number of requests processed. | ||
85 | /// </summary> | ||
86 | private Stat m_requestsProcessedStat; | ||
87 | |||
84 | private volatile int NotSocketErrors = 0; | 88 | private volatile int NotSocketErrors = 0; |
85 | public volatile bool HTTPDRunning = false; | 89 | public volatile bool HTTPDRunning = false; |
86 | 90 | ||
@@ -383,6 +387,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
383 | 387 | ||
384 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) | 388 | if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) |
385 | { | 389 | { |
390 | psEvArgs.RequestsReceived++; | ||
391 | |||
386 | PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); | 392 | PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); |
387 | 393 | ||
388 | if (psEvArgs.Request != null) | 394 | if (psEvArgs.Request != null) |
@@ -437,9 +443,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
437 | } | 443 | } |
438 | } | 444 | } |
439 | 445 | ||
440 | public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) | 446 | private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) |
441 | { | 447 | { |
442 | |||
443 | OSHttpRequest req = new OSHttpRequest(context, request); | 448 | OSHttpRequest req = new OSHttpRequest(context, request); |
444 | WebSocketRequestDelegate dWebSocketRequestDelegate = null; | 449 | WebSocketRequestDelegate dWebSocketRequestDelegate = null; |
445 | lock (m_WebSocketHandlers) | 450 | lock (m_WebSocketHandlers) |
@@ -454,9 +459,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
454 | } | 459 | } |
455 | 460 | ||
456 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); | 461 | OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); |
457 | 462 | resp.ReuseContext = true; | |
458 | HandleRequest(req, resp); | 463 | HandleRequest(req, resp); |
459 | |||
460 | 464 | ||
461 | // !!!HACK ALERT!!! | 465 | // !!!HACK ALERT!!! |
462 | // There seems to be a bug in the underlying http code that makes subsequent requests | 466 | // There seems to be a bug in the underlying http code that makes subsequent requests |
@@ -687,7 +691,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
687 | 691 | ||
688 | if (buffer != null) | 692 | if (buffer != null) |
689 | { | 693 | { |
690 | if (!response.SendChunked) | 694 | if (!response.SendChunked && response.ContentLength64 <= 0) |
691 | response.ContentLength64 = buffer.LongLength; | 695 | response.ContentLength64 = buffer.LongLength; |
692 | 696 | ||
693 | response.OutputStream.Write(buffer, 0, buffer.Length); | 697 | response.OutputStream.Write(buffer, 0, buffer.Length); |
@@ -782,7 +786,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
782 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", | 786 | "[BASE HTTP SERVER]: HTTP IN {0} :{1} {2} content type handler {3} {4} from {5}", |
783 | RequestNumber, | 787 | RequestNumber, |
784 | Port, | 788 | Port, |
785 | (request.ContentType == null || request.ContentType == "") ? "not set" : request.ContentType, | 789 | string.IsNullOrEmpty(request.ContentType) ? "not set" : request.ContentType, |
786 | request.HttpMethod, | 790 | request.HttpMethod, |
787 | request.Url.PathAndQuery, | 791 | request.Url.PathAndQuery, |
788 | request.RemoteIPEndPoint); | 792 | request.RemoteIPEndPoint); |
@@ -1053,7 +1057,21 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1053 | } | 1057 | } |
1054 | 1058 | ||
1055 | response.ContentType = "text/xml"; | 1059 | response.ContentType = "text/xml"; |
1056 | responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse); | 1060 | using (MemoryStream outs = new MemoryStream()) |
1061 | { | ||
1062 | using (XmlTextWriter writer = new XmlTextWriter(outs, Encoding.UTF8)) | ||
1063 | { | ||
1064 | writer.Formatting = Formatting.None; | ||
1065 | XmlRpcResponseSerializer.Singleton.Serialize(writer, xmlRpcResponse); | ||
1066 | writer.Flush(); | ||
1067 | outs.Flush(); | ||
1068 | outs.Position = 0; | ||
1069 | using (StreamReader sr = new StreamReader(outs)) | ||
1070 | { | ||
1071 | responseString = sr.ReadToEnd(); | ||
1072 | } | ||
1073 | } | ||
1074 | } | ||
1057 | } | 1075 | } |
1058 | else | 1076 | else |
1059 | { | 1077 | { |
@@ -1850,8 +1868,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1850 | m_httpListener2.Start(64); | 1868 | m_httpListener2.Start(64); |
1851 | 1869 | ||
1852 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events | 1870 | // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events |
1853 | // m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000); | ||
1854 | m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); | 1871 | m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); |
1872 | m_PollServiceManager.Start(); | ||
1855 | HTTPDRunning = true; | 1873 | HTTPDRunning = true; |
1856 | 1874 | ||
1857 | //HttpListenerContext context; | 1875 | //HttpListenerContext context; |
@@ -1870,6 +1888,21 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1870 | // useful without inbound HTTP. | 1888 | // useful without inbound HTTP. |
1871 | throw e; | 1889 | throw e; |
1872 | } | 1890 | } |
1891 | |||
1892 | m_requestsProcessedStat | ||
1893 | = new Stat( | ||
1894 | "HTTPRequestsServed", | ||
1895 | "Number of inbound HTTP requests processed", | ||
1896 | "", | ||
1897 | "requests", | ||
1898 | "httpserver", | ||
1899 | Port.ToString(), | ||
1900 | StatType.Pull, | ||
1901 | MeasuresOfInterest.AverageChangeOverTime, | ||
1902 | stat => stat.Value = RequestNumber, | ||
1903 | StatVerbosity.Debug); | ||
1904 | |||
1905 | StatsManager.RegisterStat(m_requestsProcessedStat); | ||
1873 | } | 1906 | } |
1874 | 1907 | ||
1875 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) | 1908 | public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) |
@@ -1902,9 +1935,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1902 | public void Stop() | 1935 | public void Stop() |
1903 | { | 1936 | { |
1904 | HTTPDRunning = false; | 1937 | HTTPDRunning = false; |
1938 | |||
1939 | StatsManager.DeregisterStat(m_requestsProcessedStat); | ||
1940 | |||
1905 | try | 1941 | try |
1906 | { | 1942 | { |
1907 | // m_PollServiceManager.Stop(); | 1943 | m_PollServiceManager.Stop(); |
1908 | 1944 | ||
1909 | m_httpListener2.ExceptionThrown -= httpServerException; | 1945 | m_httpListener2.ExceptionThrown -= httpServerException; |
1910 | //m_httpListener2.DisconnectHandler = null; | 1946 | //m_httpListener2.DisconnectHandler = null; |
@@ -1931,6 +1967,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
1931 | 1967 | ||
1932 | public void RemoveHTTPHandler(string httpMethod, string path) | 1968 | public void RemoveHTTPHandler(string httpMethod, string path) |
1933 | { | 1969 | { |
1970 | if (path == null) return; // Caps module isn't loaded, tries to remove handler where path = null | ||
1934 | lock (m_HTTPHandlers) | 1971 | lock (m_HTTPHandlers) |
1935 | { | 1972 | { |
1936 | if (httpMethod != null && httpMethod.Length == 0) | 1973 | if (httpMethod != null && httpMethod.Length == 0) |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs new file mode 100644 index 0000000..72b3065 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs | |||
@@ -0,0 +1,60 @@ | |||
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.IO; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// Base handler for writing to an output stream | ||
34 | /// </summary> | ||
35 | /// <remarks> | ||
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
38 | public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler | ||
39 | { | ||
40 | protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} | ||
41 | |||
42 | protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description) | ||
43 | : base(httpMethod, path, name, description) {} | ||
44 | |||
45 | public virtual void Handle( | ||
46 | string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
47 | { | ||
48 | RequestsReceived++; | ||
49 | |||
50 | ProcessRequest(path, request, response, httpRequest, httpResponse); | ||
51 | |||
52 | RequestsHandled++; | ||
53 | } | ||
54 | |||
55 | protected virtual void ProcessRequest( | ||
56 | string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
57 | { | ||
58 | } | ||
59 | } | ||
60 | } \ No newline at end of file | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs index ae7aaf2..bbac699 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs | |||
@@ -31,6 +31,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
31 | { | 31 | { |
32 | public abstract class BaseRequestHandler | 32 | public abstract class BaseRequestHandler |
33 | { | 33 | { |
34 | public int RequestsReceived { get; protected set; } | ||
35 | |||
36 | public int RequestsHandled { get; protected set; } | ||
37 | |||
34 | public virtual string ContentType | 38 | public virtual string ContentType |
35 | { | 39 | { |
36 | get { return "application/xml"; } | 40 | get { return "application/xml"; } |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs index 6342983..252cc2a 100644 --- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs | |||
@@ -29,14 +29,35 @@ using System.IO; | |||
29 | 29 | ||
30 | namespace OpenSim.Framework.Servers.HttpServer | 30 | namespace OpenSim.Framework.Servers.HttpServer |
31 | { | 31 | { |
32 | /// <summary> | ||
33 | /// Base streamed request handler. | ||
34 | /// </summary> | ||
35 | /// <remarks> | ||
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
32 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler | 38 | public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler |
33 | { | 39 | { |
34 | public abstract byte[] Handle(string path, Stream request, | ||
35 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse); | ||
36 | |||
37 | protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} | 40 | protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} |
38 | 41 | ||
39 | protected BaseStreamHandler(string httpMethod, string path, string name, string description) | 42 | protected BaseStreamHandler(string httpMethod, string path, string name, string description) |
40 | : base(httpMethod, path, name, description) {} | 43 | : base(httpMethod, path, name, description) {} |
44 | |||
45 | public virtual byte[] Handle( | ||
46 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
47 | { | ||
48 | RequestsReceived++; | ||
49 | |||
50 | byte[] result = ProcessRequest(path, request, httpRequest, httpResponse); | ||
51 | |||
52 | RequestsHandled++; | ||
53 | |||
54 | return result; | ||
55 | } | ||
56 | |||
57 | protected virtual byte[] ProcessRequest( | ||
58 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
59 | { | ||
60 | return null; | ||
61 | } | ||
41 | } | 62 | } |
42 | } \ No newline at end of file | 63 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs new file mode 100644 index 0000000..1b88545 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandlerBasicDOSProtector.cs | |||
@@ -0,0 +1,107 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | using OpenSim.Framework; | ||
28 | using System.IO; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | /// <summary> | ||
33 | /// BaseStreamHandlerBasicDOSProtector Base streamed request handler. | ||
34 | /// </summary> | ||
35 | /// <remarks> | ||
36 | /// Inheriting classes should override ProcessRequest() rather than Handle() | ||
37 | /// </remarks> | ||
38 | public abstract class BaseStreamHandlerBasicDOSProtector : BaseRequestHandler, IStreamedRequestHandler | ||
39 | { | ||
40 | |||
41 | private readonly BasicDosProtectorOptions _options; | ||
42 | private readonly BasicDOSProtector _dosProtector; | ||
43 | |||
44 | protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, BasicDosProtectorOptions options) : this(httpMethod, path, null, null, options) {} | ||
45 | |||
46 | protected BaseStreamHandlerBasicDOSProtector(string httpMethod, string path, string name, string description, BasicDosProtectorOptions options) | ||
47 | : base(httpMethod, path, name, description) | ||
48 | { | ||
49 | _options = options; | ||
50 | _dosProtector = new BasicDOSProtector(_options); | ||
51 | } | ||
52 | |||
53 | public virtual byte[] Handle( | ||
54 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
55 | { | ||
56 | byte[] result; | ||
57 | RequestsReceived++; | ||
58 | string clientstring = GetClientString(httpRequest); | ||
59 | string endpoint = GetRemoteAddr(httpRequest); | ||
60 | if (_dosProtector.Process(clientstring, endpoint)) | ||
61 | result = ProcessRequest(path, request, httpRequest, httpResponse); | ||
62 | else | ||
63 | result = ThrottledRequest(path, request, httpRequest, httpResponse); | ||
64 | if (_options.MaxConcurrentSessions > 0) | ||
65 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
66 | |||
67 | RequestsHandled++; | ||
68 | |||
69 | return result; | ||
70 | } | ||
71 | |||
72 | protected virtual byte[] ProcessRequest( | ||
73 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
74 | { | ||
75 | return null; | ||
76 | } | ||
77 | |||
78 | protected virtual byte[] ThrottledRequest( | ||
79 | string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | ||
80 | { | ||
81 | return new byte[0]; | ||
82 | } | ||
83 | |||
84 | |||
85 | private string GetRemoteAddr(IOSHttpRequest httpRequest) | ||
86 | { | ||
87 | string remoteaddr = string.Empty; | ||
88 | if (httpRequest.Headers["remote_addr"] != null) | ||
89 | remoteaddr = httpRequest.Headers["remote_addr"]; | ||
90 | |||
91 | return remoteaddr; | ||
92 | } | ||
93 | |||
94 | private string GetClientString(IOSHttpRequest httpRequest) | ||
95 | { | ||
96 | string clientstring = string.Empty; | ||
97 | |||
98 | if (_options.AllowXForwardedFor && httpRequest.Headers["x-forwarded-for"] != null) | ||
99 | clientstring = httpRequest.Headers["x-forwarded-for"]; | ||
100 | else | ||
101 | clientstring = GetRemoteAddr(httpRequest); | ||
102 | |||
103 | return clientstring; | ||
104 | |||
105 | } | ||
106 | } | ||
107 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs index b94bfb4..1b03f54 100644 --- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs | |||
@@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
45 | m_method = binaryMethod; | 45 | m_method = binaryMethod; |
46 | } | 46 | } |
47 | 47 | ||
48 | public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 48 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
49 | { | 49 | { |
50 | byte[] data = ReadFully(request); | 50 | byte[] data = ReadFully(request); |
51 | string param = GetParam(path); | 51 | string param = GetParam(path); |
diff --git a/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs new file mode 100644 index 0000000..cd4b8ff --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/GenericHTTPBasicDOSProtector.cs | |||
@@ -0,0 +1,119 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Collections; | ||
29 | |||
30 | namespace OpenSim.Framework.Servers.HttpServer | ||
31 | { | ||
32 | public class GenericHTTPDOSProtector | ||
33 | { | ||
34 | private readonly GenericHTTPMethod _normalMethod; | ||
35 | private readonly GenericHTTPMethod _throttledMethod; | ||
36 | |||
37 | private readonly BasicDosProtectorOptions _options; | ||
38 | private readonly BasicDOSProtector _dosProtector; | ||
39 | |||
40 | public GenericHTTPDOSProtector(GenericHTTPMethod normalMethod, GenericHTTPMethod throttledMethod, BasicDosProtectorOptions options) | ||
41 | { | ||
42 | _normalMethod = normalMethod; | ||
43 | _throttledMethod = throttledMethod; | ||
44 | |||
45 | _options = options; | ||
46 | _dosProtector = new BasicDOSProtector(_options); | ||
47 | } | ||
48 | public Hashtable Process(Hashtable request) | ||
49 | { | ||
50 | Hashtable process = null; | ||
51 | string clientstring= GetClientString(request); | ||
52 | string endpoint = GetRemoteAddr(request); | ||
53 | if (_dosProtector.Process(clientstring, endpoint)) | ||
54 | process = _normalMethod(request); | ||
55 | else | ||
56 | process = _throttledMethod(request); | ||
57 | |||
58 | if (_options.MaxConcurrentSessions>0) | ||
59 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
60 | |||
61 | return process; | ||
62 | } | ||
63 | |||
64 | private string GetRemoteAddr(Hashtable request) | ||
65 | { | ||
66 | string remoteaddr = ""; | ||
67 | if (!request.ContainsKey("headers")) | ||
68 | return remoteaddr; | ||
69 | Hashtable requestinfo = (Hashtable)request["headers"]; | ||
70 | if (!requestinfo.ContainsKey("remote_addr")) | ||
71 | return remoteaddr; | ||
72 | object remote_addrobj = requestinfo["remote_addr"]; | ||
73 | if (remote_addrobj != null) | ||
74 | { | ||
75 | if (!string.IsNullOrEmpty(remote_addrobj.ToString())) | ||
76 | { | ||
77 | remoteaddr = remote_addrobj.ToString(); | ||
78 | } | ||
79 | |||
80 | } | ||
81 | return remoteaddr; | ||
82 | } | ||
83 | |||
84 | private string GetClientString(Hashtable request) | ||
85 | { | ||
86 | string clientstring = ""; | ||
87 | if (!request.ContainsKey("headers")) | ||
88 | return clientstring; | ||
89 | |||
90 | Hashtable requestinfo = (Hashtable)request["headers"]; | ||
91 | if (_options.AllowXForwardedFor && requestinfo.ContainsKey("x-forwarded-for")) | ||
92 | { | ||
93 | object str = requestinfo["x-forwarded-for"]; | ||
94 | if (str != null) | ||
95 | { | ||
96 | if (!string.IsNullOrEmpty(str.ToString())) | ||
97 | { | ||
98 | return str.ToString(); | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | if (!requestinfo.ContainsKey("remote_addr")) | ||
103 | return clientstring; | ||
104 | |||
105 | object remote_addrobj = requestinfo["remote_addr"]; | ||
106 | if (remote_addrobj != null) | ||
107 | { | ||
108 | if (!string.IsNullOrEmpty(remote_addrobj.ToString())) | ||
109 | { | ||
110 | clientstring = remote_addrobj.ToString(); | ||
111 | } | ||
112 | } | ||
113 | |||
114 | return clientstring; | ||
115 | |||
116 | } | ||
117 | |||
118 | } | ||
119 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs index cb5cce5..b8541cb 100644 --- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs | |||
@@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
32 | { | 32 | { |
33 | public interface IRequestHandler | 33 | public interface IRequestHandler |
34 | { | 34 | { |
35 | |||
36 | /// <summary> | 35 | /// <summary> |
37 | /// Name for this handler. | 36 | /// Name for this handler. |
38 | /// </summary> | 37 | /// </summary> |
@@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
59 | 58 | ||
60 | // Return path | 59 | // Return path |
61 | string Path { get; } | 60 | string Path { get; } |
61 | |||
62 | /// <summary> | ||
63 | /// Number of requests received by this handler | ||
64 | /// </summary> | ||
65 | int RequestsReceived { get; } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Number of requests handled. | ||
69 | /// </summary> | ||
70 | /// <remarks> | ||
71 | /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock. | ||
72 | /// </remarks> | ||
73 | int RequestsHandled { get; } | ||
62 | } | 74 | } |
63 | 75 | ||
64 | public interface IStreamedRequestHandler : IRequestHandler | 76 | public interface IStreamedRequestHandler : IRequestHandler |
@@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
69 | 81 | ||
70 | public interface IStreamHandler : IRequestHandler | 82 | public interface IStreamHandler : IRequestHandler |
71 | { | 83 | { |
72 | // Handle request stream, return byte array | ||
73 | void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); | 84 | void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); |
74 | } | 85 | } |
75 | 86 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index c19ac32..3fd3bf7 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs | |||
@@ -50,25 +50,39 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
50 | 50 | ||
51 | public enum EventType : int | 51 | public enum EventType : int |
52 | { | 52 | { |
53 | Normal = 0, | 53 | LongPoll = 0, |
54 | LslHttp = 1, | 54 | LslHttp = 1, |
55 | Inventory = 2, | 55 | Inventory = 2, |
56 | Texture = 3, | 56 | Texture = 3, |
57 | Mesh = 4 | 57 | Mesh = 4 |
58 | } | 58 | } |
59 | 59 | ||
60 | public string Url { get; set; } | ||
61 | |||
62 | /// <summary> | ||
63 | /// Number of requests received for this poll service. | ||
64 | /// </summary> | ||
65 | public int RequestsReceived { get; set; } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Number of requests handled by this poll service. | ||
69 | /// </summary> | ||
70 | public int RequestsHandled { get; set; } | ||
71 | |||
60 | public PollServiceEventArgs( | 72 | public PollServiceEventArgs( |
61 | RequestMethod pRequest, | 73 | RequestMethod pRequest, |
74 | string pUrl, | ||
62 | HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, | 75 | HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, |
63 | UUID pId, int pTimeOutms) | 76 | UUID pId, int pTimeOutms) |
64 | { | 77 | { |
65 | Request = pRequest; | 78 | Request = pRequest; |
79 | Url = pUrl; | ||
66 | HasEvents = pHasEvents; | 80 | HasEvents = pHasEvents; |
67 | GetEvents = pGetEvents; | 81 | GetEvents = pGetEvents; |
68 | NoEvents = pNoEvents; | 82 | NoEvents = pNoEvents; |
69 | Id = pId; | 83 | Id = pId; |
70 | TimeOutms = pTimeOutms; | 84 | TimeOutms = pTimeOutms; |
71 | Type = EventType.Normal; | 85 | Type = EventType.LongPoll; |
72 | } | 86 | } |
73 | } | 87 | } |
74 | } | 88 | } |
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 723530a..6aa9479 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs | |||
@@ -26,13 +26,19 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections; | ||
30 | using System.Reflection; | ||
31 | using System.Text; | ||
29 | using HttpServer; | 32 | using HttpServer; |
33 | using log4net; | ||
30 | using OpenMetaverse; | 34 | using OpenMetaverse; |
31 | 35 | ||
32 | namespace OpenSim.Framework.Servers.HttpServer | 36 | namespace OpenSim.Framework.Servers.HttpServer |
33 | { | 37 | { |
34 | public class PollServiceHttpRequest | 38 | public class PollServiceHttpRequest |
35 | { | 39 | { |
40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
41 | |||
36 | public readonly PollServiceEventArgs PollServiceArgs; | 42 | public readonly PollServiceEventArgs PollServiceArgs; |
37 | public readonly IHttpClientContext HttpContext; | 43 | public readonly IHttpClientContext HttpContext; |
38 | public readonly IHttpRequest Request; | 44 | public readonly IHttpRequest Request; |
@@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
48 | RequestTime = System.Environment.TickCount; | 54 | RequestTime = System.Environment.TickCount; |
49 | RequestID = UUID.Random(); | 55 | RequestID = UUID.Random(); |
50 | } | 56 | } |
57 | |||
58 | internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata) | ||
59 | { | ||
60 | OSHttpResponse response | ||
61 | = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext); | ||
62 | |||
63 | byte[] buffer = server.DoHTTPGruntWork(responsedata, response); | ||
64 | |||
65 | response.SendChunked = false; | ||
66 | response.ContentLength64 = buffer.Length; | ||
67 | response.ContentEncoding = Encoding.UTF8; | ||
68 | |||
69 | try | ||
70 | { | ||
71 | response.OutputStream.Write(buffer, 0, buffer.Length); | ||
72 | } | ||
73 | catch (Exception ex) | ||
74 | { | ||
75 | m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex)); | ||
76 | } | ||
77 | finally | ||
78 | { | ||
79 | //response.OutputStream.Close(); | ||
80 | try | ||
81 | { | ||
82 | response.OutputStream.Flush(); | ||
83 | response.Send(); | ||
84 | |||
85 | //if (!response.KeepAlive && response.ReuseContext) | ||
86 | // response.FreeContext(); | ||
87 | } | ||
88 | catch (Exception e) | ||
89 | { | ||
90 | m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e)); | ||
91 | } | ||
92 | |||
93 | PollServiceArgs.RequestsHandled++; | ||
94 | } | ||
95 | } | ||
51 | } | 96 | } |
52 | } \ No newline at end of file | 97 | } \ No newline at end of file |
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs index 5406f00..44f7045 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs | |||
@@ -64,14 +64,17 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
64 | m_server = pSrv; | 64 | m_server = pSrv; |
65 | m_WorkerThreadCount = pWorkerThreadCount; | 65 | m_WorkerThreadCount = pWorkerThreadCount; |
66 | m_workerThreads = new Thread[m_WorkerThreadCount]; | 66 | m_workerThreads = new Thread[m_WorkerThreadCount]; |
67 | } | ||
67 | 68 | ||
69 | public void Start() | ||
70 | { | ||
68 | //startup worker threads | 71 | //startup worker threads |
69 | for (uint i = 0; i < m_WorkerThreadCount; i++) | 72 | for (uint i = 0; i < m_WorkerThreadCount; i++) |
70 | { | 73 | { |
71 | m_workerThreads[i] | 74 | m_workerThreads[i] |
72 | = Watchdog.StartThread( | 75 | = Watchdog.StartThread( |
73 | PoolWorkerJob, | 76 | PoolWorkerJob, |
74 | String.Format("PollServiceWorkerThread{0}", i), | 77 | string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port), |
75 | ThreadPriority.Normal, | 78 | ThreadPriority.Normal, |
76 | false, | 79 | false, |
77 | false, | 80 | false, |
@@ -81,7 +84,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
81 | 84 | ||
82 | m_retrysThread = Watchdog.StartThread( | 85 | m_retrysThread = Watchdog.StartThread( |
83 | this.CheckRetries, | 86 | this.CheckRetries, |
84 | "PollServiceWatcherThread", | 87 | string.Format("PollServiceWatcherThread:{0}", m_server.Port), |
85 | ThreadPriority.Normal, | 88 | ThreadPriority.Normal, |
86 | false, | 89 | false, |
87 | true, | 90 | true, |
@@ -89,7 +92,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
89 | 1000 * 60 * 10); | 92 | 1000 * 60 * 10); |
90 | } | 93 | } |
91 | 94 | ||
92 | |||
93 | private void ReQueueEvent(PollServiceHttpRequest req) | 95 | private void ReQueueEvent(PollServiceHttpRequest req) |
94 | { | 96 | { |
95 | if (m_running) | 97 | if (m_running) |
@@ -103,7 +105,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
103 | { | 105 | { |
104 | if (m_running) | 106 | if (m_running) |
105 | { | 107 | { |
106 | if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) | 108 | if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll) |
107 | { | 109 | { |
108 | m_requests.Enqueue(req); | 110 | m_requests.Enqueue(req); |
109 | } | 111 | } |
@@ -140,13 +142,13 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
140 | } | 142 | } |
141 | } | 143 | } |
142 | 144 | ||
143 | ~PollServiceRequestManager() | 145 | public void Stop() |
144 | { | 146 | { |
145 | m_running = false; | 147 | m_running = false; |
146 | Thread.Sleep(1000); // let the world move | 148 | Thread.Sleep(1000); // let the world move |
147 | 149 | ||
148 | foreach (Thread t in m_workerThreads) | 150 | foreach (Thread t in m_workerThreads) |
149 | Watchdog.AbortThread(t.ManagedThreadId); | 151 | Watchdog.AbortThread(t.ManagedThreadId); |
150 | 152 | ||
151 | try | 153 | try |
152 | { | 154 | { |
@@ -205,7 +207,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
205 | if (responsedata == null) | 207 | if (responsedata == null) |
206 | continue; | 208 | continue; |
207 | 209 | ||
208 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue | 210 | if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue |
209 | { | 211 | { |
210 | try | 212 | try |
211 | { | 213 | { |
diff --git a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs index 8e592c1..f409667 100644 --- a/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs +++ b/OpenSim/Framework/Servers/HttpServer/Properties/AssemblyInfo.cs | |||
@@ -29,5 +29,5 @@ using System.Runtime.InteropServices; | |||
29 | // Build Number | 29 | // Build Number |
30 | // Revision | 30 | // Revision |
31 | // | 31 | // |
32 | [assembly: AssemblyVersion("0.7.6.*")] | 32 | [assembly: AssemblyVersion("0.8.0.*")] |
33 | 33 | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs index 07082a8..bd55657 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs | |||
@@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
33 | { | 33 | { |
34 | public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); | 34 | public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); |
35 | 35 | ||
36 | public class RestDeserialiseHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | 36 | public class RestDeserialiseHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler |
37 | where TRequest : new() | 37 | where TRequest : new() |
38 | { | 38 | { |
39 | private RestDeserialiseMethod<TRequest, TResponse> m_method; | 39 | private RestDeserialiseMethod<TRequest, TResponse> m_method; |
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
48 | m_method = method; | 48 | m_method = method; |
49 | } | 49 | } |
50 | 50 | ||
51 | public void Handle(string path, Stream request, Stream responseStream, | 51 | protected override void ProcessRequest(string path, Stream request, Stream responseStream, |
52 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 52 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
53 | { | 53 | { |
54 | TRequest deserial; | 54 | TRequest deserial; |
diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs index edcd134..83c9848 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs | |||
@@ -183,7 +183,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
183 | 183 | ||
184 | public delegate bool CheckIdentityMethod(string sid, string aid); | 184 | public delegate bool CheckIdentityMethod(string sid, string aid); |
185 | 185 | ||
186 | public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | 186 | public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler |
187 | where TRequest : new() | 187 | where TRequest : new() |
188 | { | 188 | { |
189 | private static readonly ILog m_log | 189 | private static readonly ILog m_log |
@@ -201,7 +201,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
201 | m_method = method; | 201 | m_method = method; |
202 | } | 202 | } |
203 | 203 | ||
204 | public void Handle(string path, Stream request, Stream responseStream, | 204 | protected override void ProcessRequest(string path, Stream request, Stream responseStream, |
205 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 205 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
206 | { | 206 | { |
207 | RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); | 207 | RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); |
@@ -237,7 +237,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
237 | 237 | ||
238 | public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); | 238 | public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); |
239 | 239 | ||
240 | public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler | 240 | public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler |
241 | where TRequest : new() | 241 | where TRequest : new() |
242 | { | 242 | { |
243 | private static readonly ILog m_log | 243 | private static readonly ILog m_log |
@@ -260,7 +260,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
260 | m_method = method; | 260 | m_method = method; |
261 | } | 261 | } |
262 | 262 | ||
263 | public void Handle(string path, Stream request, Stream responseStream, | 263 | protected override void ProcessRequest(string path, Stream request, Stream responseStream, |
264 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 264 | IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
265 | { | 265 | { |
266 | TRequest deserial = default(TRequest); | 266 | TRequest deserial = default(TRequest); |
@@ -292,6 +292,5 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
292 | serializer.Serialize(xmlWriter, response); | 292 | serializer.Serialize(xmlWriter, response); |
293 | } | 293 | } |
294 | } | 294 | } |
295 | } | 295 | } |
296 | 296 | } \ No newline at end of file | |
297 | } | ||
diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs index 1f17fee..0305dee 100644 --- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs | |||
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
48 | m_restMethod = restMethod; | 48 | m_restMethod = restMethod; |
49 | } | 49 | } |
50 | 50 | ||
51 | public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) | 51 | protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) |
52 | { | 52 | { |
53 | Encoding encoding = Encoding.UTF8; | 53 | Encoding encoding = Encoding.UTF8; |
54 | StreamReader streamReader = new StreamReader(request, encoding); | 54 | StreamReader streamReader = new StreamReader(request, encoding); |
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs index ee96b47..c2925e3 100644 --- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs +++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs | |||
@@ -28,8 +28,10 @@ | |||
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.Net; | ||
31 | using System.Security.Cryptography; | 32 | using System.Security.Cryptography; |
32 | using System.Text; | 33 | using System.Text; |
34 | using System.Threading; | ||
33 | using HttpServer; | 35 | using HttpServer; |
34 | 36 | ||
35 | namespace OpenSim.Framework.Servers.HttpServer | 37 | namespace OpenSim.Framework.Servers.HttpServer |
@@ -75,7 +77,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
75 | /// <summary> | 77 | /// <summary> |
76 | /// This is a regular HTTP Request... This may be removed in the future. | 78 | /// This is a regular HTTP Request... This may be removed in the future. |
77 | /// </summary> | 79 | /// </summary> |
78 | public event RegularHttpRequestDelegate OnRegularHttpRequest; | 80 | // public event RegularHttpRequestDelegate OnRegularHttpRequest; |
79 | 81 | ||
80 | /// <summary> | 82 | /// <summary> |
81 | /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired | 83 | /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired |
@@ -98,6 +100,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
98 | /// </summary> | 100 | /// </summary> |
99 | public ValidateHandshake HandshakeValidateMethodOverride = null; | 101 | public ValidateHandshake HandshakeValidateMethodOverride = null; |
100 | 102 | ||
103 | private ManualResetEvent _receiveDone = new ManualResetEvent(false); | ||
104 | |||
101 | private OSHttpRequest _request; | 105 | private OSHttpRequest _request; |
102 | private HTTPNetworkContext _networkContext; | 106 | private HTTPNetworkContext _networkContext; |
103 | private IHttpClientContext _clientContext; | 107 | private IHttpClientContext _clientContext; |
@@ -109,6 +113,8 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
109 | private bool _closing; | 113 | private bool _closing; |
110 | private bool _upgraded; | 114 | private bool _upgraded; |
111 | private int _maxPayloadBytes = 41943040; | 115 | private int _maxPayloadBytes = 41943040; |
116 | private int _initialMsgTimeout = 0; | ||
117 | private int _defaultReadTimeout = 10000; | ||
112 | 118 | ||
113 | private const string HandshakeAcceptText = | 119 | private const string HandshakeAcceptText = |
114 | "HTTP/1.1 101 Switching Protocols\r\n" + | 120 | "HTTP/1.1 101 Switching Protocols\r\n" + |
@@ -131,6 +137,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
131 | { | 137 | { |
132 | _request = preq; | 138 | _request = preq; |
133 | _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); | 139 | _networkContext = pContext.GiveMeTheNetworkStreamIKnowWhatImDoing(); |
140 | _networkContext.Stream.ReadTimeout = _defaultReadTimeout; | ||
134 | _clientContext = pContext; | 141 | _clientContext = pContext; |
135 | _bufferLength = bufferlen; | 142 | _bufferLength = bufferlen; |
136 | _buffer = new byte[_bufferLength]; | 143 | _buffer = new byte[_bufferLength]; |
@@ -206,6 +213,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
206 | } | 213 | } |
207 | 214 | ||
208 | /// <summary> | 215 | /// <summary> |
216 | /// Set this to the maximum amount of milliseconds to wait for the first complete message to be sent or received on the websocket after upgrading | ||
217 | /// Default, it waits forever. Use this when your Websocket consuming code opens a connection and waits for a message from the other side to avoid a Denial of Service vector. | ||
218 | /// </summary> | ||
219 | public int InitialMsgTimeout | ||
220 | { | ||
221 | get { return _initialMsgTimeout; } | ||
222 | set { _initialMsgTimeout = value; } | ||
223 | } | ||
224 | |||
225 | /// <summary> | ||
209 | /// This triggers the websocket start the upgrade process | 226 | /// This triggers the websocket start the upgrade process |
210 | /// </summary> | 227 | /// </summary> |
211 | public void HandshakeAndUpgrade() | 228 | public void HandshakeAndUpgrade() |
@@ -245,6 +262,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
245 | string rawaccept = string.Format(HandshakeAcceptText, acceptKey); | 262 | string rawaccept = string.Format(HandshakeAcceptText, acceptKey); |
246 | SendUpgradeSuccess(rawaccept); | 263 | SendUpgradeSuccess(rawaccept); |
247 | 264 | ||
265 | |||
248 | } | 266 | } |
249 | else | 267 | else |
250 | { | 268 | { |
@@ -258,6 +276,10 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
258 | SendUpgradeSuccess(rawaccept); | 276 | SendUpgradeSuccess(rawaccept); |
259 | } | 277 | } |
260 | } | 278 | } |
279 | public IPEndPoint GetRemoteIPEndpoint() | ||
280 | { | ||
281 | return _request.RemoteIPEndPoint; | ||
282 | } | ||
261 | 283 | ||
262 | /// <summary> | 284 | /// <summary> |
263 | /// Generates a handshake response key string based on the client's | 285 | /// Generates a handshake response key string based on the client's |
@@ -290,9 +312,16 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
290 | WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; | 312 | WebSocketState socketState = new WebSocketState() { ReceivedBytes = new List<byte>(), Header = WebsocketFrameHeader.HeaderDefault(), FrameComplete = true}; |
291 | 313 | ||
292 | byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); | 314 | byte[] bhandshakeResponse = Encoding.UTF8.GetBytes(pHandshakeResponse); |
315 | |||
316 | |||
317 | |||
318 | |||
293 | try | 319 | try |
294 | { | 320 | { |
295 | 321 | if (_initialMsgTimeout > 0) | |
322 | { | ||
323 | _receiveDone.Reset(); | ||
324 | } | ||
296 | // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. | 325 | // Begin reading the TCP stream before writing the Upgrade success message to the other side of the stream. |
297 | _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); | 326 | _networkContext.Stream.BeginRead(_buffer, 0, _bufferLength, OnReceive, socketState); |
298 | 327 | ||
@@ -303,16 +332,20 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
303 | UpgradeCompletedDelegate d = OnUpgradeCompleted; | 332 | UpgradeCompletedDelegate d = OnUpgradeCompleted; |
304 | if (d != null) | 333 | if (d != null) |
305 | d(this, new UpgradeCompletedEventArgs()); | 334 | d(this, new UpgradeCompletedEventArgs()); |
335 | if (_initialMsgTimeout > 0) | ||
336 | { | ||
337 | if (!_receiveDone.WaitOne(TimeSpan.FromMilliseconds(_initialMsgTimeout))) | ||
338 | Close(string.Empty); | ||
339 | } | ||
306 | } | 340 | } |
307 | catch (IOException fail) | 341 | catch (IOException) |
308 | { | 342 | { |
309 | Close(string.Empty); | 343 | Close(string.Empty); |
310 | } | 344 | } |
311 | catch (ObjectDisposedException fail) | 345 | catch (ObjectDisposedException) |
312 | { | 346 | { |
313 | Close(string.Empty); | 347 | Close(string.Empty); |
314 | } | 348 | } |
315 | |||
316 | } | 349 | } |
317 | 350 | ||
318 | /// <summary> | 351 | /// <summary> |
@@ -414,8 +447,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
414 | _socketState.Header = pheader; | 447 | _socketState.Header = pheader; |
415 | } | 448 | } |
416 | 449 | ||
417 | |||
418 | |||
419 | if (_socketState.FrameComplete) | 450 | if (_socketState.FrameComplete) |
420 | { | 451 | { |
421 | ProcessFrame(_socketState); | 452 | ProcessFrame(_socketState); |
@@ -424,7 +455,6 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
424 | _socketState.ExpectedBytes = 0; | 455 | _socketState.ExpectedBytes = 0; |
425 | 456 | ||
426 | } | 457 | } |
427 | |||
428 | } | 458 | } |
429 | } | 459 | } |
430 | else | 460 | else |
@@ -457,8 +487,7 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
457 | _socketState.ReceivedBytes.Clear(); | 487 | _socketState.ReceivedBytes.Clear(); |
458 | _socketState.ExpectedBytes = 0; | 488 | _socketState.ExpectedBytes = 0; |
459 | // do some processing | 489 | // do some processing |
460 | } | 490 | } |
461 | |||
462 | } | 491 | } |
463 | } | 492 | } |
464 | if (offset > 0) | 493 | if (offset > 0) |
@@ -477,13 +506,12 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
477 | { | 506 | { |
478 | // We can't read the stream anymore... | 507 | // We can't read the stream anymore... |
479 | } | 508 | } |
480 | |||
481 | } | 509 | } |
482 | catch (IOException fail) | 510 | catch (IOException) |
483 | { | 511 | { |
484 | Close(string.Empty); | 512 | Close(string.Empty); |
485 | } | 513 | } |
486 | catch (ObjectDisposedException fail) | 514 | catch (ObjectDisposedException) |
487 | { | 515 | { |
488 | Close(string.Empty); | 516 | Close(string.Empty); |
489 | } | 517 | } |
@@ -495,6 +523,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
495 | /// <param name="message">the string message that is to be sent</param> | 523 | /// <param name="message">the string message that is to be sent</param> |
496 | public void SendMessage(string message) | 524 | public void SendMessage(string message) |
497 | { | 525 | { |
526 | if (_initialMsgTimeout > 0) | ||
527 | { | ||
528 | _receiveDone.Set(); | ||
529 | _initialMsgTimeout = 0; | ||
530 | } | ||
498 | byte[] messagedata = Encoding.UTF8.GetBytes(message); | 531 | byte[] messagedata = Encoding.UTF8.GetBytes(message); |
499 | WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; | 532 | WebSocketFrame textMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = messagedata }; |
500 | textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; | 533 | textMessageFrame.Header.Opcode = WebSocketReader.OpCode.Text; |
@@ -505,6 +538,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
505 | 538 | ||
506 | public void SendData(byte[] data) | 539 | public void SendData(byte[] data) |
507 | { | 540 | { |
541 | if (_initialMsgTimeout > 0) | ||
542 | { | ||
543 | _receiveDone.Set(); | ||
544 | _initialMsgTimeout = 0; | ||
545 | } | ||
508 | WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; | 546 | WebSocketFrame dataMessageFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = data}; |
509 | dataMessageFrame.Header.IsEnd = true; | 547 | dataMessageFrame.Header.IsEnd = true; |
510 | dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; | 548 | dataMessageFrame.Header.Opcode = WebSocketReader.OpCode.Binary; |
@@ -537,6 +575,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
537 | /// </summary> | 575 | /// </summary> |
538 | public void SendPingCheck() | 576 | public void SendPingCheck() |
539 | { | 577 | { |
578 | if (_initialMsgTimeout > 0) | ||
579 | { | ||
580 | _receiveDone.Set(); | ||
581 | _initialMsgTimeout = 0; | ||
582 | } | ||
540 | WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; | 583 | WebSocketFrame pingFrame = new WebSocketFrame() { Header = WebsocketFrameHeader.HeaderDefault(), WebSocketPayload = new byte[0] }; |
541 | pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; | 584 | pingFrame.Header.Opcode = WebSocketReader.OpCode.Ping; |
542 | pingFrame.Header.IsEnd = true; | 585 | pingFrame.Header.IsEnd = true; |
@@ -550,6 +593,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
550 | /// <param name="message"></param> | 593 | /// <param name="message"></param> |
551 | public void Close(string message) | 594 | public void Close(string message) |
552 | { | 595 | { |
596 | if (_initialMsgTimeout > 0) | ||
597 | { | ||
598 | _receiveDone.Set(); | ||
599 | _initialMsgTimeout = 0; | ||
600 | } | ||
553 | if (_networkContext == null) | 601 | if (_networkContext == null) |
554 | return; | 602 | return; |
555 | if (_networkContext.Stream != null) | 603 | if (_networkContext.Stream != null) |
@@ -589,7 +637,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
589 | WebSocketReader.Mask(psocketState.Header.Mask, unmask); | 637 | WebSocketReader.Mask(psocketState.Header.Mask, unmask); |
590 | psocketState.ReceivedBytes = new List<byte>(unmask); | 638 | psocketState.ReceivedBytes = new List<byte>(unmask); |
591 | } | 639 | } |
592 | 640 | if (psocketState.Header.Opcode != WebSocketReader.OpCode.Continue && _initialMsgTimeout > 0) | |
641 | { | ||
642 | _receiveDone.Set(); | ||
643 | _initialMsgTimeout = 0; | ||
644 | } | ||
593 | switch (psocketState.Header.Opcode) | 645 | switch (psocketState.Header.Opcode) |
594 | { | 646 | { |
595 | case WebSocketReader.OpCode.Ping: | 647 | case WebSocketReader.OpCode.Ping: |
@@ -702,6 +754,11 @@ namespace OpenSim.Framework.Servers.HttpServer | |||
702 | } | 754 | } |
703 | public void Dispose() | 755 | public void Dispose() |
704 | { | 756 | { |
757 | if (_initialMsgTimeout > 0) | ||
758 | { | ||
759 | _receiveDone.Set(); | ||
760 | _initialMsgTimeout = 0; | ||
761 | } | ||
705 | if (_networkContext != null && _networkContext.Stream != null) | 762 | if (_networkContext != null && _networkContext.Stream != null) |
706 | { | 763 | { |
707 | if (_networkContext.Stream.CanWrite) | 764 | if (_networkContext.Stream.CanWrite) |
diff --git a/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs new file mode 100644 index 0000000..f212208 --- /dev/null +++ b/OpenSim/Framework/Servers/HttpServer/XmlRpcBasicDOSProtector.cs | |||
@@ -0,0 +1,91 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System.Net; | ||
29 | using Nwc.XmlRpc; | ||
30 | using OpenSim.Framework; | ||
31 | |||
32 | |||
33 | namespace OpenSim.Framework.Servers.HttpServer | ||
34 | { | ||
35 | public class XmlRpcBasicDOSProtector | ||
36 | { | ||
37 | private readonly XmlRpcMethod _normalMethod; | ||
38 | private readonly XmlRpcMethod _throttledMethod; | ||
39 | |||
40 | private readonly BasicDosProtectorOptions _options; | ||
41 | private readonly BasicDOSProtector _dosProtector; | ||
42 | |||
43 | public XmlRpcBasicDOSProtector(XmlRpcMethod normalMethod, XmlRpcMethod throttledMethod,BasicDosProtectorOptions options) | ||
44 | { | ||
45 | _normalMethod = normalMethod; | ||
46 | _throttledMethod = throttledMethod; | ||
47 | |||
48 | _options = options; | ||
49 | _dosProtector = new BasicDOSProtector(_options); | ||
50 | |||
51 | } | ||
52 | public XmlRpcResponse Process(XmlRpcRequest request, IPEndPoint client) | ||
53 | { | ||
54 | |||
55 | XmlRpcResponse resp = null; | ||
56 | string clientstring = GetClientString(request, client); | ||
57 | string endpoint = GetEndPoint(request, client); | ||
58 | if (_dosProtector.Process(clientstring, endpoint)) | ||
59 | resp = _normalMethod(request, client); | ||
60 | else | ||
61 | resp = _throttledMethod(request, client); | ||
62 | if (_options.MaxConcurrentSessions > 0) | ||
63 | _dosProtector.ProcessEnd(clientstring, endpoint); | ||
64 | return resp; | ||
65 | } | ||
66 | |||
67 | private string GetClientString(XmlRpcRequest request, IPEndPoint client) | ||
68 | { | ||
69 | string clientstring; | ||
70 | if (_options.AllowXForwardedFor && request.Params.Count > 3) | ||
71 | { | ||
72 | object headerstr = request.Params[3]; | ||
73 | if (headerstr != null && !string.IsNullOrEmpty(headerstr.ToString())) | ||
74 | clientstring = request.Params[3].ToString(); | ||
75 | else | ||
76 | clientstring = client.Address.ToString(); | ||
77 | } | ||
78 | else | ||
79 | clientstring = client.Address.ToString(); | ||
80 | return clientstring; | ||
81 | } | ||
82 | |||
83 | private string GetEndPoint(XmlRpcRequest request, IPEndPoint client) | ||
84 | { | ||
85 | return client.Address.ToString(); | ||
86 | } | ||
87 | |||
88 | } | ||
89 | |||
90 | |||
91 | } | ||
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs index cfd34bb..57931d4 100644 --- a/OpenSim/Framework/Servers/MainServer.cs +++ b/OpenSim/Framework/Servers/MainServer.cs | |||
@@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers | |||
121 | + " level >= 2 then long warnings are logged when receiving bad input data.\n" | 121 | + " level >= 2 then long warnings are logged when receiving bad input data.\n" |
122 | + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" | 122 | + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" |
123 | + " level >= 4 then the time taken to fulfill the request is logged.\n" | 123 | + " level >= 4 then the time taken to fulfill the request is logged.\n" |
124 | + " level >= 5 then a sample from the beginning of the incoming data is logged.\n" | 124 | + " level >= 5 then a sample from the beginning of the data is logged.\n" |
125 | + " level >= 6 then the entire incoming data is logged.\n" | 125 | + " level >= 6 then the entire data is logged.\n" |
126 | + " no level is specified then the current level is returned.\n\n" | 126 | + " no level is specified then the current level is returned.\n\n" |
127 | + "If out or all and\n" | 127 | + "If out or all and\n" |
128 | + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" | 128 | + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" |
129 | + " level >= 4 then the time taken to fulfill the request is logged.\n", | 129 | + " level >= 4 then the time taken to fulfill the request is logged.\n" |
130 | + " level >= 5 then a sample from the beginning of the data is logged.\n" | ||
131 | + " level >= 6 then the entire data is logged.\n", | ||
130 | HandleDebugHttpCommand); | 132 | HandleDebugHttpCommand); |
131 | } | 133 | } |
132 | 134 | ||
@@ -283,7 +285,12 @@ namespace OpenSim.Framework.Servers | |||
283 | public static bool RemoveHttpServer(uint port) | 285 | public static bool RemoveHttpServer(uint port) |
284 | { | 286 | { |
285 | lock (m_Servers) | 287 | lock (m_Servers) |
288 | { | ||
289 | if (instance != null && instance.Port == port) | ||
290 | instance = null; | ||
291 | |||
286 | return m_Servers.Remove(port); | 292 | return m_Servers.Remove(port); |
293 | } | ||
287 | } | 294 | } |
288 | 295 | ||
289 | /// <summary> | 296 | /// <summary> |
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs index 1ff8aca..7108314 100644 --- a/OpenSim/Framework/Servers/ServerBase.cs +++ b/OpenSim/Framework/Servers/ServerBase.cs | |||
@@ -62,6 +62,8 @@ namespace OpenSim.Framework.Servers | |||
62 | 62 | ||
63 | protected string m_pidFile = String.Empty; | 63 | protected string m_pidFile = String.Empty; |
64 | 64 | ||
65 | protected ServerStatsCollector m_serverStatsCollector; | ||
66 | |||
65 | /// <summary> | 67 | /// <summary> |
66 | /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. | 68 | /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. |
67 | /// </summary> | 69 | /// </summary> |
@@ -76,6 +78,11 @@ namespace OpenSim.Framework.Servers | |||
76 | 78 | ||
77 | protected void CreatePIDFile(string path) | 79 | protected void CreatePIDFile(string path) |
78 | { | 80 | { |
81 | if (File.Exists(path)) | ||
82 | m_log.ErrorFormat( | ||
83 | "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.", | ||
84 | path); | ||
85 | |||
79 | try | 86 | try |
80 | { | 87 | { |
81 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); | 88 | string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); |
@@ -239,7 +246,7 @@ namespace OpenSim.Framework.Servers | |||
239 | "Show thread status", HandleShow); | 246 | "Show thread status", HandleShow); |
240 | 247 | ||
241 | m_console.Commands.AddCommand( | 248 | m_console.Commands.AddCommand( |
242 | "General", false, "threads abort", | 249 | "Debug", false, "threads abort", |
243 | "threads abort <thread-id>", | 250 | "threads abort <thread-id>", |
244 | "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); | 251 | "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); |
245 | 252 | ||
@@ -249,11 +256,180 @@ namespace OpenSim.Framework.Servers | |||
249 | "Show thread status. Synonym for \"show threads\"", | 256 | "Show thread status. Synonym for \"show threads\"", |
250 | (string module, string[] args) => Notice(GetThreadsReport())); | 257 | (string module, string[] args) => Notice(GetThreadsReport())); |
251 | 258 | ||
259 | m_console.Commands.AddCommand ( | ||
260 | "Debug", false, "debug comms set", | ||
261 | "debug comms set serialosdreq true|false", | ||
262 | "Set comms parameters. For debug purposes.", | ||
263 | HandleDebugCommsSet); | ||
264 | |||
265 | m_console.Commands.AddCommand ( | ||
266 | "Debug", false, "debug comms status", | ||
267 | "debug comms status", | ||
268 | "Show current debug comms parameters.", | ||
269 | HandleDebugCommsStatus); | ||
270 | |||
271 | m_console.Commands.AddCommand ( | ||
272 | "Debug", false, "debug threadpool set", | ||
273 | "debug threadpool set worker|iocp min|max <n>", | ||
274 | "Set threadpool parameters. For debug purposes.", | ||
275 | HandleDebugThreadpoolSet); | ||
276 | |||
277 | m_console.Commands.AddCommand ( | ||
278 | "Debug", false, "debug threadpool status", | ||
279 | "debug threadpool status", | ||
280 | "Show current debug threadpool parameters.", | ||
281 | HandleDebugThreadpoolStatus); | ||
282 | |||
252 | m_console.Commands.AddCommand( | 283 | m_console.Commands.AddCommand( |
253 | "General", false, "force gc", | 284 | "Debug", false, "force gc", |
254 | "force gc", | 285 | "force gc", |
255 | "Manually invoke runtime garbage collection. For debugging purposes", | 286 | "Manually invoke runtime garbage collection. For debugging purposes", |
256 | HandleForceGc); | 287 | HandleForceGc); |
288 | |||
289 | m_console.Commands.AddCommand( | ||
290 | "General", false, "quit", | ||
291 | "quit", | ||
292 | "Quit the application", (mod, args) => Shutdown()); | ||
293 | |||
294 | m_console.Commands.AddCommand( | ||
295 | "General", false, "shutdown", | ||
296 | "shutdown", | ||
297 | "Quit the application", (mod, args) => Shutdown()); | ||
298 | |||
299 | ChecksManager.RegisterConsoleCommands(m_console); | ||
300 | StatsManager.RegisterConsoleCommands(m_console); | ||
301 | } | ||
302 | |||
303 | public void RegisterCommonComponents(IConfigSource configSource) | ||
304 | { | ||
305 | IConfig networkConfig = configSource.Configs["Network"]; | ||
306 | |||
307 | if (networkConfig != null) | ||
308 | { | ||
309 | WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false); | ||
310 | } | ||
311 | |||
312 | m_serverStatsCollector = new ServerStatsCollector(); | ||
313 | m_serverStatsCollector.Initialise(configSource); | ||
314 | m_serverStatsCollector.Start(); | ||
315 | } | ||
316 | |||
317 | private void HandleDebugCommsStatus(string module, string[] args) | ||
318 | { | ||
319 | Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint); | ||
320 | } | ||
321 | |||
322 | private void HandleDebugCommsSet(string module, string[] args) | ||
323 | { | ||
324 | if (args.Length != 5) | ||
325 | { | ||
326 | Notice("Usage: debug comms set serialosdreq true|false"); | ||
327 | return; | ||
328 | } | ||
329 | |||
330 | if (args[3] != "serialosdreq") | ||
331 | { | ||
332 | Notice("Usage: debug comms set serialosdreq true|false"); | ||
333 | return; | ||
334 | } | ||
335 | |||
336 | bool setSerializeOsdRequests; | ||
337 | |||
338 | if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests)) | ||
339 | return; | ||
340 | |||
341 | WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests; | ||
342 | |||
343 | Notice("serialosdreq is now {0}", setSerializeOsdRequests); | ||
344 | } | ||
345 | |||
346 | private void HandleDebugThreadpoolStatus(string module, string[] args) | ||
347 | { | ||
348 | int workerThreads, iocpThreads; | ||
349 | |||
350 | ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); | ||
351 | Notice("Min worker threads: {0}", workerThreads); | ||
352 | Notice("Min IOCP threads: {0}", iocpThreads); | ||
353 | |||
354 | ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | ||
355 | Notice("Max worker threads: {0}", workerThreads); | ||
356 | Notice("Max IOCP threads: {0}", iocpThreads); | ||
357 | |||
358 | ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); | ||
359 | Notice("Available worker threads: {0}", workerThreads); | ||
360 | Notice("Available IOCP threads: {0}", iocpThreads); | ||
361 | } | ||
362 | |||
363 | private void HandleDebugThreadpoolSet(string module, string[] args) | ||
364 | { | ||
365 | if (args.Length != 6) | ||
366 | { | ||
367 | Notice("Usage: debug threadpool set worker|iocp min|max <n>"); | ||
368 | return; | ||
369 | } | ||
370 | |||
371 | int newThreads; | ||
372 | |||
373 | if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads)) | ||
374 | return; | ||
375 | |||
376 | string poolType = args[3]; | ||
377 | string bound = args[4]; | ||
378 | |||
379 | bool fail = false; | ||
380 | int workerThreads, iocpThreads; | ||
381 | |||
382 | if (poolType == "worker") | ||
383 | { | ||
384 | if (bound == "min") | ||
385 | { | ||
386 | ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); | ||
387 | |||
388 | if (!ThreadPool.SetMinThreads(newThreads, iocpThreads)) | ||
389 | fail = true; | ||
390 | } | ||
391 | else | ||
392 | { | ||
393 | ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | ||
394 | |||
395 | if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads)) | ||
396 | fail = true; | ||
397 | } | ||
398 | } | ||
399 | else | ||
400 | { | ||
401 | if (bound == "min") | ||
402 | { | ||
403 | ThreadPool.GetMinThreads(out workerThreads, out iocpThreads); | ||
404 | |||
405 | if (!ThreadPool.SetMinThreads(workerThreads, newThreads)) | ||
406 | fail = true; | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads); | ||
411 | |||
412 | if (!ThreadPool.SetMaxThreads(workerThreads, newThreads)) | ||
413 | fail = true; | ||
414 | } | ||
415 | } | ||
416 | |||
417 | if (fail) | ||
418 | { | ||
419 | Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads); | ||
420 | } | ||
421 | else | ||
422 | { | ||
423 | int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads; | ||
424 | |||
425 | ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads); | ||
426 | ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads); | ||
427 | |||
428 | Notice("Min worker threads now {0}", minWorkerThreads); | ||
429 | Notice("Min IOCP threads now {0}", minIocpThreads); | ||
430 | Notice("Max worker threads now {0}", maxWorkerThreads); | ||
431 | Notice("Max IOCP threads now {0}", maxIocpThreads); | ||
432 | } | ||
257 | } | 433 | } |
258 | 434 | ||
259 | private void HandleForceGc(string module, string[] args) | 435 | private void HandleForceGc(string module, string[] args) |
@@ -641,7 +817,68 @@ namespace OpenSim.Framework.Servers | |||
641 | sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); | 817 | sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); |
642 | 818 | ||
643 | sb.Append("Main threadpool (excluding script engine pools)\n"); | 819 | sb.Append("Main threadpool (excluding script engine pools)\n"); |
644 | sb.Append(Util.GetThreadPoolReport()); | 820 | sb.Append(GetThreadPoolReport()); |
821 | |||
822 | return sb.ToString(); | ||
823 | } | ||
824 | |||
825 | /// <summary> | ||
826 | /// Get a thread pool report. | ||
827 | /// </summary> | ||
828 | /// <returns></returns> | ||
829 | public static string GetThreadPoolReport() | ||
830 | { | ||
831 | string threadPoolUsed = null; | ||
832 | int maxThreads = 0; | ||
833 | int minThreads = 0; | ||
834 | int allocatedThreads = 0; | ||
835 | int inUseThreads = 0; | ||
836 | int waitingCallbacks = 0; | ||
837 | int completionPortThreads = 0; | ||
838 | |||
839 | StringBuilder sb = new StringBuilder(); | ||
840 | if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) | ||
841 | { | ||
842 | STPInfo stpi = Util.GetSmartThreadPoolInfo(); | ||
843 | |||
844 | // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. | ||
845 | if (stpi != null) | ||
846 | { | ||
847 | threadPoolUsed = "SmartThreadPool"; | ||
848 | maxThreads = stpi.MaxThreads; | ||
849 | minThreads = stpi.MinThreads; | ||
850 | inUseThreads = stpi.InUseThreads; | ||
851 | allocatedThreads = stpi.ActiveThreads; | ||
852 | waitingCallbacks = stpi.WaitingCallbacks; | ||
853 | } | ||
854 | } | ||
855 | else if ( | ||
856 | Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem | ||
857 | || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) | ||
858 | { | ||
859 | threadPoolUsed = "BuiltInThreadPool"; | ||
860 | ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); | ||
861 | ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); | ||
862 | int availableThreads; | ||
863 | ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); | ||
864 | inUseThreads = maxThreads - availableThreads; | ||
865 | allocatedThreads = -1; | ||
866 | waitingCallbacks = -1; | ||
867 | } | ||
868 | |||
869 | if (threadPoolUsed != null) | ||
870 | { | ||
871 | sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); | ||
872 | sb.AppendFormat("Max threads : {0}\n", maxThreads); | ||
873 | sb.AppendFormat("Min threads : {0}\n", minThreads); | ||
874 | sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); | ||
875 | sb.AppendFormat("In use threads : {0}\n", inUseThreads); | ||
876 | sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); | ||
877 | } | ||
878 | else | ||
879 | { | ||
880 | sb.AppendFormat("Thread pool not used\n"); | ||
881 | } | ||
645 | 882 | ||
646 | return sb.ToString(); | 883 | return sb.ToString(); |
647 | } | 884 | } |
@@ -693,5 +930,16 @@ namespace OpenSim.Framework.Servers | |||
693 | if (m_console != null) | 930 | if (m_console != null) |
694 | m_console.OutputFormat(format, components); | 931 | m_console.OutputFormat(format, components); |
695 | } | 932 | } |
933 | |||
934 | public virtual void Shutdown() | ||
935 | { | ||
936 | m_serverStatsCollector.Close(); | ||
937 | ShutdownSpecific(); | ||
938 | } | ||
939 | |||
940 | /// <summary> | ||
941 | /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing | ||
942 | /// </summary> | ||
943 | protected virtual void ShutdownSpecific() {} | ||
696 | } | 944 | } |
697 | } | 945 | } |
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs index 737c14d..33b1366 100644 --- a/OpenSim/Framework/Servers/VersionInfo.cs +++ b/OpenSim/Framework/Servers/VersionInfo.cs | |||
@@ -29,7 +29,7 @@ namespace OpenSim | |||
29 | { | 29 | { |
30 | public class VersionInfo | 30 | public class VersionInfo |
31 | { | 31 | { |
32 | private const string VERSION_NUMBER = "0.7.6CM"; | 32 | private const string VERSION_NUMBER = "0.8.0CM"; |
33 | private const Flavour VERSION_FLAVOUR = Flavour.Dev; | 33 | private const Flavour VERSION_FLAVOUR = Flavour.Dev; |
34 | 34 | ||
35 | public enum Flavour | 35 | public enum Flavour |
diff --git a/OpenSim/Framework/TaskInventoryItem.cs b/OpenSim/Framework/TaskInventoryItem.cs index 574ee56..2ec4bd1 100644 --- a/OpenSim/Framework/TaskInventoryItem.cs +++ b/OpenSim/Framework/TaskInventoryItem.cs | |||
@@ -124,7 +124,7 @@ namespace OpenSim.Framework | |||
124 | { | 124 | { |
125 | get | 125 | get |
126 | { | 126 | { |
127 | if (_creatorData != null && _creatorData != string.Empty) | 127 | if (!string.IsNullOrEmpty(_creatorData)) |
128 | return _creatorID.ToString() + ';' + _creatorData; | 128 | return _creatorID.ToString() + ';' + _creatorData; |
129 | else | 129 | else |
130 | return _creatorID.ToString(); | 130 | return _creatorID.ToString(); |
diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs index a56ecb4..3d5d1d2 100644 --- a/OpenSim/Framework/Tests/LocationTest.cs +++ b/OpenSim/Framework/Tests/LocationTest.cs | |||
@@ -51,21 +51,28 @@ namespace OpenSim.Framework.Tests | |||
51 | [Test] | 51 | [Test] |
52 | public void locationXYRegionHandle() | 52 | public void locationXYRegionHandle() |
53 | { | 53 | { |
54 | Location TestLocation1 = new Location(256000,256000); | 54 | Location TestLocation1 = new Location(255000,256000); |
55 | Location TestLocation2 = new Location(1099511628032000); | 55 | Location TestLocation2 = new Location(1095216660736000); |
56 | Assert.That(TestLocation1 == TestLocation2); | 56 | Assert.That(TestLocation1 == TestLocation2); |
57 | 57 | ||
58 | Assert.That(TestLocation2.X == 256000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); | 58 | Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor"); |
59 | Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); | ||
59 | 60 | ||
60 | Assert.That(TestLocation2.RegionHandle == 1099511628032000, | 61 | Assert.That(TestLocation2.RegionHandle == 1095216660736000, |
61 | "Location RegionHandle Property didn't match regionhandle provided in constructor"); | 62 | "Location RegionHandle Property didn't match regionhandle provided in constructor"); |
62 | 63 | ||
64 | ulong RegionHandle = TestLocation1.RegionHandle; | ||
65 | Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor"); | ||
63 | 66 | ||
64 | TestLocation1 = new Location(256001, 256001); | 67 | TestLocation2 = new Location(RegionHandle); |
65 | TestLocation2 = new Location(1099511628032000); | 68 | Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor"); |
69 | |||
70 | |||
71 | TestLocation1 = new Location(255001, 256001); | ||
72 | TestLocation2 = new Location(1095216660736000); | ||
66 | Assert.That(TestLocation1 != TestLocation2); | 73 | Assert.That(TestLocation1 != TestLocation2); |
67 | 74 | ||
68 | Assert.That(TestLocation1.Equals(256001, 256001), "Equals(x,y) failed to match the position in the constructor"); | 75 | Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor"); |
69 | 76 | ||
70 | Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); | 77 | Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); |
71 | 78 | ||
diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs index 0fbdaf3..08f2af5 100644 --- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs +++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs | |||
@@ -100,7 +100,7 @@ namespace OpenSim.Framework.Tests | |||
100 | cadu.AVHeight = Size1.Z; | 100 | cadu.AVHeight = Size1.Z; |
101 | 101 | ||
102 | AgentPosition position2 = new AgentPosition(); | 102 | AgentPosition position2 = new AgentPosition(); |
103 | position2.CopyFrom(cadu); | 103 | position2.CopyFrom(cadu, position1.SessionID); |
104 | 104 | ||
105 | Assert.IsTrue( | 105 | Assert.IsTrue( |
106 | position2.AgentID == position1.AgentID | 106 | position2.AgentID == position1.AgentID |
diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs index 11ca068..3b7f252 100644 --- a/OpenSim/Framework/Tests/UtilTest.cs +++ b/OpenSim/Framework/Tests/UtilTest.cs | |||
@@ -282,5 +282,87 @@ namespace OpenSim.Framework.Tests | |||
282 | String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); | 282 | String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); |
283 | } | 283 | } |
284 | } | 284 | } |
285 | |||
286 | [Test] | ||
287 | public void FakeParcelIDTests() | ||
288 | { | ||
289 | byte[] hexBytes8 = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }; | ||
290 | byte[] hexBytes16 = { | ||
291 | 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87, | ||
292 | 0x77, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f }; | ||
293 | UInt64 var64Bit = (UInt64)0xfedcba9876543210; | ||
294 | |||
295 | //Region handle is for location 255000,256000. | ||
296 | ulong regionHandle1 = 1095216660736000; | ||
297 | uint x1 = 100; | ||
298 | uint y1 = 200; | ||
299 | uint z1 = 22; | ||
300 | ulong regionHandle2; | ||
301 | uint x2, y2, z2; | ||
302 | UUID fakeParcelID1, fakeParcelID2, uuid; | ||
303 | |||
304 | ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8); | ||
305 | Assert.AreEqual(var64Bit, bigInt64, | ||
306 | "BytesToUint64Bit conversion of 8 bytes to UInt64 failed."); | ||
307 | |||
308 | //Test building and decoding using some typical input values | ||
309 | fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1); | ||
310 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2); | ||
311 | Assert.AreEqual(regionHandle1, regionHandle2, | ||
312 | "region handle decoded from FakeParcelID wth X/Y failed."); | ||
313 | Assert.AreEqual(x1, x2, | ||
314 | "X coordinate decoded from FakeParcelID wth X/Y failed."); | ||
315 | Assert.AreEqual(y1, y2, | ||
316 | "Y coordinate decoded from FakeParcelID wth X/Y failed."); | ||
317 | |||
318 | fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1, z1); | ||
319 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2); | ||
320 | Assert.AreEqual(regionHandle1, regionHandle2, | ||
321 | "region handle decoded from FakeParcelID with X/Y/Z failed."); | ||
322 | Assert.AreEqual(x1, x2, | ||
323 | "X coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
324 | Assert.AreEqual(y1, y2, | ||
325 | "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
326 | Assert.AreEqual(z1, z2, | ||
327 | "Z coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
328 | |||
329 | //Do some more extreme tests to check the encoding and decoding | ||
330 | x1 = 0x55aa; | ||
331 | y1 = 0x9966; | ||
332 | z1 = 0x5a96; | ||
333 | |||
334 | fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1); | ||
335 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2); | ||
336 | Assert.AreEqual(var64Bit, regionHandle2, | ||
337 | "region handle decoded from FakeParcelID with X/Y/Z failed."); | ||
338 | Assert.AreEqual(x1, x2, | ||
339 | "X coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
340 | Assert.AreEqual(y1, y2, | ||
341 | "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
342 | |||
343 | fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1, z1); | ||
344 | Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2); | ||
345 | Assert.AreEqual(var64Bit, regionHandle2, | ||
346 | "region handle decoded from FakeParcelID with X/Y/Z failed."); | ||
347 | Assert.AreEqual(x1, x2, | ||
348 | "X coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
349 | Assert.AreEqual(y1, y2, | ||
350 | "Y coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
351 | Assert.AreEqual(z1, z2, | ||
352 | "Z coordinate decoded from FakeParcelID with X/Y/Z failed."); | ||
353 | |||
354 | |||
355 | x1 = 64; | ||
356 | y1 = 192; | ||
357 | fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1); | ||
358 | Util.FakeParcelIDToGlobalPosition(fakeParcelID1, out x2, out y2); | ||
359 | Assert.AreEqual(255000+x1, x2, | ||
360 | "Global X coordinate decoded from regionHandle failed."); | ||
361 | Assert.AreEqual(256000+y1, y2, | ||
362 | "Global Y coordinate decoded from regionHandle failed."); | ||
363 | |||
364 | uuid = new UUID("00dd0700-00d1-0700-3800-000032000000"); | ||
365 | Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2); | ||
366 | } | ||
285 | } | 367 | } |
286 | } | 368 | } |
diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs new file mode 100644 index 0000000..6133591 --- /dev/null +++ b/OpenSim/Framework/UserProfiles.cs | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSimulator Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using OpenMetaverse; | ||
30 | |||
31 | namespace OpenSim.Framework | ||
32 | { | ||
33 | public class UserClassifiedAdd | ||
34 | { | ||
35 | public UUID ClassifiedId = UUID.Zero; | ||
36 | public UUID CreatorId = UUID.Zero; | ||
37 | public int CreationDate = 0; | ||
38 | public int ExpirationDate = 0; | ||
39 | public int Category = 0; | ||
40 | public string Name = string.Empty; | ||
41 | public string Description = string.Empty; | ||
42 | public UUID ParcelId = UUID.Zero; | ||
43 | public int ParentEstate = 0; | ||
44 | public UUID SnapshotId = UUID.Zero; | ||
45 | public string SimName = string.Empty; | ||
46 | public string GlobalPos = "<0,0,0>"; | ||
47 | public string ParcelName = string.Empty; | ||
48 | public byte Flags = 0; | ||
49 | public int Price = 0; | ||
50 | } | ||
51 | |||
52 | public class UserProfileProperties | ||
53 | { | ||
54 | public UUID UserId = UUID.Zero; | ||
55 | public UUID PartnerId = UUID.Zero; | ||
56 | public bool PublishProfile = false; | ||
57 | public bool PublishMature = false; | ||
58 | public string WebUrl = string.Empty; | ||
59 | public int WantToMask = 0; | ||
60 | public string WantToText = string.Empty; | ||
61 | public int SkillsMask = 0; | ||
62 | public string SkillsText = string.Empty; | ||
63 | public string Language = string.Empty; | ||
64 | public UUID ImageId = UUID.Zero; | ||
65 | public string AboutText = string.Empty; | ||
66 | public UUID FirstLifeImageId = UUID.Zero; | ||
67 | public string FirstLifeText = string.Empty; | ||
68 | } | ||
69 | |||
70 | public class UserProfilePick | ||
71 | { | ||
72 | public UUID PickId = UUID.Zero; | ||
73 | public UUID CreatorId = UUID.Zero; | ||
74 | public bool TopPick = false; | ||
75 | public string Name = string.Empty; | ||
76 | public string OriginalName = string.Empty; | ||
77 | public string Desc = string.Empty; | ||
78 | public UUID ParcelId = UUID.Zero; | ||
79 | public UUID SnapshotId = UUID.Zero; | ||
80 | public string User = string.Empty; | ||
81 | public string SimName = string.Empty; | ||
82 | public string GlobalPos = "<0,0,0>"; | ||
83 | public int SortOrder = 0; | ||
84 | public bool Enabled = false; | ||
85 | } | ||
86 | |||
87 | public class UserProfileNotes | ||
88 | { | ||
89 | public UUID UserId; | ||
90 | public UUID TargetId; | ||
91 | public string Notes; | ||
92 | } | ||
93 | |||
94 | public class UserAccountProperties | ||
95 | { | ||
96 | public string EmailAddress = string.Empty; | ||
97 | public string Firstname = string.Empty; | ||
98 | public string LastName = string.Empty; | ||
99 | public string Password = string.Empty; | ||
100 | public string UserId = string.Empty; | ||
101 | } | ||
102 | |||
103 | public class UserAccountAuth | ||
104 | { | ||
105 | public string UserId = UUID.Zero.ToString(); | ||
106 | public string Password = string.Empty; | ||
107 | } | ||
108 | |||
109 | public class UserAppData | ||
110 | { | ||
111 | public string TagId = string.Empty; | ||
112 | public string DataKey = string.Empty; | ||
113 | public string UserId = UUID.Zero.ToString(); | ||
114 | public string DataVal = string.Empty; | ||
115 | } | ||
116 | } | ||
117 | |||
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 557f38e..1775fef 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -89,9 +89,30 @@ namespace OpenSim.Framework | |||
89 | } | 89 | } |
90 | 90 | ||
91 | /// <summary> | 91 | /// <summary> |
92 | /// Class for delivering SmartThreadPool statistical information | ||
93 | /// </summary> | ||
94 | /// <remarks> | ||
95 | /// We do it this way so that we do not directly expose STP. | ||
96 | /// </remarks> | ||
97 | public class STPInfo | ||
98 | { | ||
99 | public string Name { get; set; } | ||
100 | public STPStartInfo STPStartInfo { get; set; } | ||
101 | public WIGStartInfo WIGStartInfo { get; set; } | ||
102 | public bool IsIdle { get; set; } | ||
103 | public bool IsShuttingDown { get; set; } | ||
104 | public int MaxThreads { get; set; } | ||
105 | public int MinThreads { get; set; } | ||
106 | public int InUseThreads { get; set; } | ||
107 | public int ActiveThreads { get; set; } | ||
108 | public int WaitingCallbacks { get; set; } | ||
109 | public int MaxConcurrentWorkItems { get; set; } | ||
110 | } | ||
111 | |||
112 | /// <summary> | ||
92 | /// Miscellaneous utility functions | 113 | /// Miscellaneous utility functions |
93 | /// </summary> | 114 | /// </summary> |
94 | public class Util | 115 | public static class Util |
95 | { | 116 | { |
96 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 117 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
97 | 118 | ||
@@ -109,7 +130,7 @@ namespace OpenSim.Framework | |||
109 | private static SmartThreadPool m_ThreadPool; | 130 | private static SmartThreadPool m_ThreadPool; |
110 | 131 | ||
111 | // 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. | 132 | // 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. |
112 | private static readonly DateTime unixEpoch = | 133 | public static readonly DateTime UnixEpoch = |
113 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); | 134 | DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); |
114 | 135 | ||
115 | private static readonly string rawUUIDPattern | 136 | private static readonly string rawUUIDPattern |
@@ -120,6 +141,11 @@ namespace OpenSim.Framework | |||
120 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; | 141 | public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; |
121 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; | 142 | public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; |
122 | 143 | ||
144 | public static bool IsPlatformMono | ||
145 | { | ||
146 | get { return Type.GetType("Mono.Runtime") != null; } | ||
147 | } | ||
148 | |||
123 | /// <summary> | 149 | /// <summary> |
124 | /// Gets the name of the directory where the current running executable | 150 | /// Gets the name of the directory where the current running executable |
125 | /// is located | 151 | /// is located |
@@ -307,6 +333,49 @@ namespace OpenSim.Framework | |||
307 | return Utils.UIntsToLong(X, Y); | 333 | return Utils.UIntsToLong(X, Y); |
308 | } | 334 | } |
309 | 335 | ||
336 | // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong. | ||
337 | // Several places rely on the ability to extract a region's location from its handle. | ||
338 | // Note the location is in 'world coordinates' (see below). | ||
339 | // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0. | ||
340 | public static ulong RegionWorldLocToHandle(uint X, uint Y) | ||
341 | { | ||
342 | return Utils.UIntsToLong(X, Y); | ||
343 | } | ||
344 | |||
345 | public static ulong RegionLocToHandle(uint X, uint Y) | ||
346 | { | ||
347 | return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y)); | ||
348 | } | ||
349 | |||
350 | public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) | ||
351 | { | ||
352 | X = (uint)(handle >> 32); | ||
353 | Y = (uint)(handle & (ulong)uint.MaxValue); | ||
354 | } | ||
355 | |||
356 | public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) | ||
357 | { | ||
358 | uint worldX, worldY; | ||
359 | RegionHandleToWorldLoc(handle, out worldX, out worldY); | ||
360 | X = WorldToRegionLoc(worldX); | ||
361 | Y = WorldToRegionLoc(worldY); | ||
362 | } | ||
363 | |||
364 | // A region location can be 'world coordinates' (meters from zero) or 'region coordinates' | ||
365 | // (number of regions from zero). This measurement of regions relies on the legacy 256 region size. | ||
366 | // These routines exist to make what is being converted explicit so the next person knows what was meant. | ||
367 | // Convert a region's 'world coordinate' to its 'region coordinate'. | ||
368 | public static uint WorldToRegionLoc(uint worldCoord) | ||
369 | { | ||
370 | return worldCoord / Constants.RegionSize; | ||
371 | } | ||
372 | |||
373 | // Convert a region's 'region coordinate' to its 'world coordinate'. | ||
374 | public static uint RegionToWorldLoc(uint regionCoord) | ||
375 | { | ||
376 | return regionCoord * Constants.RegionSize; | ||
377 | } | ||
378 | |||
310 | public static T Clamp<T>(T x, T min, T max) | 379 | public static T Clamp<T>(T x, T min, T max) |
311 | where T : IComparable<T> | 380 | where T : IComparable<T> |
312 | { | 381 | { |
@@ -495,20 +564,18 @@ namespace OpenSim.Framework | |||
495 | 564 | ||
496 | public static int ToUnixTime(DateTime stamp) | 565 | public static int ToUnixTime(DateTime stamp) |
497 | { | 566 | { |
498 | TimeSpan t = stamp.ToUniversalTime() - unixEpoch; | 567 | TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; |
499 | return (int) t.TotalSeconds; | 568 | return (int)t.TotalSeconds; |
500 | } | 569 | } |
501 | 570 | ||
502 | public static DateTime ToDateTime(ulong seconds) | 571 | public static DateTime ToDateTime(ulong seconds) |
503 | { | 572 | { |
504 | DateTime epoch = unixEpoch; | 573 | return UnixEpoch.AddSeconds(seconds); |
505 | return epoch.AddSeconds(seconds); | ||
506 | } | 574 | } |
507 | 575 | ||
508 | public static DateTime ToDateTime(int seconds) | 576 | public static DateTime ToDateTime(int seconds) |
509 | { | 577 | { |
510 | DateTime epoch = unixEpoch; | 578 | return UnixEpoch.AddSeconds(seconds); |
511 | return epoch.AddSeconds(seconds); | ||
512 | } | 579 | } |
513 | 580 | ||
514 | /// <summary> | 581 | /// <summary> |
@@ -976,7 +1043,7 @@ namespace OpenSim.Framework | |||
976 | else if (typeof(T) == typeof(Int32)) | 1043 | else if (typeof(T) == typeof(Int32)) |
977 | val = cnf.GetInt(varname, (int)val); | 1044 | val = cnf.GetInt(varname, (int)val); |
978 | else if (typeof(T) == typeof(float)) | 1045 | else if (typeof(T) == typeof(float)) |
979 | val = cnf.GetFloat(varname, (int)val); | 1046 | val = cnf.GetFloat(varname, (float)val); |
980 | else | 1047 | else |
981 | m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); | 1048 | m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); |
982 | } | 1049 | } |
@@ -1233,7 +1300,7 @@ namespace OpenSim.Framework | |||
1233 | byte[] bytes = | 1300 | byte[] bytes = |
1234 | { | 1301 | { |
1235 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1302 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1236 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1303 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1237 | (byte)x, (byte)(x >> 8), 0, 0, | 1304 | (byte)x, (byte)(x >> 8), 0, 0, |
1238 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1305 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1239 | return new UUID(bytes, 0); | 1306 | return new UUID(bytes, 0); |
@@ -1244,7 +1311,7 @@ namespace OpenSim.Framework | |||
1244 | byte[] bytes = | 1311 | byte[] bytes = |
1245 | { | 1312 | { |
1246 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), | 1313 | (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), |
1247 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), | 1314 | (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), |
1248 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), | 1315 | (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), |
1249 | (byte)y, (byte)(y >> 8), 0, 0 }; | 1316 | (byte)y, (byte)(y >> 8), 0, 0 }; |
1250 | return new UUID(bytes, 0); | 1317 | return new UUID(bytes, 0); |
@@ -1317,7 +1384,7 @@ namespace OpenSim.Framework | |||
1317 | ru = "OSX/Mono"; | 1384 | ru = "OSX/Mono"; |
1318 | else | 1385 | else |
1319 | { | 1386 | { |
1320 | if (Type.GetType("Mono.Runtime") != null) | 1387 | if (IsPlatformMono) |
1321 | ru = "Win/Mono"; | 1388 | ru = "Win/Mono"; |
1322 | else | 1389 | else |
1323 | ru = "Win/.NET"; | 1390 | ru = "Win/.NET"; |
@@ -1765,10 +1832,12 @@ namespace OpenSim.Framework | |||
1765 | FireAndForget(callback, null); | 1832 | FireAndForget(callback, null); |
1766 | } | 1833 | } |
1767 | 1834 | ||
1768 | public static void InitThreadPool(int maxThreads) | 1835 | public static void InitThreadPool(int minThreads, int maxThreads) |
1769 | { | 1836 | { |
1770 | if (maxThreads < 2) | 1837 | if (maxThreads < 2) |
1771 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); | 1838 | throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); |
1839 | if (minThreads > maxThreads || minThreads < 2) | ||
1840 | throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); | ||
1772 | if (m_ThreadPool != null) | 1841 | if (m_ThreadPool != null) |
1773 | throw new InvalidOperationException("SmartThreadPool is already initialized"); | 1842 | throw new InvalidOperationException("SmartThreadPool is already initialized"); |
1774 | 1843 | ||
@@ -1776,7 +1845,7 @@ namespace OpenSim.Framework | |||
1776 | startInfo.ThreadPoolName = "Util"; | 1845 | startInfo.ThreadPoolName = "Util"; |
1777 | startInfo.IdleTimeout = 2000; | 1846 | startInfo.IdleTimeout = 2000; |
1778 | startInfo.MaxWorkerThreads = maxThreads; | 1847 | startInfo.MaxWorkerThreads = maxThreads; |
1779 | startInfo.MinWorkerThreads = 2; | 1848 | startInfo.MinWorkerThreads = minThreads; |
1780 | 1849 | ||
1781 | m_ThreadPool = new SmartThreadPool(startInfo); | 1850 | m_ThreadPool = new SmartThreadPool(startInfo); |
1782 | } | 1851 | } |
@@ -1851,8 +1920,8 @@ namespace OpenSim.Framework | |||
1851 | break; | 1920 | break; |
1852 | case FireAndForgetMethod.SmartThreadPool: | 1921 | case FireAndForgetMethod.SmartThreadPool: |
1853 | if (m_ThreadPool == null) | 1922 | if (m_ThreadPool == null) |
1854 | InitThreadPool(15); | 1923 | InitThreadPool(2, 15); |
1855 | m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); | 1924 | m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); |
1856 | break; | 1925 | break; |
1857 | case FireAndForgetMethod.Thread: | 1926 | case FireAndForgetMethod.Thread: |
1858 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); | 1927 | Thread thread = new Thread(delegate(object o) { realCallback(o); }); |
@@ -1864,72 +1933,29 @@ namespace OpenSim.Framework | |||
1864 | } | 1933 | } |
1865 | 1934 | ||
1866 | /// <summary> | 1935 | /// <summary> |
1867 | /// Get a thread pool report. | 1936 | /// Get information about the current state of the smart thread pool. |
1868 | /// </summary> | 1937 | /// </summary> |
1869 | /// <returns></returns> | 1938 | /// <returns> |
1870 | public static string GetThreadPoolReport() | 1939 | /// null if this isn't the pool being used for non-scriptengine threads. |
1940 | /// </returns> | ||
1941 | public static STPInfo GetSmartThreadPoolInfo() | ||
1871 | { | 1942 | { |
1872 | string threadPoolUsed = null; | 1943 | if (m_ThreadPool == null) |
1873 | int maxThreads = 0; | 1944 | return null; |
1874 | int minThreads = 0; | ||
1875 | int allocatedThreads = 0; | ||
1876 | int inUseThreads = 0; | ||
1877 | int waitingCallbacks = 0; | ||
1878 | int completionPortThreads = 0; | ||
1879 | |||
1880 | StringBuilder sb = new StringBuilder(); | ||
1881 | if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) | ||
1882 | { | ||
1883 | // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. | ||
1884 | if (m_ThreadPool != null) | ||
1885 | { | ||
1886 | threadPoolUsed = "SmartThreadPool"; | ||
1887 | maxThreads = m_ThreadPool.MaxThreads; | ||
1888 | minThreads = m_ThreadPool.MinThreads; | ||
1889 | inUseThreads = m_ThreadPool.InUseThreads; | ||
1890 | allocatedThreads = m_ThreadPool.ActiveThreads; | ||
1891 | waitingCallbacks = m_ThreadPool.WaitingCallbacks; | ||
1892 | } | ||
1893 | } | ||
1894 | else if ( | ||
1895 | FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem | ||
1896 | || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) | ||
1897 | { | ||
1898 | threadPoolUsed = "BuiltInThreadPool"; | ||
1899 | ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); | ||
1900 | ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); | ||
1901 | int availableThreads; | ||
1902 | ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); | ||
1903 | inUseThreads = maxThreads - availableThreads; | ||
1904 | allocatedThreads = -1; | ||
1905 | waitingCallbacks = -1; | ||
1906 | } | ||
1907 | |||
1908 | if (threadPoolUsed != null) | ||
1909 | { | ||
1910 | sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); | ||
1911 | sb.AppendFormat("Max threads : {0}\n", maxThreads); | ||
1912 | sb.AppendFormat("Min threads : {0}\n", minThreads); | ||
1913 | sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); | ||
1914 | sb.AppendFormat("In use threads : {0}\n", inUseThreads); | ||
1915 | sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); | ||
1916 | } | ||
1917 | else | ||
1918 | { | ||
1919 | sb.AppendFormat("Thread pool not used\n"); | ||
1920 | } | ||
1921 | |||
1922 | return sb.ToString(); | ||
1923 | } | ||
1924 | 1945 | ||
1925 | private static object SmartThreadPoolCallback(object o) | 1946 | STPInfo stpi = new STPInfo(); |
1926 | { | 1947 | stpi.Name = m_ThreadPool.Name; |
1927 | object[] array = (object[])o; | 1948 | stpi.STPStartInfo = m_ThreadPool.STPStartInfo; |
1928 | WaitCallback callback = (WaitCallback)array[0]; | 1949 | stpi.IsIdle = m_ThreadPool.IsIdle; |
1929 | object obj = array[1]; | 1950 | stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; |
1951 | stpi.MaxThreads = m_ThreadPool.MaxThreads; | ||
1952 | stpi.MinThreads = m_ThreadPool.MinThreads; | ||
1953 | stpi.InUseThreads = m_ThreadPool.InUseThreads; | ||
1954 | stpi.ActiveThreads = m_ThreadPool.ActiveThreads; | ||
1955 | stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; | ||
1956 | stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; | ||
1930 | 1957 | ||
1931 | callback(obj); | 1958 | return stpi; |
1932 | return null; | ||
1933 | } | 1959 | } |
1934 | 1960 | ||
1935 | #endregion FireAndForget Threading Pattern | 1961 | #endregion FireAndForget Threading Pattern |
@@ -2058,8 +2084,10 @@ namespace OpenSim.Framework | |||
2058 | #region Xml Serialization Utilities | 2084 | #region Xml Serialization Utilities |
2059 | public static bool ReadBoolean(XmlTextReader reader) | 2085 | public static bool ReadBoolean(XmlTextReader reader) |
2060 | { | 2086 | { |
2087 | // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. | ||
2061 | reader.ReadStartElement(); | 2088 | reader.ReadStartElement(); |
2062 | bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); | 2089 | string val = reader.ReadContentAsString().ToLower(); |
2090 | bool result = val.Equals("true") || val.Equals("1"); | ||
2063 | reader.ReadEndElement(); | 2091 | reader.ReadEndElement(); |
2064 | 2092 | ||
2065 | return result; | 2093 | return result; |
@@ -2148,7 +2176,7 @@ namespace OpenSim.Framework | |||
2148 | /// <param name="secret">the secret part</param> | 2176 | /// <param name="secret">the secret part</param> |
2149 | public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) | 2177 | public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) |
2150 | { | 2178 | { |
2151 | uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; | 2179 | uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty; |
2152 | 2180 | ||
2153 | string[] parts = value.Split(';'); | 2181 | string[] parts = value.Split(';'); |
2154 | if (parts.Length >= 1) | 2182 | if (parts.Length >= 1) |
@@ -2282,7 +2310,7 @@ namespace OpenSim.Framework | |||
2282 | { | 2310 | { |
2283 | lock (m_syncRoot) | 2311 | lock (m_syncRoot) |
2284 | { | 2312 | { |
2285 | m_lowQueue.Enqueue(data); | 2313 | q.Enqueue(data); |
2286 | m_s.WaitOne(0); | 2314 | m_s.WaitOne(0); |
2287 | m_s.Release(); | 2315 | m_s.Release(); |
2288 | } | 2316 | } |
@@ -2322,7 +2350,7 @@ namespace OpenSim.Framework | |||
2322 | { | 2350 | { |
2323 | if (m_highQueue.Count > 0) | 2351 | if (m_highQueue.Count > 0) |
2324 | res = m_highQueue.Dequeue(); | 2352 | res = m_highQueue.Dequeue(); |
2325 | else | 2353 | else if (m_lowQueue.Count > 0) |
2326 | res = m_lowQueue.Dequeue(); | 2354 | res = m_lowQueue.Dequeue(); |
2327 | 2355 | ||
2328 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) | 2356 | if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) |
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index bf57fd4..33ef8e0 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs | |||
@@ -67,6 +67,11 @@ namespace OpenSim.Framework | |||
67 | public static int RequestNumber { get; internal set; } | 67 | public static int RequestNumber { get; internal set; } |
68 | 68 | ||
69 | /// <summary> | 69 | /// <summary> |
70 | /// Control where OSD requests should be serialized per endpoint. | ||
71 | /// </summary> | ||
72 | public static bool SerializeOSDRequestsPerEndpoint { get; set; } | ||
73 | |||
74 | /// <summary> | ||
70 | /// this is the header field used to communicate the local request id | 75 | /// this is the header field used to communicate the local request id |
71 | /// used for performance and debugging | 76 | /// used for performance and debugging |
72 | /// </summary> | 77 | /// </summary> |
@@ -145,10 +150,50 @@ namespace OpenSim.Framework | |||
145 | 150 | ||
146 | public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) | 151 | public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) |
147 | { | 152 | { |
148 | lock (EndPointLock(url)) | 153 | if (SerializeOSDRequestsPerEndpoint) |
154 | { | ||
155 | lock (EndPointLock(url)) | ||
156 | { | ||
157 | return ServiceOSDRequestWorker(url, data, method, timeout, compressed); | ||
158 | } | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | return ServiceOSDRequestWorker(url, data, method, timeout, compressed); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | public static void LogOutgoingDetail(Stream outputStream) | ||
167 | { | ||
168 | using (StreamReader reader = new StreamReader(Util.Copy(outputStream), Encoding.UTF8)) | ||
169 | { | ||
170 | string output; | ||
171 | |||
172 | if (DebugLevel == 5) | ||
173 | { | ||
174 | const int sampleLength = 80; | ||
175 | char[] sampleChars = new char[sampleLength]; | ||
176 | reader.Read(sampleChars, 0, sampleLength); | ||
177 | output = new string(sampleChars); | ||
178 | } | ||
179 | else | ||
180 | { | ||
181 | output = reader.ReadToEnd(); | ||
182 | } | ||
183 | |||
184 | LogOutgoingDetail(output); | ||
185 | } | ||
186 | } | ||
187 | |||
188 | public static void LogOutgoingDetail(string output) | ||
189 | { | ||
190 | if (DebugLevel == 5) | ||
149 | { | 191 | { |
150 | return ServiceOSDRequestWorker(url,data,method,timeout,compressed); | 192 | output = output.Substring(0, 80); |
193 | output = output + "..."; | ||
151 | } | 194 | } |
195 | |||
196 | m_log.DebugFormat("[WEB UTIL]: {0}", output.Replace("\n", @"\n")); | ||
152 | } | 197 | } |
153 | 198 | ||
154 | private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) | 199 | private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) |
@@ -178,7 +223,11 @@ namespace OpenSim.Framework | |||
178 | // If there is some input, write it into the request | 223 | // If there is some input, write it into the request |
179 | if (data != null) | 224 | if (data != null) |
180 | { | 225 | { |
181 | strBuffer = OSDParser.SerializeJsonString(data); | 226 | strBuffer = OSDParser.SerializeJsonString(data); |
227 | |||
228 | if (DebugLevel >= 5) | ||
229 | LogOutgoingDetail(strBuffer); | ||
230 | |||
182 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); | 231 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); |
183 | 232 | ||
184 | if (compressed) | 233 | if (compressed) |
@@ -358,6 +407,10 @@ namespace OpenSim.Framework | |||
358 | if (data != null) | 407 | if (data != null) |
359 | { | 408 | { |
360 | queryString = BuildQueryString(data); | 409 | queryString = BuildQueryString(data); |
410 | |||
411 | if (DebugLevel >= 5) | ||
412 | LogOutgoingDetail(queryString); | ||
413 | |||
361 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); | 414 | byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); |
362 | 415 | ||
363 | request.ContentLength = buffer.Length; | 416 | request.ContentLength = buffer.Length; |
@@ -668,7 +721,7 @@ namespace OpenSim.Framework | |||
668 | /// <returns></returns> | 721 | /// <returns></returns> |
669 | public static string[] GetPreferredImageTypes(string accept) | 722 | public static string[] GetPreferredImageTypes(string accept) |
670 | { | 723 | { |
671 | if (accept == null || accept == string.Empty) | 724 | if (string.IsNullOrEmpty(accept)) |
672 | return new string[0]; | 725 | return new string[0]; |
673 | 726 | ||
674 | string[] types = accept.Split(new char[] { ',' }); | 727 | string[] types = accept.Split(new char[] { ',' }); |
@@ -769,6 +822,9 @@ namespace OpenSim.Framework | |||
769 | int length = (int)buffer.Length; | 822 | int length = (int)buffer.Length; |
770 | request.ContentLength = length; | 823 | request.ContentLength = length; |
771 | 824 | ||
825 | if (WebUtil.DebugLevel >= 5) | ||
826 | WebUtil.LogOutgoingDetail(buffer); | ||
827 | |||
772 | request.BeginGetRequestStream(delegate(IAsyncResult res) | 828 | request.BeginGetRequestStream(delegate(IAsyncResult res) |
773 | { | 829 | { |
774 | Stream requestStream = request.EndGetRequestStream(res); | 830 | Stream requestStream = request.EndGetRequestStream(res); |
@@ -928,11 +984,12 @@ namespace OpenSim.Framework | |||
928 | /// <param name="verb"></param> | 984 | /// <param name="verb"></param> |
929 | /// <param name="requestUrl"></param> | 985 | /// <param name="requestUrl"></param> |
930 | /// <param name="obj"> </param> | 986 | /// <param name="obj"> </param> |
987 | /// <param name="timeoutsecs"> </param> | ||
931 | /// <returns></returns> | 988 | /// <returns></returns> |
932 | /// | 989 | /// |
933 | /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting | 990 | /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting |
934 | /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> | 991 | /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> |
935 | public static string MakeRequest(string verb, string requestUrl, string obj) | 992 | public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs) |
936 | { | 993 | { |
937 | int reqnum = WebUtil.RequestNumber++; | 994 | int reqnum = WebUtil.RequestNumber++; |
938 | 995 | ||
@@ -946,6 +1003,8 @@ namespace OpenSim.Framework | |||
946 | 1003 | ||
947 | WebRequest request = WebRequest.Create(requestUrl); | 1004 | WebRequest request = WebRequest.Create(requestUrl); |
948 | request.Method = verb; | 1005 | request.Method = verb; |
1006 | if (timeoutsecs > 0) | ||
1007 | request.Timeout = timeoutsecs * 1000; | ||
949 | string respstring = String.Empty; | 1008 | string respstring = String.Empty; |
950 | 1009 | ||
951 | int tickset = Util.EnvironmentTickCountSubtract(tickstart); | 1010 | int tickset = Util.EnvironmentTickCountSubtract(tickstart); |
@@ -966,6 +1025,9 @@ namespace OpenSim.Framework | |||
966 | length = (int)obj.Length; | 1025 | length = (int)obj.Length; |
967 | request.ContentLength = length; | 1026 | request.ContentLength = length; |
968 | 1027 | ||
1028 | if (WebUtil.DebugLevel >= 5) | ||
1029 | WebUtil.LogOutgoingDetail(buffer); | ||
1030 | |||
969 | Stream requestStream = null; | 1031 | Stream requestStream = null; |
970 | try | 1032 | try |
971 | { | 1033 | { |
@@ -1039,6 +1101,11 @@ namespace OpenSim.Framework | |||
1039 | 1101 | ||
1040 | return respstring; | 1102 | return respstring; |
1041 | } | 1103 | } |
1104 | |||
1105 | public static string MakeRequest(string verb, string requestUrl, string obj) | ||
1106 | { | ||
1107 | return MakeRequest(verb, requestUrl, obj, -1); | ||
1108 | } | ||
1042 | } | 1109 | } |
1043 | 1110 | ||
1044 | public class SynchronousRestObjectRequester | 1111 | public class SynchronousRestObjectRequester |
@@ -1111,6 +1178,9 @@ namespace OpenSim.Framework | |||
1111 | int length = (int)buffer.Length; | 1178 | int length = (int)buffer.Length; |
1112 | request.ContentLength = length; | 1179 | request.ContentLength = length; |
1113 | 1180 | ||
1181 | if (WebUtil.DebugLevel >= 5) | ||
1182 | WebUtil.LogOutgoingDetail(buffer); | ||
1183 | |||
1114 | Stream requestStream = null; | 1184 | Stream requestStream = null; |
1115 | try | 1185 | try |
1116 | { | 1186 | { |
@@ -1213,4 +1283,4 @@ namespace OpenSim.Framework | |||
1213 | return deserial; | 1283 | return deserial; |
1214 | } | 1284 | } |
1215 | } | 1285 | } |
1216 | } | 1286 | } \ No newline at end of file |