/* * 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 OpenSimulator 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.Reflection; using System.Collections.Generic; using log4net; using OpenMetaverse; using OpenMetaverse.StructuredData; namespace OpenSim.Framework { /// /// Circuit data for an agent. Connection information shared between /// regions that accept UDP connections from a client /// public class AgentCircuitData { private static readonly ILog m_log = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType); /// /// Avatar Unique Agent Identifier /// public UUID AgentID; /// /// Avatar's Appearance /// public AvatarAppearance Appearance; /// /// Agent's root inventory folder /// public UUID BaseFolder; /// /// Base Caps path for user /// public string CapsPath = String.Empty; /// /// Seed caps for neighbor regions that the user can see into /// public Dictionary ChildrenCapSeeds; /// /// Root agent, or Child agent /// public bool child; /// /// Number given to the client when they log-in that they provide /// as credentials to the UDP server /// public uint circuitcode; /// /// How this agent got here /// public uint teleportFlags; /// /// Agent's account first name /// public string firstname; public UUID InventoryFolder; /// /// Agent's account last name /// public string lastname; /// /// Agent's full name. /// public string Name { get { return $"{firstname} {lastname}"; } } /// /// Random Unique GUID for this session. Client gets this at login and it's /// only supposed to be disclosed over secure channels /// public UUID SecureSessionID; /// /// Non secure Session ID /// public UUID SessionID; /// /// Hypergrid service token; generated by the user domain, consumed by the receiving grid. /// There is one such unique token for each grid visited. /// public string ServiceSessionID = string.Empty; /// /// The client's IP address, as captured by the login service /// public string IPAddress; /// /// Viewer's version string as reported by the viewer at login /// private string m_viewerInternal; /// /// Viewer's version string /// public string Viewer { set { m_viewerInternal = value; } // Try to return consistent viewer string taking into account // that viewers have chaagned how version is reported // See http://opensimulator.org/mantis/view.php?id=6851 get { // Old style version string contains viewer name followed by a space followed by a version number if (m_viewerInternal is null || m_viewerInternal.Contains(' ')) { return m_viewerInternal; } else // New style version contains no spaces, just version number { return $"{Channel} {m_viewerInternal}"; } } } /// /// The channel strinf sent by the viewer at login /// public string Channel; /// /// The Mac address as reported by the viewer at login /// public string Mac; /// /// The id0 as reported by the viewer at login /// public string Id0; /// /// Position the Agent's Avatar starts in the region /// public Vector3 startpos; public float startfar = -1.0f; public Dictionary ServiceURLs; public AgentCircuitData() { } /// /// Pack AgentCircuitData into an OSDMap for transmission over LLSD XML or LLSD json /// /// map of the agent circuit data public OSDMap PackAgentCircuitData(EntityTransferContext ctx) { OSDMap args = new() { ["agent_id"] = OSD.FromUUID(AgentID), ["base_folder"] = OSD.FromUUID(BaseFolder), ["caps_path"] = OSD.FromString(CapsPath) }; if (ChildrenCapSeeds is not null) { OSDArray childrenSeeds = new(ChildrenCapSeeds.Count); foreach (KeyValuePair kvp in ChildrenCapSeeds) { OSDMap pair = new OSDMap(); pair["handle"] = OSD.FromString(kvp.Key.ToString()); pair["seed"] = OSD.FromString(kvp.Value); childrenSeeds.Add(pair); } if (ChildrenCapSeeds.Count > 0) args["children_seeds"] = childrenSeeds; } args["child"] = OSD.FromBoolean(child); args["circuit_code"] = OSD.FromString(circuitcode.ToString()); args["first_name"] = OSD.FromString(firstname); args["last_name"] = OSD.FromString(lastname); args["inventory_folder"] = OSD.FromUUID(InventoryFolder); args["secure_session_id"] = OSD.FromUUID(SecureSessionID); args["session_id"] = OSD.FromUUID(SessionID); args["service_session_id"] = OSD.FromString(ServiceSessionID); args["start_pos"] = OSD.FromString(startpos.ToString()); args["client_ip"] = OSD.FromString(IPAddress); args["viewer"] = OSD.FromString(Viewer); args["channel"] = OSD.FromString(Channel); args["mac"] = OSD.FromString(Mac); args["id0"] = OSD.FromString(Id0); if(startfar > 0) args["far"] = OSD.FromReal(startfar); if (Appearance != null) { args["appearance_serial"] = OSD.FromInteger(Appearance.Serial); OSDMap appmap = Appearance.Pack(ctx); args["packed_appearance"] = appmap; } // Old, bad way. Keeping it fow now for backwards compatibility // OBSOLETE -- soon to be deleted if (ServiceURLs != null && ServiceURLs.Count > 0) { OSDArray urls = new OSDArray(ServiceURLs.Count * 2); foreach (KeyValuePair kvp in ServiceURLs) { //System.Console.WriteLine("XXX " + kvp.Key + "=" + kvp.Value); urls.Add(OSD.FromString(kvp.Key)); urls.Add(OSD.FromString((kvp.Value == null) ? string.Empty : kvp.Value.ToString())); } args["service_urls"] = urls; } // again, this time the right way if (ServiceURLs != null && ServiceURLs.Count > 0) { OSDMap urls = new OSDMap(); foreach (KeyValuePair kvp in ServiceURLs) { //System.Console.WriteLine("XXX " + kvp.Key + "=" + kvp.Value); urls[kvp.Key] = OSD.FromString((kvp.Value == null) ? string.Empty : kvp.Value.ToString()); } args["serviceurls"] = urls; } return args; } /// /// Unpack agent circuit data map into an AgentCiruitData object /// /// public void UnpackAgentCircuitData(OSDMap args) { OSD tmpOSD; if (args.TryGetValue("agent_id", out tmpOSD)) AgentID = tmpOSD.AsUUID(); if (args.TryGetValue("base_folder", out tmpOSD)) BaseFolder =tmpOSD.AsUUID(); if (args.TryGetValue("caps_path", out tmpOSD)) CapsPath = tmpOSD.AsString(); if (args.TryGetValue("children_seeds", out tmpOSD) && tmpOSD is OSDArray) { OSDArray childrenSeeds = (OSDArray)tmpOSD; ChildrenCapSeeds = new Dictionary(); foreach (OSD o in childrenSeeds) { if (o.Type == OSDType.Map) { ulong handle = 0; string seed = ""; OSDMap pair = (OSDMap)o; if (pair.TryGetValue("handle", out tmpOSD)) { if (!UInt64.TryParse(tmpOSD.AsString(), out handle)) continue; } if (!ChildrenCapSeeds.ContainsKey(handle)) { if (pair.TryGetValue("seed", out tmpOSD)) { seed = tmpOSD.AsString(); ChildrenCapSeeds.Add(handle, seed); } } } } } else ChildrenCapSeeds = new Dictionary(); if (args.TryGetValue("child", out tmpOSD)) child = tmpOSD.AsBoolean(); if (args.TryGetValue("circuit_code", out tmpOSD)) UInt32.TryParse(tmpOSD.AsString(), out circuitcode); if (args.TryGetValue("first_name", out tmpOSD)) firstname = tmpOSD.AsString(); if (args.TryGetValue("last_name", out tmpOSD)) lastname = tmpOSD.AsString(); if (args.TryGetValue("inventory_folder", out tmpOSD)) InventoryFolder = tmpOSD.AsUUID(); if (args.TryGetValue("secure_session_id", out tmpOSD)) SecureSessionID = tmpOSD.AsUUID(); if (args.TryGetValue("session_id", out tmpOSD)) SessionID = tmpOSD.AsUUID(); if (args.TryGetValue("service_session_id", out tmpOSD)) ServiceSessionID = tmpOSD.AsString(); if (args.TryGetValue("client_ip", out tmpOSD)) IPAddress = tmpOSD.AsString(); if (args.TryGetValue("viewer", out tmpOSD)) Viewer = tmpOSD.AsString(); if (args.TryGetValue("channel", out tmpOSD)) Channel = tmpOSD.AsString(); if (args.TryGetValue("mac", out tmpOSD)) Mac = tmpOSD.AsString(); if (args.TryGetValue("id0", out tmpOSD)) Id0 = tmpOSD.AsString(); if (args.TryGetValue("teleport_flags", out tmpOSD)) teleportFlags = tmpOSD.AsUInteger(); if (args.TryGetValue("start_pos", out tmpOSD)) Vector3.TryParse(tmpOSD.AsString(), out startpos); if(args.TryGetValue("far", out tmpOSD)) startfar = (float)tmpOSD.AsReal(); //m_log.InfoFormat("[AGENTCIRCUITDATA]: agentid={0}, child={1}, startpos={2}", AgentID, child, startpos); try { // Unpack various appearance elements Appearance = new AvatarAppearance(); // Eventually this code should be deprecated, use full appearance // packing in packed_appearance if (args.TryGetValue("appearance_serial", out tmpOSD)) Appearance.Serial = tmpOSD.AsInteger(); if (args.TryGetValue("packed_appearance", out tmpOSD) && (tmpOSD is OSDMap)) { Appearance.Unpack((OSDMap)tmpOSD); // m_log.InfoFormat("[AGENTCIRCUITDATA] unpacked appearance"); } else { m_log.Warn("[AGENTCIRCUITDATA]: failed to find a valid packed_appearance"); } } catch (Exception e) { m_log.ErrorFormat("[AGENTCIRCUITDATA] failed to unpack appearance; {0}",e.Message); } ServiceURLs = new Dictionary(); // Try parse the new way, OSDMap if (args.TryGetValue("serviceurls", out tmpOSD) && (tmpOSD is OSDMap)) { OSDMap urls = (OSDMap)tmpOSD; foreach (KeyValuePair kvp in urls) { ServiceURLs[kvp.Key] = kvp.Value; //System.Console.WriteLine("XXX " + kvp.Key + "=" + ServiceURLs[kvp.Key]); } } // else try the old way, OSDArray // OBSOLETE -- soon to be deleted else if (args.TryGetValue("service_urls", out tmpOSD) && (tmpOSD is OSDArray)) { OSDArray urls = (OSDArray)tmpOSD; OSD tmpOSDb; for (int i = 0; i < urls.Count - 1; i += 2) { tmpOSD = urls[i]; tmpOSDb = urls[i + 1]; ServiceURLs[tmpOSD.AsString()] = tmpOSDb.AsString(); //System.Console.WriteLine("XXX " + urls[i * 2].AsString() + "=" + urls[(i * 2) + 1].AsString()); } } } } }