diff options
author | Melanie | 2012-11-17 02:58:14 +0000 |
---|---|---|
committer | Melanie | 2012-11-17 02:58:14 +0000 |
commit | 7ad082f7c39ba82adeae3c25ca0befcf983c879d (patch) | |
tree | 0e3c488c65ef22b53e4536dd07f46c1467b58f78 /OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |
parent | Merge branch 'master' into careminster (diff) | |
parent | Prevent a buffer overflow in asset receiving (diff) | |
download | opensim-SC_OLD-7ad082f7c39ba82adeae3c25ca0befcf983c879d.zip opensim-SC_OLD-7ad082f7c39ba82adeae3c25ca0befcf983c879d.tar.gz opensim-SC_OLD-7ad082f7c39ba82adeae3c25ca0befcf983c879d.tar.bz2 opensim-SC_OLD-7ad082f7c39ba82adeae3c25ca0befcf983c879d.tar.xz |
Merge branch 'avination' into careminster
Diffstat (limited to 'OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | 186 |
1 files changed, 172 insertions, 14 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs index 24a0190..d1ec4aa 100644 --- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs +++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs | |||
@@ -58,6 +58,13 @@ namespace OpenSim.Region.ClientStack.Linden | |||
58 | public Hashtable request; | 58 | public Hashtable request; |
59 | } | 59 | } |
60 | 60 | ||
61 | public class aPollResponse | ||
62 | { | ||
63 | public Hashtable response; | ||
64 | public int bytes; | ||
65 | } | ||
66 | |||
67 | |||
61 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 68 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
62 | 69 | ||
63 | private Scene m_scene; | 70 | private Scene m_scene; |
@@ -72,6 +79,8 @@ namespace OpenSim.Region.ClientStack.Linden | |||
72 | private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue = | 79 | private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue = |
73 | new OpenMetaverse.BlockingQueue<aPollRequest>(); | 80 | new OpenMetaverse.BlockingQueue<aPollRequest>(); |
74 | 81 | ||
82 | private Dictionary<UUID,PollServiceTextureEventArgs> m_pollservices = new Dictionary<UUID,PollServiceTextureEventArgs>(); | ||
83 | |||
75 | #region ISharedRegionModule Members | 84 | #region ISharedRegionModule Members |
76 | 85 | ||
77 | public void Initialise(IConfigSource source) | 86 | public void Initialise(IConfigSource source) |
@@ -88,6 +97,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
88 | { | 97 | { |
89 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; | 98 | m_scene.EventManager.OnRegisterCaps -= RegisterCaps; |
90 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; | 99 | m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps; |
100 | m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate; | ||
91 | m_scene = null; | 101 | m_scene = null; |
92 | } | 102 | } |
93 | 103 | ||
@@ -98,6 +108,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
98 | 108 | ||
99 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; | 109 | m_scene.EventManager.OnRegisterCaps += RegisterCaps; |
100 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; | 110 | m_scene.EventManager.OnDeregisterCaps += DeregisterCaps; |
111 | m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate; | ||
101 | 112 | ||
102 | if (m_workerThreads == null) | 113 | if (m_workerThreads == null) |
103 | { | 114 | { |
@@ -115,6 +126,56 @@ namespace OpenSim.Region.ClientStack.Linden | |||
115 | } | 126 | } |
116 | } | 127 | } |
117 | } | 128 | } |
129 | private int ExtractImageThrottle(byte[] pthrottles) | ||
130 | { | ||
131 | |||
132 | byte[] adjData; | ||
133 | int pos = 0; | ||
134 | |||
135 | if (!BitConverter.IsLittleEndian) | ||
136 | { | ||
137 | byte[] newData = new byte[7 * 4]; | ||
138 | Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4); | ||
139 | |||
140 | for (int i = 0; i < 7; i++) | ||
141 | Array.Reverse(newData, i * 4, 4); | ||
142 | |||
143 | adjData = newData; | ||
144 | } | ||
145 | else | ||
146 | { | ||
147 | adjData = pthrottles; | ||
148 | } | ||
149 | |||
150 | // 0.125f converts from bits to bytes | ||
151 | //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
152 | //pos += 4; | ||
153 | // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
154 | //pos += 4; | ||
155 | // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
156 | // pos += 4; | ||
157 | // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
158 | // pos += 4; | ||
159 | // int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
160 | // pos += 4; | ||
161 | pos = pos + 20; | ||
162 | int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4; | ||
163 | //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); | ||
164 | return texture; | ||
165 | } | ||
166 | |||
167 | // Now we know when the throttle is changed by the client in the case of a root agent or by a neighbor region in the case of a child agent. | ||
168 | public void ThrottleUpdate(ScenePresence p) | ||
169 | { | ||
170 | byte[] throttles = p.ControllingClient.GetThrottlesPacked(1); | ||
171 | UUID user = p.UUID; | ||
172 | int imagethrottle = ExtractImageThrottle(throttles); | ||
173 | PollServiceTextureEventArgs args; | ||
174 | if (m_pollservices.TryGetValue(user,out args)) | ||
175 | { | ||
176 | args.UpdateThrottle(imagethrottle); | ||
177 | } | ||
178 | } | ||
118 | 179 | ||
119 | public void PostInitialise() | 180 | public void PostInitialise() |
120 | { | 181 | { |
@@ -142,20 +203,25 @@ namespace OpenSim.Region.ClientStack.Linden | |||
142 | { | 203 | { |
143 | private List<Hashtable> requests = | 204 | private List<Hashtable> requests = |
144 | new List<Hashtable>(); | 205 | new List<Hashtable>(); |
145 | private Dictionary<UUID, Hashtable> responses = | 206 | private Dictionary<UUID, aPollResponse> responses = |
146 | new Dictionary<UUID, Hashtable>(); | 207 | new Dictionary<UUID, aPollResponse>(); |
147 | 208 | ||
148 | private Scene m_scene; | 209 | private Scene m_scene; |
149 | 210 | private CapsDataThrottler m_throttler = new CapsDataThrottler(100000, 1400000,10000); | |
150 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : | 211 | public PollServiceTextureEventArgs(UUID pId, Scene scene) : |
151 | base(null, null, null, null, pId, int.MaxValue) | 212 | base(null, null, null, null, pId, int.MaxValue) |
152 | { | 213 | { |
153 | m_scene = scene; | 214 | m_scene = scene; |
154 | 215 | // x is request id, y is userid | |
155 | HasEvents = (x, y) => | 216 | HasEvents = (x, y) => |
156 | { | 217 | { |
157 | lock (responses) | 218 | lock (responses) |
158 | return responses.ContainsKey(x); | 219 | { |
220 | bool ret = m_throttler.hasEvents(x, responses); | ||
221 | m_throttler.ProcessTime(); | ||
222 | return ret; | ||
223 | |||
224 | } | ||
159 | }; | 225 | }; |
160 | GetEvents = (x, y) => | 226 | GetEvents = (x, y) => |
161 | { | 227 | { |
@@ -163,7 +229,7 @@ namespace OpenSim.Region.ClientStack.Linden | |||
163 | { | 229 | { |
164 | try | 230 | try |
165 | { | 231 | { |
166 | return responses[x]; | 232 | return responses[x].response; |
167 | } | 233 | } |
168 | finally | 234 | finally |
169 | { | 235 | { |
@@ -171,14 +237,14 @@ namespace OpenSim.Region.ClientStack.Linden | |||
171 | } | 237 | } |
172 | } | 238 | } |
173 | }; | 239 | }; |
174 | 240 | // x is request id, y is request data hashtable | |
175 | Request = (x, y) => | 241 | Request = (x, y) => |
176 | { | 242 | { |
177 | aPollRequest reqinfo = new aPollRequest(); | 243 | aPollRequest reqinfo = new aPollRequest(); |
178 | reqinfo.thepoll = this; | 244 | reqinfo.thepoll = this; |
179 | reqinfo.reqID = x; | 245 | reqinfo.reqID = x; |
180 | reqinfo.request = y; | 246 | reqinfo.request = y; |
181 | 247 | ||
182 | m_queue.Enqueue(reqinfo); | 248 | m_queue.Enqueue(reqinfo); |
183 | }; | 249 | }; |
184 | 250 | ||
@@ -220,16 +286,29 @@ namespace OpenSim.Region.ClientStack.Linden | |||
220 | response["content_type"] = "text/plain"; | 286 | response["content_type"] = "text/plain"; |
221 | response["keepalive"] = false; | 287 | response["keepalive"] = false; |
222 | response["reusecontext"] = false; | 288 | response["reusecontext"] = false; |
223 | 289 | ||
224 | lock (responses) | 290 | lock (responses) |
225 | responses[requestID] = response; | 291 | responses[requestID] = new aPollResponse() {bytes = 0, response = response}; |
226 | 292 | ||
227 | return; | 293 | return; |
228 | } | 294 | } |
229 | 295 | ||
230 | response = m_getTextureHandler.Handle(requestinfo.request); | 296 | response = m_getTextureHandler.Handle(requestinfo.request); |
231 | lock (responses) | 297 | lock (responses) |
232 | responses[requestID] = response; | 298 | { |
299 | responses[requestID] = new aPollResponse() | ||
300 | { | ||
301 | bytes = (int) response["int_bytes"], | ||
302 | response = response | ||
303 | }; | ||
304 | |||
305 | } | ||
306 | m_throttler.ProcessTime(); | ||
307 | } | ||
308 | |||
309 | internal void UpdateThrottle(int pimagethrottle) | ||
310 | { | ||
311 | m_throttler.ThrottleBytes = pimagethrottle; | ||
233 | } | 312 | } |
234 | } | 313 | } |
235 | 314 | ||
@@ -254,19 +333,23 @@ namespace OpenSim.Region.ClientStack.Linden | |||
254 | protocol = "https"; | 333 | protocol = "https"; |
255 | } | 334 | } |
256 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); | 335 | caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl)); |
257 | 336 | m_pollservices.Add(agentID, args); | |
258 | m_capsDict[agentID] = capUrl; | 337 | m_capsDict[agentID] = capUrl; |
259 | } | 338 | } |
260 | 339 | ||
261 | private void DeregisterCaps(UUID agentID, Caps caps) | 340 | private void DeregisterCaps(UUID agentID, Caps caps) |
262 | { | 341 | { |
263 | string capUrl; | 342 | string capUrl; |
264 | 343 | PollServiceTextureEventArgs args; | |
265 | if (m_capsDict.TryGetValue(agentID, out capUrl)) | 344 | if (m_capsDict.TryGetValue(agentID, out capUrl)) |
266 | { | 345 | { |
267 | MainServer.Instance.RemoveHTTPHandler("", capUrl); | 346 | MainServer.Instance.RemoveHTTPHandler("", capUrl); |
268 | m_capsDict.Remove(agentID); | 347 | m_capsDict.Remove(agentID); |
269 | } | 348 | } |
349 | if (m_pollservices.TryGetValue(agentID, out args)) | ||
350 | { | ||
351 | m_pollservices.Remove(agentID); | ||
352 | } | ||
270 | } | 353 | } |
271 | 354 | ||
272 | private void DoTextureRequests() | 355 | private void DoTextureRequests() |
@@ -279,4 +362,79 @@ namespace OpenSim.Region.ClientStack.Linden | |||
279 | } | 362 | } |
280 | } | 363 | } |
281 | } | 364 | } |
365 | |||
366 | internal sealed class CapsDataThrottler | ||
367 | { | ||
368 | |||
369 | private volatile int currenttime = 0; | ||
370 | private volatile int lastTimeElapsed = 0; | ||
371 | private volatile int BytesSent = 0; | ||
372 | private int oversizedImages = 0; | ||
373 | public CapsDataThrottler(int pBytes, int max, int min) | ||
374 | { | ||
375 | ThrottleBytes = pBytes; | ||
376 | lastTimeElapsed = Util.EnvironmentTickCount(); | ||
377 | } | ||
378 | public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses) | ||
379 | { | ||
380 | PassTime(); | ||
381 | // Note, this is called IN LOCK | ||
382 | bool haskey = responses.ContainsKey(key); | ||
383 | if (!haskey) | ||
384 | { | ||
385 | return false; | ||
386 | } | ||
387 | GetTextureModule.aPollResponse response; | ||
388 | if (responses.TryGetValue(key,out response)) | ||
389 | { | ||
390 | |||
391 | // Normal | ||
392 | if (BytesSent + response.bytes <= ThrottleBytes) | ||
393 | { | ||
394 | BytesSent += response.bytes; | ||
395 | //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false }; | ||
396 | //m_actions.Add(timeBasedAction); | ||
397 | return true; | ||
398 | } | ||
399 | // Big textures | ||
400 | else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes%50000) + 1)) | ||
401 | { | ||
402 | Interlocked.Increment(ref oversizedImages); | ||
403 | BytesSent += response.bytes; | ||
404 | //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false }; | ||
405 | //m_actions.Add(timeBasedAction); | ||
406 | return true; | ||
407 | } | ||
408 | else | ||
409 | { | ||
410 | return false; | ||
411 | } | ||
412 | } | ||
413 | |||
414 | return haskey; | ||
415 | } | ||
416 | public void ProcessTime() | ||
417 | { | ||
418 | PassTime(); | ||
419 | } | ||
420 | |||
421 | |||
422 | private void PassTime() | ||
423 | { | ||
424 | currenttime = Util.EnvironmentTickCount(); | ||
425 | int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed); | ||
426 | //processTimeBasedActions(responses); | ||
427 | if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000) | ||
428 | { | ||
429 | lastTimeElapsed = Util.EnvironmentTickCount(); | ||
430 | BytesSent -= ThrottleBytes; | ||
431 | if (BytesSent < 0) BytesSent = 0; | ||
432 | if (BytesSent < ThrottleBytes) | ||
433 | { | ||
434 | oversizedImages = 0; | ||
435 | } | ||
436 | } | ||
437 | } | ||
438 | public int ThrottleBytes; | ||
439 | } | ||
282 | } | 440 | } |