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/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/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; } diff --git a/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs b/OpenSim/Region/CoreModules/Scripting/LSLHttp/UrlModule.cs index 61afc762e2..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; } @@ -64,17 +90,29 @@ 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. + /// + /// + /// Manipulation or retrieval from this dictionary must be locked on m_UrlMap to preserve consistency with + /// m_UrlMap + /// + 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. @@ -105,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"]; @@ -224,7 +261,6 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp urlData.urlcode = urlcode; urlData.requests = new Dictionary(); - m_UrlMap[url] = urlData; string uri = "/lslhttps/" + urlcode.ToString() + "/"; @@ -268,39 +304,47 @@ 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; } public int GetFreeUrls() { - return m_TotalUrls - m_UrlMap.Count; + lock (m_UrlMap) + return m_TotalUrls - m_UrlMap.Count; } public void ScriptRemoved(UUID itemID) @@ -339,6 +383,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,145 +394,165 @@ 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) + UrlData urlData; + + 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 + // for the request ID. if (!m_RequestMap.ContainsKey(requestID)) - return response; - url = 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) { - url.requests.Remove(requestID); - m_RequestMap.Remove(requestID); + response["int_response_code"] = 404; + response["str_response_string"] = ""; + response["keepalive"] = false; + response["reusecontext"] = false; + + return response; } - return response; + urlData = m_RequestMap[requestID]; + + if (System.Environment.TickCount - urlData.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 + urlData.requests.Remove(requestID); + m_RequestMap.Remove(requestID); + + return response; + } } - return response; } 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 + // 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)) + + UrlData urlData = m_RequestMap[requestID]; + + if (!urlData.requests.ContainsKey(requestID)) { - return false; + return true; } + + // Trigger return of timeout response. + if (System.Environment.TickCount - urlData.requests[requestID].startTime > 25000) + { + return true; + } + + return urlData.requests[requestID].requestDone; } - - if (System.Environment.TickCount-url.requests[requestID].startTime>25000) - { - return true; - } - - if (url.requests[requestID].requestDone) - return true; - else - return false; - } + 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); + 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); } return response; } + 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 url = null; - if (!is_ssl) - url = m_UrlMap["http://" + m_ExternalHostNameForLSL + ":" + m_HttpServer.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 = m_UrlMap["https://" + m_ExternalHostNameForLSL + ":" + m_HttpsServer.Port.ToString() + uri_tmp]; + 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 @@ -507,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") @@ -520,11 +586,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,34 +597,23 @@ 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.ev = new ManualResetEvent(false); - lock (url.requests) - { - url.requests.Add(requestID, requestData); - } - lock (m_RequestMap) - { - //add to request map - m_RequestMap.Add(requestID, url); - } - - url.engine.PostScriptEvent(url.itemID, "http_request", new Object[] { requestID.ToString(), request["http-method"].ToString(), request["body"].ToString() }); - - //send initial response? -// Hashtable response = new Hashtable(); - - return; + requestData.headers["x-script-url"] = urlData.url; + urlData.requests.Add(requestID, requestData); + m_RequestMap.Add(requestID, urlData); } - 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.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); } } @@ -568,4 +622,4 @@ namespace OpenSim.Region.CoreModules.Scripting.LSLHttp ScriptRemoved(itemID); } } -} +} \ No newline at end of file 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; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index e961e76b6c..25b27b90c5 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -853,15 +853,9 @@ 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); - - 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; @@ -874,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 @@ -889,12 +885,13 @@ 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; + m_InitialStartup = false; return null; } @@ -1366,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; + } } } 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 @@ - +