diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index b6776f29ab..da0ce79480 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs @@ -593,14 +593,26 @@ namespace OpenSim.Framework.Servers case "text/xml": case "application/xml": default: + // Point of note.. the DoWeHaveA methods check for an EXACT path + if (request.RawUrl.Contains("/CAPS/EQG")) + { + int i = 1; + } if (DoWeHaveALLSDHandler(request.RawUrl)) { - // Check if we have a LLSD handler here for the EXACT path. HandleLLSDRequests(request, response); - return; } + + if (DoWeHaveAHTTPHandler(request.RawUrl)) + { + HandleHTTPRequest(request, response); + return; + } + + // generic login request. HandleXmlRpcRequests(request, response); + return; } } @@ -846,11 +858,21 @@ namespace OpenSim.Framework.Servers { llsdResponse = GenerateNoLLSDHandlerResponse(); } + byte[] buffer = new byte[0]; + if (llsdResponse.ToString() == "shutdown404!") + { + response.ContentType = "text/plain"; + response.StatusCode = 404; + response.StatusDescription = "Not Found"; + response.ProtocolVersion = "HTTP/1.0"; + buffer = Encoding.UTF8.GetBytes("Not found"); + } + else + { + response.ContentType = "application/llsd+xml"; - response.ContentType = "application/llsd+xml"; - - byte[] buffer = LLSDParser.SerializeXmlBytes(llsdResponse); - + buffer = LLSDParser.SerializeXmlBytes(llsdResponse); + } response.SendChunked = false; response.ContentLength64 = buffer.Length; response.ContentEncoding = Encoding.UTF8; @@ -878,6 +900,11 @@ namespace OpenSim.Framework.Servers } } + /// + /// Checks if we have an Exact path in the LLSD handlers for the path provided + /// + /// URI of the request + /// true if we have one, false if not private bool DoWeHaveALLSDHandler(string path) { @@ -907,6 +934,59 @@ namespace OpenSim.Framework.Servers } } + // extra kicker to remove the default XMLRPC login case.. just in case.. + if (path != "/" && bestMatch == "/" && searchquery != "/") + return false; + + if (path == "/") + return false; + + if (String.IsNullOrEmpty(bestMatch)) + { + + return false; + } + else + { + + return true; + } + } + + /// + /// Checks if we have an Exact path in the HTTP handlers for the path provided + /// + /// URI of the request + /// true if we have one, false if not + private bool DoWeHaveAHTTPHandler(string path) + { + + string[] pathbase = path.Split('/'); + string searchquery = "/"; + + if (pathbase.Length < 1) + return false; + + for (int i = 1; i < pathbase.Length; i++) + { + searchquery += pathbase[i]; + if (pathbase.Length - 1 != i) + searchquery += "/"; + } + + string bestMatch = null; + + foreach (string pattern in m_HTTPHandlers.Keys) + { + + if (searchquery.StartsWith(pattern) && searchquery.Length >= pattern.Length) + { + + bestMatch = pattern; + + } + } + // extra kicker to remove the default XMLRPC login case.. just in case.. if (path == "/") return false; @@ -1074,7 +1154,7 @@ namespace OpenSim.Framework.Servers Encoding encoding = Encoding.UTF8; StreamReader reader = new StreamReader(requestStream, encoding); - //string requestBody = reader.ReadToEnd(); + string requestBody = reader.ReadToEnd(); // avoid warning for now reader.ReadToEnd(); reader.Close(); @@ -1087,6 +1167,10 @@ namespace OpenSim.Framework.Servers string[] querystringkeys = request.QueryString.AllKeys; string[] rHeaders = request.Headers.AllKeys; + keysvals.Add("body", requestBody); + keysvals.Add("uri", request.RawUrl); + keysvals.Add("content-type", request.ContentType); + foreach (string queryname in querystringkeys) { @@ -1113,8 +1197,8 @@ namespace OpenSim.Framework.Servers bool foundHandler = TryGetHTTPHandler(method, out requestprocessor); if (foundHandler) { - Hashtable responsedata = requestprocessor(keysvals); - DoHTTPGruntWork(responsedata,response); + Hashtable responsedata1 = requestprocessor(keysvals); + DoHTTPGruntWork(responsedata1,response); //SendHTML500(response); } @@ -1126,8 +1210,83 @@ namespace OpenSim.Framework.Servers } else { - //m_log.Warn("[HTTP]: No Method specified"); - SendHTML404(response, host); + + GenericHTTPMethod requestprocessor; + bool foundHandler = TryGetHTTPHandlerPathBased(request.RawUrl, out requestprocessor); + if (foundHandler) + { + Hashtable responsedata2 = requestprocessor(keysvals); + DoHTTPGruntWork(responsedata2, response); + + //SendHTML500(response); + } + else + { + //m_log.Warn("[HTTP]: Handler Not Found"); + SendHTML404(response, host); + } + } + } + + private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler) + { + httpHandler = null; + // Pull out the first part of the path + // splitting the path by '/' means we'll get the following return.. + // {0}/{1}/{2} + // where {0} isn't something we really control 100% + + string[] pathbase = path.Split('/'); + string searchquery = "/"; + + if (pathbase.Length < 1) + return false; + + for (int i = 1; i < pathbase.Length; i++) + { + searchquery += pathbase[i]; + if (pathbase.Length - 1 != i) + searchquery += "/"; + } + + // while the matching algorithm below doesn't require it, we're expecting a query in the form + // + // [] = optional + // /resource/UUID/action[/action] + // + // now try to get the closest match to the reigstered path + // at least for OGP, registered path would probably only consist of the /resource/ + + string bestMatch = null; + + foreach (string pattern in m_HTTPHandlers.Keys) + { + if (searchquery.ToLower().StartsWith(pattern.ToLower())) + { + if (String.IsNullOrEmpty(bestMatch) || searchquery.Length > bestMatch.Length) + { + // You have to specifically register for '/' and to get it, you must specificaly request it + // + if (pattern == "/" && searchquery == "/" || pattern != "/") + bestMatch = pattern; + } + } + } + + + + if (String.IsNullOrEmpty(bestMatch)) + { + httpHandler = null; + return false; + } + else + { + if (bestMatch == "/" && searchquery != "/") + return false; + + httpHandler = m_HTTPHandlers[bestMatch]; + return true; } } @@ -1342,6 +1501,11 @@ namespace OpenSim.Framework.Servers public void RemoveHTTPHandler(string httpMethod, string path) { + if (httpMethod != null && httpMethod.Length == 0) + { + m_HTTPHandlers.Remove(path); + return; + } m_HTTPHandlers.Remove(GetHandlerKey(httpMethod, path)); } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs index f56c0bfa79..c20c7bcffe 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLUDPServer.cs @@ -449,7 +449,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP else { //MainLog.Instance.Verbose("UDPSERVER", "SendPacketTo : client " + sendto.ToString()); - m_socket.SendTo(buffer, size, flags, sendto); + try + { + m_socket.SendTo(buffer, size, flags, sendto); + } + catch (SocketException SockE) + { + m_log.ErrorFormat("[UDPSERVER]: Caught Socket Error in the send buffer!. {0}",SockE.ToString()); + } } } } diff --git a/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs b/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs index 1726ea2d37..2eb1618c43 100644 --- a/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs +++ b/OpenSim/Region/Environment/Modules/Framework/EventQueueGetModule.cs @@ -90,7 +90,8 @@ namespace OpenSim.Region.Environment.Modules.Framework // Register fallback handler // Why does EQG Fail on region crossings! - scene.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); + + //scene.AddLLSDHandler("/CAPS/EQG/", EventQueueFallBack); scene.EventManager.OnNewClient += OnNewClient; scene.EventManager.OnClientClosed += ClientClosed; @@ -109,7 +110,7 @@ namespace OpenSim.Region.Environment.Modules.Framework private void ReadConfigAndPopulate(Scene scene, IConfig startupConfig, string p) { - enabledYN = startupConfig.GetBoolean("EventQueue", false); + enabledYN = startupConfig.GetBoolean("EventQueue", true); } public void PostInitialise() @@ -166,6 +167,44 @@ namespace OpenSim.Region.Environment.Modules.Framework private void ClientClosed(UUID AgentID) { queues.Remove(AgentID); + List removeitems = new List(); + lock (m_AvatarQueueUUIDMapping) + { + foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys) + { + if (ky == AgentID) + { + removeitems.Add(ky); + } + } + + foreach (UUID ky in removeitems) + { + m_AvatarQueueUUIDMapping.Remove(ky); + m_scene.RemoveHTTPHandler("","/CAPS/EQG/" + ky.ToString() + "/"); + } + + } + UUID searchval = UUID.Zero; + + removeitems.Clear(); + + lock (m_QueueUUIDAvatarMapping) + { + foreach (UUID ky in m_QueueUUIDAvatarMapping.Keys) + { + searchval = m_QueueUUIDAvatarMapping[ky]; + + if (searchval == AgentID) + { + removeitems.Add(ky); + } + } + + foreach (UUID ky in removeitems) + m_QueueUUIDAvatarMapping.Remove(ky); + + } m_log.DebugFormat("[EVENTQUEUE]: Client {0} deregistered in region {1}.", AgentID, m_scene.RegionInfo.RegionName); } @@ -177,15 +216,15 @@ namespace OpenSim.Region.Environment.Modules.Framework private void MakeChildAgent(ScenePresence avatar) { - m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); - lock (m_ids) - { - if (m_ids.ContainsKey(avatar.UUID)) - { + //m_log.DebugFormat("[EVENTQUEUE]: Make Child agent {0} in region {1}.", avatar.UUID, m_scene.RegionInfo.RegionName); + //lock (m_ids) + // { + //if (m_ids.ContainsKey(avatar.UUID)) + //{ // close the event queue. //m_ids[avatar.UUID] = -1; - } - } + //} + //} } public void OnRegisterCaps(UUID agentID, Caps caps) @@ -222,12 +261,18 @@ namespace OpenSim.Region.Environment.Modules.Framework } m_log.DebugFormat("[EVENTQUEUE]: CAPS URL: {0}", capsBase + EventQueueGetUUID.ToString() + "/"); + // Register this as a caps handler caps.RegisterHandler("EventQueueGet", - new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString(), + new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/", delegate(Hashtable m_dhttpMethod) { return ProcessQueue(m_dhttpMethod,agentID, caps); })); + + bool boolval = false; + // This will persist this beyond the expiry of the caps handlers + boolval = m_scene.AddHTTPHandler(capsBase + EventQueueGetUUID.ToString() + "/", EventQueuePath2); + Random rnd = new Random(System.Environment.TickCount); lock (m_ids) { @@ -262,6 +307,14 @@ namespace OpenSim.Region.Environment.Modules.Framework if (element == null) { + if (thisID == -1) // close-request + { + responsedata["int_response_code"] = 404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = ""; + return responsedata; + } responsedata["int_response_code"] = 502; responsedata["content_type"] = "text/plain"; responsedata["keepalive"] = false; @@ -272,6 +325,7 @@ namespace OpenSim.Region.Environment.Modules.Framework } + LLSDArray array = new LLSDArray(); if (element == null) // didn't have an event in 15s { @@ -306,6 +360,59 @@ namespace OpenSim.Region.Environment.Modules.Framework return responsedata; } + + public Hashtable EventQueuePath2(Hashtable request) + { + string capuuid = (string)request["uri"]; //path.Replace("/CAPS/EQG/",""); + // pull off the last "/" in the path. + Hashtable responsedata = new Hashtable(); + capuuid = capuuid.Substring(0, capuuid.Length - 1); + capuuid = capuuid.Replace("/CAPS/EQG/", ""); + UUID AvatarID = UUID.Zero; + UUID capUUID = UUID.Zero; + + // parse the path and search for the avatar with it registered + if (UUID.TryParse(capuuid, out capUUID)) + { + lock (m_QueueUUIDAvatarMapping) + { + if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) + { + AvatarID = m_QueueUUIDAvatarMapping[capUUID]; + } + } + if (AvatarID != UUID.Zero) + { + // m_scene.GetCapsHandlerForUser will return null if the agent doesn't have a caps handler + // registered + return ProcessQueue(request, AvatarID, m_scene.GetCapsHandlerForUser(AvatarID)); + } + else + { + responsedata["int_response_code"] = 404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "Not Found"; + responsedata["error_status_text"] = "Not Found"; + responsedata["http_protocol_version"] = "HTTP/1.0"; + return responsedata; + // return 404 + } + } + else + { + responsedata["int_response_code"] = 404; + responsedata["content_type"] = "text/plain"; + responsedata["keepalive"] = false; + responsedata["str_response_string"] = "Not Found"; + responsedata["error_status_text"] = "Not Found"; + responsedata["http_protocol_version"] = "HTTP/1.0"; + return responsedata; + // return 404 + } + + } + public LLSD EventQueueFallBack(string path, LLSD request, string endpoint) { // This is a fallback element to keep the client from loosing EventQueueGet @@ -318,7 +425,9 @@ namespace OpenSim.Region.Environment.Modules.Framework UUID capUUID = UUID.Zero; if (UUID.TryParse(capuuid, out capUUID)) { - +/* Don't remove this yet code cleaners! + * Still testing this! + * lock (m_QueueUUIDAvatarMapping) { if (m_QueueUUIDAvatarMapping.ContainsKey(capUUID)) @@ -326,8 +435,28 @@ namespace OpenSim.Region.Environment.Modules.Framework AvatarID = m_QueueUUIDAvatarMapping[capUUID]; } } + + if (AvatarID != UUID.Zero) { + // Repair the CAP! + //OpenSim.Framework.Communications.Capabilities.Caps caps = m_scene.GetCapsHandlerForUser(AvatarID); + //string capsBase = "/CAPS/EQG/"; + //caps.RegisterHandler("EventQueueGet", + //new RestHTTPHandler("POST", capsBase + capUUID.ToString() + "/", + //delegate(Hashtable m_dhttpMethod) + //{ + // return ProcessQueue(m_dhttpMethod, AvatarID, caps); + //})); + // start new ID sequence. + Random rnd = new Random(System.Environment.TickCount); + lock (m_ids) + { + if (!m_ids.ContainsKey(AvatarID)) + m_ids.Add(AvatarID, rnd.Next(30000000)); + } + + int thisID = 0; lock (m_ids) thisID = m_ids[AvatarID]; @@ -365,11 +494,14 @@ namespace OpenSim.Region.Environment.Modules.Framework { return new LLSD(); } +* +*/ } else { - return new LLSD(); + //return new LLSD(); } + return new LLSDString("shutdown404!"); } } } diff --git a/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs b/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs index 9a522ffd7f..1a15585951 100644 --- a/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs +++ b/OpenSim/Region/Environment/Modules/World/WorldMap/MapSearchModule.cs @@ -83,7 +83,12 @@ namespace OpenSim.Region.Environment.Modules.World.WorldMap // TODO currently, this only returns one region per name. LL servers will return all starting with the provided name. RegionInfo info = m_scene.SceneGridService.RequestClosestRegion(mapName); // fetch the mapblock of the named sim. We need this anyway (we have the map open, and just jumped to the sim), - // so there shouldn't be any penalty for that. + // so there shouldn't be any penalty for that. + if (info == null) + { + m_log.Warn("[MAPSEARCHMODULE]: Got Null Region Question!"); + return; + } List mapBlocks = m_scene.SceneGridService.RequestNeighbourMapBlocks((int)info.RegionLocX, (int)info.RegionLocY, (int)info.RegionLocX, diff --git a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs index 3f3a68d092..c33c777a48 100644 --- a/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs +++ b/OpenSim/Region/Environment/Scenes/SceneCommunicationService.cs @@ -608,6 +608,8 @@ namespace OpenSim.Region.Environment.Scenes { bool destRegionUp = false; + IEventQueue eq = avatar.Scene.RequestModuleInterface(); + if (regionHandle == m_regionInfo.RegionHandle) { // Teleport within the same region @@ -628,7 +630,12 @@ namespace OpenSim.Region.Environment.Scenes { position.Z = newPosZ; } - avatar.ControllingClient.SendTeleportLocationStart(); + + // Only send this if the event queue is null + if (eq == null) + avatar.ControllingClient.SendTeleportLocationStart(); + + avatar.ControllingClient.SendLocalTeleport(position, lookAt, teleportFlags); avatar.Teleport(position); } @@ -637,7 +644,9 @@ namespace OpenSim.Region.Environment.Scenes RegionInfo reg = RequestNeighbouringRegionInfo(regionHandle); if (reg != null) { - avatar.ControllingClient.SendTeleportLocationStart(); + if (eq == null) + avatar.ControllingClient.SendTeleportLocationStart(); + AgentCircuitData agent = avatar.ControllingClient.RequestClientInfo(); agent.BaseFolder = UUID.Zero; agent.InventoryFolder = UUID.Zero; @@ -687,7 +696,7 @@ namespace OpenSim.Region.Environment.Scenes m_log.DebugFormat( "[CAPS]: Sending new CAPS seed url {0} to client {1}", capsPath, avatar.UUID); - IEventQueue eq = avatar.Scene.RequestModuleInterface(); + if (eq != null) { LLSD Item = EventQueueHelper.TeleportFinishEvent(reg.RegionHandle, 13, reg.ExternalEndPoint, diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index eb2b4aa1fc..9caffee3e9 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -4,8 +4,8 @@ ; Set this to false if you are running OpenSimulator in standalone mode gridmode = false -; Experimental! Enables EventQueueGet which is highly broken right now. -EventQueue = false +; Enables EventQueueGet Service. +EventQueue = true ; ## ; ## REGIONS