From 76fdbc7f80da4a5c91c9d0094ca5bcf606c4cf69 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Sat, 27 Jan 2007 09:57:29 +0000 Subject: [PATCH] * Added an LLUUID.Combine() function * Added NetworkManager.SecureSessionID * Added a missing SendPacket function for raw payloads to non-current sims * Documented a few things in NetworkManager git-svn-id: http://libopenmetaverse.googlecode.com/svn/trunk@910 52acb1d6-8a22-11de-b505-999d5b087335 --- libsecondlife-cs/Helpers.cs | 8 +- libsecondlife-cs/NetworkManager.cs | 167 ++++++++------- libsecondlife-cs/Settings.cs | 200 +++++++++--------- libsecondlife-cs/Types.cs | 16 ++ .../libsecondlife.Utilities/Assets.cs | 27 ++- 5 files changed, 240 insertions(+), 178 deletions(-) diff --git a/libsecondlife-cs/Helpers.cs b/libsecondlife-cs/Helpers.cs index 4d4308f0..99f0ef62 100644 --- a/libsecondlife-cs/Helpers.cs +++ b/libsecondlife-cs/Helpers.cs @@ -102,6 +102,11 @@ namespace libsecondlife Transfer = 0x00002000 } + /// Provide a single instance of the MD5 class to avoid making + /// duplicate copies + public static System.Security.Cryptography.MD5 MD5Builder = + new System.Security.Cryptography.MD5CryptoServiceProvider(); + /// /// Converts an unsigned integer to a hexadecimal string /// @@ -824,8 +829,7 @@ namespace libsecondlife public static string MD5(string password) { StringBuilder digest = new StringBuilder(); - System.Security.Cryptography.MD5 md5 = new System.Security.Cryptography.MD5CryptoServiceProvider(); - byte[] hash = md5.ComputeHash(Encoding.ASCII.GetBytes(password)); + byte[] hash = MD5Builder.ComputeHash(ASCIIEncoding.Default.GetBytes(password)); // Convert the hash to a hex string foreach (byte b in hash) diff --git a/libsecondlife-cs/NetworkManager.cs b/libsecondlife-cs/NetworkManager.cs index d4ddf618..c81674e6 100644 --- a/libsecondlife-cs/NetworkManager.cs +++ b/libsecondlife-cs/NetworkManager.cs @@ -804,6 +804,7 @@ namespace libsecondlife /// A reference to the old value of CurrentSim public delegate void CurrentSimChangedCallback(Simulator PreviousSimulator); + /// /// Explains why a simulator or the grid disconnected from us /// @@ -817,40 +818,6 @@ namespace libsecondlife NetworkTimeout } - /// - /// The permanent UUID for the logged in avatar - /// - public LLUUID AgentID; - /// - /// A temporary UUID assigned to this session, used for secure - /// transactions - /// - public LLUUID SessionID; - /// - /// A string holding a descriptive error on login failure, empty - /// otherwise - /// - public string LoginError; - /// - /// The simulator that the logged in avatar is currently occupying - /// - public Simulator CurrentSim; - /// - /// The capabilities for the current simulator - /// - public Caps CurrentCaps; - /// - /// The complete dictionary of all the login values returned by the - /// RPC login server, converted to native data types wherever possible - /// - public Dictionary LoginValues = new Dictionary(); - /// - /// Shows whether the network layer is logged in to the grid or not - /// - public bool Connected - { - get { return connected; } - } /// /// An event for the connection to a simulator other than the currently @@ -867,22 +834,57 @@ namespace libsecondlife /// public event CurrentSimChangedCallback OnCurrentSimChanged; + /// + /// The permanent UUID for the logged in avatar + /// + public LLUUID AgentID = LLUUID.Zero; + /// + /// Temporary UUID assigned to this session, used for verifying + /// our identity in packets + /// + public LLUUID SessionID = LLUUID.Zero; + /// + /// Shared secret UUID that is never sent over the wire + /// + public LLUUID SecureSessionID = LLUUID.Zero; + /// + /// String holding a descriptive error on login failure, empty + /// otherwise + /// + public string LoginError = String.Empty; + /// + /// The simulator that the logged in avatar is currently occupying + /// + public Simulator CurrentSim = null; + /// + /// The capabilities for the current simulator + /// + public Caps CurrentCaps = null; + /// + /// The complete dictionary of all the login values returned by the + /// RPC login server, converted to native data types wherever possible + /// + public Dictionary LoginValues = new Dictionary(); + + /// + /// Shows whether the network layer is logged in to the grid or not + /// + public bool Connected { get { return connected; } } + private SecondLife Client; private Dictionary> Callbacks = new Dictionary>(); private List Simulators = new List(); private System.Timers.Timer DisconnectTimer; private System.Timers.Timer LogoutTimer; - private bool connected; + private bool connected = false; private List EventQueueCallbacks = new List(); - private const int NetworkTrafficTimeout = 15000; - ManualResetEvent LogoutReplyEvent = new ManualResetEvent(false); /// - /// + /// Default constructor /// - /// + /// Reference to the SecondLife client public NetworkManager(SecondLife client) { Client = client; @@ -896,16 +898,20 @@ namespace libsecondlife RegisterCallback(PacketType.KickUser, new PacketCallback(KickUserHandler)); RegisterCallback(PacketType.LogoutReply, new PacketCallback(LogoutReplyHandler)); - // Disconnect a sim if we exceed our threshold - DisconnectTimer = new System.Timers.Timer(NetworkTrafficTimeout); + // The proper timeout for this will get set at Login + DisconnectTimer = new System.Timers.Timer(); + DisconnectTimer.AutoReset = false; DisconnectTimer.Elapsed += new ElapsedEventHandler(DisconnectTimer_Elapsed); } /// - /// + /// Register an event handler for a packet. This is a low level event + /// interface and should only be used if you are doing something not + /// supported in libsecondlife /// - /// - /// + /// Packet type to trigger events for + /// Callback to fire when a packet of this type + /// is received public void RegisterCallback(PacketType type, PacketCallback callback) { if (!Callbacks.ContainsKey(type)) @@ -918,10 +924,12 @@ namespace libsecondlife } /// - /// + /// Unregister an event handler for a packet. This is a low level event + /// interface and should only be used if you are doing something not + /// supported in libsecondlife /// - /// - /// + /// Packet type this callback is registered with + /// Callback to stop firing events for public void UnregisterCallback(PacketType type, PacketCallback callback) { if (!Callbacks.ContainsKey(type)) @@ -945,69 +953,72 @@ namespace libsecondlife } /// - /// + /// Register a CAPS event handler /// - /// + /// Callback to fire when a CAPS event is received public void RegisterEventCallback(Caps.EventQueueCallback callback) { EventQueueCallbacks.Add(callback); } /// - /// + /// Send a packet to the simulator the avatar is currently occupying /// - /// + /// Packet to send public void SendPacket(Packet packet) { if (CurrentSim != null && CurrentSim.Connected) - { CurrentSim.SendPacket(packet, true); - } } /// - /// + /// Send a packet to a specified simulator /// - /// - /// + /// Packet to send + /// Simulator to send the packet to public void SendPacket(Packet packet, Simulator simulator) { if (simulator != null && simulator.Connected) - { simulator.SendPacket(packet, true); - } } /// - /// + /// Send a raw byte array as a packet to the current simulator /// - /// + /// Byte array containing a packet /// Whether to set the second, third, and fourth /// bytes of the payload to the current sequence number public void SendPacket(byte[] payload, bool setSequence) { if (connected && CurrentSim != null) - { CurrentSim.SendPacket(payload, setSequence); - } - else - { - Client.Log("Trying to send a " + payload.Length + " payload " + - "when we're not connected", Helpers.LogLevel.Warning); - } } /// - /// Use this if you want to login to a specific location + /// Send a raw byte array as a packet to the specified simulator /// - /// - /// - /// - /// - /// string with a value that can be used in the start field in .DefaultLoginValues() + /// Byte array containing a packet + /// Simulator to send the packet to + /// Whether to set the second, third, and fourth + /// bytes of the payload to the current sequence number + public void SendPacket(byte[] payload, Simulator simulator, bool setSequence) + { + if (connected && simulator != null) + simulator.SendPacket(payload, setSequence); + } + + /// + /// Build a start location URI for passing to the Login function + /// + /// Name of the simulator to start in + /// X coordinate to start at + /// Y coordinate to start at + /// Z coordinate to start at + /// String with a URI that can be used to login to a specified + /// location public static string StartLocation(string sim, int x, int y, int z) { - //uri:sim&x&y&z + // uri:sim name&x&y&z return "uri:" + sim.ToLower() + "&" + x + "&" + y + "&" + z; } @@ -1232,6 +1243,9 @@ namespace libsecondlife XmlRpcRequest xmlrpc; Hashtable loginValues; + // Re-read the timeout value for the DisconnectTimer + DisconnectTimer.Interval = Client.Settings.SIMULATOR_TIMEOUT; + // Clear possible old values from the last login LoginValues.Clear(); @@ -1386,6 +1400,7 @@ namespace libsecondlife { this.AgentID = new LLUUID((string)LoginValues["agent_id"]); this.SessionID = new LLUUID((string)LoginValues["session_id"]); + this.SecureSessionID = new LLUUID((string)LoginValues["secure_session_id"]); Client.Self.ID = this.AgentID; // Names are wrapped in quotes now, have to strip those Client.Self.FirstName = ((string)LoginValues["first_name"]).Trim(new char[] { '"' }); @@ -1558,6 +1573,10 @@ namespace libsecondlife /// public void ForceLogout() { + Client.Log("Forcing a logout", Helpers.LogLevel.Info); + + DisconnectTimer.Stop(); + // Insist on shutdown LogoutDemandPacket logoutDemand = new LogoutDemandPacket(); logoutDemand.LogoutBlock.SessionID = SessionID; diff --git a/libsecondlife-cs/Settings.cs b/libsecondlife-cs/Settings.cs index 80a5297e..0d459bd4 100644 --- a/libsecondlife-cs/Settings.cs +++ b/libsecondlife-cs/Settings.cs @@ -1,102 +1,102 @@ -/* - * Copyright (c) 2006, Second Life Reverse Engineering Team - * All rights reserved. - * - * - 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. - * - Neither the name of the Second Life Reverse Engineering Team 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Generic; -using libsecondlife.Packets; - -namespace libsecondlife -{ - /// - /// Class for controlling various system settings. - /// - public class Settings - { - /// The version of libsecondlife (not the SL protocol itself) - public string VERSION = "libsecondlife 0.0.9"; - /// XML-RPC login server to connect to - public string LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; - - /// Millisecond interval between ticks, where all ACKs are - /// sent out and the age of unACKed packets is checked - public readonly int NETWORK_TICK_LENGTH = 500; - /// The maximum value of a packet sequence number. After that - /// we assume the sequence number just rolls over? Or maybe the - /// protocol isn't able to sustain a connection past that - public readonly int MAX_SEQUENCE = 0xFFFFFF; - /// Number of milliseconds before a teleport attempt will time - /// out - public readonly int TELEPORT_TIMEOUT = 18 * 1000; - - /// Number of milliseconds before NetworkManager.Logout() will time out - public int LOGOUT_TIMEOUT = 5 * 1000; - /// Number of milliseconds for xml-rpc to timeout - public int LOGIN_TIMEOUT = 30 * 1000; - /// The maximum size of the sequence number inbox, used to - /// check for resent and/or duplicate packets - public int INBOX_SIZE = 100; - /// Milliseconds before a packet is assumed lost and resent - public int RESEND_TIMEOUT = 4000; - /// Milliseconds before the connection to a simulator is - /// assumed lost - public int SIMULATOR_TIMEOUT = 15000; - /// Maximum number of queued ACKs to be sent before SendAcks() - /// is forced - public int MAX_PENDING_ACKS = 10; - /// Maximum number of ACKs to append to a packet - public int MAX_APPENDED_ACKS = 10; - /// Cost of uploading an asset +/* + * Copyright (c) 2006, Second Life Reverse Engineering Team + * All rights reserved. + * + * - 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. + * - Neither the name of the Second Life Reverse Engineering Team 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR 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.Generic; +using libsecondlife.Packets; + +namespace libsecondlife +{ + /// + /// Class for controlling various system settings. + /// + public class Settings + { + /// The version of libsecondlife (not the SL protocol itself) + public string VERSION = "libsecondlife 0.0.9"; + /// XML-RPC login server to connect to + public string LOGIN_SERVER = "https://login.agni.lindenlab.com/cgi-bin/login.cgi"; + + /// Millisecond interval between ticks, where all ACKs are + /// sent out and the age of unACKed packets is checked + public readonly int NETWORK_TICK_LENGTH = 500; + /// The maximum value of a packet sequence number. After that + /// we assume the sequence number just rolls over? Or maybe the + /// protocol isn't able to sustain a connection past that + public readonly int MAX_SEQUENCE = 0xFFFFFF; + /// Number of milliseconds before a teleport attempt will time + /// out + public readonly int TELEPORT_TIMEOUT = 18 * 1000; + + /// Number of milliseconds before NetworkManager.Logout() will time out + public int LOGOUT_TIMEOUT = 5 * 1000; + /// Number of milliseconds for xml-rpc to timeout + public int LOGIN_TIMEOUT = 30 * 1000; + /// The maximum size of the sequence number inbox, used to + /// check for resent and/or duplicate packets + public int INBOX_SIZE = 100; + /// Milliseconds before a packet is assumed lost and resent + public int RESEND_TIMEOUT = 4000; + /// Milliseconds without receiving a packet before the + /// connection to a simulator is assumed lost + public int SIMULATOR_TIMEOUT = 15 * 1000; + /// Maximum number of queued ACKs to be sent before SendAcks() + /// is forced + public int MAX_PENDING_ACKS = 10; + /// Maximum number of ACKs to append to a packet + public int MAX_APPENDED_ACKS = 10; + /// Cost of uploading an asset public int UPLOAD_COST { get { return priceUpload; } } /// Enable/disable debugging log messages - public bool DEBUG = true; - - private SecondLife Client; - private int priceUpload = 0; - - /// - /// Constructor - /// - /// Client connection Object to use - public Settings(SecondLife client) - { - Client = client; - - Client.Network.RegisterCallback(Packets.PacketType.EconomyData, new NetworkManager.PacketCallback(EconomyDataHandler)); - } - - /// - /// Presumably for outputting asset upload costs. - /// - /// - /// - private void EconomyDataHandler(Packet packet, Simulator simulator) - { - EconomyDataPacket econ = (EconomyDataPacket)packet; - - priceUpload = econ.Info.PriceUpload; - } - } -} + public bool DEBUG = true; + + private SecondLife Client; + private int priceUpload = 0; + + /// + /// Constructor + /// + /// Client connection Object to use + public Settings(SecondLife client) + { + Client = client; + + Client.Network.RegisterCallback(Packets.PacketType.EconomyData, new NetworkManager.PacketCallback(EconomyDataHandler)); + } + + /// + /// Presumably for outputting asset upload costs. + /// + /// + /// + private void EconomyDataHandler(Packet packet, Simulator simulator) + { + EconomyDataPacket econ = (EconomyDataPacket)packet; + + priceUpload = econ.Info.PriceUpload; + } + } +} diff --git a/libsecondlife-cs/Types.cs b/libsecondlife-cs/Types.cs index 65fadae2..4d48bb2b 100644 --- a/libsecondlife-cs/Types.cs +++ b/libsecondlife-cs/Types.cs @@ -104,6 +104,22 @@ namespace libsecondlife return retval; } + /// + /// Combine two UUIDs together by taking the MD5 hash of a byte array + /// containing both UUIDs + /// + /// The UUID to combine with this one + /// The UUID product of the combination + public LLUUID Combine(LLUUID other) + { + // Build the buffer to MD5 + byte[] input = new byte[32]; + Array.Copy(data, input, 16); + Array.Copy(other.Data, 0, input, 16, 16); + + return new LLUUID(Helpers.MD5Builder.ComputeHash(input), 0); + } + /// /// Parse the bytes for a LLUUID from a string /// diff --git a/libsecondlife-cs/libsecondlife.Utilities/Assets.cs b/libsecondlife-cs/libsecondlife.Utilities/Assets.cs index 4c46b1f2..e0f27c1a 100644 --- a/libsecondlife-cs/libsecondlife.Utilities/Assets.cs +++ b/libsecondlife-cs/libsecondlife.Utilities/Assets.cs @@ -206,8 +206,8 @@ namespace libsecondlife.Utilities.Assets Client.Network.RegisterCallback(PacketType.TransferPacket, new NetworkManager.PacketCallback(TransferPacketHandler)); // Xfer packets for uploading large assets - //Client.Network.RegisterCallback(PacketType.AssetUploadComplete, new NetworkManager.PacketCallback(AssetUploadCompleteHandler)); - //Client.Network.RegisterCallback(PacketType.ConfirmXferPacket, new NetworkManager.PacketCallback(ConfirmXferPacketHandler)); + Client.Network.RegisterCallback(PacketType.AssetUploadComplete, new NetworkManager.PacketCallback(AssetUploadCompleteHandler)); + Client.Network.RegisterCallback(PacketType.ConfirmXferPacket, new NetworkManager.PacketCallback(ConfirmXferPacketHandler)); //Client.Network.RegisterCallback(PacketType.RequestXfer, new NetworkManager.PacketCallback(RequestXferHandler)); } @@ -289,6 +289,19 @@ namespace libsecondlife.Utilities.Assets } public void RequestEstateAsset() + { + throw new Exception("This function is not implemented yet!"); + } + + /// + /// + /// + /// + /// + /// + /// + /// + public void RequestUpload(LLUUID transactionID, AssetType type, byte[] data, bool tempFile, bool isPriority) { ; } @@ -424,6 +437,16 @@ namespace libsecondlife.Utilities.Assets } } } + + private void AssetUploadCompleteHandler(Packet packet, Simulator simulator) + { + ; + } + + private void ConfirmXferPacketHandler(Packet packet, Simulator simulator) + { + ; + } } public class ImageManager