diff --git a/CONTRIBUTORS.txt b/CONTRIBUTORS.txt index a3413a1c53..8e49fad4fc 100644 --- a/CONTRIBUTORS.txt +++ b/CONTRIBUTORS.txt @@ -35,7 +35,7 @@ Patches * BigFootAg * CharlieO -* jhurliman (LLSD Login) +* jhurliman * kinoc (Daxtron Labs) * dmiles (Daxtron Labs) * daTwitch diff --git a/OpenSim/Framework/AgentCircuitManager.cs b/OpenSim/Framework/AgentCircuitManager.cs index 426e8e2ae1..80e2f87afd 100644 --- a/OpenSim/Framework/AgentCircuitManager.cs +++ b/OpenSim/Framework/AgentCircuitManager.cs @@ -103,10 +103,41 @@ namespace OpenSim.Framework AgentCircuits[(uint) agentData.circuitcode].firstname = agentData.firstname; AgentCircuits[(uint) agentData.circuitcode].lastname = agentData.lastname; AgentCircuits[(uint) agentData.circuitcode].startpos = agentData.startpos; + + // Updated for when we don't know them before calling Scene.NewUserConnection + AgentCircuits[(uint) agentData.circuitcode].SecureSessionID = agentData.SecureSessionID; + AgentCircuits[(uint) agentData.circuitcode].SessionID = agentData.SessionID; + // Console.WriteLine("update user start pos is " + agentData.startpos.X + " , " + agentData.startpos.Y + " , " + agentData.startpos.Z); } } + + /// + /// Sometimes the circuitcode may not be known before setting up the connection + /// + /// + /// + + public bool TryChangeCiruitCode(uint circuitcode, uint newcircuitcode) + { + lock (AgentCircuits) + { + if (AgentCircuits.ContainsKey((uint)circuitcode) && !AgentCircuits.ContainsKey((uint)newcircuitcode)) + { + AgentCircuitData agentData = AgentCircuits[(uint)circuitcode]; + + agentData.circuitcode = newcircuitcode; + + AgentCircuits.Remove((uint)circuitcode); + AgentCircuits.Add(newcircuitcode, agentData); + return true; + } + } + return false; + + } + public void UpdateAgentChildStatus(uint circuitcode, bool childstatus) { if (AgentCircuits.ContainsKey(circuitcode)) diff --git a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs index 4e3840b597..3b02c888b9 100644 --- a/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs +++ b/OpenSim/Framework/Communications/Cache/UserProfileCacheService.cs @@ -159,6 +159,31 @@ namespace OpenSim.Framework.Communications.Cache } } + /// + /// Preloads User data into the region cache. Modules may use this service to add non-standard clients + /// + /// + /// + public void PreloadUserCache(LLUUID userID, UserProfileData userData) + { + if (userID == LLUUID.Zero) + return; + + lock (m_userProfiles) + { + if (m_userProfiles.ContainsKey(userID)) + { + return; + } + else + { + + CachedUserInfo userInfo = new CachedUserInfo(m_commsManager, userData); + m_userProfiles.Add(userID, userInfo); + } + } + } + /// /// Handle an inventory folder creation request from the client. /// diff --git a/OpenSim/Framework/Communications/Capabilities/LLSDMethodString.cs b/OpenSim/Framework/Communications/Capabilities/LLSDMethodString.cs new file mode 100644 index 0000000000..31325d802c --- /dev/null +++ b/OpenSim/Framework/Communications/Capabilities/LLSDMethodString.cs @@ -0,0 +1,31 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +namespace OpenSim.Framework.Communications.Capabilities +{ + public delegate TResponse LLSDMethodString(TRequest request, string path); +} diff --git a/OpenSim/Framework/Communications/UserManagerBase.cs b/OpenSim/Framework/Communications/UserManagerBase.cs index fd02382896..a35ed725a2 100644 --- a/OpenSim/Framework/Communications/UserManagerBase.cs +++ b/OpenSim/Framework/Communications/UserManagerBase.cs @@ -339,6 +339,11 @@ namespace OpenSim.Framework.Communications public void ClearUserAgent(LLUUID agentID) { UserProfileData profile = GetUserProfile(agentID); + + if (profile == null) + { + return; + } profile.CurrentAgent = null; UpdateUserProfile(profile); diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index b2d13c7874..f43790252d 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -349,6 +349,11 @@ namespace OpenSim.Framework set; } + bool SendLogoutPacketWhenClosing + { + set; + } + // [Obsolete("LLClientView Specific - Circuits are unique to LLClientView")] uint CircuitCode { get; } // [Obsolete("LLClientView Specific - Replace with more bare-bones arguments.")] @@ -741,5 +746,6 @@ namespace OpenSim.Framework void SendRegionHandle(LLUUID regoinID, ulong handle); void SendParcelInfo(RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y); + void KillEndDone(); } } diff --git a/OpenSim/Framework/Servers/BaseHttpServer.cs b/OpenSim/Framework/Servers/BaseHttpServer.cs index 23c28e6328..7b2b599be6 100644 --- a/OpenSim/Framework/Servers/BaseHttpServer.cs +++ b/OpenSim/Framework/Servers/BaseHttpServer.cs @@ -47,8 +47,9 @@ namespace OpenSim.Framework.Servers protected Thread m_workerThread; protected HttpListener m_httpListener; - protected Dictionary m_rpcHandlers = new Dictionary(); - protected LLSDMethod m_llsdHandler = null; + protected Dictionary m_rpcHandlers = new Dictionary(); + protected DefaultLLSDMethod m_defaultLlsdHandler = null; // <-- Moving away from the monolithic.. and going to /registered/ + protected Dictionary m_llsdHandlers = new Dictionary(); protected Dictionary m_streamHandlers = new Dictionary(); protected Dictionary m_HTTPHandlers = new Dictionary(); protected Dictionary m_agentHandlers = new Dictionary(); @@ -148,9 +149,28 @@ namespace OpenSim.Framework.Servers return false; } - public bool SetLLSDHandler(LLSDMethod handler) + /// + /// Adds a LLSD handler, yay. + /// + /// /resource/ path + /// handle the LLSD response + /// + public bool AddLLSDHandler(string path, LLSDMethod handler) { - m_llsdHandler = handler; + lock (m_llsdHandlers) + { + if (!m_llsdHandlers.ContainsKey(path)) + { + m_llsdHandlers.Add(path, handler); + return true; + } + } + return false; + } + + public bool SetDefaultLLSDHandler(DefaultLLSDMethod handler) + { + m_defaultLlsdHandler = handler; return true; } @@ -239,20 +259,21 @@ namespace OpenSim.Framework.Servers switch (request.ContentType) { - case null: - case "text/html": - HandleHTTPRequest(request, response); - return; + case null: + case "text/html": + HandleHTTPRequest(request, response); + return; - case "application/xml+llsd": - HandleLLSDRequests(request, response); - return; + case "application/llsd+xml": + case "application/xml+llsd": + HandleLLSDRequests(request, response); + return; - case "text/xml": - case "application/xml": - default: - HandleXmlRpcRequests(request, response); - return; + case "text/xml": + case "application/xml": + default: + HandleXmlRpcRequests(request, response); + return; } } catch (SocketException e) @@ -456,17 +477,37 @@ namespace OpenSim.Framework.Servers m_log.Warn("[HTTPD]: Error - " + ex.Message); } - if (llsdRequest != null && m_llsdHandler != null) + if (llsdRequest != null)// && m_defaultLlsdHandler != null) { - llsdResponse = m_llsdHandler(llsdRequest); + + LLSDMethod llsdhandler = null; + + if (TryGetLLSDHandler(request.RawUrl, out llsdhandler)) + { + // we found a registered llsd handler to service this request + llsdResponse = llsdhandler(request.RawUrl, llsdRequest, request.RemoteIPEndPoint.ToString()); + } + else + { + // we didn't find a registered llsd handler to service this request + // check if we have a default llsd handler + + if (m_defaultLlsdHandler != null) + { + // LibOMV path + llsdResponse = m_defaultLlsdHandler(llsdRequest); + } + else + { + // Oops, no handler for this.. give em the failed message + llsdResponse = GenerateNoLLSDHandlerResponse(); + } + } + } else { - LLSDMap map = new LLSDMap(); - map["reason"] = LLSD.FromString("LLSDRequest"); - map["message"] = LLSD.FromString("No handler registered for LLSD Requests"); - map["login"] = LLSD.FromString("false"); - llsdResponse = map; + llsdResponse = GenerateNoLLSDHandlerResponse(); } response.ContentType = "application/xml+llsd"; @@ -491,6 +532,68 @@ namespace OpenSim.Framework.Servers } } + private bool TryGetLLSDHandler(string path, out LLSDMethod llsdHandler) + { + llsdHandler = 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 bestMatch.Length) + { + bestMatch = pattern; + } + } + } + + if (String.IsNullOrEmpty(bestMatch)) + { + llsdHandler = null; + return false; + } + else + { + llsdHandler = m_llsdHandlers[bestMatch]; + return true; + } + } + + private LLSDMap GenerateNoLLSDHandlerResponse() + { + LLSDMap map = new LLSDMap(); + map["reason"] = LLSD.FromString("LLSDRequest"); + map["message"] = LLSD.FromString("No handler registered for LLSD Requests"); + map["login"] = LLSD.FromString("false"); + return map; + } /// /// A specific agent handler was provided. Such a handler is expecetd to have an /// intimate, and highly specific relationship with the client. Consequently, @@ -809,6 +912,25 @@ namespace OpenSim.Framework.Servers return false; } + public bool RemoveLLSDHandler(string path, LLSDMethod handler) + { + + try + { + if (handler == m_llsdHandlers[path]) + { + m_llsdHandlers.Remove(path); + return true; + } + } + catch (KeyNotFoundException) + { + // This is an exception to prevent crashing because of invalid code + } + + return false; + } + public string GetHTTP404(string host) { diff --git a/OpenSim/Framework/Servers/LLSDMethod.cs b/OpenSim/Framework/Servers/LLSDMethod.cs index 05c23b0530..7bb946efd4 100644 --- a/OpenSim/Framework/Servers/LLSDMethod.cs +++ b/OpenSim/Framework/Servers/LLSDMethod.cs @@ -29,5 +29,6 @@ using libsecondlife.StructuredData; namespace OpenSim.Framework.Servers { - public delegate LLSD LLSDMethod(LLSD request); + public delegate LLSD LLSDMethod( string path, LLSD request, string endpoint ); + public delegate LLSD DefaultLLSDMethod(LLSD request); } diff --git a/OpenSim/Framework/Servers/LLSDMethodString.cs b/OpenSim/Framework/Servers/LLSDMethodString.cs new file mode 100644 index 0000000000..8d20b6991b --- /dev/null +++ b/OpenSim/Framework/Servers/LLSDMethodString.cs @@ -0,0 +1,33 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using libsecondlife.StructuredData; + +namespace OpenSim.Framework.Servers +{ + public delegate LLSD LLSDMethodString(LLSD request, string thePath); +} diff --git a/OpenSim/Grid/UserServer/Main.cs b/OpenSim/Grid/UserServer/Main.cs index 9a3e4318c4..20d0cbf445 100644 --- a/OpenSim/Grid/UserServer/Main.cs +++ b/OpenSim/Grid/UserServer/Main.cs @@ -128,7 +128,7 @@ namespace OpenSim.Grid.UserServer if (Cfg.EnableLLSDLogin) { - m_httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); + m_httpServer.SetDefaultLLSDHandler(m_loginService.LLSDLoginMethod); } m_httpServer.AddXmlRPCHandler("get_user_by_name", m_userManager.XmlRPCGetUserMethodName); diff --git a/OpenSim/Region/Application/OpenSimBase.cs b/OpenSim/Region/Application/OpenSimBase.cs index 0dd037d0be..78064dafad 100644 --- a/OpenSim/Region/Application/OpenSimBase.cs +++ b/OpenSim/Region/Application/OpenSimBase.cs @@ -384,7 +384,7 @@ namespace OpenSim m_httpServer.AddHTTPHandler("login", m_loginService.ProcessHTMLLogin); // Provides the LLSD login - m_httpServer.SetLLSDHandler(m_loginService.LLSDLoginMethod); + m_httpServer.SetDefaultLLSDHandler(m_loginService.LLSDLoginMethod); // provide grid info // m_gridInfoService = new GridInfoService(m_config.Source.Configs["Startup"].GetString("inifile", Path.Combine(Util.configDir(), "OpenSim.ini"))); diff --git a/OpenSim/Region/ClientStack/LindenUDP/KillPacket.cs b/OpenSim/Region/ClientStack/LindenUDP/KillPacket.cs new file mode 100644 index 0000000000..dfdabc8e5b --- /dev/null +++ b/OpenSim/Region/ClientStack/LindenUDP/KillPacket.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Text; +using libsecondlife.Packets; + +namespace OpenSim.Region.ClientStack.LindenUDP +{ + class KillPacket : Packet + { + private Header header; + public override void FromBytes(Header header, byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + + } + + public override void FromBytes(byte[] bytes, ref int i, ref int packetEnd, byte[] zeroBuffer) + { + + } + + public override Header Header { get { return header; } set { header = value; }} + + public override byte[] ToBytes() + { + return new byte[0]; + } + public KillPacket() + { + Header = new LowHeader(); + Header.ID = 65531; + Header.Reliable = true; + } + + public override PacketType Type + { + get + { + return PacketType.UseCircuitCode; + } + } + } +} diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs index 7c531f3efb..8214045833 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLClientView.cs @@ -92,6 +92,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP private Dictionary m_defaultAnimations = new Dictionary(); + private bool m_SendLogoutPacketWhenClosing = true; + /* protected variables */ protected static Dictionary PacketHandlers = @@ -368,6 +370,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP set { m_IsActive = value; } } + public bool SendLogoutPacketWhenClosing + { + set { m_SendLogoutPacketWhenClosing = value; } + } + /* METHODS */ public LLClientView(EndPoint remoteEP, IScene scene, AssetCache assetCache, LLPacketServer packServer, @@ -451,7 +458,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP if (!(shutdownCircuit)) { GC.Collect(); - m_clientThread.Abort(); + + // Sends a KillPacket object, with which, the + // blockingqueue dequeues and sees it's a killpacket + // and terminates within the context of the client thread. + // This ensures that it's done from within the context + // of the client thread regardless of where Close() is called. + KillEndDone(); } } @@ -752,7 +765,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP ClientLoop(); } } - catch (Exception e) + catch (System.Exception e) { if (e is ThreadAbortException) throw e; @@ -3740,6 +3753,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP m_PacketHandler.InPacket((Packet) NewPack); } + /// /// The dreaded OutPacket. This should only be called from within /// the ClientStack itself right now @@ -6093,15 +6107,23 @@ namespace OpenSim.Region.ClientStack.LindenUDP public void SendLogoutPacket() { - LogoutReplyPacket logReply = (LogoutReplyPacket)PacketPool.Instance.GetPacket(PacketType.LogoutReply); - // TODO: don't create new blocks if recycling an old packet - logReply.AgentData.AgentID = AgentId; - logReply.AgentData.SessionID = SessionId; - logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1]; - logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock(); - logReply.InventoryData[0].ItemID = LLUUID.Zero; + // I know this is a bit of a hack, however there are times when you don't + // want to send this, but still need to do the rest of the shutdown process + // this method gets called from the packet server.. which makes it practically + // impossible to do any other way. - OutPacket(logReply, ThrottleOutPacketType.Task); + if (m_SendLogoutPacketWhenClosing) + { + LogoutReplyPacket logReply = (LogoutReplyPacket)PacketPool.Instance.GetPacket(PacketType.LogoutReply); + // TODO: don't create new blocks if recycling an old packet + logReply.AgentData.AgentID = AgentId; + logReply.AgentData.SessionID = SessionId; + logReply.InventoryData = new LogoutReplyPacket.InventoryDataBlock[1]; + logReply.InventoryData[0] = new LogoutReplyPacket.InventoryDataBlock(); + logReply.InventoryData[0].ItemID = LLUUID.Zero; + + OutPacket(logReply, ThrottleOutPacketType.Task); + } } public void SendHealth(float health) @@ -6443,5 +6465,11 @@ namespace OpenSim.Region.ClientStack.LindenUDP OutPacket(reply, ThrottleOutPacketType.Land); } + + public void KillEndDone() + { + KillPacket kp = new KillPacket(); + OutPacket(kp, ThrottleOutPacketType.Task | ThrottleOutPacketType.LowPriority); + } } } diff --git a/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs b/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs index 209ec36b7a..830074a374 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/LLPacketHandler.cs @@ -30,6 +30,7 @@ using System.Collections; using System.Collections.Generic; using System.Net; using System.Net.Sockets; +using System.Threading; using System.Timers; using System.Reflection; using libsecondlife; @@ -233,6 +234,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP // to. Packet drop notifies will not be triggered in this // configuration! // + if ((m_SynchronizeClient != null) && (!m_Client.IsActive)) { if (m_SynchronizeClient(m_Client.Scene, packet, @@ -744,6 +746,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP } } + // If we sent a killpacket + if (packet is KillPacket) + Thread.CurrentThread.Abort(); + // Actually make the byte array and send it byte[] sendbuffer = packet.ToBytes(); diff --git a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs index a2e1e0c83a..a2c3c2cc3e 100644 --- a/OpenSim/Region/Communications/Local/LocalBackEndServices.cs +++ b/OpenSim/Region/Communications/Local/LocalBackEndServices.cs @@ -107,7 +107,7 @@ namespace OpenSim.Region.Communications.Local // connectivity errors. // Don't change this line below to 'm_regions[regionInfo.RegionHandle] = regionInfo' unless you // *REALLY* know what you are doing here. - m_regions.Remove(regionInfo.RegionHandle); + m_regions[regionInfo.RegionHandle] = regionInfo; m_log.Warn("[INTERREGION STANDALONE]: Region registered twice. Region went down and came back up."); diff --git a/OpenSim/Region/Communications/Local/LocalInventoryService.cs b/OpenSim/Region/Communications/Local/LocalInventoryService.cs index 4f6046258d..6e7ace51e2 100644 --- a/OpenSim/Region/Communications/Local/LocalInventoryService.cs +++ b/OpenSim/Region/Communications/Local/LocalInventoryService.cs @@ -49,6 +49,9 @@ namespace OpenSim.Region.Communications.Local m_log.InfoFormat("[LOCAL INVENTORY SERVICE]: Requesting inventory for user {0}", userID); List skeletonFolders = GetInventorySkeleton(userID); + if (skeletonFolders == null) + return; + InventoryFolderImpl rootFolder = null; List folders = new List(); diff --git a/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs b/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs new file mode 100644 index 0000000000..f6f0e8f3c9 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/InterGrid/OpenGridProtocolModule.cs @@ -0,0 +1,881 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSim Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Security; +using System.Net.Sockets; +using System.Reflection; +using System.Text.RegularExpressions; +using System.Threading; + +using libsecondlife; +using libsecondlife.StructuredData; + +using log4net; +using Nini.Config; +using Nwc.XmlRpc; + +using OpenSim.Framework; +using OpenSim.Region.Environment.Interfaces; +using OpenSim.Region.Environment.Scenes; +using OpenSim.Framework.Communications.Cache; +using OpenSim.Framework.Communications.Capabilities; +using OpenSim.Framework.Statistics; +using LLSD = libsecondlife.StructuredData.LLSD; +using LLSDMap = libsecondlife.StructuredData.LLSDMap; +using LLSDArray = libsecondlife.StructuredData.LLSDArray; + +namespace OpenSim.Region.Environment.Modules.InterGrid +{ + public struct OGPState + { + public string first_name; + public string last_name; + public LLUUID agent_id; + public LLUUID local_agent_id; + public LLUUID region_id; + public uint circuit_code; + public LLUUID secure_session_id; + public LLUUID session_id; + public bool agent_access; + public string sim_access; + public uint god_level; + public bool god_overide; + public bool identified; + public bool transacted; + public bool age_verified; + public bool allow_redirect; + public int limited_to_estate; + public string inventory_host; + public bool src_can_see_mainland; + public int src_estate_id; + } + + + public class OpenGridProtocolModule : IRegionModule + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private List m_scene = new List(); + + private Dictionary CapsLoginID = new Dictionary(); + private Dictionary m_OGPState = new Dictionary(); + + + + #region IRegionModule Members + + public void Initialise(Scene scene, IConfigSource config) + { + bool enabled = false; + IConfig cfg = null; + try + { + cfg = config.Configs["OpenGridProtocol"]; + } catch (NullReferenceException) + { + enabled = false; + } + if (cfg != null) + { + enabled = cfg.GetBoolean("ogp_enabled", false); + if (enabled) + { + m_log.Warn("[OGP]: Open Grid Protocol is on, Listening for Clients on /agent/"); + lock (m_scene) + { + if (m_scene.Count == 0) + { + scene.AddLLSDHandler("/agent/", ProcessAgentDomainMessage); + } + + if (!m_scene.Contains(scene)) + m_scene.Add(scene); + } + } + } + // Of interest to this module potentially + //scene.EventManager.OnNewClient += OnNewClient; + //scene.EventManager.OnGridInstantMessageToFriendsModule += OnGridInstantMessage; + //scene.EventManager.OnAvatarEnteringNewParcel += AvatarEnteringParcel; + //scene.EventManager.OnMakeChildAgent += MakeChildAgent; + //scene.EventManager.OnClientClosed += ClientLoggedOut; + } + + public void PostInitialise() + { + } + + public void Close() + { + } + + public string Name + { + get { return "OpenGridProtocolModule"; } + } + + public bool IsSharedModule + { + get { return true; } + } + + #endregion + + public LLSD ProcessAgentDomainMessage(string path, LLSD request, string endpoint) + { + // /agent/* + + string[] pathSegments = path.Split('/'); + if (pathSegments.Length < 1) + { + return GenerateNoHandlerMessage(); + } + + m_log.InfoFormat("[OGP]: path {0}, segments {1} segment[1] {2} Last segment {3}", + path, pathSegments.Length, pathSegments[1], pathSegments[pathSegments.Length - 1]); + + switch (pathSegments[pathSegments.Length - 1]) + { + case "rez_avatar": + return RezAvatarMethod(path, request); + //break; + case "derez_avatar": + return DerezAvatarMethod(path, request); + //break; + + } + if (path.Length < 2) + { + return GenerateNoHandlerMessage(); + } + + switch (pathSegments[pathSegments.Length - 2] + "/" + pathSegments[pathSegments.Length - 1]) + { + case "rez_avatar/rez": + return RezAvatarMethod(path, request); + //break; + case "rez_avatar/request": + return RequestRezAvatarMethod(path, request); + //break; + default: + return GenerateNoHandlerMessage(); + } + //return null; + } + + public LLSD RequestRezAvatarMethod(string path, LLSD request) + { + m_log.WarnFormat("[REQUESTREZAVATAR]: {0}", request.ToString()); + + LLSDMap requestMap = (LLSDMap)request; + + Scene homeScene = GetRootScene(); + + + + if (homeScene == null) + return GenerateNoHandlerMessage(); + + + RegionInfo reg = homeScene.RegionInfo; + ulong regionhandle = GetOSCompatibleRegionHandle(reg); + string RegionURI = reg.ServerURI; + int RegionPort = (int)reg.HttpPort; + + LLUUID RemoteAgentID = requestMap["agent_id"].AsUUID(); + + // will be used in the future. The client always connects with the aditi agentid currently + LLUUID LocalAgentID = RemoteAgentID; + + string FirstName = requestMap["first_name"].AsString(); + string LastName = requestMap["last_name"].AsString(); + + + OGPState userState = GetOGPState(LocalAgentID); + + userState.first_name = requestMap["first_name"].AsString(); + userState.last_name = requestMap["last_name"].AsString(); + userState.age_verified = requestMap["age_verified"].AsBoolean(); + userState.transacted = requestMap["transacted"].AsBoolean(); + userState.agent_access = requestMap["agent_access"].AsBoolean(); + userState.allow_redirect = requestMap["allow_redirect"].AsBoolean(); + userState.identified = requestMap["identified"].AsBoolean(); + userState.god_level = (uint)requestMap["god_level"].AsInteger(); + userState.sim_access = requestMap["sim_access"].AsString(); + userState.agent_id = RemoteAgentID; + userState.limited_to_estate = requestMap["limited_to_estate"].AsInteger(); + userState.src_can_see_mainland = requestMap["src_can_see_mainland"].AsBoolean(); + userState.src_estate_id = requestMap["src_estate_id"].AsInteger(); + userState.local_agent_id = LocalAgentID; + + UpdateOGPState(LocalAgentID, userState); + + LLSDMap responseMap = new LLSDMap(); + responseMap["sim_host"] = LLSD.FromString(Util.GetHostFromDNS(reg.ExternalHostName).ToString()); + responseMap["sim_ip"] = LLSD.FromString(Util.GetHostFromDNS(reg.ExternalHostName).ToString()); + responseMap["connect"] = LLSD.FromBoolean(true); + responseMap["sim_port"] = LLSD.FromInteger(reg.InternalEndPoint.Port); + responseMap["region_x"] = LLSD.FromInteger(reg.RegionLocX * (uint)Constants.RegionSize); // LLX + responseMap["region_Y"] = LLSD.FromInteger(reg.RegionLocY * (uint)Constants.RegionSize); // LLY + responseMap["region_id"] = LLSD.FromUUID(reg.originRegionID); + responseMap["sim_access"] = LLSD.FromString((reg.RegionSettings.Maturity == 1) ? "Mature" : "PG"); + + // Generate a dummy agent for the user so we can get back a CAPS path + AgentCircuitData agentData = new AgentCircuitData(); + agentData.AgentID = LocalAgentID; + agentData.BaseFolder=LLUUID.Zero; + agentData.CapsPath=Util.GetRandomCapsPath(); + agentData.child = false; + agentData.circuitcode = (uint)(Util.RandomClass.Next()); + agentData.firstname = FirstName; + agentData.lastname = LastName; + agentData.SecureSessionID=LLUUID.Random(); + agentData.SessionID=LLUUID.Random(); + agentData.startpos=LLVector3.Zero; + + // Pre-Fill our region cache with information on the agent. + UserAgentData useragent = new UserAgentData(); + useragent.AgentIP="unknown"; + useragent.AgentOnline=true; + useragent.AgentPort = (uint)0; + useragent.Handle = regionhandle; + useragent.InitialRegion = reg.originRegionID; + useragent.LoginTime=Util.UnixTimeSinceEpoch(); + useragent.LogoutTime = 0; + useragent.Position=agentData.startpos; + useragent.PositionX=agentData.startpos.X; + useragent.PositionY=agentData.startpos.Y; + useragent.PositionZ=agentData.startpos.Z; + useragent.Region=reg.originRegionID; + useragent.SecureSessionID=agentData.SecureSessionID; + useragent.SessionID = agentData.SessionID; + + + UserProfileData userProfile = new UserProfileData(); + userProfile.AboutText = "OGP User"; + userProfile.CanDoMask = (uint)0; + userProfile.Created = Util.UnixTimeSinceEpoch(); + userProfile.CurrentAgent = useragent; + userProfile.CustomType = "OGP"; + userProfile.FirstLifeAboutText = "I'm testing OpenGrid Protocol"; + userProfile.FirstLifeImage = LLUUID.Zero; + userProfile.FirstName = agentData.firstname; + userProfile.GodLevel = 0; + userProfile.HomeLocation = agentData.startpos; + userProfile.HomeLocationX = agentData.startpos.X; + userProfile.HomeLocationY = agentData.startpos.Y; + userProfile.HomeLocationZ = agentData.startpos.Z; + userProfile.HomeLookAt = LLVector3.Zero; + userProfile.HomeLookAtX = userProfile.HomeLookAt.X; + userProfile.HomeLookAtY = userProfile.HomeLookAt.Y; + userProfile.HomeLookAtZ = userProfile.HomeLookAt.Z; + userProfile.HomeRegion = reg.RegionHandle; + userProfile.HomeRegionID = reg.originRegionID; + userProfile.HomeRegionX = reg.RegionLocX; + userProfile.HomeRegionY = reg.RegionLocY; + userProfile.ID = agentData.AgentID; + userProfile.Image = LLUUID.Zero; + userProfile.LastLogin = Util.UnixTimeSinceEpoch(); + userProfile.Partner = LLUUID.Zero; + userProfile.PasswordHash = "$1$"; + userProfile.PasswordSalt = ""; + userProfile.RootInventoryFolderID = LLUUID.Zero; + userProfile.SurName = agentData.lastname; + userProfile.UserAssetURI = homeScene.CommsManager.NetworkServersInfo.AssetURL; + userProfile.UserFlags = 0; + userProfile.UserInventoryURI = homeScene.CommsManager.NetworkServersInfo.InventoryURL; + userProfile.WantDoMask = 0; + userProfile.WebLoginKey = LLUUID.Random(); + + // Do caps registration + // get seed cap + + + // Stick our data in the cache so the region will know something about us + homeScene.CommsManager.UserProfileCacheService.PreloadUserCache(agentData.AgentID, userProfile); + + // Call 'new user' event handler + homeScene.NewUserConnection(reg.RegionHandle, agentData); + + + string raCap = string.Empty; + + LLUUID AvatarRezCapUUID = LLUUID.Random(); + string rezAvatarPath = "/agent/" + AvatarRezCapUUID + "/rez_avatar"; + + // Get a reference to the user's cap so we can pull out the Caps Object Path + OpenSim.Framework.Communications.Capabilities.Caps userCap = homeScene.GetCapsHandlerForUser(agentData.AgentID); + + responseMap["seed_capability"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + userCap.CapsObjectPath + "0000/"); + + responseMap["rez_avatar/rez"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + rezAvatarPath); + + // Add the user to the list of CAPS that are outstanding. + // well allow the caps hosts in this dictionary + lock (CapsLoginID) + { + if (CapsLoginID.ContainsKey(rezAvatarPath)) + { + m_log.Error("[OGP]: Holy anomoly batman! Caps path already existed! All the UUID Duplication worries were founded!"); + } + else + { + CapsLoginID.Add(rezAvatarPath, agentData); + } + } + + return responseMap; + } + + public LLSD RezAvatarMethod(string path, LLSD request) + { + m_log.WarnFormat("[REZAVATAR]: {0}", request.ToString()); + + LLSDMap responseMap = new LLSDMap(); + + AgentCircuitData userData = null; + + // Only people we've issued a cap can go further + if (TryGetAgentCircuitData(path,out userData)) + { + LLSDMap requestMap = (LLSDMap)request; + + // take these values to start. There's a few more + LLUUID SecureSessionID=requestMap["secure_session_id"].AsUUID(); + LLUUID SessionID = requestMap["session_id"].AsUUID(); + int circuitcode = requestMap["circuit_code"].AsInteger(); + + //Update our Circuit data with the real values + userData.SecureSessionID = SecureSessionID; + userData.SessionID = SessionID; + + // Locate a home scene suitable for the user. + Scene homeScene = GetRootScene(); + + if (homeScene != null) + { + // Get a reference to their Cap object so we can pull out the capobjectroot + OpenSim.Framework.Communications.Capabilities.Caps userCap = + homeScene.GetCapsHandlerForUser(userData.AgentID); + + //Update the circuit data in the region so this user is authorized + homeScene.UpdateCircuitData(userData); + homeScene.ChangeCircuitCode(userData.circuitcode,(uint)circuitcode); + + // Load state + OGPState userState = GetOGPState(userData.AgentID); + + // Keep state changes + userState.first_name = requestMap["first_name"].AsString(); + userState.secure_session_id = requestMap["secure_session_id"].AsUUID(); + userState.age_verified = requestMap["age_verified"].AsBoolean(); + userState.region_id = homeScene.RegionInfo.originRegionID; // replace 0000000 with our regionid + userState.transacted = requestMap["transacted"].AsBoolean(); + userState.agent_access = requestMap["agent_access"].AsBoolean(); + userState.inventory_host = requestMap["inventory_host"].AsString(); + userState.identified = requestMap["identified"].AsBoolean(); + userState.session_id = requestMap["session_id"].AsUUID(); + userState.god_level = (uint)requestMap["god_level"].AsInteger(); + userState.last_name = requestMap["last_name"].AsString(); + userState.god_overide = requestMap["god_override"].AsBoolean(); + userState.circuit_code = (uint)requestMap["circuit_code"].AsInteger(); + userState.limited_to_estate = requestMap["limited_to_estate"].AsInteger(); + + // Save state changes + UpdateOGPState(userData.AgentID, userState); + + // Get the region information for the home region. + RegionInfo reg = homeScene.RegionInfo; + + // Dummy positional and look at info.. we don't have it. + LLSDArray PositionArray = new LLSDArray(); + PositionArray.Add(LLSD.FromInteger(128)); + PositionArray.Add(LLSD.FromInteger(128)); + PositionArray.Add(LLSD.FromInteger(40)); + + LLSDArray LookAtArray = new LLSDArray(); + LookAtArray.Add(LLSD.FromInteger(1)); + LookAtArray.Add(LLSD.FromInteger(1)); + LookAtArray.Add(LLSD.FromInteger(1)); + + // Our region's X and Y position in OpenSimulator space. + uint fooX = reg.RegionLocX; + uint fooY = reg.RegionLocY; + m_log.InfoFormat("[OGP]: region x({0}) region y({1})", fooX, fooY); + m_log.InfoFormat("[OGP]: region http {0} {1}", reg.ServerURI, reg.HttpPort); + m_log.InfoFormat("[OGO]: region UUID {0} ", reg.RegionID); + + // Convert the X and Y position to LL space + responseMap["region_x"] = LLSD.FromInteger(fooX * (uint)Constants.RegionSize); // convert it to LL X + responseMap["region_y"] = LLSD.FromInteger(fooY * (uint)Constants.RegionSize); // convert it to LL Y + + // Give em a new seed capability + responseMap["seed_capability"] = LLSD.FromString("http://" + reg.ExternalHostName + ":" + reg.HttpPort + "/CAPS/" + userCap.CapsObjectPath + "0000/"); + responseMap["region"] = LLSD.FromUUID(reg.originRegionID); + responseMap["look_at"] = LookAtArray; + + responseMap["sim_port"] = LLSD.FromInteger(reg.InternalEndPoint.Port); + responseMap["sim_host"] = LLSD.FromString(Util.GetHostFromDNS(reg.ExternalHostName).ToString());// + ":" + reg.InternalEndPoint.Port.ToString()); + responseMap["sim_ip"] = LLSD.FromString(Util.GetHostFromDNS(reg.ExternalHostName).ToString()); + + responseMap["session_id"] = LLSD.FromUUID(SessionID); + responseMap["secure_session_id"] = LLSD.FromUUID(SecureSessionID); + responseMap["circuit_code"] = LLSD.FromInteger(circuitcode); + + responseMap["position"] = PositionArray; + + responseMap["region_id"] = LLSD.FromUUID(reg.originRegionID); + + responseMap["sim_access"] = LLSD.FromString("Mature"); + + responseMap["connect"] = LLSD.FromBoolean(true); + + m_log.InfoFormat("[OGP]: host: {0}, IP {1}", responseMap["sim_host"].ToString(), responseMap["sim_ip"].ToString()); + + } + + } + + return responseMap; + } + + + + public LLSD DerezAvatarMethod(string path, LLSD request) + { + + + m_log.ErrorFormat("DerezPath: {0}, Request: {1}", path, request.ToString()); + + LLSD llsdResponse = null; + LLSDMap responseMap = new LLSDMap(); + + + + string[] PathArray = path.Split('/'); + m_log.InfoFormat("[OGP]: prefix {0}, uuid {1}, suffix {2}", PathArray[1], PathArray[2], PathArray[3]); + string uuidString = PathArray[2]; + m_log.InfoFormat("[OGP]: Request to Derez avatar with UUID {0}", uuidString); + LLUUID userUUID = LLUUID.Zero; + if (Helpers.TryParse(uuidString, out userUUID)) + { + + LLUUID RemoteID = uuidString; + LLUUID LocalID = RemoteID; + // FIXME: TODO: Routine to map RemoteUUIDs to LocalUUIds + // would be done already.. but the client connects with the Aditi UUID + // regardless over the UDP stack + + OGPState userState = GetOGPState(LocalID); + if (userState.agent_id != LLUUID.Zero) + { + + LLSDMap outboundRequestMap = new LLSDMap(); + LLSDMap inboundRequestMap = (LLSDMap)request; + string rezAvatarString = inboundRequestMap["rez_avatar"].AsString(); + + LLSDArray LookAtArray = new LLSDArray(); + LookAtArray.Add(LLSD.FromInteger(1)); + LookAtArray.Add(LLSD.FromInteger(1)); + LookAtArray.Add(LLSD.FromInteger(1)); + + + LLSDArray PositionArray = new LLSDArray(); + PositionArray.Add(LLSD.FromInteger(128)); + PositionArray.Add(LLSD.FromInteger(128)); + PositionArray.Add(LLSD.FromInteger(40)); + + LLSDArray lookArray = new LLSDArray(); + lookArray.Add(LLSD.FromInteger(128)); + lookArray.Add(LLSD.FromInteger(128)); + lookArray.Add(LLSD.FromInteger(40)); + + responseMap["connect"] = LLSD.FromBoolean(true);// it's okay to give this user up + responseMap["look_at"] = LookAtArray; + + m_log.WarnFormat("[OGP]: Invoking rez_avatar on host:{0} for avatar: {1} {2}", rezAvatarString, userState.first_name, userState.last_name); + + LLSDMap rezResponseMap = invokeRezAvatarCap(responseMap, rezAvatarString,userState); + + // If invoking it returned an error, parse and end + if (rezResponseMap.ContainsKey("connect")) + { + if (rezResponseMap["connect"].AsBoolean() == false) + { + return responseMap; + } + } + + string rezRespSeedCap = rezResponseMap["seed_capability"].AsString(); + string rezRespSim_ip = rezResponseMap["sim_ip"].AsString(); + string rezRespSim_host = rezResponseMap["sim_host"].AsString(); + + int rrPort = rezResponseMap["sim_port"].AsInteger(); + int rrX = rezResponseMap["region_x"].AsInteger(); + int rrY = rezResponseMap["region_y"].AsInteger(); + m_log.ErrorFormat("X:{0}, Y:{1}", rrX, rrY); + LLUUID rrRID = rezResponseMap["region_id"].AsUUID(); + + string rrAccess = rezResponseMap["sim_access"].AsString(); + + LLSDArray RezResponsePositionArray = (LLSDArray)rezResponseMap["position"]; + + responseMap["seed_capability"] = LLSD.FromString(rezRespSeedCap); + responseMap["sim_ip"] = LLSD.FromString(Util.GetHostFromDNS(rezRespSim_ip).ToString()); + responseMap["sim_host"] = LLSD.FromString(Util.GetHostFromDNS(rezRespSim_host).ToString()); + responseMap["sim_port"] = LLSD.FromInteger(rrPort); + responseMap["region_x"] = LLSD.FromInteger(rrX * (int)Constants.RegionSize); + responseMap["region_y"] = LLSD.FromInteger(rrY * (int)Constants.RegionSize); + responseMap["region_id"] = LLSD.FromUUID(rrRID); + responseMap["sim_access"] = LLSD.FromString(rrAccess); + + + + responseMap["position"] = RezResponsePositionArray; + responseMap["look_at"] = lookArray; + responseMap["connect"] = LLSD.FromBoolean(true); + + ShutdownConnection(LocalID,this); + + + m_log.Warn("RESPONSEDEREZ: " + responseMap.ToString()); + return responseMap; + + } + else + { + + return GenerateNoHandlerMessage(); + } + } + else + { + return GenerateNoHandlerMessage(); + } + + return responseMap; + } + + private LLSDMap invokeRezAvatarCap(LLSDMap responseMap, string CapAddress, OGPState userState) + { + + WebRequest DeRezRequest = WebRequest.Create(CapAddress); + DeRezRequest.Method = "POST"; + DeRezRequest.ContentType = "application/xml+llsd"; + + LLSDMap RAMap = new LLSDMap(); + LLSDMap AgentParms = new LLSDMap(); + LLSDMap RegionParms = new LLSDMap(); + + + AgentParms["first_name"] = LLSD.FromString(userState.first_name); + AgentParms["last_name"] = LLSD.FromString(userState.last_name); + AgentParms["agent_id"] = LLSD.FromUUID(userState.agent_id); + RegionParms["region_id"] = LLSD.FromUUID(userState.region_id); + AgentParms["circuit_code"] = LLSD.FromInteger(userState.circuit_code); + AgentParms["secure_session_id"] = LLSD.FromUUID(userState.secure_session_id); + AgentParms["session_id"] = LLSD.FromUUID(userState.session_id); + AgentParms["agent_access"] = LLSD.FromBoolean(userState.agent_access); + AgentParms["god_level"] = LLSD.FromInteger(userState.god_level); + AgentParms["god_overide"] = LLSD.FromBoolean(userState.god_overide); + AgentParms["identified"] = LLSD.FromBoolean(userState.identified); + AgentParms["transacted"] = LLSD.FromBoolean(userState.transacted); + AgentParms["age_verified"] = LLSD.FromBoolean(userState.age_verified); + AgentParms["limited_to_estate"] = LLSD.FromInteger(userState.limited_to_estate); + AgentParms["inventory_host"] = LLSD.FromString(userState.inventory_host); + RAMap["agent_params"] = AgentParms; + RAMap["region_params"] = RegionParms; + + string RAMapString = AgentParms.ToString(); + m_log.InfoFormat("[OGP] RAMap string {0}", RAMapString); + LLSD LLSDofRAMap = AgentParms; // RENAME if this works + + m_log.InfoFormat("[OGP]: LLSD of map as string was {0}", LLSDofRAMap.ToString()); + byte[] buffer = LLSDParser.SerializeXmlBytes(LLSDofRAMap); + + //string bufferDump = System.Text.Encoding.ASCII.GetString(buffer); + //m_log.InfoFormat("[OGP]: buffer form is {0}",bufferDump); + //m_log.InfoFormat("[OGP]: LLSD of map was {0}",buffer.Length); + + Stream os = null; + try + { // send the Post + DeRezRequest.ContentLength = buffer.Length; //Count bytes to send + os = DeRezRequest.GetRequestStream(); + os.Write(buffer, 0, buffer.Length); //Send it + os.Close(); + m_log.InfoFormat("[OGP]: Derez Avatar Posted Rez Avatar request to remote sim {0}", CapAddress); + } + catch (WebException ex) + { + m_log.InfoFormat("[OGP] Bad send on de_rez_avatar {0}", ex.Message); + responseMap["connect"] = LLSD.FromBoolean(false); + + return responseMap; + } + + m_log.Info("[OGP] waiting for a reply after rez avatar send"); + string rez_avatar_reply = null; + { // get the response + try + { + WebResponse webResponse = DeRezRequest.GetResponse(); + if (webResponse == null) + { + m_log.Info("[OGP:] Null reply on rez_avatar post"); + } + + StreamReader sr = new StreamReader(webResponse.GetResponseStream()); + rez_avatar_reply = sr.ReadToEnd().Trim(); + m_log.InfoFormat("[OGP]: rez_avatar reply was {0} ", rez_avatar_reply); + + } + catch (WebException ex) + { + m_log.InfoFormat("[OGP]: exception on read after send of rez avatar {0}", ex.Message); + responseMap["connect"] = LLSD.FromBoolean(false); + + return responseMap; + } + LLSD rezResponse = null; + try + { + rezResponse = LLSDParser.DeserializeXml(rez_avatar_reply); + + responseMap = (LLSDMap)rezResponse; + } + catch (Exception ex) + { + m_log.InfoFormat("[OGP]: exception on parse of rez reply {0}", ex.Message); + responseMap["connect"] = LLSD.FromBoolean(false); + + return responseMap; + } + } + return responseMap; + } + + + + public LLSD GenerateNoHandlerMessage() + { + LLSDMap map = new LLSDMap(); + map["reason"] = LLSD.FromString("LLSDRequest"); + map["message"] = LLSD.FromString("No handler registered for LLSD Requests"); + map["login"] = LLSD.FromString("false"); + + return map; + } + + private bool TryGetAgentCircuitData(string path, out AgentCircuitData userdata) + { + userdata = null; + lock (CapsLoginID) + { + if (CapsLoginID.ContainsKey(path)) + { + userdata = CapsLoginID[path]; + DiscardUsedCap(path); + return true; + } + } + return false; + } + + private void DiscardUsedCap(string path) + { + CapsLoginID.Remove(path); + } + + + private Scene GetRootScene() + { + Scene ReturnScene = null; + lock (m_scene) + { + if (m_scene.Count > 0) + { + ReturnScene = m_scene[0]; + } + } + + return ReturnScene; + + } + + private ulong GetOSCompatibleRegionHandle(RegionInfo reg) + { + return Util.UIntsToLong(reg.RegionLocX, reg.RegionLocY); + } + + private ulong GetOSCompatibleRegionHandle(uint x, uint y) + { + return Util.UIntsToLong(x, y); + } + + private ulong GetOSCompatibleRegionHandle(ulong regionhandle) + { + uint x,y; + Helpers.LongToUInts(regionhandle,out x, out y); + return GetOSCompatibleRegionHandle(x,y); + } + + + private ulong GetOGPCompatibleRegionHandle(RegionInfo reg) + { + return Util.UIntsToLong((reg.RegionLocX * (uint)Constants.RegionSize), (reg.RegionLocY * (uint)Constants.RegionSize)); + } + + private ulong GetOGPCompatibleRegionHandle(uint x, uint y) + { + return Util.UIntsToLong((x * (uint)Constants.RegionSize), (y * (uint)Constants.RegionSize)); + } + + private ulong GetOGPCompatibleRegionHandle(ulong regionhandle) + { + uint x, y; + Helpers.LongToUInts(regionhandle, out x, out y); + return GetOGPCompatibleRegionHandle(x, y); + } + + private OGPState InitializeNewState() + { + OGPState returnState = new OGPState(); + returnState.first_name = ""; + returnState.last_name = ""; + returnState.agent_id = LLUUID.Zero; + returnState.local_agent_id = LLUUID.Zero; + returnState.region_id = LLUUID.Zero; + returnState.circuit_code = 0; + returnState.secure_session_id = LLUUID.Zero; + returnState.session_id = LLUUID.Zero; + returnState.agent_access = true; + returnState.god_level = 0; + returnState.god_overide = false; + returnState.identified = false; + returnState.transacted = false; + returnState.age_verified = false; + returnState.limited_to_estate = 1; + returnState.inventory_host = "http://inv4.mysql.aditi.lindenlab.com"; + returnState.allow_redirect = true; + returnState.sim_access = ""; + returnState.src_can_see_mainland = true; + returnState.src_estate_id = 1; + + return returnState; + } + + private OGPState GetOGPState(LLUUID agentId) + { + lock (m_OGPState) + { + if (m_OGPState.ContainsKey(agentId)) + { + return m_OGPState[agentId]; + } + else + { + return InitializeNewState(); + } + } + } + + public void DeleteOGPState(LLUUID agentId) + { + lock (m_OGPState) + if (m_OGPState.ContainsKey(agentId)) + m_OGPState.Remove(agentId); + + } + + private void UpdateOGPState(LLUUID agentId, OGPState state) + { + lock (m_OGPState) + { + if (m_OGPState.ContainsKey(agentId)) + { + m_OGPState[agentId] = state; + } + else + { + m_OGPState.Add(agentId,state); + } + } + } + public void ShutdownConnection(LLUUID avatarId, OpenGridProtocolModule mod) + { + Scene homeScene = GetRootScene(); + ScenePresence avatar = null; + if (homeScene.TryGetAvatar(avatarId,out avatar)) + { + KillAUser ku = new KillAUser(avatar,mod); + Thread ta = new Thread(ku.ShutdownNoLogout); + ta.IsBackground = true; + ta.Name = "ShutdownThread"; + ta.Start(); + } + } + } + + public class KillAUser + { + private ScenePresence avToBeKilled = null; + private OpenGridProtocolModule m_mod = null; + + public KillAUser(ScenePresence avatar, OpenGridProtocolModule mod) + { + avToBeKilled = avatar; + m_mod = mod; + } + + public void ShutdownNoLogout() + { + LLUUID avUUID = LLUUID.Zero; + + if (avToBeKilled != null) + { + avUUID = avToBeKilled.UUID; + avToBeKilled.MakeChildAgent(); + + avToBeKilled.ControllingClient.SendLogoutPacketWhenClosing = false; + + Thread.Sleep(30000); + + // test for child agent because they might have come back + if (avToBeKilled.IsChildAgent) + { + m_mod.DeleteOGPState(avUUID); + avToBeKilled.ControllingClient.Close(true); + } + } + } + + } +} diff --git a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs index 4754a04ae1..2d27b11920 100644 --- a/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs +++ b/OpenSim/Region/Environment/Modules/World/NPC/NPCAvatar.cs @@ -43,6 +43,7 @@ namespace OpenSim.Region.Environment.Modules.World.NPC private readonly LLUUID m_uuid = LLUUID.Random(); private readonly Scene m_scene; + public NPCAvatar(string firstname, string lastname, LLVector3 position, Scene scene) { m_firstname = firstname; @@ -124,6 +125,11 @@ namespace OpenSim.Region.Environment.Modules.World.NPC set { m_scene.Entities[m_uuid].AbsolutePosition = value; } } + public bool SendLogoutPacketWhenClosing + { + set { } + } + #region Internal Functions private void SendOnChatFromViewer(string message, ChatTypeEnum chatType) @@ -857,5 +863,9 @@ namespace OpenSim.Region.Environment.Modules.World.NPC public void SendParcelInfo (RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y) { } + + public void KillEndDone() + { + } } } diff --git a/OpenSim/Region/Environment/Scenes/Scene.cs b/OpenSim/Region/Environment/Scenes/Scene.cs index a21f701724..6f3267a895 100644 --- a/OpenSim/Region/Environment/Scenes/Scene.cs +++ b/OpenSim/Region/Environment/Scenes/Scene.cs @@ -2599,6 +2599,17 @@ namespace OpenSim.Region.Environment.Scenes "[CONNECTION DEBUGGING]: Skipping this region for welcoming avatar {0} [{1}] at {2}", agent.AgentID, regionHandle, RegionInfo.RegionName); } + + } + + public void UpdateCircuitData(AgentCircuitData data) + { + m_authenticateHandler.UpdateAgentData(data); + } + + public bool ChangeCircuitCode(uint oldcc, uint newcc) + { + return m_authenticateHandler.TryChangeCiruitCode(oldcc, newcc); } protected void HandleLogOffUserFromGrid(ulong regionHandle, LLUUID AvatarID, LLUUID RegionSecret, string message) @@ -2664,6 +2675,18 @@ namespace OpenSim.Region.Environment.Scenes m_capsHandlers[agentId] = cap; } + public Caps GetCapsHandlerForUser(LLUUID agentId) + { + lock (m_capsHandlers) + { + if (m_capsHandlers.ContainsKey(agentId)) + { + return m_capsHandlers[agentId]; + } + } + return null; + } + /// /// Remove the caps handler for a given agent. /// @@ -3838,6 +3861,12 @@ namespace OpenSim.Region.Environment.Scenes m_httpListener.AddStreamHandler(handler); } + public bool AddLLSDHandler(string path, LLSDMethod handler) + { + return m_httpListener.AddLLSDHandler(path, handler); + } + + public void RemoveStreamHandler(string httpMethod, string path) { m_httpListener.RemoveStreamHandler(httpMethod, path); @@ -3848,6 +3877,11 @@ namespace OpenSim.Region.Environment.Scenes m_httpListener.RemoveHTTPHandler(httpMethod, path); } + public bool RemoveLLSDHandler(string path, LLSDMethod handler) + { + return m_httpListener.RemoveLLSDHandler(path, handler); + } + #endregion #region Avatar Appearance Default diff --git a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs index 655dfe4098..3ea518fffe 100644 --- a/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs +++ b/OpenSim/Region/Examples/SimpleModule/MyNpcCharacter.cs @@ -302,6 +302,11 @@ namespace OpenSim.Region.Examples.SimpleModule get { return m_scene; } } + public bool SendLogoutPacketWhenClosing + { + set { } + } + public virtual void ActivateGesture(LLUUID assetId, LLUUID gestureId) { } @@ -855,5 +860,9 @@ namespace OpenSim.Region.Examples.SimpleModule public void SendParcelInfo (RegionInfo info, LandData land, LLUUID parcelID, uint x, uint y) { } + + public void KillEndDone() + { + } } } diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example index eb1cc0ba80..f0e7d5f753 100644 --- a/bin/OpenSim.ini.example +++ b/bin/OpenSim.ini.example @@ -697,3 +697,8 @@ help = http://127.0.0.1/help ; password help: optional: page providing password assistance for users of your grid password = http://127.0.0.1/password + +;These are the settings for the Open Grid Protocol.. the Agent Domain, Region Domain, you know.. +[OpenGridProtocol] +;On/true or Off/false +ogp_enabled=false \ No newline at end of file