aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region
diff options
context:
space:
mode:
authorMelanie2012-09-14 21:24:25 +0200
committerMelanie2012-09-14 21:24:25 +0200
commit387e59ff7f60f2b12526eaacd93581f76abe26e1 (patch)
tree6255bde5b8aed92e48eee4fb2e1caa03819c355f /OpenSim/Region
parentAllow setting connection limits, part 2 (diff)
downloadopensim-SC-387e59ff7f60f2b12526eaacd93581f76abe26e1.zip
opensim-SC-387e59ff7f60f2b12526eaacd93581f76abe26e1.tar.gz
opensim-SC-387e59ff7f60f2b12526eaacd93581f76abe26e1.tar.bz2
opensim-SC-387e59ff7f60f2b12526eaacd93581f76abe26e1.tar.xz
Revamp the HTTP textures handler to allow a maximum of four fetches
at any time and to drop requests for avatars n longer in the scene
Diffstat (limited to 'OpenSim/Region')
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs223
1 files changed, 179 insertions, 44 deletions
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
index 5ae9cc3..5b125ea 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/GetTextureModule.cs
@@ -27,18 +27,13 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Specialized; 30using System.Collections.Generic;
31using System.Drawing;
32using System.Drawing.Imaging;
33using System.Reflection; 31using System.Reflection;
34using System.IO; 32using System.Threading;
35using System.Web;
36using log4net; 33using log4net;
37using Nini.Config; 34using Nini.Config;
38using Mono.Addins; 35using Mono.Addins;
39using OpenMetaverse; 36using OpenMetaverse;
40using OpenMetaverse.StructuredData;
41using OpenMetaverse.Imaging;
42using OpenSim.Framework; 37using OpenSim.Framework;
43using OpenSim.Framework.Servers; 38using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 39using OpenSim.Framework.Servers.HttpServer;
@@ -47,64 +42,73 @@ using OpenSim.Region.Framework.Scenes;
47using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
48using Caps = OpenSim.Framework.Capabilities.Caps; 43using Caps = OpenSim.Framework.Capabilities.Caps;
49using OpenSim.Capabilities.Handlers; 44using OpenSim.Capabilities.Handlers;
45using OpenSim.Framework.Monitoring;
50 46
51namespace OpenSim.Region.ClientStack.Linden 47namespace OpenSim.Region.ClientStack.Linden
52{ 48{
53 49
54 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] 50 /// <summary>
51 /// This module implements both WebFetchTextureDescendents and FetchTextureDescendents2 capabilities.
52 /// </summary>
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GetTextureModule")]
55 public class GetTextureModule : INonSharedRegionModule 54 public class GetTextureModule : INonSharedRegionModule
56 { 55 {
57// private static readonly ILog m_log = 56 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58// LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 57
59
60 private Scene m_scene; 58 private Scene m_scene;
61 private IAssetService m_assetService;
62 59
63 private bool m_Enabled = false; 60 private static GetTextureHandler m_getTextureHandler;
61
62 private IAssetService m_assetService = null;
64 63
65 // TODO: Change this to a config option 64 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
66 const string REDIRECT_URL = null; 65 private static Thread[] m_workerThreads = null;
67 66
68 private string m_URL; 67 private static OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs> m_queue =
68 new OpenMetaverse.BlockingQueue<PollServiceTextureEventArgs>();
69 69
70 #region ISharedRegionModule Members 70 #region ISharedRegionModule Members
71 71
72 public void Initialise(IConfigSource source) 72 public void Initialise(IConfigSource source)
73 { 73 {
74 IConfig config = source.Configs["ClientStack.LindenCaps"];
75 if (config == null)
76 return;
77
78 m_URL = config.GetString("Cap_GetTexture", string.Empty);
79 // Cap doesn't exist
80 if (m_URL != string.Empty)
81 m_Enabled = true;
82 } 74 }
83 75
84 public void AddRegion(Scene s) 76 public void AddRegion(Scene s)
85 { 77 {
86 if (!m_Enabled)
87 return;
88
89 m_scene = s; 78 m_scene = s;
79 m_assetService = s.AssetService;
90 } 80 }
91 81
92 public void RemoveRegion(Scene s) 82 public void RemoveRegion(Scene s)
93 { 83 {
94 if (!m_Enabled)
95 return;
96
97 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 84 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
85 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
98 m_scene = null; 86 m_scene = null;
99 } 87 }
100 88
101 public void RegionLoaded(Scene s) 89 public void RegionLoaded(Scene s)
102 { 90 {
103 if (!m_Enabled) 91 // We'll reuse the same handler for all requests.
104 return; 92 m_getTextureHandler = new GetTextureHandler(m_assetService);
105 93
106 m_assetService = m_scene.RequestModuleInterface<IAssetService>();
107 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 94 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
95 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
96
97 if (m_workerThreads == null)
98 {
99 m_workerThreads = new Thread[4];
100
101 for (uint i = 0; i < 4; i++)
102 {
103 m_workerThreads[i] = Watchdog.StartThread(DoTextureRequests,
104 String.Format("TextureWorkerThread{0}", i),
105 ThreadPriority.Normal,
106 false,
107 true,
108 null,
109 int.MaxValue);
110 }
111 }
108 } 112 }
109 113
110 public void PostInitialise() 114 public void PostInitialise()
@@ -122,24 +126,155 @@ namespace OpenSim.Region.ClientStack.Linden
122 126
123 #endregion 127 #endregion
124 128
125 public void RegisterCaps(UUID agentID, Caps caps) 129 ~GetTextureModule()
130 {
131 foreach (Thread t in m_workerThreads)
132 t.Abort();
133 }
134
135 private class PollServiceTextureEventArgs : PollServiceEventArgs
126 { 136 {
127 UUID capID = UUID.Random(); 137 private List<Hashtable> requests =
138 new List<Hashtable>();
139 private Dictionary<UUID, Hashtable> responses =
140 new Dictionary<UUID, Hashtable>();
141
142 private Scene m_scene;
128 143
129 //caps.RegisterHandler("GetTexture", new StreamHandler("GET", "/CAPS/" + capID, ProcessGetTexture)); 144 public PollServiceTextureEventArgs(UUID pId, Scene scene) :
130 if (m_URL == "localhost") 145 base(null, null, null, null, pId, 30000)
131 { 146 {
132// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName); 147 m_scene = scene;
133 caps.RegisterHandler( 148
134 "GetTexture", 149 HasEvents = (x, y) => { return this.responses.ContainsKey(x); };
135 new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString())); 150 GetEvents = (x, y, s) =>
151 {
152 try
153 {
154 return this.responses[x];
155 }
156 finally
157 {
158 responses.Remove(x);
159 }
160 };
161
162 Request = (x, y) =>
163 {
164 y["RequestID"] = x.ToString();
165 lock (this.requests)
166 this.requests.Add(y);
167
168 m_queue.Enqueue(this);
169 };
170
171 NoEvents = (x, y) =>
172 {
173 lock (this.requests)
174 {
175 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
176 requests.Remove(request);
177 }
178
179 Hashtable response = new Hashtable();
180
181 response["int_response_code"] = 500;
182 response["str_response_string"] = "Script timeout";
183 response["content_type"] = "text/plain";
184 response["keepalive"] = false;
185 response["reusecontext"] = false;
186
187 return response;
188 };
136 } 189 }
137 else 190
191 public void Process()
138 { 192 {
139// m_log.DebugFormat("[GETTEXTURE]: {0} in region {1}", m_URL, m_scene.RegionInfo.RegionName); 193 Hashtable response;
140 caps.RegisterHandler("GetTexture", m_URL); 194 Hashtable request = null;
195
196 try
197 {
198 lock (this.requests)
199 {
200 request = requests[0];
201 requests.RemoveAt(0);
202 }
203 }
204 catch
205 {
206 return;
207 }
208
209 UUID requestID = new UUID(request["RequestID"].ToString());
210
211 // If the avatar is gone, don't bother to get the texture
212 if (m_scene.GetScenePresence(Id) == null)
213 {
214 response = new Hashtable();
215
216 response["int_response_code"] = 500;
217 response["str_response_string"] = "Script timeout";
218 response["content_type"] = "text/plain";
219 response["keepalive"] = false;
220 response["reusecontext"] = false;
221
222 responses[requestID] = response;
223 return;
224 }
225
226 response = m_getTextureHandler.Handle(request);
227
228 responses[requestID] = response;
229 }
230 }
231
232 private void RegisterCaps(UUID agentID, Caps caps)
233 {
234 string capUrl = "/CAPS/" + UUID.Random() + "/";
235
236 // Register this as a poll service
237 // absurd large timeout to tune later to make a bit less than viewer
238 PollServiceTextureEventArgs args = new PollServiceTextureEventArgs(agentID, m_scene);
239
240 args.Type = PollServiceEventArgs.EventType.Texture;
241 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
242
243 string hostName = m_scene.RegionInfo.ExternalHostName;
244 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
245 string protocol = "http";
246
247 if (MainServer.Instance.UseSSL)
248 {
249 hostName = MainServer.Instance.SSLCommonName;
250 port = MainServer.Instance.SSLPort;
251 protocol = "https";
141 } 252 }
253 caps.RegisterHandler("GetTexture", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
254
255 m_capsDict[agentID] = capUrl;
142 } 256 }
143 257
258 private void DeregisterCaps(UUID agentID, Caps caps)
259 {
260 string capUrl;
261
262 if (m_capsDict.TryGetValue(agentID, out capUrl))
263 {
264 MainServer.Instance.RemoveHTTPHandler("", capUrl);
265 m_capsDict.Remove(agentID);
266 }
267 }
268
269 private void DoTextureRequests()
270 {
271 while (true)
272 {
273 PollServiceTextureEventArgs args = m_queue.Dequeue();
274
275 args.Process();
276 }
277 }
144 } 278 }
279
145} 280}