From fda39c11bf8e440414f44e8233aa67818da51036 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 01:33:27 +0100 Subject: [PATCH 1/7] Fix bug where attachments would not retain position if just rotated and not moved. This was because we were not setting AttachedPos in SOG.UpdateGroupPositionPR, unlike UpdateGroupPosition --- OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 18877c1e3b..1e900a0746 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -2911,6 +2911,11 @@ namespace OpenSim.Region.Framework.Scenes m_scene.PhysicsScene.AddPhysicsActorTaint(actor); } + if (IsAttachment) + { + m_rootPart.AttachedPos = pos; + } + AbsolutePosition = pos; HasGroupChanged = true; From 4cf49369b51c21a0eadd719eb46f53d207e1e5f7 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 01:39:39 +0100 Subject: [PATCH 2/7] Stop flicking IsAttachment false and then true in AttachmentsModule.UpdateAttachmentPosition() in order to avoid a hud update race condition. Previously, setting IsAttachment to false then true was necessary to serialize the updated attachment object information. However, UpdateAttachmentPosition no longer does this update. Whilst IsAttachment is set to false there is a race condition where the update thread can wrongly send hud object updates to clients that do not own the hud, resulting in screen artifacts. --- .../Avatar/Attachments/AttachmentsModule.cs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs index b74c0ba646..a2b95ebb0b 100644 --- a/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs @@ -408,17 +408,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments if (!Enabled) return; - // First we save the - // attachment point information, then we update the relative - // positioning. Then we have to mark the object as NOT an - // attachment. This is necessary in order to correctly save - // and retrieve GroupPosition information for the attachment. - // Finally, we restore the object's attachment status. - uint attachmentPoint = sog.AttachmentPoint; sog.UpdateGroupPosition(pos); - sog.IsAttachment = false; - sog.AbsolutePosition = sog.RootPart.AttachedPos; - sog.AttachmentPoint = attachmentPoint; sog.HasGroupChanged = true; } From f907182ab28cd761bebd398dab38f9a997ecd19d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 01:57:14 +0100 Subject: [PATCH 3/7] Eliminate unnecessary extra call to TriggerEmptyScriptCompileQueue in XEngine.DoOnRezScriptQueue() The later invocation of this function will happen on an empty compile queue. --- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index e961e76b6c..26df758357 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -855,13 +855,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine { m_InitialStartup = false; System.Threading.Thread.Sleep(15000); - - if (m_CompileQueue.Count == 0) - { - // No scripts on region, so won't get triggered later - // by the queue becoming empty so we trigger it here - m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); - } } object[] o; @@ -889,11 +882,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine // due to a race condition // lock (m_CompileQueue) - { m_CurrentCompile = null; - } + m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, m_ScriptErrorMessage); + m_ScriptFailCount = 0; return null; From 9f3feeff8d3a00b965b2151477df5b0b2de3ff1d Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 02:10:27 +0100 Subject: [PATCH 4/7] If starting scripts on initial sim start, provide INFO level log feedback each time 50 scripts have been started. This is to provide an indication of what's happening now that the default isn't to report every single script start. Changes XEngine logging level in OpenSim.exe.config from WARN to INFO. --- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 2 +- OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 16 ++++++++++------ bin/OpenSim.exe.config | 2 +- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 62ea9e3cc5..9459f76a5e 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -321,7 +321,7 @@ namespace OpenSim.Framework.Servers TimeSpan timeTaken = DateTime.Now - m_startuptime; m_log.InfoFormat( - "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS.", + "[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.", timeTaken.Minutes, timeTaken.Seconds); } diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 26df758357..40f48e376d 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -853,7 +853,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine { if (m_InitialStartup) { - m_InitialStartup = false; + // This delay exists to stop mono problems where script compilation and startup would stop the sim + // working properly for the session. System.Threading.Thread.Sleep(15000); } @@ -867,14 +868,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine { scriptsStarted++; -// if (scriptsStarted % 50 == 0) -// m_log.DebugFormat( -// "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); + if (m_InitialStartup) + if (scriptsStarted % 50 == 0) + m_log.InfoFormat( + "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); } } -// m_log.DebugFormat( -// "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); + if (m_InitialStartup) + m_log.InfoFormat( + "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName); // NOTE: Despite having a lockless queue, this lock is required // to make sure there is never no compile thread while there @@ -888,6 +891,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine m_ScriptErrorMessage); m_ScriptFailCount = 0; + m_InitialStartup = false; return null; } diff --git a/bin/OpenSim.exe.config b/bin/OpenSim.exe.config index f1e3709688..e3107abc87 100755 --- a/bin/OpenSim.exe.config +++ b/bin/OpenSim.exe.config @@ -33,7 +33,7 @@ - + From 80a41e670dd9bbd2771fbcf250362cefa2797306 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 02:23:25 +0100 Subject: [PATCH 5/7] Avoid race condition between m_PrimObjects iteration in XEngine.PostObjectEvent and places where the list is modified by extending the m_PrimObjects lock. --- .../Region/ScriptEngine/XEngine/XEngine.cs | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 40f48e376d..25b27b90c5 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1363,22 +1363,22 @@ namespace OpenSim.Region.ScriptEngine.XEngine return false; uuids = m_PrimObjects[localID]; - } - foreach (UUID itemID in uuids) - { - IScriptInstance instance = null; - try + foreach (UUID itemID in uuids) { - if (m_Scripts.ContainsKey(itemID)) - instance = m_Scripts[itemID]; - } - catch { /* ignore race conditions */ } - - if (instance != null) - { - instance.PostEvent(p); - result = true; + IScriptInstance instance = null; + try + { + if (m_Scripts.ContainsKey(itemID)) + instance = m_Scripts[itemID]; + } + catch { /* ignore race conditions */ } + + if (instance != null) + { + instance.PostEvent(p); + result = true; + } } } From dca04c7b61abb7b7ea70299a192425ce3bd05937 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 23:16:18 +0100 Subject: [PATCH 6/7] Avoid a race condition where an incoming request to a script external URL can trigger an exception is the URL was being removed at the same time. This involves three steps 1) Return gracefully in UrlModule.HttpRequestHandler() instead of throwing an exception when the url cannot be found in its index 2) Return true instead of false in HasEvents() if no matching request is found in the map. This call will only happen in the first place for raced requests. 3) Return a 404 in GetEvents() if the request is not in the index, rather than a blank 200 OK. Many thanks to Tom Haines in http://opensimulator.org/mantis/view.php?id=6051 for doing some of the work on this. --- .../HttpServer/PollServiceEventArgs.cs | 9 +- .../HttpServer/PollServiceHttpRequest.cs | 7 +- .../Scripting/LSLHttp/UrlModule.cs | 114 ++++++++++++------ 3 files changed, 87 insertions(+), 43 deletions(-) diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs index 9d512c6249..3089351a69 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs @@ -28,6 +28,7 @@ using System; using System.Collections; using OpenMetaverse; + namespace OpenSim.Framework.Servers.HttpServer { public delegate void RequestMethod(UUID requestID, Hashtable request); @@ -44,7 +45,11 @@ namespace OpenSim.Framework.Servers.HttpServer public NoEventsMethod NoEvents; public RequestMethod Request; public UUID Id; - public PollServiceEventArgs(RequestMethod pRequest, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,UUID pId) + + public PollServiceEventArgs( + RequestMethod pRequest, + HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, + UUID pId) { Request = pRequest; HasEvents = pHasEvents; @@ -53,4 +58,4 @@ namespace OpenSim.Framework.Servers.HttpServer Id = pId; } } -} +} \ No newline at end of file diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs index 553a7eb123..723530ae15 100644 --- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs +++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs @@ -31,7 +31,6 @@ using OpenMetaverse; namespace OpenSim.Framework.Servers.HttpServer { - public class PollServiceHttpRequest { public readonly PollServiceEventArgs PollServiceArgs; @@ -39,7 +38,9 @@ namespace OpenSim.Framework.Servers.HttpServer public readonly IHttpRequest Request; public readonly int RequestTime; public readonly UUID RequestID; - public PollServiceHttpRequest(PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) + + public PollServiceHttpRequest( + PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest) { PollServiceArgs = pPollServiceArgs; HttpContext = pHttpContext; @@ -48,4 +49,4 @@ namespace OpenSim.Framework.Servers.HttpServer RequestID = UUID.Random(); } } -} +} \ No newline at end of file diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 61afc762e2..5c05500718 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -64,17 +64,25 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public string uri; } + /// + /// This module provides external URLs for in-world scripts. + /// public class UrlModule : ISharedRegionModule, IUrlModule { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); - private Dictionary m_RequestMap = - new Dictionary(); + /// + /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the request ID + /// randomly generated when a request is received for this URL. + /// + private Dictionary m_RequestMap = new Dictionary(); - private Dictionary m_UrlMap = - new Dictionary(); + /// + /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the full URL + /// + private Dictionary m_UrlMap = new Dictionary(); /// /// Maximum number of external urls that can be set up by this module. @@ -224,7 +232,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.urlcode = urlcode; urlData.requests = new Dictionary(); - m_UrlMap[url] = urlData; string uri = "/lslhttps/" + urlcode.ToString() + "/"; @@ -286,7 +293,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { if (m_RequestMap.ContainsKey(requestId)) { - UrlData urlData=m_RequestMap[requestId]; + UrlData urlData = m_RequestMap[requestId]; string value; if (urlData.requests[requestId].headers.TryGetValue(header,out value)) return value; @@ -295,6 +302,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); } + return String.Empty; } @@ -339,6 +347,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { RemoveUrl(url.Value); removeURLs.Add(url.Key); + foreach (UUID req in url.Value.requests.Keys) m_RequestMap.Remove(req); } @@ -349,20 +358,31 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp } } - private void RemoveUrl(UrlData data) { - m_HttpServer.RemoveHTTPHandler("", "/lslhttp/"+data.urlcode.ToString()+"/"); + m_HttpServer.RemoveHTTPHandler("", "/lslhttp/" + data.urlcode.ToString() + "/"); } private Hashtable NoEvents(UUID requestID, UUID sessionID) { Hashtable response = new Hashtable(); UrlData url; + lock (m_RequestMap) { + // We need to return a 404 here in case the request URL was removed at exactly the same time that a + // request was made. In this case, the request thread can outrace llRemoveURL() and still be polling + // for the request ID. if (!m_RequestMap.ContainsKey(requestID)) + { + response["int_response_code"] = 404; + response["str_response_string"] = ""; + response["keepalive"] = false; + response["reusecontext"] = false; + return response; + } + url = m_RequestMap[requestID]; } @@ -384,53 +404,57 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return response; } - return response; } private bool HasEvents(UUID requestID, UUID sessionID) { - UrlData url=null; + UrlData url = null; lock (m_RequestMap) { + // We return true here because an external URL request that happened at the same time as an llRemoveURL() + // can still make it through to HttpRequestHandler(). That will return without setting up a request + // when it detects that the URL has been removed. The poller, however, will continue to ask for + // events for that request, so here we will signal that there are events and in GetEvents we will + // return a 404. if (!m_RequestMap.ContainsKey(requestID)) { - return false; + return true; } + url = m_RequestMap[requestID]; if (!url.requests.ContainsKey(requestID)) { - return false; + return true; } } - if (System.Environment.TickCount-url.requests[requestID].startTime>25000) + // Trigger return of timeout response. + if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) { return true; } - if (url.requests[requestID].requestDone) - return true; - else - return false; - + return url.requests[requestID].requestDone; } + private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) { - UrlData url = null; + UrlData url = null; RequestData requestData = null; lock (m_RequestMap) { if (!m_RequestMap.ContainsKey(requestID)) - return NoEvents(requestID,sessionID); + return NoEvents(requestID, sessionID); + url = m_RequestMap[requestID]; requestData = url.requests[requestID]; } if (!requestData.requestDone) - return NoEvents(requestID,sessionID); + return NoEvents(requestID, sessionID); Hashtable response = new Hashtable(); @@ -443,6 +467,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp response["reusecontext"] = false; return response; } + //put response response["int_response_code"] = requestData.responseCode; response["str_response_string"] = requestData.responseBody; @@ -459,6 +484,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return response; } + public void HttpRequestHandler(UUID requestID, Hashtable request) { lock (request) @@ -483,11 +509,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp pathInfo = uri.Substring(pos3); - UrlData url = null; - if (!is_ssl) - url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp]; - else - url = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp]; + UrlData urlData = null; + + lock (m_UrlMap) + { + string url; + + if (is_ssl) + url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; + else + url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; + + // Avoid a race - the request URL may have been released via llRequestUrl() whilst this + // request was being processed. + if (!m_UrlMap.TryGetValue(url, out urlData)) + return; + } //for llGetHttpHeader support we need to store original URI here //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers @@ -520,11 +557,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp queryString = queryString + key + "=" + val + "&"; } } + if (queryString.Length > 1) queryString = queryString.Substring(0, queryString.Length - 1); - } - } //if this machine is behind DNAT/port forwarding, currently this is being @@ -532,26 +568,28 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp requestData.headers["x-remote-ip"] = requestData.headers["remote_addr"]; requestData.headers["x-path-info"] = pathInfo; requestData.headers["x-query-string"] = queryString; - requestData.headers["x-script-url"] = url.url; + requestData.headers["x-script-url"] = urlData.url; //requestData.ev = new ManualResetEvent(false); - lock (url.requests) + lock (urlData.requests) { - url.requests.Add(requestID, requestData); - } - lock (m_RequestMap) - { - //add to request map - m_RequestMap.Add(requestID, url); + urlData.requests.Add(requestID, requestData); } - url.engine.PostScriptEvent(url.itemID, "http_request", new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); + lock (m_RequestMap) + { + m_RequestMap.Add(requestID, urlData); + } + + urlData.engine.PostScriptEvent( + urlData.itemID, + "http_request", + new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); //send initial response? // Hashtable response = new Hashtable(); return; - } catch (Exception we) { From 78143769bfdf316bbec63e6232bf9be993eb078a Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 22 Jun 2012 23:49:52 +0100 Subject: [PATCH 7/7] Resolve various race conditions between accessing and removing external script URLs by more consistently locking on m_UrlMap --- .../Scripting/LSLHttp/UrlModule.cs | 280 +++++++++--------- 1 file changed, 148 insertions(+), 132 deletions(-) diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 5c05500718..05d54f03a2 100644 --- a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs +++ b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs @@ -41,13 +41,39 @@ using OpenSim.Region.Framework.Scenes; namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { + /// + /// Data describing an external URL set up by a script. + /// public class UrlData { + /// + /// Scene object part hosting the script + /// public UUID hostID; + + /// + /// The item ID of the script that requested the URL. + /// public UUID itemID; + + /// + /// The script engine that runs the script. + /// public IScriptModule engine; + + /// + /// The generated URL. + /// public string url; + + /// + /// The random UUID component of the generated URL. + /// public UUID urlcode; + + /// + /// The external requests currently being processed or awaiting retrieval for this URL. + /// public Dictionary requests; } @@ -77,6 +103,10 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp /// Indexs the URL request metadata (which script requested it, outstanding requests, etc.) by the request ID /// randomly generated when a request is received for this URL. /// + /// + /// Manipulation or retrieval from this dictionary must be locked on m_UrlMap to preserve consistency with + /// m_UrlMap + /// private Dictionary m_RequestMap = new Dictionary(); /// @@ -113,10 +143,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp { m_ExternalHostNameForLSL = config.Configs["Network"].GetString("ExternalHostNameForLSL", System.Environment.MachineName); bool ssl_enabled = config.Configs["Network"].GetBoolean("https_listener",false); + if (ssl_enabled) - { https_port = (uint) config.Configs["Network"].GetInt("https_port",0); - } IConfig llFunctionsConfig = config.Configs["LL-Functions"]; @@ -275,32 +304,38 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void HttpResponse(UUID request, int status, string body) { - if (m_RequestMap.ContainsKey(request)) + lock (m_UrlMap) { - UrlData urlData = m_RequestMap[request]; - urlData.requests[request].responseCode = status; - urlData.requests[request].responseBody = body; - //urlData.requests[request].ev.Set(); - urlData.requests[request].requestDone =true; - } - else - { - m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString()); + if (m_RequestMap.ContainsKey(request)) + { + UrlData urlData = m_RequestMap[request]; + urlData.requests[request].responseCode = status; + urlData.requests[request].responseBody = body; + //urlData.requests[request].ev.Set(); + urlData.requests[request].requestDone =true; + } + else + { + m_log.Info("[HttpRequestHandler] There is no http-in request with id " + request.ToString()); + } } } public string GetHttpHeader(UUID requestId, string header) { - if (m_RequestMap.ContainsKey(requestId)) + lock (m_UrlMap) { - UrlData urlData = m_RequestMap[requestId]; - string value; - if (urlData.requests[requestId].headers.TryGetValue(header,out value)) - return value; - } - else - { - m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); + if (m_RequestMap.ContainsKey(requestId)) + { + UrlData urlData = m_RequestMap[requestId]; + string value; + if (urlData.requests[requestId].headers.TryGetValue(header, out value)) + return value; + } + else + { + m_log.Warn("[HttpRequestHandler] There was no http-in request with id " + requestId); + } } return String.Empty; @@ -308,7 +343,8 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public int GetFreeUrls() { - return m_TotalUrls - m_UrlMap.Count; + lock (m_UrlMap) + return m_TotalUrls - m_UrlMap.Count; } public void ScriptRemoved(UUID itemID) @@ -366,9 +402,9 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp private Hashtable NoEvents(UUID requestID, UUID sessionID) { Hashtable response = new Hashtable(); - UrlData url; + UrlData urlData; - lock (m_RequestMap) + lock (m_UrlMap) { // We need to return a 404 here in case the request URL was removed at exactly the same time that a // request was made. In this case, the request thread can outrace llRemoveURL() and still be polling @@ -383,25 +419,22 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return response; } - url = m_RequestMap[requestID]; - } + urlData = m_RequestMap[requestID]; - if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) - { - response["int_response_code"] = 500; - response["str_response_string"] = "Script timeout"; - response["content_type"] = "text/plain"; - response["keepalive"] = false; - response["reusecontext"] = false; - - //remove from map - lock (url) + if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000) { - url.requests.Remove(requestID); + response["int_response_code"] = 500; + response["str_response_string"] = "Script timeout"; + response["content_type"] = "text/plain"; + response["keepalive"] = false; + response["reusecontext"] = false; + + //remove from map + urlData.requests.Remove(requestID); m_RequestMap.Remove(requestID); - } - return response; + return response; + } } return response; @@ -409,9 +442,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp private bool HasEvents(UUID requestID, UUID sessionID) { - UrlData url = null; - - lock (m_RequestMap) + lock (m_UrlMap) { // We return true here because an external URL request that happened at the same time as an llRemoveURL() // can still make it through to HttpRequestHandler(). That will return without setting up a request @@ -423,61 +454,61 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp return true; } - url = m_RequestMap[requestID]; - if (!url.requests.ContainsKey(requestID)) + UrlData urlData = m_RequestMap[requestID]; + + if (!urlData.requests.ContainsKey(requestID)) { return true; } - } - // Trigger return of timeout response. - if (System.Environment.TickCount - url.requests[requestID].startTime > 25000) - { - return true; - } + // Trigger return of timeout response. + if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000) + { + return true; + } - return url.requests[requestID].requestDone; + return urlData.requests[requestID].requestDone; + } } private Hashtable GetEvents(UUID requestID, UUID sessionID, string request) { - UrlData url = null; - RequestData requestData = null; + Hashtable response; - lock (m_RequestMap) + lock (m_UrlMap) { + UrlData url = null; + RequestData requestData = null; + if (!m_RequestMap.ContainsKey(requestID)) return NoEvents(requestID, sessionID); url = m_RequestMap[requestID]; requestData = url.requests[requestID]; - } - if (!requestData.requestDone) - return NoEvents(requestID, sessionID); - - Hashtable response = new Hashtable(); + if (!requestData.requestDone) + return NoEvents(requestID, sessionID); - if (System.Environment.TickCount - requestData.startTime > 25000) - { - response["int_response_code"] = 500; - response["str_response_string"] = "Script timeout"; + response = new Hashtable(); + + if (System.Environment.TickCount - requestData.startTime > 25000) + { + response["int_response_code"] = 500; + response["str_response_string"] = "Script timeout"; + response["content_type"] = "text/plain"; + response["keepalive"] = false; + response["reusecontext"] = false; + return response; + } + + //put response + response["int_response_code"] = requestData.responseCode; + response["str_response_string"] = requestData.responseBody; response["content_type"] = "text/plain"; response["keepalive"] = false; response["reusecontext"] = false; - return response; - } - //put response - response["int_response_code"] = requestData.responseCode; - response["str_response_string"] = requestData.responseBody; - response["content_type"] = "text/plain"; - response["keepalive"] = false; - response["reusecontext"] = false; - - //remove from map - lock (url) - { + //remove from map url.requests.Remove(requestID); m_RequestMap.Remove(requestID); } @@ -487,44 +518,41 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp public void HttpRequestHandler(UUID requestID, Hashtable request) { - lock (request) - { - string uri = request["uri"].ToString(); - bool is_ssl = uri.Contains("lslhttps"); + string uri = request["uri"].ToString(); + bool is_ssl = uri.Contains("lslhttps"); - try - { - Hashtable headers = (Hashtable)request["headers"]; + try + { + Hashtable headers = (Hashtable)request["headers"]; // string uri_full = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri;// "/lslhttp/" + urlcode.ToString() + "/"; - int pos1 = uri.IndexOf("/");// /lslhttp - int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ - int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp// - string uri_tmp = uri.Substring(0, pos3 + 1); - //HTTP server code doesn't provide us with QueryStrings - string pathInfo; - string queryString; - queryString = ""; + int pos1 = uri.IndexOf("/");// /lslhttp + int pos2 = uri.IndexOf("/", pos1 + 1);// /lslhttp/ + int pos3 = uri.IndexOf("/", pos2 + 1);// /lslhttp// + string uri_tmp = uri.Substring(0, pos3 + 1); + //HTTP server code doesn't provide us with QueryStrings + string pathInfo; + string queryString; + queryString = ""; - pathInfo = uri.Substring(pos3); + pathInfo = uri.Substring(pos3); - UrlData urlData = null; + UrlData urlData = null; - lock (m_UrlMap) - { - string url; + lock (m_UrlMap) + { + string url; - if (is_ssl) - url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; - else - url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; + if (is_ssl) + url = "https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp; + else + url = "http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.Port.ToString() + uri_tmp; - // Avoid a race - the request URL may have been released via llRequestUrl() whilst this - // request was being processed. - if (!m_UrlMap.TryGetValue(url, out urlData)) - return; - } + // Avoid a race - the request URL may have been released via llRequestUrl() whilst this + // request was being processed. + if (!m_UrlMap.TryGetValue(url, out urlData)) + return; //for llGetHttpHeader support we need to store original URI here //to make x-path-info / x-query-string / x-script-url / x-remote-ip headers @@ -544,6 +572,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp string value = (string)header.Value; requestData.headers.Add(key, value); } + foreach (DictionaryEntry de in request) { if (de.Key.ToString() == "querystringkeys") @@ -570,34 +599,21 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp requestData.headers["x-query-string"] = queryString; requestData.headers["x-script-url"] = urlData.url; - //requestData.ev = new ManualResetEvent(false); - lock (urlData.requests) - { - urlData.requests.Add(requestID, requestData); - } - - lock (m_RequestMap) - { - m_RequestMap.Add(requestID, urlData); - } - - urlData.engine.PostScriptEvent( - urlData.itemID, - "http_request", - new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); - - //send initial response? -// Hashtable response = new Hashtable(); - - return; - } - catch (Exception we) - { - //Hashtable response = new Hashtable(); - m_log.Warn("[HttpRequestHandler]: http-in request failed"); - m_log.Warn(we.Message); - m_log.Warn(we.StackTrace); + urlData.requests.Add(requestID, requestData); + m_RequestMap.Add(requestID, urlData); } + + urlData.engine.PostScriptEvent( + urlData.itemID, + "http_request", + new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); + } + catch (Exception we) + { + //Hashtable response = new Hashtable(); + m_log.Warn("[HttpRequestHandler]: http-in request failed"); + m_log.Warn(we.Message); + m_log.Warn(we.StackTrace); } } @@ -606,4 +622,4 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp ScriptRemoved(itemID); } } -} +} \ No newline at end of file