diff --git a/OpenMetaverse.Http/CapsServer.cs b/OpenMetaverse.Http/CapsServer.cs
index 71b81af0..26eb21f2 100644
--- a/OpenMetaverse.Http/CapsServer.cs
+++ b/OpenMetaverse.Http/CapsServer.cs
@@ -34,19 +34,31 @@ using HttpServer;
namespace OpenMetaverse.Http
{
+ ///
+ /// Delegate for handling incoming HTTP requests through a capability
+ ///
+ /// Client context
+ /// HTTP request
+ /// HTTP response
+ /// User-defined state object
+ /// True to send the response and close the connection, false to leave the connection open
+ public delegate bool CapsRequestCallback(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state);
+
public class CapsServer
{
struct CapsRedirector
{
- public HttpRequestCallback LocalCallback;
+ public CapsRequestCallback LocalCallback;
public Uri RemoteHandler;
public bool ClientCertRequired;
+ public object State;
- public CapsRedirector(HttpRequestCallback localCallback, Uri remoteHandler, bool clientCertRequired)
+ public CapsRedirector(CapsRequestCallback localCallback, Uri remoteHandler, bool clientCertRequired, object state)
{
LocalCallback = localCallback;
RemoteHandler = remoteHandler;
ClientCertRequired = clientCertRequired;
+ State = state;
}
}
@@ -60,7 +72,7 @@ namespace OpenMetaverse.Http
public CapsServer(IPAddress address, int port)
{
serverOwned = true;
- capsHandler = BuildCapsHandler("^/");
+ capsHandler = BuildCapsHandler(@"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
server = new WebServer(address, port);
server.LogWriter = new log4netLogWriter(Logger.Log);
}
@@ -68,7 +80,7 @@ namespace OpenMetaverse.Http
public CapsServer(IPAddress address, int port, X509Certificate sslCertificate, X509Certificate rootCA, bool requireClientCertificate)
{
serverOwned = true;
- capsHandler = BuildCapsHandler("^/");
+ capsHandler = BuildCapsHandler(@"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
server = new WebServer(address, port, sslCertificate, rootCA, requireClientCertificate);
server.LogWriter = new log4netLogWriter(Logger.Log);
}
@@ -96,10 +108,10 @@ namespace OpenMetaverse.Http
server.RemoveHandler(capsHandler);
}
- public UUID CreateCapability(HttpRequestCallback localHandler, bool clientCertRequired)
+ public UUID CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state)
{
UUID id = UUID.Random();
- CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired);
+ CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired, state);
lock (syncRoot)
fixedCaps.Add(id, redirector);
@@ -110,7 +122,7 @@ namespace OpenMetaverse.Http
public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired)
{
UUID id = UUID.Random();
- CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired);
+ CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired, null);
lock (syncRoot)
fixedCaps.Add(id, redirector);
@@ -118,10 +130,10 @@ namespace OpenMetaverse.Http
return id;
}
- public UUID CreateCapability(HttpRequestCallback localHandler, bool clientCertRequired, double ttlSeconds)
+ public UUID CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state, double ttlSeconds)
{
UUID id = UUID.Random();
- CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired);
+ CapsRedirector redirector = new CapsRedirector(localHandler, null, clientCertRequired, state);
lock (syncRoot)
expiringCaps.Add(id, redirector, DateTime.Now + TimeSpan.FromSeconds(ttlSeconds));
@@ -129,10 +141,10 @@ namespace OpenMetaverse.Http
return id;
}
- public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired, double ttlSeconds)
+ public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired, object state, double ttlSeconds)
{
UUID id = UUID.Random();
- CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired);
+ CapsRedirector redirector = new CapsRedirector(null, remoteHandler, clientCertRequired, state);
lock (syncRoot)
expiringCaps.Add(id, redirector, DateTime.Now + TimeSpan.FromSeconds(ttlSeconds));
@@ -156,9 +168,10 @@ namespace OpenMetaverse.Http
UUID capsID;
CapsRedirector redirector;
bool success;
- string uuidString = request.UriParts[request.UriParts.Length - 1];
- if (UUID.TryParse(uuidString, out capsID))
+ string path = request.Uri.PathAndQuery.TrimEnd('/');
+
+ if (UUID.TryParse(path.Substring(path.Length - 36), out capsID))
{
lock (syncRoot)
success = (expiringCaps.TryGetValue(capsID, out redirector) || fixedCaps.TryGetValue(capsID, out redirector));
@@ -179,7 +192,7 @@ namespace OpenMetaverse.Http
if (redirector.RemoteHandler != null)
ProxyCapCallback(client, request, response, redirector.RemoteHandler);
else
- return redirector.LocalCallback(client, request, response);
+ return redirector.LocalCallback(client, request, response, redirector.State);
return true;
}
@@ -234,7 +247,7 @@ namespace OpenMetaverse.Http
}
}
- HttpServer.HttpRequestHandler BuildCapsHandler(string path)
+ HttpRequestHandler BuildCapsHandler(string path)
{
HttpRequestSignature signature = new HttpRequestSignature();
signature.ContentType = "application/xml";
diff --git a/OpenMetaverse.Http/EventQueueServer.cs b/OpenMetaverse.Http/EventQueueServer.cs
index 57d1d7ba..6e092bb0 100644
--- a/OpenMetaverse.Http/EventQueueServer.cs
+++ b/OpenMetaverse.Http/EventQueueServer.cs
@@ -108,15 +108,15 @@ namespace OpenMetaverse.Http
eventQueue.Enqueue(events[i]);
}
- public bool EventQueueHandler(ref HttpListenerContext context)
+ public bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response)
{
// Decode the request
- OSD request = null;
+ OSD osdRequest = null;
- try { request = OSDParser.DeserializeLLSDXml(context.Request.InputStream); }
+ try { osdRequest = OSDParser.DeserializeLLSDXml(request.Body); }
catch (Exception) { }
- if (request != null && request.Type == OSDType.Map)
+ if (request != null && osdRequest.Type == OSDType.Map)
{
OSDMap requestMap = (OSDMap)request;
int ack = requestMap["ack"].AsInteger();
@@ -130,7 +130,7 @@ namespace OpenMetaverse.Http
if (!done)
{
- StartEventQueueThread(context);
+ StartEventQueueThread(context, request, response);
// Tell HttpServer to leave the connection open
return false;
@@ -138,25 +138,25 @@ namespace OpenMetaverse.Http
else
{
Logger.Log.InfoFormat("[EventQueue] Shutting down the event queue {0} at the client's request",
- context.Request.Url);
+ request.Uri);
Stop();
- context.Response.KeepAlive = context.Request.KeepAlive;
+ response.Connection = request.Connection;
return true;
}
}
else
{
Logger.Log.WarnFormat("[EventQueue] Received a request with invalid or missing LLSD at {0}, closing the connection",
- context.Request.Url);
+ request.Uri);
- context.Response.KeepAlive = context.Request.KeepAlive;
- context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
+ response.Connection = request.Connection;
+ response.Status = HttpStatusCode.BadRequest;
return true;
}
}
- void StartEventQueueThread(HttpListenerContext httpContext)
+ void StartEventQueueThread(IHttpClientContext context, IHttpRequest request, IHttpResponse response)
{
// Spawn a new thread to hold the connection open and return from our precious IOCP thread
Thread thread = new Thread(new ThreadStart(
@@ -188,7 +188,7 @@ namespace OpenMetaverse.Http
batchMsPassed = (int)(DateTime.Now - start).TotalMilliseconds;
}
- SendResponse(httpContext, eventsToSend);
+ SendResponse(context, request, response, eventsToSend);
return;
}
else
@@ -202,7 +202,7 @@ namespace OpenMetaverse.Http
Logger.Log.DebugFormat(
"[EventQueue] {0}ms passed without an event, timing out the event queue",
totalMsPassed);
- SendResponse(httpContext, null);
+ SendResponse(context, request, response, null);
return;
}
}
@@ -215,9 +215,9 @@ namespace OpenMetaverse.Http
thread.Start();
}
- void SendResponse(HttpListenerContext httpContext, List eventsToSend)
+ void SendResponse(IHttpClientContext context, IHttpRequest request, IHttpResponse response, List eventsToSend)
{
- httpContext.Response.KeepAlive = httpContext.Request.KeepAlive;
+ response.Connection = request.Connection;
if (eventsToSend != null)
{
@@ -241,19 +241,19 @@ namespace OpenMetaverse.Http
// Serialize the events and send the response
byte[] buffer = OSDParser.SerializeLLSDXmlBytes(responseMap);
- httpContext.Response.ContentType = "application/xml";
- httpContext.Response.ContentLength64 = buffer.Length;
- httpContext.Response.OutputStream.Write(buffer, 0, buffer.Length);
- httpContext.Response.OutputStream.Close();
- httpContext.Response.Close();
+ response.ContentType = "application/xml";
+ response.ContentLength = buffer.Length;
+ response.Body.Write(buffer, 0, buffer.Length);
+ response.Body.Flush();
}
else
{
// The 502 response started as a bug in the LL event queue server implementation,
// but is now hardcoded into the protocol as the code to use for a timeout
- httpContext.Response.StatusCode = (int)HttpStatusCode.BadGateway;
- httpContext.Response.Close();
+ response.Status = HttpStatusCode.BadGateway;
}
+
+ response.Send();
}
}
}
diff --git a/OpenMetaverse.StructuredData/JSON/OSDJson.cs b/OpenMetaverse.StructuredData/JSON/OSDJson.cs
index 0dcda91d..5323f62b 100644
--- a/OpenMetaverse.StructuredData/JSON/OSDJson.cs
+++ b/OpenMetaverse.StructuredData/JSON/OSDJson.cs
@@ -132,12 +132,14 @@ namespace OpenMetaverse.StructuredData
return new JsonData("b64::" + Convert.ToBase64String(osd.AsBinary()));
case OSDType.Array:
JsonData jsonarray = new JsonData();
+ jsonarray.SetJsonType(JsonType.Array);
OSDArray array = (OSDArray)osd;
for (int i = 0; i < array.Count; i++)
jsonarray.Add(SerializeJson(array[i]));
return jsonarray;
case OSDType.Map:
JsonData jsonmap = new JsonData();
+ jsonmap.SetJsonType(JsonType.Object);
OSDMap map = (OSDMap)osd;
foreach (KeyValuePair kvp in map)
jsonmap[kvp.Key] = SerializeJson(kvp.Value);
diff --git a/Programs/Simian/Extensions/AssetManager.cs b/Programs/Simian/Extensions/AssetManager.cs
index 453ad841..22c9a40f 100644
--- a/Programs/Simian/Extensions/AssetManager.cs
+++ b/Programs/Simian/Extensions/AssetManager.cs
@@ -23,12 +23,12 @@ namespace Simian.Extensions
{
this.server = server;
- UploadDir = Path.Combine(server.DataDir, UPLOAD_DIR);
+ UploadDir = Path.Combine(Simian.DATA_DIR, UPLOAD_DIR);
// Try to create the data directories if they don't already exist
- if (!Directory.Exists(server.DataDir))
+ if (!Directory.Exists(Simian.DATA_DIR))
{
- try { Directory.CreateDirectory(server.DataDir); }
+ try { Directory.CreateDirectory(Simian.DATA_DIR); }
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex); }
}
if (!Directory.Exists(UploadDir))
@@ -37,7 +37,7 @@ namespace Simian.Extensions
catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Warning, ex); }
}
- LoadAssets(server.DataDir);
+ LoadAssets(Simian.DATA_DIR);
LoadAssets(UploadDir);
}
diff --git a/Programs/Simian/Extensions/AvatarManager.cs b/Programs/Simian/Extensions/AvatarManager.cs
index 601fe106..edcad733 100644
--- a/Programs/Simian/Extensions/AvatarManager.cs
+++ b/Programs/Simian/Extensions/AvatarManager.cs
@@ -106,26 +106,6 @@ namespace Simian.Extensions
server.UDP.BroadcastPacket(sound, PacketCategory.State);
}
- public void Disconnect(Agent agent)
- {
- // Remove the avatar from the scene
- SimulationObject obj;
- if (server.Scene.TryGetObject(agent.Avatar.ID, out obj))
- server.Scene.ObjectRemove(this, obj.Prim.LocalID);
- else
- Logger.Log("Disconnecting an agent that is not in the scene", Helpers.LogLevel.Warning);
-
- // Remove the UDP client
- server.UDP.RemoveClient(agent);
-
- // HACK: Notify everyone when someone disconnects
- OfflineNotificationPacket offline = new OfflineNotificationPacket();
- offline.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[1];
- offline.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
- offline.AgentBlock[0].AgentID = agent.Avatar.ID;
- server.UDP.BroadcastPacket(offline, PacketCategory.State);
- }
-
public void SendAlert(Agent agent, string message)
{
AlertMessagePacket alert = new AlertMessagePacket();
@@ -450,8 +430,16 @@ namespace Simian.Extensions
update.Index.Prey = -1;
update.Index.You = 0;
- update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[agentDatas.Count - 1];
- update.Location = new CoarseLocationUpdatePacket.LocationBlock[agentDatas.Count - 1];
+ // Count the number of blocks to send out
+ int count = 0;
+ for (int i = 0; i < agentDatas.Count; i++)
+ {
+ if (agentDatas[i].AgentID != agent.Avatar.ID)
+ ++count;
+ }
+
+ update.AgentData = new CoarseLocationUpdatePacket.AgentDataBlock[count];
+ update.Location = new CoarseLocationUpdatePacket.LocationBlock[count];
int j = 0;
for (int i = 0; i < agentDatas.Count; i++)
diff --git a/Programs/Simian/Extensions/CapsManager.cs b/Programs/Simian/Extensions/CapsManager.cs
index 20a16716..b0314cf6 100644
--- a/Programs/Simian/Extensions/CapsManager.cs
+++ b/Programs/Simian/Extensions/CapsManager.cs
@@ -13,7 +13,6 @@ namespace Simian.Extensions
{
Simian server;
CapsServer capsServer;
- Dictionary eventQueues = new Dictionary();
public CapsManager()
{
@@ -22,47 +21,45 @@ namespace Simian.Extensions
public void Start(Simian server)
{
this.server = server;
- capsServer = new CapsServer(server.HttpServer, @"^/caps/");
+ capsServer = new CapsServer(server.HttpServer, @"^/caps/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");
+ capsServer.Start();
}
public void Stop()
{
- lock (eventQueues)
- {
- foreach (EventQueueServer eventQueue in eventQueues.Values)
- eventQueue.Stop();
- }
-
capsServer.Stop();
}
- public UUID CreateCapability(HttpServer.HttpRequestCallback localHandler, bool clientCertRequired)
+ public Uri CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state)
{
- return capsServer.CreateCapability(localHandler, clientCertRequired);
+ UUID capID = capsServer.CreateCapability(localHandler, clientCertRequired, state);
+ return new Uri(
+ (server.SSL ? "https://" : "http://") +
+ server.HostName +
+ (server.HttpPort == 80 ? String.Empty : ":" + server.HttpPort) +
+ "/caps/" + capID.ToString());
}
- public UUID CreateCapability(Uri remoteHandler, bool clientCertRequired)
+ public Uri CreateCapability(Uri remoteHandler, bool clientCertRequired)
{
- return capsServer.CreateCapability(remoteHandler, clientCertRequired);
+ UUID capID = capsServer.CreateCapability(remoteHandler, clientCertRequired);
+ return new Uri(
+ (server.SSL ? "https://" : "http://") +
+ server.HostName +
+ (server.HttpPort == 80 ? String.Empty : ":" + server.HttpPort) +
+ "/caps/" + capID.ToString());
}
- public bool RemoveCapability(UUID capID)
+ public bool RemoveCapability(Uri cap)
{
- return capsServer.RemoveCapability(capID);
- }
+ string path = cap.PathAndQuery.TrimEnd('/');
+ UUID capID;
- public void SendEvent(Agent agent, string name, OSDMap body)
- {
- EventQueueServer eventQueue;
- if (eventQueues.TryGetValue(agent.Avatar.ID, out eventQueue))
- {
- eventQueue.SendEvent(name, body);
- }
+ // Parse the capability UUID out of the URI
+ if (UUID.TryParse(path.Substring(path.Length - 36), out capID))
+ return capsServer.RemoveCapability(capID);
else
- {
- Logger.Log(String.Format("Cannot send the event {0} to agent {1} {2}, no event queue for that avatar",
- name, agent.FirstName, agent.LastName), Helpers.LogLevel.Warning);
- }
+ return false;
}
}
}
diff --git a/Programs/Simian/Extensions/ConnectionManagement.cs b/Programs/Simian/Extensions/ConnectionManagement.cs
index 055962da..5cd906e8 100644
--- a/Programs/Simian/Extensions/ConnectionManagement.cs
+++ b/Programs/Simian/Extensions/ConnectionManagement.cs
@@ -82,7 +82,7 @@ namespace Simian.Extensions
server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
- server.Avatars.Disconnect(agent);
+ server.Scene.ObjectRemove(this, agent.Avatar.ID);
}
}
}
diff --git a/Programs/Simian/Extensions/LindenLogin.cs b/Programs/Simian/Extensions/LindenLogin.cs
index e9e49bbe..293e0927 100644
--- a/Programs/Simian/Extensions/LindenLogin.cs
+++ b/Programs/Simian/Extensions/LindenLogin.cs
@@ -141,10 +141,16 @@ namespace Simian.Extensions
if (responseData.Success)
responseData.InventorySkeleton = server.Inventory.CreateInventorySkeleton(responseData.AgentID);
- XmlWriter writer = XmlWriter.Create(response.Body);
- responseData.ToXmlRpc(writer);
- writer.Flush();
- writer.Close();
+ MemoryStream memoryStream = new MemoryStream();
+ using (XmlWriter writer = XmlWriter.Create(memoryStream))
+ {
+ responseData.ToXmlRpc(writer);
+ writer.Flush();
+ }
+
+ response.ContentLength = memoryStream.Length;
+ response.Body.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
+ response.Body.Flush();
}
catch (Exception ex)
{
@@ -178,6 +184,9 @@ namespace Simian.Extensions
// Authentication successful, create a login instance of this agent
agent = server.Accounts.CreateInstance(agentID);
+ // Create a seed capability for this agent
+ Uri seedCap = server.Capabilities.CreateCapability(server.Scene.SeedCapabilityHandler, false, agentID);
+
if (agent != null)
{
// Assign a circuit code and insert the agent into the unassociatedAgents dictionary
@@ -217,8 +226,7 @@ namespace Simian.Extensions
response.RegionY = regionY;
response.SecondsSinceEpoch = DateTime.Now;
- // FIXME: Actually generate a seed capability
- response.SeedCapability = String.Format("http://{0}:{1}/seed_caps", simIP, server.HttpPort);
+ response.SeedCapability = seedCap.ToString();
response.SimIP = simIP;
response.SimPort = (ushort)server.UDPPort;
response.StartLocation = "last"; // FIXME:
diff --git a/Programs/Simian/Extensions/MapLocal.cs b/Programs/Simian/Extensions/MapLocal.cs
index 1664b4e6..fa669a7f 100644
--- a/Programs/Simian/Extensions/MapLocal.cs
+++ b/Programs/Simian/Extensions/MapLocal.cs
@@ -1,10 +1,24 @@
using System;
+using System.IO;
+using System.Net;
+using System.Xml;
using ExtensionLoader;
using OpenMetaverse;
using OpenMetaverse.Packets;
+using OpenMetaverse.StructuredData;
namespace Simian.Extensions
{
+ class HyperGridLink
+ {
+ public string RegionName;
+ public ulong RegionHandle;
+ public UUID RegionID;
+ public UUID RegionImage;
+ public int UDPPort;
+ public int RemotingPort;
+ }
+
public class MapLocal : IExtension
{
Simian server;
@@ -84,6 +98,8 @@ namespace Simian.Extensions
{
TeleportRequestPacket request = (TeleportRequestPacket)packet;
+ // TODO: Stand the avatar up first
+
if (request.Info.RegionID == server.Scene.RegionID)
{
// Local teleport
@@ -102,7 +118,11 @@ namespace Simian.Extensions
}
else
{
- Logger.Log("Ignoring teleport request to " + request.Info.RegionID, Helpers.LogLevel.Warning);
+ TeleportFailedPacket reply = new TeleportFailedPacket();
+ reply.Info.AgentID = agent.Avatar.ID;
+ reply.Info.Reason = Utils.StringToBytes("Unknown region");
+
+ server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
}
}
@@ -110,6 +130,8 @@ namespace Simian.Extensions
{
TeleportLocationRequestPacket request = (TeleportLocationRequestPacket)packet;
+ // TODO: Stand the avatar up first
+
if (request.Info.RegionHandle == server.Scene.RegionHandle)
{
// Local teleport
@@ -126,10 +148,410 @@ namespace Simian.Extensions
server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
}
+ else if (request.Info.RegionHandle == Utils.UIntsToLong((server.Scene.RegionX + 1) * 256, server.Scene.RegionY * 256))
+ {
+ // Special case: adjacent simulator is the HyperGrid portal
+ HyperGridTeleport(agent, new Uri(/*"http://192.168.1.2:9010/"*/ "http://osl2.nac.uci.edu:9006/"), request.Info.Position);
+ }
else
{
- Logger.Log("Ignoring teleport request to " + request.Info.RegionHandle, Helpers.LogLevel.Warning);
+ TeleportFailedPacket reply = new TeleportFailedPacket();
+ reply.Info.AgentID = agent.Avatar.ID;
+ reply.Info.Reason = Utils.StringToBytes("Unknown region");
+
+ server.UDP.SendPacket(agent.Avatar.ID, reply, PacketCategory.Transaction);
}
}
+
+ bool HyperGridTeleport(Agent agent, Uri destination, Vector3 destPos)
+ {
+ HyperGridLink link;
+
+ TeleportProgress(agent, "Resolving destination IP address", TeleportFlags.ViaLocation);
+
+ IPHostEntry entry = Dns.GetHostEntry(destination.DnsSafeHost);
+ if (entry.AddressList != null && entry.AddressList.Length >= 1)
+ {
+ TeleportProgress(agent, "Retrieving destination details", TeleportFlags.ViaLocation);
+
+ if (LinkRegion(destination, out link))
+ {
+ TeleportProgress(agent, "Creating foreign agent", TeleportFlags.ViaLocation);
+
+ if (ExpectHyperGridUser(agent, destination, destPos, link))
+ {
+ TeleportProgress(agent, "Establishing foreign agent presence", TeleportFlags.ViaLocation);
+
+ // This is a crufty part of the HyperGrid protocol. We need to generate a fragment of a UUID
+ // (missing the last four digits) and send that as the caps_path variable. Locally, we expand
+ // that out to http://foreignsim:httpport/CAPS/fragment0000/ and use it as the seed caps path
+ // that is sent to the client
+ UUID seedID = UUID.Random();
+ string seedCapFragment = seedID.ToString().Substring(0, 32);
+ Uri seedCap = new Uri(destination, "/CAPS/" + seedCapFragment + "0000/");
+
+ if (CreateChildAgent(agent, destination, destPos, link, seedCapFragment))
+ {
+ // Send the final teleport packet to the client
+ TeleportFinishPacket teleport = new TeleportFinishPacket();
+ teleport.Info.AgentID = agent.Avatar.ID;
+ teleport.Info.LocationID = 0; // Unused by the client
+ teleport.Info.RegionHandle = link.RegionHandle;
+ teleport.Info.SeedCapability = Utils.StringToBytes(seedCap.ToString());
+ teleport.Info.SimAccess = (byte)SimAccess.Min;
+ teleport.Info.SimIP = Utils.BytesToUInt(entry.AddressList[0].GetAddressBytes());
+ teleport.Info.SimPort = (ushort)link.UDPPort;
+ teleport.Info.TeleportFlags = (uint)TeleportFlags.ViaLocation;
+
+ server.UDP.SendPacket(agent.Avatar.ID, teleport, PacketCategory.Transaction);
+
+ // Remove the agent from the local scene (will also tear down the UDP connection)
+ //server.Scene.ObjectRemove(this, agent.Avatar.ID);
+
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ }
+
+ bool LinkRegion(Uri destination, out HyperGridLink link)
+ {
+ try
+ {
+ #region Build Request
+
+ HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
+ request.Method = "POST";
+ request.ContentType = "text/xml";
+
+ MemoryStream memoryStream = new MemoryStream();
+ using (XmlWriter writer = XmlWriter.Create(memoryStream))
+ {
+ writer.WriteStartElement("methodCall");
+ {
+ writer.WriteElementString("methodName", "link_region");
+
+ writer.WriteStartElement("params");
+ writer.WriteStartElement("param");
+ writer.WriteStartElement("value");
+ writer.WriteStartElement("struct");
+ {
+ WriteStringMember(writer, "region_name", String.Empty);
+ }
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ }
+ writer.WriteEndElement();
+
+ writer.Flush();
+ }
+
+ request.ContentLength = memoryStream.Length;
+
+ using (Stream writeStream = request.GetRequestStream())
+ {
+ writeStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
+ }
+
+ #endregion Build Request
+
+ #region Parse Response
+
+ HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+
+ XmlReaderSettings settings = new XmlReaderSettings();
+ settings.IgnoreComments = true;
+ settings.IgnoreWhitespace = true;
+
+ using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
+ {
+ link = new HyperGridLink();
+
+ reader.ReadStartElement("methodResponse");
+ {
+ reader.ReadStartElement("params");
+ reader.ReadStartElement("param");
+ reader.ReadStartElement("value");
+ reader.ReadStartElement("struct");
+ {
+ while (reader.Name == "member")
+ {
+ reader.ReadStartElement("member");
+ {
+ string name = reader.ReadElementContentAsString("name", String.Empty);
+
+ reader.ReadStartElement("value");
+ {
+ switch (name)
+ {
+ case "region_name":
+ link.RegionName = reader.ReadElementContentAsString("string", String.Empty);
+ break;
+ case "handle":
+ string handle = reader.ReadElementContentAsString("string", String.Empty);
+ link.RegionHandle = UInt64.Parse(handle);
+ break;
+ case "uuid":
+ string uuid = reader.ReadElementContentAsString("string", String.Empty);
+ link.RegionID = UUID.Parse(uuid);
+ break;
+ case "internal_port":
+ link.UDPPort = reader.ReadElementContentAsInt("string", String.Empty);
+ break;
+ case "region_image":
+ string imageuuid = reader.ReadElementContentAsString("string", String.Empty);
+ link.RegionImage = UUID.Parse(imageuuid);
+ break;
+ case "remoting_port":
+ link.RemotingPort = reader.ReadElementContentAsInt("string", String.Empty);
+ break;
+ default:
+ Logger.Log("[HyperGrid] Unrecognized response XML chunk: " + reader.ReadInnerXml(),
+ Helpers.LogLevel.Warning);
+ break;
+ }
+ }
+ reader.ReadEndElement();
+ }
+ reader.ReadEndElement();
+ }
+ }
+ reader.ReadEndElement();
+ reader.ReadEndElement();
+ reader.ReadEndElement();
+ reader.ReadEndElement();
+ }
+ reader.ReadEndElement();
+
+ return true;
+ }
+
+ #endregion Parse Response
+ }
+ catch (Exception ex)
+ {
+ Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
+ }
+
+ link = null;
+ return false;
+ }
+
+ bool ExpectHyperGridUser(Agent agent, Uri destination, Vector3 destPos, HyperGridLink link)
+ {
+ try
+ {
+ #region Build Request
+
+ HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
+ request.Method = "POST";
+ request.ContentType = "text/xml";
+
+ MemoryStream memoryStream = new MemoryStream();
+ using (XmlWriter writer = XmlWriter.Create(memoryStream))
+ {
+ writer.WriteStartElement("methodCall");
+ {
+ writer.WriteElementString("methodName", "expect_hg_user");
+
+ writer.WriteStartElement("params");
+ writer.WriteStartElement("param");
+ writer.WriteStartElement("value");
+ writer.WriteStartElement("struct");
+ {
+ WriteStringMember(writer, "session_id", agent.SessionID.ToString());
+ WriteStringMember(writer, "secure_session_id", agent.SecureSessionID.ToString());
+ WriteStringMember(writer, "firstname", agent.FirstName);
+ WriteStringMember(writer, "lastname", agent.LastName);
+ WriteStringMember(writer, "agent_id", agent.Avatar.ID.ToString());
+ WriteStringMember(writer, "circuit_code", agent.CircuitCode.ToString());
+ WriteStringMember(writer, "startpos_x", destPos.X.ToString(Utils.EnUsCulture));
+ WriteStringMember(writer, "startpos_y", destPos.Y.ToString(Utils.EnUsCulture));
+ WriteStringMember(writer, "startpos_z", destPos.Z.ToString(Utils.EnUsCulture));
+ WriteStringMember(writer, "caps_path", String.Empty);
+
+ WriteStringMember(writer, "region_uuid", link.RegionID.ToString());
+ //WriteStringMember(writer, "userserver_id", "");
+ //WriteStringMember(writer, "assetserver_id", "");
+ //WriteStringMember(writer, "inventoryserver_id", "");
+ WriteStringMember(writer, "root_folder_id", agent.InventoryRoot.ToString());
+
+ WriteStringMember(writer, "internal_port", server.HttpPort.ToString());
+ WriteStringMember(writer, "regionhandle", link.RegionHandle.ToString());
+ WriteStringMember(writer, "home_address", IPAddress.Loopback.ToString());
+ WriteStringMember(writer, "home_port", server.HttpPort.ToString());
+ WriteStringMember(writer, "home_remoting", server.HttpPort.ToString());
+ }
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ writer.WriteEndElement();
+ }
+ writer.WriteEndElement();
+
+ writer.Flush();
+ }
+
+ request.ContentLength = memoryStream.Length;
+
+ using (Stream writeStream = request.GetRequestStream())
+ {
+ writeStream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
+ }
+
+ #endregion Build Request
+
+ #region Parse Response
+
+ HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+
+ XmlReaderSettings settings = new XmlReaderSettings();
+ settings.IgnoreComments = true;
+ settings.IgnoreWhitespace = true;
+
+ using (XmlReader reader = XmlReader.Create(response.GetResponseStream(), settings))
+ {
+ bool success = false;
+ string reason = String.Empty;
+
+ reader.ReadStartElement("methodResponse");
+ {
+ reader.ReadStartElement("params");
+ reader.ReadStartElement("param");
+ reader.ReadStartElement("value");
+ reader.ReadStartElement("struct");
+ {
+ while (reader.Name == "member")
+ {
+ reader.ReadStartElement("member");
+ {
+ string name = reader.ReadElementContentAsString("name", String.Empty);
+
+ reader.ReadStartElement("value");
+ {
+ switch (name)
+ {
+ case "success":
+ success = (reader.ReadElementContentAsString("string", String.Empty).ToUpper() == "TRUE");
+ break;
+ case "reason":
+ reason = reader.ReadElementContentAsString("string", String.Empty);
+ break;
+ default:
+ Logger.Log("[HyperGrid] Unrecognized response XML chunk: " + reader.ReadInnerXml(),
+ Helpers.LogLevel.Warning);
+ break;
+ }
+ }
+ reader.ReadEndElement();
+ }
+ reader.ReadEndElement();
+ }
+ }
+ reader.ReadEndElement();
+ reader.ReadEndElement();
+ reader.ReadEndElement();
+ reader.ReadEndElement();
+ }
+ reader.ReadEndElement();
+
+ if (!success)
+ Logger.Log("[HyperGrid] Teleport failed, reason: " + reason, Helpers.LogLevel.Warning);
+
+ return success;
+ }
+
+ #endregion Parse Response
+ }
+ catch (Exception ex)
+ {
+ Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
+ }
+
+ return false;
+ }
+
+ bool CreateChildAgent(Agent agent, Uri destination, Vector3 destPos, HyperGridLink link, string seedCapFragment)
+ {
+ try
+ {
+ destination = new Uri(destination, "/agent/" + agent.Avatar.ID.ToString() + "/");
+
+ OSDMap args = new OSDMap();
+ args["agent_id"] = OSD.FromUUID(agent.Avatar.ID);
+ args["base_folder"] = OSD.FromUUID(UUID.Zero);
+ args["caps_path"] = OSD.FromString(seedCapFragment);
+ args["children_seeds"] = OSD.FromBoolean(false);
+ args["child"] = OSD.FromBoolean(false);
+ args["circuit_code"] = OSD.FromString(agent.CircuitCode.ToString());
+ args["first_name"] = OSD.FromString(agent.FirstName);
+ args["last_name"] = OSD.FromString(agent.LastName);
+ args["inventory_folder"] = OSD.FromUUID(agent.InventoryRoot);
+ args["secure_session_id"] = OSD.FromUUID(agent.SecureSessionID);
+ args["session_id"] = OSD.FromUUID(agent.SessionID);
+ args["start_pos"] = OSD.FromString(destPos.ToString());
+ args["destination_handle"] = OSD.FromString(link.RegionHandle.ToString());
+
+ LitJson.JsonData jsonData = OSDParser.SerializeJson(args);
+ byte[] data = System.Text.Encoding.UTF8.GetBytes(jsonData.ToJson());
+
+ HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(destination);
+ request.Method = "POST";
+ request.ContentType = "application/json";
+ request.ContentLength = data.Length;
+
+ using (Stream requestStream = request.GetRequestStream())
+ {
+ requestStream.Write(data, 0, data.Length);
+ requestStream.Flush();
+ }
+
+ HttpWebResponse response = (HttpWebResponse)request.GetResponse();
+
+ bool success = false;
+ using (StreamReader reader = new StreamReader(response.GetResponseStream()))
+ {
+ Boolean.TryParse(reader.ReadToEnd(), out success);
+ }
+
+ return success;
+ }
+ catch (Exception ex)
+ {
+ Logger.Log(ex.Message, Helpers.LogLevel.Error, ex);
+ }
+
+ return false;
+ }
+
+ void TeleportProgress(Agent agent, string message, TeleportFlags flags)
+ {
+ TeleportProgressPacket progress = new TeleportProgressPacket();
+ progress.AgentData.AgentID = agent.Avatar.ID;
+ progress.Info.Message = Utils.StringToBytes(message);
+ progress.Info.TeleportFlags = (uint)flags;
+
+ server.UDP.SendPacket(agent.Avatar.ID, progress, PacketCategory.Transaction);
+ }
+
+ static void WriteStringMember(XmlWriter writer, string name, string value)
+ {
+ writer.WriteStartElement("member");
+ {
+ writer.WriteElementString("name", name);
+
+ writer.WriteStartElement("value");
+ {
+ writer.WriteElementString("string", value);
+ }
+ writer.WriteEndElement();
+ }
+ writer.WriteEndElement();
+ }
}
}
diff --git a/Programs/Simian/Extensions/SceneManager.cs b/Programs/Simian/Extensions/SceneManager.cs
index 0019ecec..5ee7cf6c 100644
--- a/Programs/Simian/Extensions/SceneManager.cs
+++ b/Programs/Simian/Extensions/SceneManager.cs
@@ -3,22 +3,37 @@ using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
+using System.Net;
using System.Runtime.InteropServices;
using System.Threading;
using ExtensionLoader;
+using HttpServer;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using OpenMetaverse.Packets;
+using OpenMetaverse.StructuredData;
+using OpenMetaverse.Http;
namespace Simian.Extensions
{
-
+ class EventQueueServerCap
+ {
+ public EventQueueServer Server;
+ public Uri Capability;
+
+ public EventQueueServerCap(EventQueueServer server, Uri capability)
+ {
+ Server = server;
+ Capability = capability;
+ }
+ }
public class SceneManager : IExtension, ISceneProvider
{
Simian server;
DoubleDictionary sceneObjects = new DoubleDictionary();
DoubleDictionary sceneAgents = new DoubleDictionary();
+ Dictionary eventQueues = new Dictionary();
int currentLocalID = 1;
ulong regionHandle;
UUID regionID = UUID.Random();
@@ -57,11 +72,19 @@ namespace Simian.Extensions
this.server = server;
server.UDP.RegisterPacketCallback(PacketType.CompleteAgentMovement, new PacketCallback(CompleteAgentMovementHandler));
- LoadTerrain(server.DataDir + "heightmap.tga");
+ LoadTerrain(Simian.DATA_DIR + "heightmap.tga");
}
public void Stop()
{
+ lock (eventQueues)
+ {
+ foreach (EventQueueServerCap eventQueue in eventQueues.Values)
+ {
+ server.Capabilities.RemoveCapability(eventQueue.Capability);
+ eventQueue.Server.Stop();
+ }
+ }
}
public float[,] GetTerrainPatch(uint x, uint y)
@@ -150,14 +173,7 @@ namespace Simian.Extensions
if (OnAgentRemove != null)
OnAgentRemove(sender, agent);
- sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID);
-
- KillObjectPacket kill = new KillObjectPacket();
- kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
- kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
- kill.ObjectData[0].ID = agent.Avatar.LocalID;
-
- server.UDP.BroadcastPacket(kill, PacketCategory.State);
+ AgentRemove(agent);
return true;
}
else
@@ -193,14 +209,7 @@ namespace Simian.Extensions
if (OnAgentRemove != null)
OnAgentRemove(sender, agent);
- sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID);
-
- KillObjectPacket kill = new KillObjectPacket();
- kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
- kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
- kill.ObjectData[0].ID = agent.Avatar.LocalID;
-
- server.UDP.BroadcastPacket(kill, PacketCategory.State);
+ AgentRemove(agent);
return true;
}
else
@@ -210,6 +219,33 @@ namespace Simian.Extensions
}
}
+ void AgentRemove(Agent agent)
+ {
+ Logger.Log("Removing agent " + agent.FullName + " from the scene", Helpers.LogLevel.Info);
+
+ sceneAgents.Remove(agent.Avatar.LocalID, agent.Avatar.ID);
+
+ KillObjectPacket kill = new KillObjectPacket();
+ kill.ObjectData = new KillObjectPacket.ObjectDataBlock[1];
+ kill.ObjectData[0] = new KillObjectPacket.ObjectDataBlock();
+ kill.ObjectData[0].ID = agent.Avatar.LocalID;
+
+ server.UDP.BroadcastPacket(kill, PacketCategory.State);
+
+ // Kill the EventQueue
+ RemoveEventQueue(agent.Avatar.ID);
+
+ // Remove the UDP client
+ server.UDP.RemoveClient(agent);
+
+ // Notify everyone in the scene that this agent has gone offline
+ OfflineNotificationPacket offline = new OfflineNotificationPacket();
+ offline.AgentBlock = new OfflineNotificationPacket.AgentBlockBlock[1];
+ offline.AgentBlock[0] = new OfflineNotificationPacket.AgentBlockBlock();
+ offline.AgentBlock[0].AgentID = agent.Avatar.ID;
+ server.UDP.BroadcastPacket(offline, PacketCategory.State);
+ }
+
public void ObjectTransform(object sender, uint localID, Vector3 position, Quaternion rotation,
Vector3 velocity, Vector3 acceleration, Vector3 angularVelocity)
{
@@ -420,6 +456,87 @@ namespace Simian.Extensions
sceneAgents.ForEach(action);
}
+ public bool SeedCapabilityHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
+ {
+ UUID agentID = (UUID)state;
+
+ OSDArray array = OSDParser.DeserializeLLSDXml(request.Body) as OSDArray;
+ if (array != null)
+ {
+ OSDMap osdResponse = new OSDMap();
+
+ for (int i = 0; i < array.Count; i++)
+ {
+ string capName = array[i].AsString();
+
+ switch (capName)
+ {
+ case "EventQueueGet":
+ Uri eqCap = null;
+
+ // Check if this agent already has an event queue
+ EventQueueServerCap eqServer;
+ if (eventQueues.TryGetValue(agentID, out eqServer))
+ eqCap = eqServer.Capability;
+
+ // If not, create one
+ if (eqCap == null)
+ eqCap = CreateEventQueue(agentID);
+
+ osdResponse.Add("EventQueueGet", OSD.FromUri(eqCap));
+ break;
+ }
+ }
+
+ byte[] responseData = OSDParser.SerializeLLSDXmlBytes(osdResponse);
+ response.ContentLength = responseData.Length;
+ response.Body.Write(responseData, 0, responseData.Length);
+ response.Body.Flush();
+ }
+ else
+ {
+ response.Status = HttpStatusCode.BadRequest;
+ }
+
+ return true;
+ }
+
+ public Uri CreateEventQueue(UUID agentID)
+ {
+ EventQueueServer eqServer = new EventQueueServer(server.HttpServer);
+ EventQueueServerCap eqServerCap = new EventQueueServerCap(eqServer,
+ server.Capabilities.CreateCapability(EventQueueHandler, false, eqServer));
+
+ eventQueues.Add(agentID, eqServerCap);
+
+ return eqServerCap.Capability;
+ }
+
+ public bool RemoveEventQueue(UUID agentID)
+ {
+ return eventQueues.Remove(agentID);
+ }
+
+ public void SendEvent(Agent agent, string name, OSDMap body)
+ {
+ EventQueueServerCap eventQueue;
+ if (eventQueues.TryGetValue(agent.Avatar.ID, out eventQueue))
+ {
+ eventQueue.Server.SendEvent(name, body);
+ }
+ else
+ {
+ Logger.Log(String.Format("Cannot send the event {0} to agent {1}, no event queue for that avatar",
+ name, agent.FullName), Helpers.LogLevel.Warning);
+ }
+ }
+
+ bool EventQueueHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state)
+ {
+ EventQueueServer eqServer = (EventQueueServer)state;
+ return eqServer.EventQueueHandler(context, request, response);
+ }
+
void BroadcastObjectUpdate(Primitive prim)
{
ObjectUpdatePacket update =
diff --git a/Programs/Simian/Extensions/UDPManager.cs b/Programs/Simian/Extensions/UDPManager.cs
index ad08a93e..8c4132bc 100644
--- a/Programs/Simian/Extensions/UDPManager.cs
+++ b/Programs/Simian/Extensions/UDPManager.cs
@@ -186,7 +186,7 @@ namespace Simian
lock (unassociatedAgents)
unassociatedAgents[circuitCode] = agent;
- Logger.Log("Created a circuit for " + agent.FirstName, Helpers.LogLevel.Info);
+ Logger.Log("Created circuit " + circuitCode + " for " + agent.FirstName, Helpers.LogLevel.Info);
return circuitCode;
}
@@ -411,7 +411,7 @@ namespace Simian
Logger.Log(String.Format("Ack timeout for {0}, disconnecting", client.Agent.Avatar.Name),
Helpers.LogLevel.Warning);
- server.Avatars.Disconnect(client.Agent);
+ server.Scene.ObjectRemove(this, client.Agent.Avatar.ID);
return;
}
}
diff --git a/Programs/Simian/Extensions/XMLPersistence.cs b/Programs/Simian/Extensions/XMLPersistence.cs
index f3b60f65..62fc5c1c 100644
--- a/Programs/Simian/Extensions/XMLPersistence.cs
+++ b/Programs/Simian/Extensions/XMLPersistence.cs
@@ -24,7 +24,7 @@ namespace Simian.Extensions
try
{
- XmlTextReader reader = new XmlTextReader(File.OpenRead(server.DataDir + "simiandata.xml"));
+ XmlTextReader reader = new XmlTextReader(File.OpenRead(Simian.DATA_DIR + "simiandata.xml"));
osd = OSDParser.DeserializeLLSDXml(reader);
reader.Close();
}
@@ -76,7 +76,7 @@ namespace Simian.Extensions
try
{
- XmlTextWriter writer = new XmlTextWriter(server.DataDir + "simiandata.xml", System.Text.Encoding.UTF8);
+ XmlTextWriter writer = new XmlTextWriter(Simian.DATA_DIR + "simiandata.xml", System.Text.Encoding.UTF8);
writer.Formatting = Formatting.Indented;
writer.WriteStartElement("llsd");
OSDParser.SerializeLLSDXmlElement(writer, dictionary);
diff --git a/Programs/Simian/Interfaces/IAvatarProvider.cs b/Programs/Simian/Interfaces/IAvatarProvider.cs
index 05acfccf..e6046acd 100644
--- a/Programs/Simian/Interfaces/IAvatarProvider.cs
+++ b/Programs/Simian/Interfaces/IAvatarProvider.cs
@@ -10,7 +10,6 @@ namespace Simian
bool RemoveAnimation(Agent agent, UUID animID);
bool ClearAnimations(Agent agent);
void SendAnimations(Agent agent);
- void Disconnect(Agent agent);
void SendAlert(Agent agent, string message);
}
diff --git a/Programs/Simian/Interfaces/ICapabilitiesProvider.cs b/Programs/Simian/Interfaces/ICapabilitiesProvider.cs
index d37b7f59..63525464 100644
--- a/Programs/Simian/Interfaces/ICapabilitiesProvider.cs
+++ b/Programs/Simian/Interfaces/ICapabilitiesProvider.cs
@@ -8,10 +8,8 @@ namespace Simian
{
public interface ICapabilitiesProvider
{
- UUID CreateCapability(HttpRequestCallback localHandler, bool clientCertRequired);
- UUID CreateCapability(Uri remoteHandler, bool clientCertRequired);
- bool RemoveCapability(UUID capID);
-
- void SendEvent(Agent agent, string name, OSDMap body);
+ Uri CreateCapability(CapsRequestCallback localHandler, bool clientCertRequired, object state);
+ Uri CreateCapability(Uri remoteHandler, bool clientCertRequired);
+ bool RemoveCapability(Uri cap);
}
}
diff --git a/Programs/Simian/Interfaces/ISceneProvider.cs b/Programs/Simian/Interfaces/ISceneProvider.cs
index a44891d7..23a6bb8b 100644
--- a/Programs/Simian/Interfaces/ISceneProvider.cs
+++ b/Programs/Simian/Interfaces/ISceneProvider.cs
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
+using HttpServer;
using OpenMetaverse;
+using OpenMetaverse.StructuredData;
namespace Simian
{
@@ -76,5 +78,8 @@ namespace Simian
bool TryGetAgent(uint localID, out Agent agent);
bool TryGetAgent(UUID id, out Agent agent);
void ForEachAgent(Action action);
+
+ void SendEvent(Agent agent, string name, OSDMap body);
+ bool SeedCapabilityHandler(IHttpClientContext context, IHttpRequest request, IHttpResponse response, object state);
}
}
diff --git a/Programs/Simian/Simian.cs b/Programs/Simian/Simian.cs
index 67dcf3e4..eaeff543 100644
--- a/Programs/Simian/Simian.cs
+++ b/Programs/Simian/Simian.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Xml;
using System.Threading;
using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
using ExtensionLoader;
using ExtensionLoader.Config;
using HttpServer;
@@ -17,10 +18,12 @@ namespace Simian
public partial class Simian
{
public const string CONFIG_FILE = "Simian.ini";
+ public const string DATA_DIR = "SimianData/";
- public int UDPPort = 9000;
- public int HttpPort = 8002;
- public string DataDir = "SimianData/";
+ public int UDPPort { get { return 9000; } }
+ public int HttpPort { get { return 8002; } }
+ public bool SSL { get { return false; } }
+ public string HostName { get { return Dns.GetHostName(); } }
public WebServer HttpServer;
public IniConfigSource ConfigFile;
@@ -35,7 +38,7 @@ namespace Simian
public IInventoryProvider Inventory;
public IParcelProvider Parcels;
public IMeshingProvider Mesher;
- //public ICapabilitiesProvider Capabilities;
+ public ICapabilitiesProvider Capabilities;
// Persistent extensions
public List PersistentExtensions = new List();
@@ -61,7 +64,9 @@ namespace Simian
return false;
}
- InitHttpServer(HttpPort, true);
+ // TODO: SSL support
+ HttpServer = new WebServer(IPAddress.Any, HttpPort);
+ HttpServer.Start();
try
{
@@ -123,12 +128,5 @@ namespace Simian
HttpServer.Stop();
}
-
- void InitHttpServer(int port, bool ssl)
- {
- HttpServer = new WebServer(IPAddress.Any, port);
-
- HttpServer.Start();
- }
}
}
diff --git a/bin/Simian.ini b/bin/Simian.ini
index 91afc55c..47f6d92f 100644
--- a/bin/Simian.ini
+++ b/bin/Simian.ini
@@ -36,6 +36,10 @@ InventoryManager
; ---End Local Simulator Stores---
;
+; Manages creation and deletion of capabilities (see
+; http://wiki.secondlife.com/wiki/Capabilities for more information).
+CapsManager
+
; Various avatar-related functions including appearance, animations and sounds
AvatarManager