aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/Util.cs108
-rw-r--r--OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs265
-rw-r--r--OpenSim/Region/Framework/Scenes/ScenePresence.cs32
-rw-r--r--prebuild.xml1
4 files changed, 343 insertions, 63 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index ada4e89..7f0850f 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -2233,4 +2233,112 @@ namespace OpenSim.Framework
2233 return str.Replace("_", "\\_").Replace("%", "\\%"); 2233 return str.Replace("_", "\\_").Replace("%", "\\%");
2234 } 2234 }
2235 } 2235 }
2236
2237 public class DoubleQueue<T> where T:class
2238 {
2239 private Queue<T> m_lowQueue = new Queue<T>();
2240 private Queue<T> m_highQueue = new Queue<T>();
2241
2242 private object m_syncRoot = new object();
2243 private Semaphore m_s = new Semaphore(0, 1);
2244
2245 public DoubleQueue()
2246 {
2247 }
2248
2249 public virtual int Count
2250 {
2251 get { return m_highQueue.Count + m_lowQueue.Count; }
2252 }
2253
2254 public virtual void Enqueue(T data)
2255 {
2256 Enqueue(m_lowQueue, data);
2257 }
2258
2259 public virtual void EnqueueLow(T data)
2260 {
2261 Enqueue(m_lowQueue, data);
2262 }
2263
2264 public virtual void EnqueueHigh(T data)
2265 {
2266 Enqueue(m_highQueue, data);
2267 }
2268
2269 private void Enqueue(Queue<T> q, T data)
2270 {
2271 lock (m_syncRoot)
2272 {
2273 m_lowQueue.Enqueue(data);
2274 m_s.WaitOne(0);
2275 m_s.Release();
2276 }
2277 }
2278
2279 public virtual T Dequeue()
2280 {
2281 return Dequeue(Timeout.Infinite);
2282 }
2283
2284 public virtual T Dequeue(int tmo)
2285 {
2286 return Dequeue(TimeSpan.FromMilliseconds(tmo));
2287 }
2288
2289 public virtual T Dequeue(TimeSpan wait)
2290 {
2291 T res = null;
2292
2293 if (!Dequeue(wait, ref res))
2294 return null;
2295
2296 return res;
2297 }
2298
2299 public bool Dequeue(int timeout, ref T res)
2300 {
2301 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
2302 }
2303
2304 public bool Dequeue(TimeSpan wait, ref T res)
2305 {
2306 if (!m_s.WaitOne(wait))
2307 return false;
2308
2309 lock (m_syncRoot)
2310 {
2311 if (m_highQueue.Count > 0)
2312 res = m_highQueue.Dequeue();
2313 else
2314 res = m_lowQueue.Dequeue();
2315
2316 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
2317 return true;
2318
2319 try
2320 {
2321 m_s.Release();
2322 }
2323 catch
2324 {
2325 }
2326
2327 return true;
2328 }
2329 }
2330
2331 public virtual void Clear()
2332 {
2333
2334 lock (m_syncRoot)
2335 {
2336 // Make sure sem count is 0
2337 m_s.WaitOne(0);
2338
2339 m_lowQueue.Clear();
2340 m_highQueue.Clear();
2341 }
2342 }
2343 }
2236} 2344}
diff --git a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
index 6890f4a..7dd9770 100644
--- a/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
+++ b/OpenSim/Region/ClientStack/Linden/Caps/WebFetchInvDescModule.cs
@@ -27,18 +27,25 @@
27 27
28using System; 28using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic;
30using System.Reflection; 31using System.Reflection;
32using System.Threading;
31using log4net; 33using log4net;
32using Nini.Config; 34using Nini.Config;
33using Mono.Addins; 35using Mono.Addins;
34using OpenMetaverse; 36using OpenMetaverse;
35using OpenSim.Framework; 37using OpenSim.Framework;
38using OpenSim.Framework.Monitoring;
39using OpenSim.Framework.Servers;
36using OpenSim.Framework.Servers.HttpServer; 40using OpenSim.Framework.Servers.HttpServer;
37using OpenSim.Region.Framework.Interfaces; 41using OpenSim.Region.Framework.Interfaces;
38using OpenSim.Region.Framework.Scenes; 42using OpenSim.Region.Framework.Scenes;
43using OpenSim.Framework.Capabilities;
39using OpenSim.Services.Interfaces; 44using OpenSim.Services.Interfaces;
40using Caps = OpenSim.Framework.Capabilities.Caps; 45using Caps = OpenSim.Framework.Capabilities.Caps;
41using OpenSim.Capabilities.Handlers; 46using OpenSim.Capabilities.Handlers;
47using OpenMetaverse;
48using OpenMetaverse.StructuredData;
42 49
43namespace OpenSim.Region.ClientStack.Linden 50namespace OpenSim.Region.ClientStack.Linden
44{ 51{
@@ -48,67 +55,74 @@ namespace OpenSim.Region.ClientStack.Linden
48 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")] 55 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "WebFetchInvDescModule")]
49 public class WebFetchInvDescModule : INonSharedRegionModule 56 public class WebFetchInvDescModule : INonSharedRegionModule
50 { 57 {
51// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 58 class aPollRequest
59 {
60 public PollServiceInventoryEventArgs thepoll;
61 public UUID reqID;
62 public Hashtable request;
63 public ScenePresence presence;
64 public List<UUID> folders;
65 }
66
67 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
52 68
53 private Scene m_scene; 69 private Scene m_scene;
54 70
55 private IInventoryService m_InventoryService; 71 private IInventoryService m_InventoryService;
56 private ILibraryService m_LibraryService; 72 private ILibraryService m_LibraryService;
57 73
58 private bool m_Enabled; 74 private static WebFetchInvDescHandler m_webFetchHandler;
59 75
60 private string m_fetchInventoryDescendents2Url; 76 private Dictionary<UUID, string> m_capsDict = new Dictionary<UUID, string>();
61 private string m_webFetchInventoryDescendentsUrl; 77 private static Thread[] m_workerThreads = null;
62 78
63 private WebFetchInvDescHandler m_webFetchHandler; 79 private static DoubleQueue<aPollRequest> m_queue =
80 new DoubleQueue<aPollRequest>();
64 81
65 #region ISharedRegionModule Members 82 #region ISharedRegionModule Members
66 83
67 public void Initialise(IConfigSource source) 84 public void Initialise(IConfigSource source)
68 { 85 {
69 IConfig config = source.Configs["ClientStack.LindenCaps"];
70 if (config == null)
71 return;
72
73 m_fetchInventoryDescendents2Url = config.GetString("Cap_FetchInventoryDescendents2", string.Empty);
74 m_webFetchInventoryDescendentsUrl = config.GetString("Cap_WebFetchInventoryDescendents", string.Empty);
75
76 if (m_fetchInventoryDescendents2Url != string.Empty || m_webFetchInventoryDescendentsUrl != string.Empty)
77 {
78 m_Enabled = true;
79 }
80 } 86 }
81 87
82 public void AddRegion(Scene s) 88 public void AddRegion(Scene s)
83 { 89 {
84 if (!m_Enabled)
85 return;
86
87 m_scene = s; 90 m_scene = s;
88 } 91 }
89 92
90 public void RemoveRegion(Scene s) 93 public void RemoveRegion(Scene s)
91 { 94 {
92 if (!m_Enabled)
93 return;
94
95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps; 95 m_scene.EventManager.OnRegisterCaps -= RegisterCaps;
96 m_scene.EventManager.OnDeregisterCaps -= DeregisterCaps;
96 m_scene = null; 97 m_scene = null;
97 } 98 }
98 99
99 public void RegionLoaded(Scene s) 100 public void RegionLoaded(Scene s)
100 { 101 {
101 if (!m_Enabled)
102 return;
103
104 m_InventoryService = m_scene.InventoryService; 102 m_InventoryService = m_scene.InventoryService;
105 m_LibraryService = m_scene.LibraryService; 103 m_LibraryService = m_scene.LibraryService;
106 104
107 // We'll reuse the same handler for all requests. 105 // We'll reuse the same handler for all requests.
108 if (m_fetchInventoryDescendents2Url == "localhost" || m_webFetchInventoryDescendentsUrl == "localhost") 106 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
109 m_webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
110 107
111 m_scene.EventManager.OnRegisterCaps += RegisterCaps; 108 m_scene.EventManager.OnRegisterCaps += RegisterCaps;
109 m_scene.EventManager.OnDeregisterCaps += DeregisterCaps;
110
111 if (m_workerThreads == null)
112 {
113 m_workerThreads = new Thread[2];
114
115 for (uint i = 0; i < 2; i++)
116 {
117 m_workerThreads[i] = Watchdog.StartThread(DoInventoryRequests,
118 String.Format("InventoryWorkerThread{0}", i),
119 ThreadPriority.Normal,
120 false,
121 true,
122 null,
123 int.MaxValue);
124 }
125 }
112 } 126 }
113 127
114 public void PostInitialise() 128 public void PostInitialise()
@@ -126,43 +140,190 @@ namespace OpenSim.Region.ClientStack.Linden
126 140
127 #endregion 141 #endregion
128 142
129 private void RegisterCaps(UUID agentID, Caps caps) 143 ~WebFetchInvDescModule()
130 { 144 {
131 if (m_webFetchInventoryDescendentsUrl != "") 145 foreach (Thread t in m_workerThreads)
132 RegisterFetchCap(agentID, caps, "WebFetchInventoryDescendents", m_webFetchInventoryDescendentsUrl); 146 Watchdog.AbortThread(t.ManagedThreadId);
133
134 if (m_fetchInventoryDescendents2Url != "")
135 RegisterFetchCap(agentID, caps, "FetchInventoryDescendents2", m_fetchInventoryDescendents2Url);
136 } 147 }
137 148
138 private void RegisterFetchCap(UUID agentID, Caps caps, string capName, string url) 149 private class PollServiceInventoryEventArgs : PollServiceEventArgs
139 { 150 {
140 string capUrl; 151 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
152
153 private Dictionary<UUID, Hashtable> responses =
154 new Dictionary<UUID, Hashtable>();
155
156 private Scene m_scene;
141 157
142 if (url == "localhost") 158 public PollServiceInventoryEventArgs(Scene scene, UUID pId) :
159 base(null, null, null, null, pId)
143 { 160 {
144 capUrl = "/CAPS/" + UUID.Random(); 161 m_scene = scene;
162
163 HasEvents = (x, y) => { lock (responses) return responses.ContainsKey(x); };
164 GetEvents = (x, y, z) =>
165 {
166 lock (responses)
167 {
168 try
169 {
170 return responses[x];
171 }
172 finally
173 {
174 responses.Remove(x);
175 }
176 }
177 };
178
179 Request = (x, y) =>
180 {
181 ScenePresence sp = m_scene.GetScenePresence(Id);
182 if (sp == null)
183 {
184 m_log.ErrorFormat("[INVENTORY]: Unable to find ScenePresence for {0}", Id);
185 return;
186 }
187
188 aPollRequest reqinfo = new aPollRequest();
189 reqinfo.thepoll = this;
190 reqinfo.reqID = x;
191 reqinfo.request = y;
192 reqinfo.presence = sp;
193 reqinfo.folders = new List<UUID>();
194
195 // Decode the request here
196 string request = y["body"].ToString();
197
198 request = request.Replace("<string>00000000-0000-0000-0000-000000000000</string>", "<uuid>00000000-0000-0000-0000-000000000000</uuid>");
199
200 request = request.Replace("<key>fetch_folders</key><integer>0</integer>", "<key>fetch_folders</key><boolean>0</boolean>");
201 request = request.Replace("<key>fetch_folders</key><integer>1</integer>", "<key>fetch_folders</key><boolean>1</boolean>");
202
203 Hashtable hash = new Hashtable();
204 try
205 {
206 hash = (Hashtable)LLSD.LLSDDeserialize(Utils.StringToBytes(request));
207 }
208 catch (LLSD.LLSDParseException e)
209 {
210 m_log.ErrorFormat("[INVENTORY]: Fetch error: {0}{1}" + e.Message, e.StackTrace);
211 m_log.Error("Request: " + request);
212 return;
213 }
214 catch (System.Xml.XmlException)
215 {
216 m_log.ErrorFormat("[INVENTORY]: XML Format error");
217 }
218
219 ArrayList foldersrequested = (ArrayList)hash["folders"];
220
221 bool highPriority = false;
222
223 for (int i = 0; i < foldersrequested.Count; i++)
224 {
225 Hashtable inventoryhash = (Hashtable)foldersrequested[i];
226 string folder = inventoryhash["folder_id"].ToString();
227 UUID folderID;
228 if (UUID.TryParse(folder, out folderID))
229 {
230 if (!reqinfo.folders.Contains(folderID))
231 {
232 //TODO: Port COF handling from Avination
233 reqinfo.folders.Add(folderID);
234 }
235 }
236 }
237
238 if (highPriority)
239 m_queue.EnqueueHigh(reqinfo);
240 else
241 m_queue.EnqueueLow(reqinfo);
242 };
243
244 NoEvents = (x, y) =>
245 {
246/*
247 lock (requests)
248 {
249 Hashtable request = requests.Find(id => id["RequestID"].ToString() == x.ToString());
250 requests.Remove(request);
251 }
252*/
253 Hashtable response = new Hashtable();
254
255 response["int_response_code"] = 500;
256 response["str_response_string"] = "Script timeout";
257 response["content_type"] = "text/plain";
258 response["keepalive"] = false;
259 response["reusecontext"] = false;
260
261 return response;
262 };
263 }
145 264
146 IRequestHandler reqHandler 265 public void Process(aPollRequest requestinfo)
147 = new RestStreamHandler( 266 {
148 "POST", 267 UUID requestID = requestinfo.reqID;
149 capUrl, 268
150 m_webFetchHandler.FetchInventoryDescendentsRequest, 269 Hashtable response = new Hashtable();
151 "FetchInventoryDescendents2", 270
152 agentID.ToString()); 271 response["int_response_code"] = 200;
272 response["content_type"] = "text/plain";
273 response["keepalive"] = false;
274 response["reusecontext"] = false;
153 275
154 caps.RegisterHandler(capName, reqHandler); 276 response["str_response_string"] = m_webFetchHandler.FetchInventoryDescendentsRequest(
277 requestinfo.request["body"].ToString(), String.Empty, String.Empty, null, null);
278
279 lock (responses)
280 responses[requestID] = response;
155 } 281 }
156 else 282 }
283
284 private void RegisterCaps(UUID agentID, Caps caps)
285 {
286 string capUrl = "/CAPS/" + UUID.Random() + "/";
287
288 // Register this as a poll service
289 PollServiceInventoryEventArgs args = new PollServiceInventoryEventArgs(m_scene, agentID);
290
291 MainServer.Instance.AddPollServiceHTTPHandler(capUrl, args);
292
293 string hostName = m_scene.RegionInfo.ExternalHostName;
294 uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
295 string protocol = "http";
296
297 if (MainServer.Instance.UseSSL)
157 { 298 {
158 capUrl = url; 299 hostName = MainServer.Instance.SSLCommonName;
300 port = MainServer.Instance.SSLPort;
301 protocol = "https";
302 }
303 caps.RegisterHandler("FetchInventoryDescendents2", String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, capUrl));
304
305 m_capsDict[agentID] = capUrl;
306 }
159 307
160 caps.RegisterHandler(capName, capUrl); 308 private void DeregisterCaps(UUID agentID, Caps caps)
309 {
310 string capUrl;
311
312 if (m_capsDict.TryGetValue(agentID, out capUrl))
313 {
314 MainServer.Instance.RemoveHTTPHandler("", capUrl);
315 m_capsDict.Remove(agentID);
161 } 316 }
317 }
162 318
163// m_log.DebugFormat( 319 private void DoInventoryRequests()
164// "[WEB FETCH INV DESC MODULE]: Registered capability {0} at {1} in region {2} for {3}", 320 {
165// capName, capUrl, m_scene.RegionInfo.RegionName, agentID); 321 while (true)
322 {
323 aPollRequest poolreq = m_queue.Dequeue();
324
325 poolreq.thepoll.Process(poolreq);
326 }
166 } 327 }
167 } 328 }
168} \ No newline at end of file 329}
diff --git a/OpenSim/Region/Framework/Scenes/ScenePresence.cs b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
index b8ff7f7..bab14dd 100644
--- a/OpenSim/Region/Framework/Scenes/ScenePresence.cs
+++ b/OpenSim/Region/Framework/Scenes/ScenePresence.cs
@@ -121,6 +121,8 @@ namespace OpenSim.Region.Framework.Scenes
121 /// <remarks> 121 /// <remarks>
122 /// TODO: For some reason, we effectively have a list both here and in Appearance. Need to work out if this is 122 /// TODO: For some reason, we effectively have a list both here and in Appearance. Need to work out if this is
123 /// necessary. 123 /// necessary.
124 /// NOTE: To avoid deadlocks, do not lock m_attachments and then perform other tasks under that lock. Take a copy
125 /// of the list and act on that instead.
124 /// </remarks> 126 /// </remarks>
125 private List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>(); 127 private List<SceneObjectGroup> m_attachments = new List<SceneObjectGroup>();
126 128
@@ -971,19 +973,27 @@ namespace OpenSim.Region.Framework.Scenes
971 // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently 973 // and CHANGED_REGION) when the attachments have been rezzed in the new region. This cannot currently
972 // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are 974 // be done in AttachmentsModule.CopyAttachments(AgentData ad, IScenePresence sp) itself since we are
973 // not transporting the required data. 975 // not transporting the required data.
974 lock (m_attachments) 976 //
977 // We must take a copy of the attachments list here (rather than locking) to avoid a deadlock where a script in one of
978 // the attachments may start processing an event (which locks ScriptInstance.m_Script) that then calls a method here
979 // which needs to lock m_attachments. ResumeScripts() needs to take a ScriptInstance.m_Script lock to try to unset the Suspend status.
980 //
981 // FIXME: In theory, this deadlock should not arise since scripts should not be processing events until ResumeScripts().
982 // But XEngine starts all scripts unsuspended. Starting them suspended will not currently work because script rezzing
983 // is placed in an asynchronous queue in XEngine and so the ResumeScripts() call will almost certainly execute before the
984 // script is rezzed. This means the ResumeScripts() does absolutely nothing when using XEngine.
985 List<SceneObjectGroup> attachments = GetAttachments();
986
987 if (attachments.Count > 0)
975 { 988 {
976 if (HasAttachments()) 989 m_log.DebugFormat(
977 { 990 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
978 m_log.DebugFormat(
979 "[SCENE PRESENCE]: Restarting scripts in attachments for {0} in {1}", Name, Scene.Name);
980 991
981 // Resume scripts 992 // Resume scripts
982 foreach (SceneObjectGroup sog in m_attachments) 993 foreach (SceneObjectGroup sog in attachments)
983 { 994 {
984 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource()); 995 sog.RootPart.ParentGroup.CreateScriptInstances(0, false, m_scene.DefaultScriptEngine, GetStateSource());
985 sog.ResumeScripts(); 996 sog.ResumeScripts();
986 }
987 } 997 }
988 } 998 }
989 } 999 }
diff --git a/prebuild.xml b/prebuild.xml
index 03cac76..5531558 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -1531,6 +1531,7 @@
1531 <Reference name="OpenSim.Capabilities"/> 1531 <Reference name="OpenSim.Capabilities"/>
1532 <Reference name="OpenSim.Capabilities.Handlers"/> 1532 <Reference name="OpenSim.Capabilities.Handlers"/>
1533 <Reference name="OpenSim.Framework"/> 1533 <Reference name="OpenSim.Framework"/>
1534 <Reference name="OpenSim.Framework.Monitoring"/>
1534 <Reference name="OpenSim.Framework.Servers"/> 1535 <Reference name="OpenSim.Framework.Servers"/>
1535 <Reference name="OpenSim.Framework.Servers.HttpServer"/> 1536 <Reference name="OpenSim.Framework.Servers.HttpServer"/>
1536 <Reference name="OpenSim.Framework.Console"/> 1537 <Reference name="OpenSim.Framework.Console"/>