aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorMelanie2012-11-20 00:48:13 +0100
committerMelanie2012-11-20 00:48:13 +0100
commit0bf66434bc87694c7a19b899afd9b068c67f3bec (patch)
tree5c373252d92103dbd7c8376ef8ebd5e7ff8cecc9 /OpenSim
parentPrevent a buffer overflow in asset receiving (diff)
parent* Plumbing and basic setting of the GetMesh Cap Throttler. (diff)
downloadopensim-SC-0bf66434bc87694c7a19b899afd9b068c67f3bec.zip
opensim-SC-0bf66434bc87694c7a19b899afd9b068c67f3bec.tar.gz
opensim-SC-0bf66434bc87694c7a19b899afd9b068c67f3bec.tar.bz2
opensim-SC-0bf66434bc87694c7a19b899afd9b068c67f3bec.tar.xz
Merge branch 'teravuswork' into avination
Diffstat (limited to '')
-rw-r--r--OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs159
-rw-r--r--OpenSim/Framework/IClientAPI.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs3
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs416
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs121
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs12
-rw-r--r--OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs4
-rw-r--r--OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs5
-rw-r--r--OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs6
-rw-r--r--OpenSim/Tests/Common/Mock/TestClient.cs6
10 files changed, 655 insertions, 79 deletions
diff --git a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
index 720640e..380705f 100644
--- a/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
+++ b/OpenSim/Capabilities/Handlers/GetMesh/GetMeshHandler.cs
@@ -45,16 +45,53 @@ namespace OpenSim.Capabilities.Handlers
45{ 45{
46 public class GetMeshHandler 46 public class GetMeshHandler
47 { 47 {
48// private static readonly ILog m_log = 48 private static readonly ILog m_log =
49// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 49 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
50 50
51 private IAssetService m_assetService; 51 private IAssetService m_assetService;
52 52
53 public const string DefaultFormat = "vnd.ll.mesh";
54
53 public GetMeshHandler(IAssetService assService) 55 public GetMeshHandler(IAssetService assService)
54 { 56 {
55 m_assetService = assService; 57 m_assetService = assService;
56 } 58 }
59 public Hashtable Handle(Hashtable request)
60 {
61 Hashtable ret = new Hashtable();
62 ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
63 ret["content_type"] = "text/plain";
64 ret["keepalive"] = false;
65 ret["reusecontext"] = false;
66 ret["int_bytes"] = 0;
67 string MeshStr = (string)request["mesh_id"];
68
69
70 //m_log.DebugFormat("[GETMESH]: called {0}", MeshStr);
71
72 if (m_assetService == null)
73 {
74 m_log.Error("[GETMESH]: Cannot fetch mesh " + MeshStr + " without an asset service");
75 }
76
77 UUID meshID;
78 if (!String.IsNullOrEmpty(MeshStr) && UUID.TryParse(MeshStr, out meshID))
79 {
80 // m_log.DebugFormat("[GETMESH]: Received request for mesh id {0}", meshID);
57 81
82
83 ret = ProcessGetMesh(request, UUID.Zero, null);
84
85
86 }
87 else
88 {
89 m_log.Warn("[GETMESH]: Failed to parse a mesh_id from GetMesh request: " + (string)request["uri"]);
90 }
91
92
93 return ret;
94 }
58 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap) 95 public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
59 { 96 {
60 Hashtable responsedata = new Hashtable(); 97 Hashtable responsedata = new Hashtable();
@@ -62,6 +99,7 @@ namespace OpenSim.Capabilities.Handlers
62 responsedata["content_type"] = "text/plain"; 99 responsedata["content_type"] = "text/plain";
63 responsedata["keepalive"] = false; 100 responsedata["keepalive"] = false;
64 responsedata["str_response_string"] = "Request wasn't what was expected"; 101 responsedata["str_response_string"] = "Request wasn't what was expected";
102 responsedata["reusecontext"] = false;
65 103
66 string meshStr = string.Empty; 104 string meshStr = string.Empty;
67 105
@@ -77,6 +115,7 @@ namespace OpenSim.Capabilities.Handlers
77 responsedata["content_type"] = "text/plain"; 115 responsedata["content_type"] = "text/plain";
78 responsedata["keepalive"] = false; 116 responsedata["keepalive"] = false;
79 responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh."; 117 responsedata["str_response_string"] = "The asset service is unavailable. So is your mesh.";
118 responsedata["reusecontext"] = false;
80 return responsedata; 119 return responsedata;
81 } 120 }
82 121
@@ -86,9 +125,100 @@ namespace OpenSim.Capabilities.Handlers
86 { 125 {
87 if (mesh.Type == (SByte)AssetType.Mesh) 126 if (mesh.Type == (SByte)AssetType.Mesh)
88 { 127 {
89 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data); 128
90 responsedata["content_type"] = "application/vnd.ll.mesh"; 129 Hashtable headers = new Hashtable();
91 responsedata["int_response_code"] = 200; 130 responsedata["headers"] = headers;
131
132 string range = String.Empty;
133
134 if (((Hashtable)request["headers"])["range"] != null)
135 range = (string)((Hashtable)request["headers"])["range"];
136
137 else if (((Hashtable)request["headers"])["Range"] != null)
138 range = (string)((Hashtable)request["headers"])["Range"];
139
140 if (!String.IsNullOrEmpty(range)) // Mesh Asset LOD // Physics
141 {
142 // Range request
143 int start, end;
144 if (TryParseRange(range, out start, out end))
145 {
146 // Before clamping start make sure we can satisfy it in order to avoid
147 // sending back the last byte instead of an error status
148 if (start >= mesh.Data.Length)
149 {
150 responsedata["int_response_code"] = 404; //501; //410; //404;
151 responsedata["content_type"] = "text/plain";
152 responsedata["keepalive"] = false;
153 responsedata["str_response_string"] = "This range doesnt exist.";
154 responsedata["reusecontext"] = false;
155 responsedata["int_lod"] = 3;
156 return responsedata;
157 }
158 else
159 {
160 end = Utils.Clamp(end, 0, mesh.Data.Length - 1);
161 start = Utils.Clamp(start, 0, end);
162 int len = end - start + 1;
163
164 //m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
165
166 if (start > 20000)
167 {
168 responsedata["int_lod"] = 3;
169 }
170 else if (start < 4097)
171 {
172 responsedata["int_lod"] = 1;
173 }
174 else
175 {
176 responsedata["int_lod"] = 2;
177 }
178
179
180 if (start == 0 && len == mesh.Data.Length) // well redudante maybe
181 {
182 responsedata["int_response_code"] = (int) System.Net.HttpStatusCode.OK;
183 responsedata["bin_response_data"] = mesh.Data;
184 responsedata["int_bytes"] = mesh.Data.Length;
185 responsedata["reusecontext"] = false;
186 responsedata["int_lod"] = 3;
187
188 }
189 else
190 {
191 responsedata["int_response_code"] =
192 (int) System.Net.HttpStatusCode.PartialContent;
193 headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end,
194 mesh.Data.Length);
195
196 byte[] d = new byte[len];
197 Array.Copy(mesh.Data, start, d, 0, len);
198 responsedata["bin_response_data"] = d;
199 responsedata["int_bytes"] = len;
200 responsedata["reusecontext"] = false;
201 }
202 }
203 }
204 else
205 {
206 m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]);
207 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
208 responsedata["content_type"] = "application/vnd.ll.mesh";
209 responsedata["int_response_code"] = 200;
210 responsedata["reusecontext"] = false;
211 responsedata["int_lod"] = 3;
212 }
213 }
214 else
215 {
216 responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
217 responsedata["content_type"] = "application/vnd.ll.mesh";
218 responsedata["int_response_code"] = 200;
219 responsedata["reusecontext"] = false;
220 responsedata["int_lod"] = 3;
221 }
92 } 222 }
93 // Optionally add additional mesh types here 223 // Optionally add additional mesh types here
94 else 224 else
@@ -97,6 +227,8 @@ namespace OpenSim.Capabilities.Handlers
97 responsedata["content_type"] = "text/plain"; 227 responsedata["content_type"] = "text/plain";
98 responsedata["keepalive"] = false; 228 responsedata["keepalive"] = false;
99 responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh."; 229 responsedata["str_response_string"] = "Unfortunately, this asset isn't a mesh.";
230 responsedata["reusecontext"] = false;
231 responsedata["int_lod"] = 1;
100 return responsedata; 232 return responsedata;
101 } 233 }
102 } 234 }
@@ -106,11 +238,28 @@ namespace OpenSim.Capabilities.Handlers
106 responsedata["content_type"] = "text/plain"; 238 responsedata["content_type"] = "text/plain";
107 responsedata["keepalive"] = false; 239 responsedata["keepalive"] = false;
108 responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!"; 240 responsedata["str_response_string"] = "Your Mesh wasn't found. Sorry!";
241 responsedata["reusecontext"] = false;
242 responsedata["int_lod"] = 0;
109 return responsedata; 243 return responsedata;
110 } 244 }
111 } 245 }
112 246
113 return responsedata; 247 return responsedata;
114 } 248 }
249 private bool TryParseRange(string header, out int start, out int end)
250 {
251 if (header.StartsWith("bytes="))
252 {
253 string[] rangeValues = header.Substring(6).Split('-');
254 if (rangeValues.Length == 2)
255 {
256 if (Int32.TryParse(rangeValues[0], out start) && Int32.TryParse(rangeValues[1], out end))
257 return true;
258 }
259 }
260
261 start = end = 0;
262 return false;
263 }
115 } 264 }
116} \ No newline at end of file 265} \ No newline at end of file
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index e31c7f6..6559638 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -1135,6 +1135,8 @@ namespace OpenSim.Framework
1135 1135
1136 void SetChildAgentThrottle(byte[] throttle); 1136 void SetChildAgentThrottle(byte[] throttle);
1137 1137
1138 void SetAgentThrottleSilent(int throttle, int setting);
1139
1138 void SendAvatarDataImmediate(ISceneEntity avatar); 1140 void SendAvatarDataImmediate(ISceneEntity avatar);
1139 1141
1140 /// <summary> 1142 /// <summary>
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index d0a37d0..c19ac32 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -53,7 +53,8 @@ namespace OpenSim.Framework.Servers.HttpServer
53 Normal = 0, 53 Normal = 0,
54 LslHttp = 1, 54 LslHttp = 1,
55 Inventory = 2, 55 Inventory = 2,
56 Texture = 3 56 Texture = 3,
57 Mesh = 4
57 } 58 }
58 59
59 public PollServiceEventArgs( 60 public PollServiceEventArgs(
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
index 0d7b1fc..96b48ad 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetMeshModule.cs
@@ -27,11 +27,14 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Collections.Specialized; 31using System.Collections.Specialized;
31using System.Reflection; 32using System.Reflection;
32using System.IO; 33using System.IO;
34using System.Threading;
33using System.Web; 35using System.Web;
34using Mono.Addins; 36using Mono.Addins;
37using OpenSim.Framework.Monitoring;
35using log4net; 38using log4net;
36using Nini.Config; 39using Nini.Config;
37using OpenMetaverse; 40using OpenMetaverse;
@@ -57,8 +60,44 @@ namespace OpenSim.Region.ClientStack.Linden
57 private IAssetService m_AssetService; 60 private IAssetService m_AssetService;
58 private bool m_Enabled = true; 61 private bool m_Enabled = true;
59 private string m_URL; 62 private string m_URL;
63
64 struct aPollRequest
65 {
66 public PollServiceMeshEventArgs thepoll;
67 public UUID reqID;
68 public Hashtable request;
69 }
70
71 public class aPollResponse
72 {
73 public Hashtable response;
74 public int bytes;
75 public int lod;
76 }
77
78
79 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
80
81 private static GetMeshHandler m_getMeshHandler;
82
83 private IAssetService m_assetService = null;
84
85 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
86 private static Thread[] m_workerThreads = null;
87
88 private static OpenMetaverse.BlockingQueue<aPollRequest> m_queue =
89 new OpenMetaverse.BlockingQueue<aPollRequest>();
90
91 private Dictionary<UUID, PollServiceMeshEventArgs> m_pollservices = new Dictionary<UUID, PollServiceMeshEventArgs>();
92
93 #region ISharedRegionModule Members
94
95 ~GetMeshModule()
96 {
97 foreach (Thread t in m_workerThreads)
98 Watchdog.AbortThread(t.ManagedThreadId);
60 99
61 #region IRegionModuleBase Members 100 }
62 101
63 public Type ReplaceableInterface 102 public Type ReplaceableInterface
64 { 103 {
@@ -75,6 +114,7 @@ namespace OpenSim.Region.ClientStack.Linden
75 // Cap doesn't exist 114 // Cap doesn't exist
76 if (m_URL != string.Empty) 115 if (m_URL != string.Empty)
77 m_Enabled = true; 116 m_Enabled = true;
117
78 } 118 }
79 119
80 public void AddRegion(Scene pScene) 120 public void AddRegion(Scene pScene)
@@ -83,6 +123,8 @@ namespace OpenSim.Region.ClientStack.Linden
83 return; 123 return;
84 124
85 m_scene = pScene; 125 m_scene = pScene;
126
127 m_assetService = pScene.AssetService;
86 } 128 }
87 129
88 public void RemoveRegion(Scene scene) 130 public void RemoveRegion(Scene scene)
@@ -91,6 +133,9 @@ namespace OpenSim.Region.ClientStack.Linden
91 return; 133 return;
92 134
93 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 135 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
136 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
137 m_scene.EventManager.OnThrottleUpdate -= ThrottleUpdate;
138
94 m_scene = null; 139 m_scene = null;
95 } 140 }
96 141
@@ -101,6 +146,27 @@ namespace OpenSim.Region.ClientStack.Linden
101 146
102 m_AssetService = m_scene.RequestModuleInterface<IAssetService>(); 147 m_AssetService = m_scene.RequestModuleInterface<IAssetService>();
103 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 148 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
149 // We'll reuse the same handler for all requests.
150 m_getMeshHandler = new GetMeshHandler(m_assetService);
151 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
152 m_scene.EventManager.OnThrottleUpdate += ThrottleUpdate;
153
154 if (m_workerThreads == null)
155 {
156 m_workerThreads = new Thread[2];
157
158 for (uint i = 0; i < 2; i++)
159 {
160 m_workerThreads[i] = Watchdog.StartThread(DoMeshRequests,
161 String.Format("MeshWorkerThread{0}", i),
162 ThreadPriority.Normal,
163 false,
164 false,
165 null,
166 int.MaxValue);
167 }
168 }
169
104 } 170 }
105 171
106 172
@@ -110,25 +176,212 @@ namespace OpenSim.Region.ClientStack.Linden
110 176
111 #endregion 177 #endregion
112 178
179 private void DoMeshRequests()
180 {
181 while (true)
182 {
183 aPollRequest poolreq = m_queue.Dequeue();
184
185 poolreq.thepoll.Process(poolreq);
186 }
187 }
188
189 // 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.
190 public void ThrottleUpdate(ScenePresence p)
191 {
192 byte[] throttles = p.ControllingClient.GetThrottlesPacked(1);
193 UUID user = p.UUID;
194 int imagethrottle = ExtractTaskThrottle(throttles);
195 PollServiceMeshEventArgs args;
196 if (m_pollservices.TryGetValue(user, out args))
197 {
198 args.UpdateThrottle(imagethrottle, p);
199 }
200 }
201
202 private int ExtractTaskThrottle(byte[] pthrottles)
203 {
204
205 byte[] adjData;
206 int pos = 0;
207
208 if (!BitConverter.IsLittleEndian)
209 {
210 byte[] newData = new byte[7 * 4];
211 Buffer.BlockCopy(pthrottles, 0, newData, 0, 7 * 4);
212
213 for (int i = 0; i < 7; i++)
214 Array.Reverse(newData, i * 4, 4);
215
216 adjData = newData;
217 }
218 else
219 {
220 adjData = pthrottles;
221 }
222
223 // 0.125f converts from bits to bytes
224 //int resend = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
225 //pos += 4;
226 // int land = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
227 //pos += 4;
228 // int wind = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
229 // pos += 4;
230 // int cloud = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
231 // pos += 4;
232 pos += 16;
233 int task = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
234 // pos += 4;
235 //int texture = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f); //pos += 4;
236 //int asset = (int)(BitConverter.ToSingle(adjData, pos) * 0.125f);
237 return task;
238 }
239
240 private class PollServiceMeshEventArgs : PollServiceEventArgs
241 {
242 private List<Hashtable> requests =
243 new List<Hashtable>();
244 private Dictionary<UUID, aPollResponse> responses =
245 new Dictionary<UUID, aPollResponse>();
246
247 private Scene m_scene;
248 private MeshCapsDataThrottler m_throttler;
249 public PollServiceMeshEventArgs(UUID pId, Scene scene) :
250 base(null, null, null, null, pId, int.MaxValue)
251 {
252 m_scene = scene;
253 m_throttler = new MeshCapsDataThrottler(100000, 1400000, 10000, scene);
254 // x is request id, y is userid
255 HasEvents = (x, y) =>
256 {
257 lock (responses)
258 {
259 bool ret = m_throttler.hasEvents(x, responses);
260 m_throttler.ProcessTime();
261 return ret;
262
263 }
264 };
265 GetEvents = (x, y) =>
266 {
267 lock (responses)
268 {
269 try
270 {
271 return responses[x].response;
272 }
273 finally
274 {
275 m_throttler.ProcessTime();
276 responses.Remove(x);
277 }
278 }
279 };
280 // x is request id, y is request data hashtable
281 Request = (x, y) =>
282 {
283 aPollRequest reqinfo = new aPollRequest();
284 reqinfo.thepoll = this;
285 reqinfo.reqID = x;
286 reqinfo.request = y;
287
288 m_queue.Enqueue(reqinfo);
289 };
290
291 // this should never happen except possible on shutdown
292 NoEvents = (x, y) =>
293 {
294 /*
295 lock (requests)
296 {
297 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
298 requests.Remove(request);
299 }
300 */
301 Hashtable response = new Hashtable();
302
303 response["int_response_code"] = 500;
304 response["str_response_string"] = "Script timeout";
305 response["content_type"] = "text/plain";
306 response["keepalive"] = false;
307 response["reusecontext"] = false;
308
309 return response;
310 };
311 }
312
313 public void Process(aPollRequest requestinfo)
314 {
315 Hashtable response;
316
317 UUID requestID = requestinfo.reqID;
318
319 // If the avatar is gone, don't bother to get the texture
320 if (m_scene.GetScenePresence(Id) == null)
321 {
322 response = new Hashtable();
323
324 response["int_response_code"] = 500;
325 response["str_response_string"] = "Script timeout";
326 response["content_type"] = "text/plain";
327 response["keepalive"] = false;
328 response["reusecontext"] = false;
329
330 lock (responses)
331 responses[requestID] = new aPollResponse() { bytes = 0, response = response, lod = 0 };
332
333 return;
334 }
335
336 response = m_getMeshHandler.Handle(requestinfo.request);
337 lock (responses)
338 {
339 responses[requestID] = new aPollResponse()
340 {
341 bytes = (int)response["int_bytes"],
342 lod = (int)response["int_lod"],
343 response = response
344 };
345
346 }
347 m_throttler.ProcessTime();
348 }
349
350 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
351 {
352 m_throttler.UpdateThrottle(pimagethrottle, p);
353 }
354 }
113 355
114 public void RegisterCaps(UUID agentID, Caps caps) 356 public void RegisterCaps(UUID agentID, Caps caps)
115 { 357 {
116// UUID capID = UUID.Random(); 358// UUID capID = UUID.Random();
117
118 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture));
119 if (m_URL == "localhost") 359 if (m_URL == "localhost")
120 { 360 {
121// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 361 string capUrl = "/CAPS/" + UUID.Random() + "/";
122 GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
123 IRequestHandler reqHandler
124 = new RestHTTPHandler(
125 "GET",
126 "/CAPS/" + UUID.Random(),
127 httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null),
128 "GetMesh",
129 agentID.ToString());
130 362
131 caps.RegisterHandler("GetMesh", reqHandler); 363 // Register this as a poll service
364 PollServiceMeshEventArgs args = new PollServiceMeshEventArgs(agentID, m_scene);
365
366 args.Type = PollServiceEventArgs.EventType.Mesh;
367 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
368
369 string hostName = m_scene.RegionInfo.ExternalHostName;
370 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
371 string protocol = "http";
372
373 if (MainServer.Instance.UseSSL)
374 {
375 hostName = MainServer.Instance.SSLCommonName;
376 port = MainServer.Instance.SSLPort;
377 protocol = "https";
378 }
379 caps.RegisterHandler("GetMesh", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
380 m_pollservices.Add(agentID, args);
381 m_capsDict[agentID] = capUrl;
382
383
384
132 } 385 }
133 else 386 else
134 { 387 {
@@ -136,6 +389,143 @@ namespace OpenSim.Region.ClientStack.Linden
136 caps.RegisterHandler("GetMesh", m_URL); 389 caps.RegisterHandler("GetMesh", m_URL);
137 } 390 }
138 } 391 }
392 private void DeregisterCaps(UUID agentID, Caps caps)
393 {
394 string capUrl;
395 PollServiceMeshEventArgs args;
396 if (m_capsDict.TryGetValue(agentID, out capUrl))
397 {
398 MainServer.Instance.RemoveHTTPHandler("", capUrl);
399 m_capsDict.Remove(agentID);
400 }
401 if (m_pollservices.TryGetValue(agentID, out args))
402 {
403 m_pollservices.Remove(agentID);
404 }
405 }
406
407 internal sealed class MeshCapsDataThrottler
408 {
409
410 private volatile int currenttime = 0;
411 private volatile int lastTimeElapsed = 0;
412 private volatile int BytesSent = 0;
413 private int Lod3 = 0;
414 private int Lod2 = 0;
415 private int Lod1 = 0;
416 private int UserSetThrottle = 0;
417 private int UDPSetThrottle = 0;
418 private int CapSetThrottle = 0;
419 private float CapThrottleDistributon = 0.30f;
420 private readonly Scene m_scene;
421 private ThrottleOutPacketType Throttle;
422
423 public MeshCapsDataThrottler(int pBytes, int max, int min, Scene pScene)
424 {
425 ThrottleBytes = pBytes;
426 lastTimeElapsed = Util.EnvironmentTickCount();
427 Throttle = ThrottleOutPacketType.Task;
428 m_scene = pScene;
429 }
430
431
432 public bool hasEvents(UUID key, Dictionary<UUID, aPollResponse> responses)
433 {
434 PassTime();
435 // Note, this is called IN LOCK
436 bool haskey = responses.ContainsKey(key);
437 if (!haskey)
438 {
439 return false;
440 }
441 aPollResponse response;
442 if (responses.TryGetValue(key, out response))
443 {
444
445 // Normal
446 if (BytesSent + response.bytes <= ThrottleBytes)
447 {
448 BytesSent += response.bytes;
449
450 return true;
451 }
452 // Lod3 Over
453 else if (response.bytes > ThrottleBytes && Lod3 <= (((ThrottleBytes * .30f) % 50000) + 1))
454 {
455 Interlocked.Increment(ref Lod3);
456 BytesSent += response.bytes;
457
458 return true;
459 }
460 // Lod2 Over
461 else if (response.bytes > ThrottleBytes && Lod2 <= (((ThrottleBytes * .30f) % 10000) + 1))
462 {
463 Interlocked.Increment(ref Lod2);
464 BytesSent += response.bytes;
465
466 return true;
467 }
468 else
469 {
470 return false;
471 }
472 }
473
474 return haskey;
475 }
476 public void SubtractBytes(int bytes,int lod)
477 {
478 BytesSent -= bytes;
479 }
480
481 public void ProcessTime()
482 {
483 PassTime();
484 }
485
486
487 private void PassTime()
488 {
489 currenttime = Util.EnvironmentTickCount();
490 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
491 //processTimeBasedActions(responses);
492 if (currenttime - timeElapsed >= 1000)
493 {
494 lastTimeElapsed = Util.EnvironmentTickCount();
495 BytesSent -= ThrottleBytes;
496 if (BytesSent < 0) BytesSent = 0;
497 if (BytesSent < ThrottleBytes)
498 {
499 Lod3 = 0;
500 Lod2 = 0;
501 Lod1 = 0;
502 }
503 }
504 }
505 private void AlterThrottle(int setting, ScenePresence p)
506 {
507 p.ControllingClient.SetAgentThrottleSilent((int)Throttle,setting);
508 }
509
510 public int ThrottleBytes
511 {
512 get { return CapSetThrottle; }
513 set { CapSetThrottle = value; }
514 }
515
516 internal void UpdateThrottle(int pimagethrottle, ScenePresence p)
517 {
518 // Client set throttle !
519 UserSetThrottle = pimagethrottle;
520 CapSetThrottle = (int)(pimagethrottle*CapThrottleDistributon);
521 UDPSetThrottle = (int) (pimagethrottle*(100 - CapThrottleDistributon));
522 if (CapSetThrottle < 4068)
523 CapSetThrottle = 4068; // at least two discovery mesh
524 p.ControllingClient.SetAgentThrottleSilent((int) Throttle, UDPSetThrottle);
525 ProcessTime();
526
527 }
528 }
139 529
140 } 530 }
141} 531}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 8cba6c8..c8c709a 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -364,80 +364,81 @@ namespace OpenSim.Region.ClientStack.Linden
364 poolreq.thepoll.Process(poolreq); 364 poolreq.thepoll.Process(poolreq);
365 } 365 }
366 } 366 }
367 } 367 internal sealed class CapsDataThrottler
368
369 internal sealed class CapsDataThrottler
370 {
371
372 private volatile int currenttime = 0;
373 private volatile int lastTimeElapsed = 0;
374 private volatile int BytesSent = 0;
375 private int oversizedImages = 0;
376 public CapsDataThrottler(int pBytes, int max, int min)
377 {
378 ThrottleBytes = pBytes;
379 lastTimeElapsed = Util.EnvironmentTickCount();
380 }
381 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
382 { 368 {
383 PassTime(); 369
384 // Note, this is called IN LOCK 370 private volatile int currenttime = 0;
385 bool haskey = responses.ContainsKey(key); 371 private volatile int lastTimeElapsed = 0;
386 if (!haskey) 372 private volatile int BytesSent = 0;
373 private int oversizedImages = 0;
374 public CapsDataThrottler(int pBytes, int max, int min)
387 { 375 {
388 return false; 376 ThrottleBytes = pBytes;
377 lastTimeElapsed = Util.EnvironmentTickCount();
389 } 378 }
390 GetTextureModule.aPollResponse response; 379 public bool hasEvents(UUID key, Dictionary<UUID, GetTextureModule.aPollResponse> responses)
391 if (responses.TryGetValue(key,out response))
392 { 380 {
393 381 PassTime();
394 // Normal 382 // Note, this is called IN LOCK
395 if (BytesSent + response.bytes <= ThrottleBytes) 383 bool haskey = responses.ContainsKey(key);
384 if (!haskey)
396 { 385 {
397 BytesSent += response.bytes; 386 return false;
398 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
399 //m_actions.Add(timeBasedAction);
400 return true;
401 }
402 // Big textures
403 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes%50000) + 1))
404 {
405 Interlocked.Increment(ref oversizedImages);
406 BytesSent += response.bytes;
407 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
408 //m_actions.Add(timeBasedAction);
409 return true;
410 } 387 }
411 else 388 GetTextureModule.aPollResponse response;
389 if (responses.TryGetValue(key, out response))
412 { 390 {
413 return false; 391
392 // Normal
393 if (BytesSent + response.bytes <= ThrottleBytes)
394 {
395 BytesSent += response.bytes;
396 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + 1000, unlockyn = false };
397 //m_actions.Add(timeBasedAction);
398 return true;
399 }
400 // Big textures
401 else if (response.bytes > ThrottleBytes && oversizedImages <= ((ThrottleBytes % 50000) + 1))
402 {
403 Interlocked.Increment(ref oversizedImages);
404 BytesSent += response.bytes;
405 //TimeBasedAction timeBasedAction = new TimeBasedAction { byteRemoval = response.bytes, requestId = key, timeMS = currenttime + (((response.bytes % ThrottleBytes)+1)*1000) , unlockyn = false };
406 //m_actions.Add(timeBasedAction);
407 return true;
408 }
409 else
410 {
411 return false;
412 }
414 } 413 }
414
415 return haskey;
416 }
417 public void ProcessTime()
418 {
419 PassTime();
415 } 420 }
416 421
417 return haskey; 422
418 } 423 private void PassTime()
419 public void ProcessTime()
420 {
421 PassTime();
422 }
423
424
425 private void PassTime()
426 {
427 currenttime = Util.EnvironmentTickCount();
428 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
429 //processTimeBasedActions(responses);
430 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
431 { 424 {
432 lastTimeElapsed = Util.EnvironmentTickCount(); 425 currenttime = Util.EnvironmentTickCount();
433 BytesSent -= ThrottleBytes; 426 int timeElapsed = Util.EnvironmentTickCountSubtract(currenttime, lastTimeElapsed);
434 if (BytesSent < 0) BytesSent = 0; 427 //processTimeBasedActions(responses);
435 if (BytesSent < ThrottleBytes) 428 if (Util.EnvironmentTickCountSubtract(currenttime, timeElapsed) >= 1000)
436 { 429 {
437 oversizedImages = 0; 430 lastTimeElapsed = Util.EnvironmentTickCount();
431 BytesSent -= ThrottleBytes;
432 if (BytesSent < 0) BytesSent = 0;
433 if (BytesSent < ThrottleBytes)
434 {
435 oversizedImages = 0;
436 }
438 } 437 }
439 } 438 }
439 public int ThrottleBytes;
440 } 440 }
441 public int ThrottleBytes;
442 } 441 }
442
443
443} 444}
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
index ae9ed7f..533a1a8 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLClientView.cs
@@ -11884,6 +11884,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP
11884 } 11884 }
11885 11885
11886 /// <summary> 11886 /// <summary>
11887 /// Sets the throttles from values supplied by the client
11888 /// </summary>
11889 /// <param name="throttles"></param>
11890 public void SetAgentThrottleSilent(int throttle, int setting)
11891 {
11892 m_udpClient.ForceThrottleSetting(throttle,setting);
11893 //m_udpClient.SetThrottles(throttles);
11894
11895 }
11896
11897
11898 /// <summary>
11887 /// Get the current throttles for this client as a packed byte array 11899 /// Get the current throttles for this client as a packed byte array
11888 /// </summary> 11900 /// </summary>
11889 /// <param name="multiplier">Unused</param> 11901 /// <param name="multiplier">Unused</param>
diff --git a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
index c472176..f675377 100644
--- a/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
+++ b/OpenSim/Region/ClientStack/Linden/UDP/LLUDPClient.cs
@@ -682,6 +682,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
682 if (m_nextOnQueueEmpty == 0) 682 if (m_nextOnQueueEmpty == 0)
683 m_nextOnQueueEmpty = 1; 683 m_nextOnQueueEmpty = 1;
684 } 684 }
685 internal void ForceThrottleSetting(int throttle, int setting)
686 {
687 m_throttleCategories[throttle].RequestedDripRate = Math.Max(setting, LLUDPServer.MTU); ;
688 }
685 689
686 /// <summary> 690 /// <summary>
687 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a 691 /// Converts a <seealso cref="ThrottleOutPacketType"/> integer to a
diff --git a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
index 28b8293..563fd12 100644
--- a/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
+++ b/OpenSim/Region/OptionalModules/Agent/InternetRelayClientView/Server/IRCClientView.cs
@@ -1428,6 +1428,11 @@ namespace OpenSim.Region.OptionalModules.Agent.InternetRelayClientView.Server
1428 1428
1429 } 1429 }
1430 1430
1431 public void SetAgentThrottleSilent(int throttle, int setting)
1432 {
1433
1434
1435 }
1431 public byte[] GetThrottlesPacked(float multiplier) 1436 public byte[] GetThrottlesPacked(float multiplier)
1432 { 1437 {
1433 return new byte[0]; 1438 return new byte[0];
diff --git a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
index 6c8e2fc..ef53c48 100644
--- a/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
+++ b/OpenSim/Region/OptionalModules/World/NPC/NPCAvatar.cs
@@ -597,6 +597,12 @@ namespace OpenSim.Region.OptionalModules.World.NPC
597 public virtual void SetChildAgentThrottle(byte[] throttle) 597 public virtual void SetChildAgentThrottle(byte[] throttle)
598 { 598 {
599 } 599 }
600
601 public void SetAgentThrottleSilent(int throttle, int setting)
602 {
603
604
605 }
600 public byte[] GetThrottlesPacked(float multiplier) 606 public byte[] GetThrottlesPacked(float multiplier)
601 { 607 {
602 return new byte[0]; 608 return new byte[0];
diff --git a/OpenSim/Tests/Common/Mock/TestClient.cs b/OpenSim/Tests/Common/Mock/TestClient.cs
index 78bb18e..d1af0fc 100644
--- a/OpenSim/Tests/Common/Mock/TestClient.cs
+++ b/OpenSim/Tests/Common/Mock/TestClient.cs
@@ -521,6 +521,12 @@ namespace OpenSim.Tests.Common.Mock
521 public virtual void SetChildAgentThrottle(byte[] throttle) 521 public virtual void SetChildAgentThrottle(byte[] throttle)
522 { 522 {
523 } 523 }
524
525 public void SetAgentThrottleSilent(int throttle, int setting)
526 {
527
528
529 }
524 public byte[] GetThrottlesPacked(float multiplier) 530 public byte[] GetThrottlesPacked(float multiplier)
525 { 531 {
526 return new byte[0]; 532 return new byte[0];