From 61c8451facffd70d7e4364dda0e5f071397b5f57 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 5 Nov 2008 01:50:24 +0000 Subject: [PATCH] * Allow HttpServer AddHandler() and RemoveHandler() while the server is running * Simplified HttpServer calback exception handling * Fixed a recently introduced typo in LLSD binary serialization * Allow LLSD binary serialization to work with any Stream instead of only MemoryStream * Improved Utils.HexStringToBytes(), changed function signature * Added an efficient Utils.EnumTryParse() git-svn-id: http://libopenmetaverse.googlecode.com/svn/libopenmetaverse/trunk@2323 52acb1d6-8a22-11de-b505-999d5b087335 --- OpenMetaverse/AssetManager.cs | 4 +- OpenMetaverse/Capabilities/HttpServer.cs | 46 +++-------- OpenMetaverse/StructuredData/BinaryLLSD.cs | 22 ++--- OpenMetaverse/Types/UtilsConversions.cs | 94 +++++++++++++++------- Programs/Simian/Extensions/UDPServer.cs | 1 - 5 files changed, 89 insertions(+), 78 deletions(-) diff --git a/OpenMetaverse/AssetManager.cs b/OpenMetaverse/AssetManager.cs index 0aa7711c..bee6ae58 100644 --- a/OpenMetaverse/AssetManager.cs +++ b/OpenMetaverse/AssetManager.cs @@ -529,8 +529,8 @@ namespace OpenMetaverse request.TransferInfo.TransferID = transfer.ID; byte[] paramField = new byte[20]; - Array.Copy(assetID.GetBytes(), 0, paramField, 0, 16); - Array.Copy(Utils.IntToBytes((int)type), 0, paramField, 16, 4); + Buffer.BlockCopy(assetID.GetBytes(), 0, paramField, 0, 16); + Buffer.BlockCopy(Utils.IntToBytes((int)type), 0, paramField, 16, 4); request.TransferInfo.Params = paramField; Client.Network.SendPacket(request, transfer.Simulator); diff --git a/OpenMetaverse/Capabilities/HttpServer.cs b/OpenMetaverse/Capabilities/HttpServer.cs index ed9f2174..7fdebe83 100644 --- a/OpenMetaverse/Capabilities/HttpServer.cs +++ b/OpenMetaverse/Capabilities/HttpServer.cs @@ -65,6 +65,7 @@ namespace OpenMetaverse.Capabilities AsyncCallback serverCallback; //int serverPort; //bool sslEnabled; + // TODO: Replace this with an immutable list to avoid locking List requestHandlers; bool isRunning; @@ -97,18 +98,12 @@ namespace OpenMetaverse.Capabilities public void AddHandler(HttpRequestHandler handler) { - if (!isRunning) - requestHandlers.Add(handler); - else - throw new InvalidOperationException("Cannot add HTTP request handlers while the server is running"); + lock (requestHandlers) requestHandlers.Add(handler); } public void RemoveHandler(HttpRequestHandler handler) { - if (!isRunning) - requestHandlers.Remove(handler); - else - throw new InvalidOperationException("Cannot add HTTP request handlers while the server is running"); + lock (requestHandlers) requestHandlers.Remove(handler); } public void Start() @@ -153,35 +148,18 @@ namespace OpenMetaverse.Capabilities HttpRequestSignature signature = new HttpRequestSignature(context); // Look for a signature match in our handlers - for (int i = 0; i < requestHandlers.Count; i++) + lock (requestHandlers) { - HttpRequestHandler handler = requestHandlers[i]; - - if (signature == handler.Signature) + for (int i = 0; i < requestHandlers.Count; i++) { - // Request signature matched, handle it - try - { - handler.Callback(signature, ref context); - } - catch (Exception e) - { - try - { - context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - context.Response.StatusDescription = e.ToString(); - } - catch (Exception) - { - Logger.Log(e.ToString(), Helpers.LogLevel.Error); - } - } - finally - { - context.Response.Close(); - } + HttpRequestHandler handler = requestHandlers[i]; - return; + if (signature == handler.Signature) + { + // Request signature matched, handle it + handler.Callback(signature, ref context); + return; + } } } diff --git a/OpenMetaverse/StructuredData/BinaryLLSD.cs b/OpenMetaverse/StructuredData/BinaryLLSD.cs index b990c454..cb177ba9 100644 --- a/OpenMetaverse/StructuredData/BinaryLLSD.cs +++ b/OpenMetaverse/StructuredData/BinaryLLSD.cs @@ -53,7 +53,7 @@ namespace OpenMetaverse.StructuredData private const int int32Length = 4; private const int doubleLength = 8; - private static byte[] binaryHead = Encoding.ASCII.GetBytes("\n"); + private static byte[] llsdBinaryHead = Encoding.ASCII.GetBytes("\n"); private const byte undefBinaryValue = (byte)'!'; private const byte trueBinaryValue = (byte)'1'; private const byte falseBinaryValue = (byte)'0'; @@ -89,11 +89,11 @@ namespace OpenMetaverse.StructuredData /// /// /// - public static OSD DeserializeLLSDBinary(MemoryStream stream) + public static OSD DeserializeLLSDBinary(Stream stream) { SkipWhiteSpace(stream); - bool result = FindByteArray(stream, binaryHead); + bool result = FindByteArray(stream, llsdBinaryHead); if (!result) throw new OSDException("No binary encoded SD."); @@ -123,7 +123,7 @@ namespace OpenMetaverse.StructuredData { MemoryStream stream = new MemoryStream(initialBufferSize); - stream.Write(binaryHead, 0, binaryHead.Length); + stream.Write(llsdBinaryHead, 0, llsdBinaryHead.Length); SerializeLLSDBinaryElement(stream, data); return stream; } @@ -218,7 +218,7 @@ namespace OpenMetaverse.StructuredData stream.WriteByte(mapEndBinaryMarker); } - private static OSD ParseLLSDBinaryElement(MemoryStream stream) + private static OSD ParseLLSDBinaryElement(Stream stream) { SkipWhiteSpace(stream); OSD osd; @@ -291,7 +291,7 @@ namespace OpenMetaverse.StructuredData return osd; } - private static OSD ParseLLSDBinaryArray(MemoryStream stream) + private static OSD ParseLLSDBinaryArray(Stream stream) { int numElements = NetworkToHostInt(ConsumeBytes(stream, int32Length)); int crrElement = 0; @@ -308,7 +308,7 @@ namespace OpenMetaverse.StructuredData return (OSD)osdArray; } - private static OSD ParseLLSDBinaryMap(MemoryStream stream) + private static OSD ParseLLSDBinaryMap(Stream stream) { int numElements = NetworkToHostInt(ConsumeBytes(stream, int32Length)); int crrElement = 0; @@ -333,7 +333,7 @@ namespace OpenMetaverse.StructuredData /// /// /// - public static void SkipWhiteSpace(MemoryStream stream) + public static void SkipWhiteSpace(Stream stream) { int bt; @@ -352,7 +352,7 @@ namespace OpenMetaverse.StructuredData /// /// /// - public static bool FindByte(MemoryStream stream, byte toFind) + public static bool FindByte(Stream stream, byte toFind) { int bt = stream.ReadByte(); if (bt < 0) @@ -372,7 +372,7 @@ namespace OpenMetaverse.StructuredData /// /// /// - public static bool FindByteArray(MemoryStream stream, byte[] toFind) + public static bool FindByteArray(Stream stream, byte[] toFind) { int lastIndexToFind = toFind.Length - 1; int crrIndex = 0; @@ -412,7 +412,7 @@ namespace OpenMetaverse.StructuredData /// /// /// - public static byte[] ConsumeBytes(MemoryStream stream, int consumeBytes) + public static byte[] ConsumeBytes(Stream stream, int consumeBytes) { byte[] bytes = new byte[consumeBytes]; if (stream.Read(bytes, 0, consumeBytes) < consumeBytes) diff --git a/OpenMetaverse/Types/UtilsConversions.cs b/OpenMetaverse/Types/UtilsConversions.cs index 3313dc2e..5cd26502 100644 --- a/OpenMetaverse/Types/UtilsConversions.cs +++ b/OpenMetaverse/Types/UtilsConversions.cs @@ -413,45 +413,48 @@ namespace OpenMetaverse return System.Text.UTF8Encoding.UTF8.GetBytes(str); } - ///// - ///// Converts a string containing hexadecimal characters to a byte array - ///// - ///// String containing hexadecimal characters - ///// The converted byte array - public static byte[] HexStringToBytes(string hexString) + /// + /// Converts a string containing hexadecimal characters to a byte array + /// + /// String containing hexadecimal characters + /// If true, gracefully handles null, empty and + /// uneven strings as well as stripping unconvertable characters + /// The converted byte array + public static byte[] HexStringToBytes(string hexString, bool handleDirty) { - if (String.IsNullOrEmpty(hexString)) - return new byte[0]; - - StringBuilder stripped = new StringBuilder(hexString.Length); - char c; - - // remove all non A-F, 0-9, characters - for (int i = 0; i < hexString.Length; i++) + if (handleDirty) { - c = hexString[i]; - if (IsHexDigit(c)) - stripped.Append(c); + if (String.IsNullOrEmpty(hexString)) + return new byte[0]; + + StringBuilder stripped = new StringBuilder(hexString.Length); + char c; + + // remove all non A-F, 0-9, characters + for (int i = 0; i < hexString.Length; i++) + { + c = hexString[i]; + if (IsHexDigit(c)) + stripped.Append(c); + } + + hexString = stripped.ToString(); + + // if odd number of characters, discard last character + if (hexString.Length % 2 != 0) + { + hexString = hexString.Substring(0, hexString.Length - 1); + } } - string newString = stripped.ToString(); - - // if odd number of characters, discard last character - if (newString.Length % 2 != 0) - { - newString = newString.Substring(0, newString.Length - 1); - } - - int byteLength = newString.Length / 2; + int byteLength = hexString.Length / 2; byte[] bytes = new byte[byteLength]; - string hex; int j = 0; for (int i = 0; i < bytes.Length; i++) { - hex = new String(new Char[] { newString[j], newString[j + 1] }); - bytes[i] = HexToByte(hex); - j = j + 2; + bytes[i] = HexToByte(hexString.Substring(j, 2)); + j += 2; } return bytes; @@ -730,6 +733,37 @@ namespace OpenMetaverse rhs = temp; } + /// + /// Try to parse an enumeration value from a string + /// + /// Enumeration type + /// String value to parse + /// Enumeration value on success + /// True if the parsing succeeded, otherwise false + public static bool EnumTryParse(string strType, out T result) + { + Type t = typeof(T); + + if (Enum.IsDefined(t, strType)) + { + result = (T)Enum.Parse(t, strType, true); + return true; + } + else + { + foreach (string value in Enum.GetNames(typeof(T))) + { + if (value.Equals(strType, StringComparison.OrdinalIgnoreCase)) + { + result = (T)Enum.Parse(typeof(T), value); + return true; + } + } + result = default(T); + return false; + } + } + #endregion Miscellaneous } } diff --git a/Programs/Simian/Extensions/UDPServer.cs b/Programs/Simian/Extensions/UDPServer.cs index 10d51626..6da03c9e 100644 --- a/Programs/Simian/Extensions/UDPServer.cs +++ b/Programs/Simian/Extensions/UDPServer.cs @@ -80,7 +80,6 @@ namespace Simian public void Start(Simian server) { this.server = server; - udpServer = new UDPServer(server.UDPPort, server); }