From 8de395d379ba3278b2160b66dd8da7f973a2cf10 Mon Sep 17 00:00:00 2001
From: Teravus Ovares
Date: Fri, 3 Oct 2008 09:53:49 +0000
Subject: * EventQueueGet is now working. * Switched it on by default * Updated
OpenSim.ini.example to reflect this * Caught a UDP Server issue that occurs
when the network pipe is saturated * Still experimental :D
---
OpenSim/Framework/Servers/BaseHttpServer.cs | 184 +++++++++++++++++++--
.../Region/ClientStack/LindenUDP/LLUDPServer.cs | 9 +-
.../Modules/Framework/EventQueueGetModule.cs | 156 +++++++++++++++--
.../Modules/World/WorldMap/MapSearchModule.cs | 7 +-
.../Scenes/SceneCommunicationService.cs | 15 +-
bin/OpenSim.ini.example | 4 +-
6 files changed, 346 insertions(+), 29 deletions(-)
diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs
index b6776f2..da0ce79 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)
{
@@ -908,6 +935,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,26 @@ 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);
+ }
+ else
+ {
+ //m_log.Warn("[HTTP]: Handler Not Found");
+ SendHTML404(response, host);
+ }
+ }
+ else
+ {
+
+ GenericHTTPMethod requestprocessor;
+ bool foundHandler = TryGetHTTPHandlerPathBased(request.RawUrl, out requestprocessor);
+ if (foundHandler)
+ {
+ Hashtable responsedata2 = requestprocessor(keysvals);
+ DoHTTPGruntWork(responsedata2, response);
//SendHTML500(response);
}
@@ -1124,10 +1226,67 @@ namespace OpenSim.Framework.Servers
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
{
- //m_log.Warn("[HTTP]: No Method specified");
- SendHTML404(response, host);
+ 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 f56c0bf..c20c7bc 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 1726ea2..2eb1618 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 9a522ff..1a15585 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 3f3a68d..c33c777 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 eb2b4aa..9caffee 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
--
cgit v1.1