From 064404ab409ddd0a3b25027a98582696295c46fd Mon Sep 17 00:00:00 2001 From: lbsa71 Date: Wed, 31 Oct 2007 07:28:23 +0000 Subject: * Moved OpenSim/Framework/General to OpenSim/Framework for great justice. --- OpenSim/Framework/Util.cs | 371 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 371 insertions(+) create mode 100644 OpenSim/Framework/Util.cs (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs new file mode 100644 index 0000000..c731561 --- /dev/null +++ b/OpenSim/Framework/Util.cs @@ -0,0 +1,371 @@ +/* +* 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.Generic; +using System.Data; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography; +using System.Text; +using libsecondlife; +using Nini.Config; + +namespace OpenSim.Framework +{ + public class Util + { + private static Random randomClass = new Random(); + private static uint nextXferID = 5000; + private static object XferLock = new object(); + private static Dictionary capsURLS = new Dictionary(); + + + public static ulong UIntsToLong(uint X, uint Y) + { + return Helpers.UIntsToLong(X, Y); + } + + public static Random RandomClass + { + get { return randomClass; } + } + + public static uint GetNextXferID() + { + uint id = 0; + lock (XferLock) + { + id = nextXferID; + nextXferID++; + } + return id; + } + + public Util() + { + } + + public static string GetFileName(string file) + { + // Return just the filename on UNIX platforms + // TODO: this should be customisable with a prefix, but that's something to do later. + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + return file; + } + + // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA + // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + if (!Directory.Exists("%APPDATA%\\OpenSim\\")) + { + Directory.CreateDirectory("%APPDATA%\\OpenSim"); + } + + return "%APPDATA%\\OpenSim\\" + file; + } + + // Catch all - covers older windows versions + // (but those probably wont work anyway) + return file; + } + + public static bool IsEnvironmentSupported(ref string reason) + { + // Must have .NET 2.0 (Generics / libsl) + if (Environment.Version.Major < 2) + { + reason = ".NET 1.0/1.1 lacks components that is used by OpenSim"; + return false; + } + + // Windows 95/98/ME are unsupported + if (Environment.OSVersion.Platform == PlatformID.Win32Windows && + Environment.OSVersion.Platform != PlatformID.Win32NT) + { + reason = "Windows 95/98/ME will not run OpenSim"; + return false; + } + + // Windows 2000 / Pre-SP2 XP + if (Environment.OSVersion.Version.Major == 5 && ( + Environment.OSVersion.Version.Minor == 0)) + { + reason = "Please update to Windows XP Service Pack 2 or Server2003"; + return false; + } + + return true; + } + + public static int UnixTimeSinceEpoch() + { + TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); + int timestamp = (int) t.TotalSeconds; + return timestamp; + } + + public static string Md5Hash(string pass) + { + MD5 md5 = MD5CryptoServiceProvider.Create(); + byte[] dataMd5 = md5.ComputeHash(Encoding.Default.GetBytes(pass)); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < dataMd5.Length; i++) + sb.AppendFormat("{0:x2}", dataMd5[i]); + return sb.ToString(); + } + + public static string GetRandomCapsPath() + { + LLUUID caps = LLUUID.Random(); + string capsPath = caps.ToStringHyphenated(); + capsPath = capsPath.Remove(capsPath.Length - 4, 4); + return capsPath; + } + + public static int fast_distance2d(int x, int y) + { + x = Math.Abs(x); + y = Math.Abs(y); + + int min = Math.Min(x, y); + + return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); + } + + public static string FieldToString(byte[] bytes) + { + return FieldToString(bytes, String.Empty); + } + + /// + /// Convert a variable length field (byte array) to a string, with a + /// field name prepended to each line of the output + /// + /// If the byte array has unprintable characters in it, a + /// hex dump will be put in the string instead + /// The byte array to convert to a string + /// A field name to prepend to each line of output + /// An ASCII string or a string containing a hex dump, minus + /// the null terminator + public static string FieldToString(byte[] bytes, string fieldName) + { + // Check for a common case + if (bytes.Length == 0) return String.Empty; + + StringBuilder output = new StringBuilder(); + bool printable = true; + + for (int i = 0; i < bytes.Length; ++i) + { + // Check if there are any unprintable characters in the array + if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 + && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) + { + printable = false; + break; + } + } + + if (printable) + { + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + if (bytes[bytes.Length - 1] == 0x00) + output.Append(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1)); + else + output.Append(UTF8Encoding.UTF8.GetString(bytes)); + } + else + { + for (int i = 0; i < bytes.Length; i += 16) + { + if (i != 0) + output.Append(Environment.NewLine); + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + for (int j = 0; j < 16; j++) + { + if ((i + j) < bytes.Length) + output.Append(String.Format("{0:X2} ", bytes[i + j])); + else + output.Append(" "); + } + + for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) + { + if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) + output.Append((char) bytes[i + j]); + else + output.Append("."); + } + } + } + + return output.ToString(); + } + + /// + /// Returns a IP address from a specified DNS, favouring IPv4 addresses. + /// + /// DNS Hostname + /// An IP address, or null + public static IPAddress GetHostFromDNS(string dnsAddress) + { + // Is it already a valid IP? No need to look it up. + IPAddress ipa; + if (IPAddress.TryParse(dnsAddress, out ipa)) + return ipa; + + // Not an IP, lookup required + IPAddress[] hosts = Dns.GetHostEntry(dnsAddress).AddressList; + + foreach (IPAddress host in hosts) + { + if (host.AddressFamily == AddressFamily.InterNetwork) + { + return host; + } + } + + if (hosts.Length > 0) + return hosts[0]; + + return null; + } + + public static IPAddress GetLocalHost() + { + string dnsAddress = "localhost"; + + IPAddress[] hosts = Dns.GetHostEntry(dnsAddress).AddressList; + + foreach (IPAddress host in hosts) + { + if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) + { + return host; + } + } + + if (hosts.Length > 0) + return hosts[0]; + + return null; + } + + // + // directory locations + // + + public static string homeDir() + { + string temp; +// string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); +// temp = Path.Combine(personal,".OpenSim"); + temp = "."; + return temp; + } + + public static string configDir() + { + string temp; + temp = "."; + return temp; + } + + public static string dataDir() + { + string temp; + temp = "."; + return temp; + } + + public static string logDir() + { + string temp; + temp = "."; + return temp; + } + + public static string GetCapsURL(LLUUID userID) + { + if (capsURLS.ContainsKey(userID)) + { + return capsURLS[userID]; + } + return ""; + } + + public static void SetCapsURL(LLUUID userID, string url) + { + if (capsURLS.ContainsKey(userID)) + { + capsURLS[userID] = url; + } + else + { + capsURLS.Add(userID, url); + } + } + + // Nini (config) related Methods + public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) + { + if (!File.Exists(fileName)) + { + //create new file + } + XmlConfigSource config = new XmlConfigSource(fileName); + AddDataRowToConfig(config, row); + config.Save(); + + return config; + } + + public static void AddDataRowToConfig(IConfigSource config, DataRow row) + { + config.Configs.Add((string) row[0]); + for (int i = 0; i < row.Table.Columns.Count; i++) + { + config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); + } + } + } +} \ No newline at end of file -- cgit v1.1 From 3d938f76b7c2f8ede862f9979383d79dfb21372c Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Fri, 7 Dec 2007 08:54:31 +0000 Subject: Updates to LibSL revision 1498. Thanks Johan! --- OpenSim/Framework/Util.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c731561..a9aff60 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -46,6 +46,12 @@ namespace OpenSim.Framework private static object XferLock = new object(); private static Dictionary capsURLS = new Dictionary(); + public static double GetDistanceTo(LLVector3 a, LLVector3 b) { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return Math.Sqrt(dx * dx + dy * dy + dz * dz); + } public static ulong UIntsToLong(uint X, uint Y) { -- cgit v1.1 From af6eb67999875f12270ef19ed33c179556696754 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Mon, 10 Dec 2007 05:25:16 +0000 Subject: saved OpenSim source code from the giant rampaging unterminated copyright notice of doom --- OpenSim/Framework/Util.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a9aff60..a8eef51 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -13,7 +13,7 @@ * 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 +* 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 @@ -374,4 +374,4 @@ namespace OpenSim.Framework } } } -} \ No newline at end of file +} -- cgit v1.1 From 6702b0373371fd2a546a580ad82f5cc175fa29e0 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Wed, 19 Dec 2007 08:44:25 +0000 Subject: Misc. cleanup: * added Util.Clip(value, min, max) * modified asset cache's numPackets calculation to use max packet size (600) instead of 1000 * removed a few magic numbers --- OpenSim/Framework/Util.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a8eef51..740f527 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -373,5 +373,15 @@ namespace OpenSim.Framework config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); } } + + public static float Clip(float x, float min, float max) + { + return Math.Min(Math.Max(x, min), max); + } + + public static int Clip(int x, int min, int max) + { + return Math.Min(Math.Max(x, min), max); + } } } -- cgit v1.1 From be2ad79e52efb5eb543057e8e73fa601d0b91c87 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Thu, 20 Dec 2007 05:43:02 +0000 Subject: Added patch from Johan. First attempt to solve the LibSL.Packet GC problem. Works with LibSL rev>1532 --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 740f527..db841cf 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -152,7 +152,7 @@ namespace OpenSim.Framework public static string GetRandomCapsPath() { LLUUID caps = LLUUID.Random(); - string capsPath = caps.ToStringHyphenated(); + string capsPath = caps.ToString(); capsPath = capsPath.Remove(capsPath.Length - 4, 4); return capsPath; } -- cgit v1.1 From dd1e2c8eb9de34c2464bd526a782b47ec1c823e5 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Thu, 20 Dec 2007 18:43:39 +0000 Subject: Establish Util.ToRawUuidString to get LLUUIDs in unhyphenated form Apply method to UUID crud in SqliteInventoryStore as an initial test This appears now to successfully recover inventory upon login This will almost certainly only work on standalone --- OpenSim/Framework/Util.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index db841cf..0b05eac 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -383,5 +383,15 @@ namespace OpenSim.Framework { return Math.Min(Math.Max(x, min), max); } + + /// + /// Convert an LLUUID to a raw uuid string. This is a string without hyphens. + /// + /// + /// + public static String ToRawUuidString(LLUUID lluuid) + { + return lluuid.UUID.ToString("n"); + } } } -- cgit v1.1 From f1ebe79824aa82fa30af35d07bf6720e719cd741 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Thu, 20 Dec 2007 19:13:34 +0000 Subject: Fix up other sqlite db interactions to use non-hyphenated uuid Inventory contents retrieval and persistent region storage standalone now appear to work as well as they did before :) This patch will not fix grid problems. May be bugs present due to conversions I didn't spot. I personally probably don't have any more time for this today. I'm also not entirely convinced this is the right way forward so this might be a handy pause for thought. I'll also be delighted if I wake up tommorrow and everything is fine again. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0b05eac..1c8f273 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -385,7 +385,7 @@ namespace OpenSim.Framework } /// - /// Convert an LLUUID to a raw uuid string. This is a string without hyphens. + /// Convert an LLUUID to a raw uuid string. Right now this is a string without hyphens. /// /// /// -- cgit v1.1 From efd90b56b761219af6425b1c7a2cdd3b6ffb4de2 Mon Sep 17 00:00:00 2001 From: lbsa71 Date: Thu, 27 Dec 2007 21:41:48 +0000 Subject: * Optimized usings * shortened references * Removed redundant 'this' * Normalized EOF --- OpenSim/Framework/Util.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 1c8f273..3654a7d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -46,12 +46,13 @@ namespace OpenSim.Framework private static object XferLock = new object(); private static Dictionary capsURLS = new Dictionary(); - public static double GetDistanceTo(LLVector3 a, LLVector3 b) { - float dx = a.X - b.X; - float dy = a.Y - b.Y; - float dz = a.Z - b.Z; - return Math.Sqrt(dx * dx + dy * dy + dz * dz); - } + public static double GetDistanceTo(LLVector3 a, LLVector3 b) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return Math.Sqrt(dx*dx + dy*dy + dz*dz); + } public static ulong UIntsToLong(uint X, uint Y) { @@ -383,7 +384,7 @@ namespace OpenSim.Framework { return Math.Min(Math.Max(x, min), max); } - + /// /// Convert an LLUUID to a raw uuid string. Right now this is a string without hyphens. /// @@ -394,4 +395,4 @@ namespace OpenSim.Framework return lluuid.UUID.ToString("n"); } } -} +} \ No newline at end of file -- cgit v1.1 From 67bbed820290b0307f09f29343e5fc96bdfc669a Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Fri, 28 Dec 2007 05:25:21 +0000 Subject: * Added ability to create new prim on existing prim (rezzing prim from inventory on other prim coming soon). No more new prim buried in the ground by accident. * The prim are at the absolute position of the prim you rezzed it on top of + (0,0,0.5) for now. --- OpenSim/Framework/Util.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 3654a7d..e6512c2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -46,6 +46,8 @@ namespace OpenSim.Framework private static object XferLock = new object(); private static Dictionary capsURLS = new Dictionary(); + #region Vector Equasions + public static double GetDistanceTo(LLVector3 a, LLVector3 b) { float dx = a.X - b.X; @@ -53,6 +55,16 @@ namespace OpenSim.Framework float dz = a.Z - b.Z; return Math.Sqrt(dx*dx + dy*dy + dz*dz); } + public static double GetMagnitude(LLVector3 a) { + return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); + } + public static LLVector3 GetNormal(LLVector3 a) + { + float Mag = (float)GetMagnitude(a); + return new LLVector3(a.X / Mag, a.Y / Mag, a.Z / Mag); + + } + # endregion public static ulong UIntsToLong(uint X, uint Y) { -- cgit v1.1 From 0631151e08174fffbc5bf3f646ef32e16e2c5145 Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Fri, 28 Dec 2007 23:19:03 +0000 Subject: * Patch from Melanie provides Util.CleanString and uses it on the prim name and description. Thanks Melanie. --- OpenSim/Framework/Util.cs | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e6512c2..08b3a9d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -222,10 +222,7 @@ namespace OpenSim.Framework output.Append(": "); } - if (bytes[bytes.Length - 1] == 0x00) - output.Append(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1)); - else - output.Append(UTF8Encoding.UTF8.GetString(bytes)); + output.Append(CleanString(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1))); } else { @@ -406,5 +403,31 @@ namespace OpenSim.Framework { return lluuid.UUID.ToString("n"); } + + public static string CleanString(string input) + { + if(input.Length == 0) + return input; + + int clip=input.Length; + + // Test for ++ string terminator + int pos=input.IndexOf("\0"); + if(pos != -1 && pos < clip) + clip=pos; + + // Test for CR + pos=input.IndexOf("\r"); + if(pos != -1 && pos < clip) + clip=pos; + + // Test for LF + pos=input.IndexOf("\n"); + if(pos != -1 && pos < clip) + clip=pos; + + // Truncate string before first end-of-line character found + return input.Substring(0, clip); + } } -} \ No newline at end of file +} -- cgit v1.1 From 1b1649791fbfdd57173c16f0bf2353898ceb8852 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Sat, 29 Dec 2007 19:01:55 +0000 Subject: Allow OpenSim operators to specify their own asset sets without needing to change the default OpenSim set. Equivalent changes to allow operators to also specify their own standard inventory library directories and items to follow. --- OpenSim/Framework/Util.cs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 08b3a9d..c742cf3 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -318,6 +318,11 @@ namespace OpenSim.Framework temp = "."; return temp; } + + public static string assetsDir() + { + return "assets"; + } public static string configDir() { -- cgit v1.1 From b8975ecbd9510bd8e766cb4ca06c5a70110187cd Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 31 Dec 2007 23:20:49 +0000 Subject: Make it possible for new inventory 'libraries' to be added without changing the default OpenSimLibrary files. Additional library folders and items can be added in a separate directory and linked in by an entry to inventory/Libraries.xml --- OpenSim/Framework/Util.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c742cf3..0f41380 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -321,7 +321,12 @@ namespace OpenSim.Framework public static string assetsDir() { - return "assets"; + return Path.Combine(configDir(), "assets"); + } + + public static string inventoryDir() + { + return Path.Combine(configDir(), "inventory"); } public static string configDir() -- cgit v1.1 From 5a6fd21a2c31a41c617f1d2a7e390956b5aafb0a Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Thu, 10 Jan 2008 06:49:29 +0000 Subject: Whitespace cleanup. --- OpenSim/Framework/Util.cs | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0f41380..f80350e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -222,7 +222,7 @@ namespace OpenSim.Framework output.Append(": "); } - output.Append(CleanString(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1))); + output.Append(CleanString(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1))); } else { @@ -414,30 +414,30 @@ namespace OpenSim.Framework return lluuid.UUID.ToString("n"); } - public static string CleanString(string input) - { - if(input.Length == 0) - return input; + public static string CleanString(string input) + { + if(input.Length == 0) + return input; - int clip=input.Length; + int clip=input.Length; - // Test for ++ string terminator - int pos=input.IndexOf("\0"); - if(pos != -1 && pos < clip) - clip=pos; + // Test for ++ string terminator + int pos=input.IndexOf("\0"); + if(pos != -1 && pos < clip) + clip=pos; - // Test for CR - pos=input.IndexOf("\r"); - if(pos != -1 && pos < clip) - clip=pos; + // Test for CR + pos=input.IndexOf("\r"); + if(pos != -1 && pos < clip) + clip=pos; - // Test for LF - pos=input.IndexOf("\n"); - if(pos != -1 && pos < clip) - clip=pos; + // Test for LF + pos=input.IndexOf("\n"); + if(pos != -1 && pos < clip) + clip=pos; - // Truncate string before first end-of-line character found - return input.Substring(0, clip); - } + // Truncate string before first end-of-line character found + return input.Substring(0, clip); + } } } -- cgit v1.1 From b25f9f322cdbcde7fd8c043137bf07992e5ef318 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Tue, 15 Jan 2008 02:09:55 +0000 Subject: * Mother of all commits: * Cleaned up copyright notices in AssemblyInfo.cs's * Added Copyright headers to a bunch of files missing them * Replaced several common string instances with a static constant to prevent reallocation of the same strings thousands of times. "" -> String.Empty is the first such candidate. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f80350e..191205b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -356,7 +356,7 @@ namespace OpenSim.Framework { return capsURLS[userID]; } - return ""; + return String.Empty; } public static void SetCapsURL(LLUUID userID, string url) -- cgit v1.1 From 09a616e1ea0cc1927b7ed94d646a91be9a7b435f Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Wed, 23 Jan 2008 23:32:19 +0000 Subject: * Added ReadEtcIssue to Util * If you have Debian running, you should get a platform line that says, 'Found Debian!' when starting up your sim. * If someone running Debian will confirm this does occur, that would be most helpful. --- OpenSim/Framework/Util.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 191205b..5bfd8e1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -439,5 +439,27 @@ namespace OpenSim.Framework // Truncate string before first end-of-line character found return input.Substring(0, clip); } + + /// + /// returns the contents of /etc/issue on Unix Systems + /// Use this for where it's absolutely necessary to implement platform specific stuff + /// ( like the ODE library :P + /// + /// + public static string ReadEtcIssue() + { + try + { + StreamReader sr = new StreamReader("/etc/issue.net"); + string issue = sr.ReadToEnd(); + sr.Close(); + return issue; + } + catch (System.Exception) + { + return ""; + } + + } } } -- cgit v1.1 From a1625a54104da7872c15618db9e68656c6f6ec2a Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Fri, 8 Feb 2008 17:54:30 +0000 Subject: * Applying mantis 339 patches round 2 -- Thanks daedius --- OpenSim/Framework/Util.cs | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5bfd8e1..856cac3 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -47,7 +47,12 @@ namespace OpenSim.Framework private static Dictionary capsURLS = new Dictionary(); #region Vector Equasions - + /// + /// Get the distance between two 3d vectors + /// + /// A 3d vector + /// A 3d vector + /// The distance between the two vectors public static double GetDistanceTo(LLVector3 a, LLVector3 b) { float dx = a.X - b.X; @@ -55,14 +60,43 @@ namespace OpenSim.Framework float dz = a.Z - b.Z; return Math.Sqrt(dx*dx + dy*dy + dz*dz); } + + /// + /// Get the magnitude of a 3d vector + /// + /// A 3d vector + /// The magnitude of the vector public static double GetMagnitude(LLVector3 a) { return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); } - public static LLVector3 GetNormal(LLVector3 a) + + /// + /// Get a normalized form of a 3d vector + /// + /// A 3d vector + /// A new vector which is normalized form of the vector + /// The vector paramater cannot be <0,0,0> + public static LLVector3 GetNormalizedVector(LLVector3 a) { + if (IsZeroVector(a)) + throw new ArgumentException("Vector paramater cannot be a zero vector."); + float Mag = (float)GetMagnitude(a); return new LLVector3(a.X / Mag, a.Y / Mag, a.Z / Mag); + } + /// + /// Returns if a vector is a zero vector (has all zero components) + /// + /// + public static bool IsZeroVector( LLVector3 v ) + { + if( v.X == 0 && v.Y == 0 && v.Z == 0) + { + return true; + } + + return false; } # endregion -- cgit v1.1 From fe49c96ee0db0974a91b9b175ac1b00aef035797 Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Mon, 3 Mar 2008 08:30:36 +0000 Subject: * Applying Ahzz's profile patch. Thanks Ahzz! * Fixed a few bugs in the patch that are sim crashers. * There's still a bug in mySQL mode/ grid mode where the main userprofile text doesn't save. --- OpenSim/Framework/Util.cs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 856cac3..35e795b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -181,9 +181,25 @@ namespace OpenSim.Framework public static int UnixTimeSinceEpoch() { - TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); - int timestamp = (int) t.TotalSeconds; - return timestamp; + return ToUnixTime(DateTime.UtcNow); + } + + public static int ToUnixTime(DateTime stamp) + { + TimeSpan t = (stamp.ToUniversalTime() - Convert.ToDateTime("1/1/1970 8:00:00 AM")); + return (int)t.TotalSeconds; + } + + public static DateTime ToDateTime(ulong seconds) + { + DateTime epoch = Convert.ToDateTime("1/1/1970 8:00:00 AM"); + return epoch.AddSeconds(seconds); + } + + public static DateTime ToDateTime(int seconds) + { + DateTime epoch = Convert.ToDateTime("1/1/1970 8:00:00 AM"); + return epoch.AddSeconds(seconds); } public static string Md5Hash(string pass) -- cgit v1.1 From 279e0061c515ee0a03036bef68eea9738273d785 Mon Sep 17 00:00:00 2001 From: Johan Berntsson Date: Tue, 4 Mar 2008 05:31:54 +0000 Subject: Merged 3Di code that provides scene and avatar serialization, and plugin support for region move/split/merge. See ThirdParty/3Di/README.txt. Unless the new modules are used there should be no noticeable changes when running OpenSim. --- OpenSim/Framework/Util.cs | 58 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 35e795b..8ba6643 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -37,6 +37,8 @@ using System.Text; using libsecondlife; using Nini.Config; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; namespace OpenSim.Framework { public class Util @@ -509,7 +511,63 @@ namespace OpenSim.Framework { return ""; } + } + + public static void SerializeToFile(string filename, Object obj) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + + try + { + stream = new FileStream( + filename, FileMode.Create, + FileAccess.Write, FileShare.None); + + formatter.Serialize(stream, obj); + } + catch (Exception e) + { + System.Console.WriteLine(e.Message); + System.Console.WriteLine(e.StackTrace); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + } + + public static Object DeserializeFromFile(string filename) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + Object ret = null; + + try + { + stream = new FileStream( + filename, FileMode.Open, + FileAccess.Read, FileShare.None); + + ret = formatter.Deserialize(stream); + } + catch (Exception e) + { + System.Console.WriteLine(e.Message); + System.Console.WriteLine(e.StackTrace); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + return ret; } } } -- cgit v1.1 From 2fea38a5f2d0ee71eef998ec6f7bf4351f188bd7 Mon Sep 17 00:00:00 2001 From: MW Date: Wed, 12 Mar 2008 15:45:56 +0000 Subject: Applied patch from mantis #610, fixed invalid filenames with dump_assets_to_file set to true. thanks tyre. --- OpenSim/Framework/Util.cs | 81 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 26 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8ba6643..847436f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -37,8 +37,8 @@ using System.Text; using libsecondlife; using Nini.Config; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; namespace OpenSim.Framework { public class Util @@ -48,7 +48,13 @@ namespace OpenSim.Framework private static object XferLock = new object(); private static Dictionary capsURLS = new Dictionary(); - #region Vector Equasions + // Get a list of invalid path characters (OS dependent) + private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; + // Get a list of invalid file characters (OS dependent) + private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; + + + #region Vector Equasions /// /// Get the distance between two 3d vectors /// @@ -60,7 +66,7 @@ namespace OpenSim.Framework float dx = a.X - b.X; float dy = a.Y - b.Y; float dz = a.Z - b.Z; - return Math.Sqrt(dx*dx + dy*dy + dz*dz); + return Math.Sqrt(dx * dx + dy * dy + dz * dz); } /// @@ -68,7 +74,8 @@ namespace OpenSim.Framework /// /// A 3d vector /// The magnitude of the vector - public static double GetMagnitude(LLVector3 a) { + public static double GetMagnitude(LLVector3 a) + { return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); } @@ -91,16 +98,16 @@ namespace OpenSim.Framework /// Returns if a vector is a zero vector (has all zero components) /// /// - public static bool IsZeroVector( LLVector3 v ) + public static bool IsZeroVector(LLVector3 v) { - if( v.X == 0 && v.Y == 0 && v.Z == 0) + if (v.X == 0 && v.Y == 0 && v.Z == 0) { return true; } - + return false; } - # endregion + # endregion public static ulong UIntsToLong(uint X, uint Y) { @@ -299,7 +306,7 @@ namespace OpenSim.Framework for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) { if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) - output.Append((char) bytes[i + j]); + output.Append((char)bytes[i + j]); else output.Append("."); } @@ -358,6 +365,28 @@ namespace OpenSim.Framework return null; } + /// + /// Removes all invalid path chars (OS dependent) + /// + /// path + /// safe path + public static string safePath(string path) + { + return System.Text.RegularExpressions.Regex.Replace(path, @regexInvalidPathChars, string.Empty); + } + + /// + /// Removes all invalid filename chars (OS dependent) + /// + /// filename + /// safe filename + public static string safeFileName(string filename) + { + return System.Text.RegularExpressions.Regex.Replace(filename, @regexInvalidFileChars, string.Empty); ; + } + + + // // directory locations // @@ -365,12 +394,12 @@ namespace OpenSim.Framework public static string homeDir() { string temp; -// string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); -// temp = Path.Combine(personal,".OpenSim"); + // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); + // temp = Path.Combine(personal,".OpenSim"); temp = "."; return temp; } - + public static string assetsDir() { return Path.Combine(configDir(), "assets"); @@ -439,10 +468,10 @@ namespace OpenSim.Framework public static void AddDataRowToConfig(IConfigSource config, DataRow row) { - config.Configs.Add((string) row[0]); + config.Configs.Add((string)row[0]); for (int i = 0; i < row.Table.Columns.Count; i++) { - config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); + config.Configs[(string)row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); } } @@ -468,25 +497,25 @@ namespace OpenSim.Framework public static string CleanString(string input) { - if(input.Length == 0) + if (input.Length == 0) return input; - int clip=input.Length; + int clip = input.Length; // Test for ++ string terminator - int pos=input.IndexOf("\0"); - if(pos != -1 && pos < clip) - clip=pos; + int pos = input.IndexOf("\0"); + if (pos != -1 && pos < clip) + clip = pos; // Test for CR - pos=input.IndexOf("\r"); - if(pos != -1 && pos < clip) - clip=pos; + pos = input.IndexOf("\r"); + if (pos != -1 && pos < clip) + clip = pos; // Test for LF - pos=input.IndexOf("\n"); - if(pos != -1 && pos < clip) - clip=pos; + pos = input.IndexOf("\n"); + if (pos != -1 && pos < clip) + clip = pos; // Truncate string before first end-of-line character found return input.Substring(0, clip); -- cgit v1.1 From 47180080f0f4b93c60232b47ca4e093bd7c73a1d Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Tue, 18 Mar 2008 05:16:43 +0000 Subject: Formatting cleanup. --- OpenSim/Framework/Util.cs | 51 +++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 26 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 847436f..0f1f0d9 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1,30 +1,29 @@ /* -* 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. -* -*/ + * 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.Generic; -- cgit v1.1 From 42857fe4e9e898c8e350da2f9acb3b252b31694a Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Tue, 18 Mar 2008 05:44:25 +0000 Subject: * Added the ability to type the partial name of a region in the start location box and go to that region if it's there. If no close match was found, it sends you home. This is tested on mySQL. There's untested code on grids that are based on sqlite and MSSQL. The SQL statements *should* be right, but your results may very. * Ex, if you want to go to Wright Plaza, you simply need to type Wright Plaza in the start location in the client when you log-in. --- OpenSim/Framework/Util.cs | 48 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0f1f0d9..37ddb3e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -597,5 +597,53 @@ namespace OpenSim.Framework return ret; } + public static string[] ParseStartLocationRequest(string startLocationRequest) + { + string[] returnstring = new string[4]; + // format uri:RegionName&X&Y&Z + returnstring[0] = "last"; + returnstring[1] = "127"; + returnstring[2] = "127"; + returnstring[3] = "0"; + // This is the crappy way of doing it. + + if (startLocationRequest.Contains(":") && startLocationRequest.Contains("&")) + { + //System.Console.WriteLine("StartLocationRequest Contains proper elements"); + + string[] splitstr = startLocationRequest.Split(':');//,2,StringSplitOptions.RemoveEmptyEntries); + + //System.Console.WriteLine("Found " + splitstr.GetLength(0) + " elements in 1st split result"); + + if (splitstr.GetLength(0) == 2) + { + + string[] splitstr2 = splitstr[1].Split('&');//, 4, StringSplitOptions.RemoveEmptyEntries); + + //System.Console.WriteLine("Found " + splitstr2.GetLength(0) + " elements in 2nd split result"); + + if (splitstr2.GetLength(0) >= 1) + { + returnstring[0] = splitstr2[0]; + } + if (splitstr2.GetLength(0) >= 2) + { + returnstring[1] = splitstr2[1]; + } + if (splitstr2.GetLength(0) >= 3) + { + returnstring[2] = splitstr2[2]; + } + if (splitstr2.GetLength(0) >= 4) + { + returnstring[3] = splitstr2[3]; + } + } + + } + return returnstring; + + + } } } -- cgit v1.1 From bf8b5844f24d294c459f54147bd511e7112288bf Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Tue, 18 Mar 2008 14:51:42 +0000 Subject: Formatting cleanup. Minor refactoring. --- OpenSim/Framework/Util.cs | 50 +++++++++++++++-------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 37ddb3e..e16d15e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -52,7 +52,6 @@ namespace OpenSim.Framework // Get a list of invalid file characters (OS dependent) private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; - #region Vector Equasions /// /// Get the distance between two 3d vectors @@ -106,6 +105,7 @@ namespace OpenSim.Framework return false; } + # endregion public static ulong UIntsToLong(uint X, uint Y) @@ -384,8 +384,6 @@ namespace OpenSim.Framework return System.Text.RegularExpressions.Regex.Replace(filename, @regexInvalidFileChars, string.Empty); ; } - - // // directory locations // @@ -411,23 +409,17 @@ namespace OpenSim.Framework public static string configDir() { - string temp; - temp = "."; - return temp; + return "."; } public static string dataDir() { - string temp; - temp = "."; - return temp; + return "."; } public static string logDir() { - string temp; - temp = "."; - return temp; + return "."; } public static string GetCapsURL(LLUUID userID) @@ -549,8 +541,8 @@ namespace OpenSim.Framework try { stream = new FileStream( - filename, FileMode.Create, - FileAccess.Write, FileShare.None); + filename, FileMode.Create, + FileAccess.Write, FileShare.None); formatter.Serialize(stream, obj); } @@ -577,8 +569,8 @@ namespace OpenSim.Framework try { stream = new FileStream( - filename, FileMode.Open, - FileAccess.Read, FileShare.None); + filename, FileMode.Open, + FileAccess.Read, FileShare.None); ret = formatter.Deserialize(stream); } @@ -597,6 +589,7 @@ namespace OpenSim.Framework return ret; } + public static string[] ParseStartLocationRequest(string startLocationRequest) { string[] returnstring = new string[4]; @@ -617,33 +610,22 @@ namespace OpenSim.Framework if (splitstr.GetLength(0) == 2) { - string[] splitstr2 = splitstr[1].Split('&');//, 4, StringSplitOptions.RemoveEmptyEntries); //System.Console.WriteLine("Found " + splitstr2.GetLength(0) + " elements in 2nd split result"); - if (splitstr2.GetLength(0) >= 1) - { - returnstring[0] = splitstr2[0]; - } - if (splitstr2.GetLength(0) >= 2) - { - returnstring[1] = splitstr2[1]; - } - if (splitstr2.GetLength(0) >= 3) - { - returnstring[2] = splitstr2[2]; - } - if (splitstr2.GetLength(0) >= 4) + int len = Math.Min(splitstr2.GetLength(0), 4); + + for (int i = 0; i < 4; ++i) { - returnstring[3] = splitstr2[3]; + if (len > i) + { + returnstring[i] = splitstr2[i]; + } } } - } return returnstring; - - } } } -- cgit v1.1 From c1beb85315aad09197ca7ffaa8ec194346af82cb Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Thu, 20 Mar 2008 20:04:45 +0000 Subject: * First draft resolution of mantis 777, 734, 389 - scripts do not save in non-home regions * Should work in multi-region standalone and grid modes * This should also solve other non-home region caps issues (map requests, RC client inventory requests, etc) * We now pass CAPS information on to the destination region on region crossing, and set up a CAPS object when an agent becomes a master * Current limitation is that this will only work if your http_listener_port is 9000 * This is a very early code cut (lots of bad practice, hard coding and inefficiency). However, I wanted to get this out there for feedback and my own sanity. Next few patches will clean up the mess. --- OpenSim/Framework/Util.cs | 22 ---------------------- 1 file changed, 22 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e16d15e..6c95c88 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -45,7 +45,6 @@ namespace OpenSim.Framework private static Random randomClass = new Random(); private static uint nextXferID = 5000; private static object XferLock = new object(); - private static Dictionary capsURLS = new Dictionary(); // Get a list of invalid path characters (OS dependent) private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; @@ -422,27 +421,6 @@ namespace OpenSim.Framework return "."; } - public static string GetCapsURL(LLUUID userID) - { - if (capsURLS.ContainsKey(userID)) - { - return capsURLS[userID]; - } - return String.Empty; - } - - public static void SetCapsURL(LLUUID userID, string url) - { - if (capsURLS.ContainsKey(userID)) - { - capsURLS[userID] = url; - } - else - { - capsURLS.Add(userID, url); - } - } - // Nini (config) related Methods public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) { -- cgit v1.1 From 39f340e6875c55927fc9dbeb51af2357c7d28c04 Mon Sep 17 00:00:00 2001 From: Johan Berntsson Date: Mon, 24 Mar 2008 01:37:00 +0000 Subject: XmlRpcCommand refactoring --- OpenSim/Framework/Util.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 6c95c88..a184f89 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -35,6 +35,7 @@ using System.Security.Cryptography; using System.Text; using libsecondlife; using Nini.Config; +using Nwc.XmlRpc; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; @@ -605,5 +606,17 @@ namespace OpenSim.Framework } return returnstring; } + + static public XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) + { + return SendXmlRpcCommand(url, methodName, args); + } + + static public XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) + { + XmlRpcRequest client = new XmlRpcRequest(methodName, args); + return client.Send(url, 6000); + } + } } -- cgit v1.1 From 5c52068dd7a3bea8ff31e78bf933a985ef97f1b4 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 14 Apr 2008 15:32:39 +0000 Subject: * Get Util.GetHostFromDNS to tell us the dns address it was trying to resolve if it fails. --- OpenSim/Framework/Util.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a184f89..ac1145f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -43,6 +43,8 @@ namespace OpenSim.Framework { public class Util { + private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static Random randomClass = new Random(); private static uint nextXferID = 5000; private static object XferLock = new object(); @@ -327,8 +329,20 @@ namespace OpenSim.Framework if (IPAddress.TryParse(dnsAddress, out ipa)) return ipa; + IPAddress[] hosts = null; + // Not an IP, lookup required - IPAddress[] hosts = Dns.GetHostEntry(dnsAddress).AddressList; + try + { + hosts = Dns.GetHostEntry(dnsAddress).AddressList; + } + catch (Exception e) + { + m_log.ErrorFormat("[UTIL]: An error occurred while resolving {0}, {1}", dnsAddress, e); + + // Still going to throw the exception on for now, since this was what was happening in the first place + throw e; + } foreach (IPAddress host in hosts) { -- cgit v1.1 From fef3b3689492dea63693c964bcdbec9f5137eb5e Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Mon, 21 Apr 2008 07:09:17 +0000 Subject: * Optimised using statements and namespace references across entire project (this took a while to run). --- OpenSim/Framework/Util.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ac1145f..2396519 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -26,24 +26,26 @@ */ using System; -using System.Collections.Generic; using System.Data; using System.IO; using System.Net; using System.Net.Sockets; +using System.Reflection; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using System.Text; +using System.Text.RegularExpressions; using libsecondlife; +using log4net; using Nini.Config; using Nwc.XmlRpc; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; namespace OpenSim.Framework { public class Util { - private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static Random randomClass = new Random(); private static uint nextXferID = 5000; @@ -385,7 +387,7 @@ namespace OpenSim.Framework /// safe path public static string safePath(string path) { - return System.Text.RegularExpressions.Regex.Replace(path, @regexInvalidPathChars, string.Empty); + return Regex.Replace(path, @regexInvalidPathChars, string.Empty); } /// @@ -395,7 +397,7 @@ namespace OpenSim.Framework /// safe filename public static string safeFileName(string filename) { - return System.Text.RegularExpressions.Regex.Replace(filename, @regexInvalidFileChars, string.Empty); ; + return Regex.Replace(filename, @regexInvalidFileChars, string.Empty); ; } // @@ -520,7 +522,7 @@ namespace OpenSim.Framework sr.Close(); return issue; } - catch (System.Exception) + catch (Exception) { return ""; } -- cgit v1.1 From 2a2ef42e64e202c81762adf0cc0e4cb1393f71ef Mon Sep 17 00:00:00 2001 From: Sean Dague Date: Thu, 24 Apr 2008 12:27:24 +0000 Subject: replace hard tabs with 4 spaces to be consistant in the source. Please adjust your editors to not use hard tabs. --- OpenSim/Framework/Util.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2396519..8114957 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -622,15 +622,15 @@ namespace OpenSim.Framework } return returnstring; } - - static public XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) + + static public XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) { return SendXmlRpcCommand(url, methodName, args); } - + static public XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) { - XmlRpcRequest client = new XmlRpcRequest(methodName, args); + XmlRpcRequest client = new XmlRpcRequest(methodName, args); return client.Send(url, 6000); } -- cgit v1.1 From 375163a6fece8b3a57c7555246abe8338223a599 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Tue, 29 Apr 2008 14:04:55 +0000 Subject: * Spring cleaning. * Added new generic "Location" class to handle 2D integer locations. Going to use it to replace all RegionHandle and X,Y coordinate references throughout the entire project. You have been warned. --- OpenSim/Framework/Util.cs | 65 +++++++++++++++++++++++------------------------ 1 file changed, 32 insertions(+), 33 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8114957..0943626 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -45,18 +45,17 @@ namespace OpenSim.Framework { public class Util { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private static Random randomClass = new Random(); - private static uint nextXferID = 5000; - private static object XferLock = new object(); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - // Get a list of invalid path characters (OS dependent) - private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; + private static uint nextXferID = 5000; + private static Random randomClass = new Random(); // Get a list of invalid file characters (OS dependent) private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; + private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; + private static object XferLock = new object(); #region Vector Equasions + /// /// Get the distance between two 3d vectors /// @@ -92,7 +91,7 @@ namespace OpenSim.Framework if (IsZeroVector(a)) throw new ArgumentException("Vector paramater cannot be a zero vector."); - float Mag = (float)GetMagnitude(a); + float Mag = (float) GetMagnitude(a); return new LLVector3(a.X / Mag, a.Y / Mag, a.Z / Mag); } @@ -112,9 +111,8 @@ namespace OpenSim.Framework # endregion - public static ulong UIntsToLong(uint X, uint Y) + public Util() { - return Helpers.UIntsToLong(X, Y); } public static Random RandomClass @@ -122,6 +120,11 @@ namespace OpenSim.Framework get { return randomClass; } } + public static ulong UIntsToLong(uint X, uint Y) + { + return Helpers.UIntsToLong(X, Y); + } + public static uint GetNextXferID() { uint id = 0; @@ -133,10 +136,6 @@ namespace OpenSim.Framework return id; } - public Util() - { - } - public static string GetFileName(string file) { // Return just the filename on UNIX platforms @@ -199,7 +198,7 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { TimeSpan t = (stamp.ToUniversalTime() - Convert.ToDateTime("1/1/1970 8:00:00 AM")); - return (int)t.TotalSeconds; + return (int) t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) @@ -309,7 +308,7 @@ namespace OpenSim.Framework for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) { if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) - output.Append((char)bytes[i + j]); + output.Append((char) bytes[i + j]); else output.Append("."); } @@ -332,7 +331,7 @@ namespace OpenSim.Framework return ipa; IPAddress[] hosts = null; - + // Not an IP, lookup required try { @@ -341,7 +340,7 @@ namespace OpenSim.Framework catch (Exception e) { m_log.ErrorFormat("[UTIL]: An error occurred while resolving {0}, {1}", dnsAddress, e); - + // Still going to throw the exception on for now, since this was what was happening in the first place throw e; } @@ -397,7 +396,8 @@ namespace OpenSim.Framework /// safe filename public static string safeFileName(string filename) { - return Regex.Replace(filename, @regexInvalidFileChars, string.Empty); ; + return Regex.Replace(filename, @regexInvalidFileChars, string.Empty); + ; } // @@ -454,10 +454,10 @@ namespace OpenSim.Framework public static void AddDataRowToConfig(IConfigSource config, DataRow row) { - config.Configs.Add((string)row[0]); + config.Configs.Add((string) row[0]); for (int i = 0; i < row.Table.Columns.Count; i++) { - config.Configs[(string)row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); + config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); } } @@ -594,19 +594,19 @@ namespace OpenSim.Framework returnstring[2] = "127"; returnstring[3] = "0"; // This is the crappy way of doing it. - + if (startLocationRequest.Contains(":") && startLocationRequest.Contains("&")) { //System.Console.WriteLine("StartLocationRequest Contains proper elements"); - string[] splitstr = startLocationRequest.Split(':');//,2,StringSplitOptions.RemoveEmptyEntries); - + string[] splitstr = startLocationRequest.Split(':'); //,2,StringSplitOptions.RemoveEmptyEntries); + //System.Console.WriteLine("Found " + splitstr.GetLength(0) + " elements in 1st split result"); - + if (splitstr.GetLength(0) == 2) { - string[] splitstr2 = splitstr[1].Split('&');//, 4, StringSplitOptions.RemoveEmptyEntries); - + string[] splitstr2 = splitstr[1].Split('&'); //, 4, StringSplitOptions.RemoveEmptyEntries); + //System.Console.WriteLine("Found " + splitstr2.GetLength(0) + " elements in 2nd split result"); int len = Math.Min(splitstr2.GetLength(0), 4); @@ -622,17 +622,16 @@ namespace OpenSim.Framework } return returnstring; } - - static public XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) + + public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) { return SendXmlRpcCommand(url, methodName, args); } - - static public XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) + + public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) { XmlRpcRequest client = new XmlRpcRequest(methodName, args); return client.Send(url, 6000); } - } -} +} \ No newline at end of file -- cgit v1.1 From 6e2c7da0182c0ee5bf95cb50e95878caa968a77b Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Fri, 9 May 2008 15:51:02 +0000 Subject: * Minor: Insert utility function to format raw xml strings into indented xml for debugging purposes --- OpenSim/Framework/Util.cs | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0943626..5577140 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -36,6 +36,7 @@ using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; +using System.Xml; using libsecondlife; using log4net; using Nini.Config; @@ -43,6 +44,9 @@ using Nwc.XmlRpc; namespace OpenSim.Framework { + /// + /// Miscellaneous utility functions + /// public class Util { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -161,6 +165,36 @@ namespace OpenSim.Framework // (but those probably wont work anyway) return file; } + + /// + /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. + /// + /// Please don't delete me even if I appear currently unused! + /// + /// + /// + public static string GetFormattedXml(string rawXml) + { + XmlDocument xd = new XmlDocument(); + xd.LoadXml(rawXml); + + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + XmlTextWriter xtw = new XmlTextWriter(sw); + xtw.Formatting = Formatting.Indented; + + try + { + xd.WriteTo(xtw); + } + finally + { + xtw.Close(); + } + + return sb.ToString(); + } public static bool IsEnvironmentSupported(ref string reason) { @@ -634,4 +668,4 @@ namespace OpenSim.Framework return client.Send(url, 6000); } } -} \ No newline at end of file +} -- cgit v1.1 From 65c5efe43b68700bad94076d4cd421160203c5de Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Fri, 16 May 2008 01:22:11 +0000 Subject: Formatting cleanup. --- OpenSim/Framework/Util.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5577140..8e5b02d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -165,10 +165,10 @@ namespace OpenSim.Framework // (but those probably wont work anyway) return file; } - + /// /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. - /// + /// /// Please don't delete me even if I appear currently unused! /// /// @@ -177,22 +177,22 @@ namespace OpenSim.Framework { XmlDocument xd = new XmlDocument(); xd.LoadXml(rawXml); - + StringBuilder sb = new StringBuilder(); - StringWriter sw = new StringWriter(sb); - + StringWriter sw = new StringWriter(sb); + XmlTextWriter xtw = new XmlTextWriter(sw); xtw.Formatting = Formatting.Indented; - + try { xd.WriteTo(xtw); } finally { - xtw.Close(); + xtw.Close(); } - + return sb.ToString(); } @@ -284,11 +284,11 @@ namespace OpenSim.Framework /// Convert a variable length field (byte array) to a string, with a /// field name prepended to each line of the output /// - /// If the byte array has unprintable characters in it, a + /// If the byte array has unprintable characters in it, a /// hex dump will be put in the string instead /// The byte array to convert to a string /// A field name to prepend to each line of output - /// An ASCII string or a string containing a hex dump, minus + /// An ASCII string or a string containing a hex dump, minus /// the null terminator public static string FieldToString(byte[] bytes, string fieldName) { -- cgit v1.1 From 7fefb80abbde4bd8a9b19cb631736b5860274134 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Fri, 16 May 2008 13:33:57 +0000 Subject: Minor cleanup. --- OpenSim/Framework/Util.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8e5b02d..719dda6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -58,7 +58,7 @@ namespace OpenSim.Framework private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; private static object XferLock = new object(); - #region Vector Equasions + #region Vector Equations /// /// Get the distance between two 3d vectors @@ -214,8 +214,8 @@ namespace OpenSim.Framework } // Windows 2000 / Pre-SP2 XP - if (Environment.OSVersion.Version.Major == 5 && ( - Environment.OSVersion.Version.Minor == 0)) + if (Environment.OSVersion.Version.Major == 5 && + Environment.OSVersion.Version.Minor == 0) { reason = "Please update to Windows XP Service Pack 2 or Server2003"; return false; @@ -544,7 +544,6 @@ namespace OpenSim.Framework /// /// returns the contents of /etc/issue on Unix Systems /// Use this for where it's absolutely necessary to implement platform specific stuff - /// ( like the ODE library :P /// /// public static string ReadEtcIssue() -- cgit v1.1 From 7a9922af27658ac570517df530dd7c2cf6d6dded Mon Sep 17 00:00:00 2001 From: MW Date: Wed, 25 Jun 2008 19:33:19 +0000 Subject: Added support for terrain map to be serialised to xml(as base64 binary). useful for places that the terrain map is needed in a serialised form. Also could add console commands to save and load from files, which should be faster than .raw files (these load/save commands are not included/implemented) Add util functions to compress and uncompress strings. Fixed a couple of modules so they use SceneCommunicationService rather than directly call functions on the CommsManager. --- OpenSim/Framework/Util.cs | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 719dda6..a835cec 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -28,6 +28,7 @@ using System; using System.Data; using System.IO; +using System.IO.Compression; using System.Net; using System.Net.Sockets; using System.Reflection; @@ -618,6 +619,47 @@ namespace OpenSim.Framework return ret; } + public static string Compress(string text) + { + byte[] buffer = Encoding.UTF8.GetBytes(text); + MemoryStream memory = new MemoryStream(); + using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) + { + compressor.Write(buffer, 0, buffer.Length); + } + + memory.Position = 0; + MemoryStream outStream = new MemoryStream(); + + byte[] compressed = new byte[memory.Length]; + memory.Read(compressed, 0, compressed.Length); + + byte[] compressedBuffer = new byte[compressed.Length + 4]; + System.Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); + System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); + return Convert.ToBase64String(compressedBuffer); + } + + public static string Decompress(string compressedText) + { + byte[] compressedBuffer = Convert.FromBase64String(compressedText); + using (MemoryStream memory = new MemoryStream()) + { + int msgLength = BitConverter.ToInt32(compressedBuffer, 0); + memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); + + byte[] buffer = new byte[msgLength]; + + memory.Position = 0; + using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) + { + decompressor.Read(buffer, 0, buffer.Length); + } + + return Encoding.UTF8.GetString(buffer); + } + } + public static string[] ParseStartLocationRequest(string startLocationRequest) { string[] returnstring = new string[4]; -- cgit v1.1 From 76e24d02ad422987f1bff7c2202e6c9955cfedd8 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Thu, 26 Jun 2008 02:03:40 +0000 Subject: Minor refactoring of POS. Adds a Util.Clamp(x, min, max) function. --- OpenSim/Framework/Util.cs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a835cec..5b529da 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -130,6 +130,14 @@ namespace OpenSim.Framework return Helpers.UIntsToLong(X, Y); } + public static T Clamp(T x, T min, T max) + where T : System.IComparable + { + return x.CompareTo(max) > 0 ? max : + x.CompareTo(min) < 0 ? min : + x; + } + public static uint GetNextXferID() { uint id = 0; -- cgit v1.1 From feb30217de48f4b3d869bf13453a945a04ee2524 Mon Sep 17 00:00:00 2001 From: Dr Scofield Date: Fri, 27 Jun 2008 16:58:21 +0000 Subject: dr scofield's warning safari: * commented out [Obsolete(....)] attributes where no replacement feature was available: if we want to attribute code that we think needs to be reworked, we should define a new attribute and use that instead (together with a little tool to retrieve all the attributed code then) * commenting out unused variables --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5b529da..d72e03e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -637,7 +637,7 @@ namespace OpenSim.Framework } memory.Position = 0; - MemoryStream outStream = new MemoryStream(); + // MemoryStream outStream = new MemoryStream(); byte[] compressed = new byte[memory.Length]; memory.Read(compressed, 0, compressed.Length); -- cgit v1.1 From d9cc908471922a1239bb8a757e07084072852982 Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Sat, 16 Aug 2008 19:20:14 +0000 Subject: Mantis#1965. Thank you kindly, HomerHorwitz for a patch that: Places touched: - Added two events for in-packets to LLCLientView: RegionHandleRequest and ParcelInfoRequest - Added sending of two out-packets to LLCLientView: RegionIDAndHandleReply and ParcelInfoReply. - Scene handles the RegionHandleRequest, LandManagementModule the ParcelInfoRequest - Added inter-region request for LandData by RegionHandle and local position. This was implemented as XML-RPC request. The returned LandData isn't complete, it only contains the data necessary for answering the ParcelInfoRequest - Added new CAPS (0009) for RemoteParcelRequest and some methods for LandData handling to LandManagementModule - Added methods for fake parcelID creation and parsing to Util - Fixed missing implementation of interface methods. - Added new file: OpenSim/Framework/Communications/Capabilities/LLSDRemoteParcelResponse.cs NOTE: This is part of the patch, too. Due to the many places touched, I would consider this patch as experimental. --- OpenSim/Framework/Util.cs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d72e03e..bc35fa6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -716,5 +716,24 @@ namespace OpenSim.Framework XmlRpcRequest client = new XmlRpcRequest(methodName, args); return client.Send(url, 6000); } + + // used for RemoteParcelRequest (for "About Landmark") + public static LLUUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { + byte[] bytes = { + (byte)(regionHandle >> 56), (byte)(regionHandle >> 48), (byte)(regionHandle >> 40), (byte)(regionHandle >> 32), + (byte)(regionHandle >> 24), (byte)(regionHandle >> 16), (byte)(regionHandle >> 8), (byte)regionHandle, + (byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)x, + (byte)(y >> 24), (byte)(y >> 16), (byte)(y >> 8), (byte)y }; + return new LLUUID(bytes, 0); + } + + public static void ParseFakeParcelID(LLUUID parcelID, out ulong regionHandle, out uint x, out uint y) { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Helpers.BytesToUInt64(bytes); + x = Helpers.BytesToUInt(bytes, 8); + // grrr. I'd like to use that code in the next line, but libsl has an off-by-one bug here and returns 0. + //uint y = Helpers.BytesToUInt(bytes, 12); + y = (uint)((bytes[12] << 24) | (bytes[13] << 16) | (bytes[14] << 8) | bytes[15]); + } } } -- cgit v1.1 From 6ef9d4da901a346c232458317cca6268da888e2e Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Mon, 18 Aug 2008 00:39:10 +0000 Subject: Formatting cleanup. --- OpenSim/Framework/Util.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index bc35fa6..2a21221 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -716,7 +716,7 @@ namespace OpenSim.Framework XmlRpcRequest client = new XmlRpcRequest(methodName, args); return client.Send(url, 6000); } - + // used for RemoteParcelRequest (for "About Landmark") public static LLUUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { byte[] bytes = { @@ -726,7 +726,7 @@ namespace OpenSim.Framework (byte)(y >> 24), (byte)(y >> 16), (byte)(y >> 8), (byte)y }; return new LLUUID(bytes, 0); } - + public static void ParseFakeParcelID(LLUUID parcelID, out ulong regionHandle, out uint x, out uint y) { byte[] bytes = parcelID.GetBytes(); regionHandle = Helpers.BytesToUInt64(bytes); -- cgit v1.1 From 50a62145ad554277281a3166de0a29353adb07c4 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sat, 30 Aug 2008 12:58:54 +0000 Subject: * Initial inspection of UserLoginService.cs, cleaned up source code slightly to make it easier to work with. --- OpenSim/Framework/Util.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2a21221..09bf029 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -362,6 +362,16 @@ namespace OpenSim.Framework } /// + /// Converts a URL to a IPAddress + /// + /// URL Standard Format + /// A resolved IP Address + public static IPAddress GetHostFromURL(string url) + { + return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); + } + + /// /// Returns a IP address from a specified DNS, favouring IPv4 addresses. /// /// DNS Hostname -- cgit v1.1 From 7d89e122930be39e84a6d174548fa2d12ac0484a Mon Sep 17 00:00:00 2001 From: Teravus Ovares Date: Sat, 6 Sep 2008 07:52:41 +0000 Subject: * This is the fabled LibOMV update with all of the libOMV types from JHurliman * This is a HUGE OMG update and will definitely have unknown side effects.. so this is really only for the strong hearted at this point. Regular people should let the dust settle. * This has been tested to work with most basic functions. However.. make sure you back up 'everything' before using this. It's that big! * Essentially we're back at square 1 in the testing phase.. so lets identify things that broke. --- OpenSim/Framework/Util.cs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 09bf029..d7dcf19 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -38,7 +38,7 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Xml; -using libsecondlife; +using OpenMetaverse; using log4net; using Nini.Config; using Nwc.XmlRpc; @@ -67,7 +67,7 @@ namespace OpenSim.Framework /// A 3d vector /// A 3d vector /// The distance between the two vectors - public static double GetDistanceTo(LLVector3 a, LLVector3 b) + public static double GetDistanceTo(Vector3 a, Vector3 b) { float dx = a.X - b.X; float dy = a.Y - b.Y; @@ -80,7 +80,7 @@ namespace OpenSim.Framework /// /// A 3d vector /// The magnitude of the vector - public static double GetMagnitude(LLVector3 a) + public static double GetMagnitude(Vector3 a) { return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); } @@ -91,20 +91,20 @@ namespace OpenSim.Framework /// A 3d vector /// A new vector which is normalized form of the vector /// The vector paramater cannot be <0,0,0> - public static LLVector3 GetNormalizedVector(LLVector3 a) + public static Vector3 GetNormalizedVector(Vector3 a) { if (IsZeroVector(a)) throw new ArgumentException("Vector paramater cannot be a zero vector."); float Mag = (float) GetMagnitude(a); - return new LLVector3(a.X / Mag, a.Y / Mag, a.Z / Mag); + return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); } /// /// Returns if a vector is a zero vector (has all zero components) /// /// - public static bool IsZeroVector(LLVector3 v) + public static bool IsZeroVector(Vector3 v) { if (v.X == 0 && v.Y == 0 && v.Z == 0) { @@ -268,7 +268,7 @@ namespace OpenSim.Framework public static string GetRandomCapsPath() { - LLUUID caps = LLUUID.Random(); + UUID caps = UUID.Random(); string capsPath = caps.ToString(); capsPath = capsPath.Remove(capsPath.Length - 4, 4); return capsPath; @@ -525,13 +525,13 @@ namespace OpenSim.Framework } /// - /// Convert an LLUUID to a raw uuid string. Right now this is a string without hyphens. + /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. /// - /// + /// /// - public static String ToRawUuidString(LLUUID lluuid) + public static String ToRawUuidString(UUID UUID) { - return lluuid.UUID.ToString("n"); + return UUID.Guid.ToString("n"); } public static string CleanString(string input) @@ -728,16 +728,16 @@ namespace OpenSim.Framework } // used for RemoteParcelRequest (for "About Landmark") - public static LLUUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { byte[] bytes = { (byte)(regionHandle >> 56), (byte)(regionHandle >> 48), (byte)(regionHandle >> 40), (byte)(regionHandle >> 32), (byte)(regionHandle >> 24), (byte)(regionHandle >> 16), (byte)(regionHandle >> 8), (byte)regionHandle, (byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)x, (byte)(y >> 24), (byte)(y >> 16), (byte)(y >> 8), (byte)y }; - return new LLUUID(bytes, 0); + return new UUID(bytes, 0); } - public static void ParseFakeParcelID(LLUUID parcelID, out ulong regionHandle, out uint x, out uint y) { + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) { byte[] bytes = parcelID.GetBytes(); regionHandle = Helpers.BytesToUInt64(bytes); x = Helpers.BytesToUInt(bytes, 8); -- cgit v1.1 From b85a29d1b8d7e50361a3cbb5bfd2350ef11cbfea Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Sat, 6 Sep 2008 23:08:08 +0000 Subject: Mantis#2136. Thank you kindly, HomerHorwitz for a patch that: libomv corrected the endianess of some Helper methods, which broke the fake parcelID computation for "About Landmark". The attached patch fixes this. --- OpenSim/Framework/Util.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d7dcf19..de42bf8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -730,10 +730,10 @@ namespace OpenSim.Framework // used for RemoteParcelRequest (for "About Landmark") public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { byte[] bytes = { - (byte)(regionHandle >> 56), (byte)(regionHandle >> 48), (byte)(regionHandle >> 40), (byte)(regionHandle >> 32), - (byte)(regionHandle >> 24), (byte)(regionHandle >> 16), (byte)(regionHandle >> 8), (byte)regionHandle, - (byte)(x >> 24), (byte)(x >> 16), (byte)(x >> 8), (byte)x, - (byte)(y >> 24), (byte)(y >> 16), (byte)(y >> 8), (byte)y }; + (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24), + (byte)y, (byte)(y >> 8), (byte)(y >> 16), (byte)(y >> 24) }; return new UUID(bytes, 0); } @@ -741,9 +741,7 @@ namespace OpenSim.Framework byte[] bytes = parcelID.GetBytes(); regionHandle = Helpers.BytesToUInt64(bytes); x = Helpers.BytesToUInt(bytes, 8); - // grrr. I'd like to use that code in the next line, but libsl has an off-by-one bug here and returns 0. - //uint y = Helpers.BytesToUInt(bytes, 12); - y = (uint)((bytes[12] << 24) | (bytes[13] << 16) | (bytes[14] << 8) | bytes[15]); + y = Helpers.BytesToUInt(bytes, 12); } } } -- cgit v1.1 From 58d79b33ff507a1d861d1196a925d2d09ad1c3f2 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 7 Sep 2008 20:09:11 +0000 Subject: Mantis #2142 Thank you, HomerHorwitz, for a patch that fixes landmark teleport and about landmarks with the new OMV types. --- OpenSim/Framework/Util.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index de42bf8..427832d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -727,6 +727,21 @@ namespace OpenSim.Framework return client.Send(url, 6000); } + /// + /// Converts a byte array in big endian order into an ulong. + /// + /// + /// The array of bytes + /// + /// + /// The extracted ulong + /// + public static ulong BytesToUInt64Big(byte[] bytes) { + if(bytes.Length < 8) return 0; + return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | + ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; + } + // used for RemoteParcelRequest (for "About Landmark") public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { byte[] bytes = { -- cgit v1.1 From fae34bb10cfa10702faf5c19d8c8517faa018cb5 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Tue, 9 Sep 2008 01:26:48 +0000 Subject: Update svn properties, formatting cleanup. --- OpenSim/Framework/Util.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 427832d..d289978 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -737,11 +737,11 @@ namespace OpenSim.Framework /// The extracted ulong /// public static ulong BytesToUInt64Big(byte[] bytes) { - if(bytes.Length < 8) return 0; + if (bytes.Length < 8) return 0; return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; } - + // used for RemoteParcelRequest (for "About Landmark") public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { byte[] bytes = { -- cgit v1.1 From 52a4c4d82f9c5b808e6c61fd51c1c70e42865565 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Fri, 12 Sep 2008 20:12:03 +0000 Subject: * Check in first part of http://opensimulator.org/mantis/view.php?id=2073 * This patch aims to introduce look at direction persistence between logins. It won't be active until the second part of the patch is committed in about two weeks time. At this point, region servers that haven't upgraded past this revision may run into problems * This checkin upgrades the user database. As always, we recommend you have backups in case something goes wrong. * Many thanks to tyre for this patch. --- OpenSim/Framework/Util.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d289978..333ab81 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -678,6 +678,7 @@ namespace OpenSim.Framework } } +/* 2008-08-28-tyre: Obsolete (see LocalLoginService UserLoginService) public static string[] ParseStartLocationRequest(string startLocationRequest) { string[] returnstring = new string[4]; @@ -715,6 +716,7 @@ namespace OpenSim.Framework } return returnstring; } +*/ public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) { -- cgit v1.1 From 2b9e115fd72ae7a014bbd8bd2911336fa6b9993e Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 15 Sep 2008 20:50:57 +0000 Subject: * minor: eat up some yummy warnings --- OpenSim/Framework/Util.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 333ab81..ec03d25 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -116,10 +116,6 @@ namespace OpenSim.Framework # endregion - public Util() - { - } - public static Random RandomClass { get { return randomClass; } @@ -256,6 +252,11 @@ namespace OpenSim.Framework return epoch.AddSeconds(seconds); } + /// + /// Return an md5 hash of the given string + /// + /// + /// public static string Md5Hash(string pass) { MD5 md5 = MD5CryptoServiceProvider.Create(); -- cgit v1.1 From b8a50c40b100ba4ab147aab0c5cf716a9cbc23d2 Mon Sep 17 00:00:00 2001 From: Homer Horwitz Date: Sun, 12 Oct 2008 18:07:39 +0000 Subject: - Added helper method to compute global coordinates from a fake parcelID - Some formatting cleanups --- OpenSim/Framework/Util.cs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ec03d25..57c1601 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -739,15 +739,18 @@ namespace OpenSim.Framework /// /// The extracted ulong /// - public static ulong BytesToUInt64Big(byte[] bytes) { + public static ulong BytesToUInt64Big(byte[] bytes) + { if (bytes.Length < 8) return 0; return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; } // used for RemoteParcelRequest (for "About Landmark") - public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) { - byte[] bytes = { + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) + { + byte[] bytes = + { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), (byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24), @@ -755,11 +758,24 @@ namespace OpenSim.Framework return new UUID(bytes, 0); } - public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) { + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) + { byte[] bytes = parcelID.GetBytes(); regionHandle = Helpers.BytesToUInt64(bytes); x = Helpers.BytesToUInt(bytes, 8); y = Helpers.BytesToUInt(bytes, 12); } + + public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) + { + ulong regionHandle; + uint rx, ry; + + ParseFakeParcelID(parcelID, out regionHandle, out x, out y); + Helpers.LongToUInts(regionHandle, out rx, out ry); + + x += rx; + y += ry; + } } } -- cgit v1.1 From 901acddbdd38c441426f43cbfa78c422a19cec17 Mon Sep 17 00:00:00 2001 From: Dahlia Trimble Date: Wed, 15 Oct 2008 04:42:28 +0000 Subject: Thanks to M. Igarashi and nlin for a patch that implements llGetCameraRot(). --- OpenSim/Framework/Util.cs | 54 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 57c1601..28c818a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -116,6 +116,60 @@ namespace OpenSim.Framework # endregion + public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up) + { + float s; + float tr = (float) (fwd.X + left.Y + up.Z + 1.0); + + if (tr >= 1.0) + { + s = (float) (0.5 / Math.Sqrt(tr)); + return new Quaternion( + (left.Z - up.Y) * s, + (up.X - fwd.Z) * s, + (fwd.Y - left.X) * s, + (float) 0.25 / s); + } + else + { + float max = (left.Y > up.Z) ? left.Y : up.Z; + + if (max < fwd.X) + { + s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0)); + float x = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + x, + (fwd.Y + left.X) * s, + (up.X + fwd.Z) * s, + (left.Z - up.Y) * s); + } + else if (max == left.Y) + { + s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0)); + float y = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + (fwd.Y + left.X) * s, + y, + (left.Z + up.Y) * s, + (up.X - fwd.Z) * s); + } + else + { + s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0)); + float z = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + (up.X + fwd.Z) * s, + (left.Z + up.Y) * s, + z, + (fwd.Y - left.X) * s); + } + } + } + public static Random RandomClass { get { return randomClass; } -- cgit v1.1 From 98fdf504d9833dc8a58b141765378a1167d2c680 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Wed, 15 Oct 2008 20:24:44 +0000 Subject: * Truncate outgoing media and music urls to 254 characters. * Hopefully this will resolve http://opensimulator.org/mantis/view.php?id=2383 --- OpenSim/Framework/Util.cs | 40 ---------------------------------------- 1 file changed, 40 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 28c818a..0f0aa47 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -733,46 +733,6 @@ namespace OpenSim.Framework } } -/* 2008-08-28-tyre: Obsolete (see LocalLoginService UserLoginService) - public static string[] ParseStartLocationRequest(string startLocationRequest) - { - string[] returnstring = new string[4]; - // format uri:RegionName&X&Y&Z - returnstring[0] = "last"; - returnstring[1] = "127"; - returnstring[2] = "127"; - returnstring[3] = "0"; - // This is the crappy way of doing it. - - if (startLocationRequest.Contains(":") && startLocationRequest.Contains("&")) - { - //System.Console.WriteLine("StartLocationRequest Contains proper elements"); - - string[] splitstr = startLocationRequest.Split(':'); //,2,StringSplitOptions.RemoveEmptyEntries); - - //System.Console.WriteLine("Found " + splitstr.GetLength(0) + " elements in 1st split result"); - - if (splitstr.GetLength(0) == 2) - { - string[] splitstr2 = splitstr[1].Split('&'); //, 4, StringSplitOptions.RemoveEmptyEntries); - - //System.Console.WriteLine("Found " + splitstr2.GetLength(0) + " elements in 2nd split result"); - - int len = Math.Min(splitstr2.GetLength(0), 4); - - for (int i = 0; i < 4; ++i) - { - if (len > i) - { - returnstring[i] = splitstr2[i]; - } - } - } - } - return returnstring; - } -*/ - public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) { return SendXmlRpcCommand(url, methodName, args); -- cgit v1.1 From 3a75a54da1d973d0a8044a680c97bc2a54995548 Mon Sep 17 00:00:00 2001 From: Homer Horwitz Date: Sat, 18 Oct 2008 15:26:41 +0000 Subject: - Fix Util.UnixTimeSinceEpoch: * Unix epoch starts at midnight, not at 8:00am * All date/time handling should be done in UTC in the server, not in the local timezone. * Refactor out repeated computation of a constant value - Added setting of CreationTime to some places where inventoryitems are created This fixes Mantis#2390. --- OpenSim/Framework/Util.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0f0aa47..c5334a8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -27,6 +27,7 @@ using System; using System.Data; +using System.Globalization; using System.IO; using System.IO.Compression; using System.Net; @@ -59,6 +60,10 @@ namespace OpenSim.Framework private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; private static object XferLock = new object(); + // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. + private static readonly DateTime unixEpoch = + DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); + #region Vector Equations /// @@ -290,19 +295,19 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { - TimeSpan t = (stamp.ToUniversalTime() - Convert.ToDateTime("1/1/1970 8:00:00 AM")); + TimeSpan t = stamp.ToUniversalTime() - unixEpoch; return (int) t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) { - DateTime epoch = Convert.ToDateTime("1/1/1970 8:00:00 AM"); + DateTime epoch = unixEpoch; return epoch.AddSeconds(seconds); } public static DateTime ToDateTime(int seconds) { - DateTime epoch = Convert.ToDateTime("1/1/1970 8:00:00 AM"); + DateTime epoch = unixEpoch; return epoch.AddSeconds(seconds); } -- cgit v1.1 From 499f1428f707cbb116349dc0a2f07a19658df668 Mon Sep 17 00:00:00 2001 From: Homer Horwitz Date: Sun, 2 Nov 2008 13:07:57 +0000 Subject: - Add Util.isUUID - Add tests for Util.isUUID - First part of the fix for protocol interoperability between viewer 1.20 and 1.21 for friend offers. --- OpenSim/Framework/Util.cs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c5334a8..b8080ec 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -64,6 +64,8 @@ namespace OpenSim.Framework private static readonly DateTime unixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); + private static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); + #region Vector Equations /// @@ -796,5 +798,10 @@ namespace OpenSim.Framework x += rx; y += ry; } + + public static bool isUUID(string s) + { + return UUIDPattern.IsMatch(s); + } } } -- cgit v1.1 From 57caef119c55eb5bc5504c9a36cb52fe541845f5 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 3 Nov 2008 16:57:03 +0000 Subject: * Use the UUID regex sitting in utils for detection of uuids embedded in scripts * Replaces the one in the module itself, which had a dumb bug in it anyway --- OpenSim/Framework/Util.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b8080ec..122f104 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -64,7 +64,8 @@ namespace OpenSim.Framework private static readonly DateTime unixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); - private static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); + public static readonly Regex UUIDPattern + = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); #region Vector Equations @@ -799,6 +800,11 @@ namespace OpenSim.Framework y += ry; } + /// + /// Is the given string a UUID? + /// + /// + /// public static bool isUUID(string s) { return UUIDPattern.IsMatch(s); -- cgit v1.1 From cf0a14bec94322656f57890d49fead85ed31730e Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sat, 8 Nov 2008 17:20:54 +0000 Subject: * Added IClientIM to IClientCore interfaces * Changed SendInstantMessage, dropped fromAgentSession and imSessionID as security precaution, see http://opensimulator.org/wiki/OpenSim_0.6_IClientAPI#Porting_Guide for details on porting. * Removed unused usings from Framework.* --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 122f104..7caa414 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -39,10 +39,10 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Xml; -using OpenMetaverse; using log4net; using Nini.Config; using Nwc.XmlRpc; +using OpenMetaverse; namespace OpenSim.Framework { -- cgit v1.1 From 97816f8c901bf56e3b29bdbd5f8e320de352f45f Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Tue, 11 Nov 2008 17:02:46 +0000 Subject: * Implement basic region filtering as described in https://lists.berlios.de/pipermail/opensim-dev/2008-November/003468.html * This is done by sending a 'major interface version' number on sim registration. Developers must increment this every time they make a change that would make the previous OpenSim revision failure incompatible with the new one (non-fatal incompatibilities are fine). * This number resides in OpenSim.Framework.Servers.VersionInfo.MajorInterfaceVersion * This allows the grid service to stop older, incompatible regions from connecting --- OpenSim/Framework/Util.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7caa414..f72797f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -799,6 +799,33 @@ namespace OpenSim.Framework x += rx; y += ry; } + + /// + /// Get operating system information if available. Returns only the first 45 characters of information + /// + /// + /// Operating system information. Returns an empty string if none was available. + /// + public static string GetOperatingSystemInformation() + { + string os = String.Empty; + + if (System.Environment.OSVersion.Platform != PlatformID.Unix) + { + os = System.Environment.OSVersion.ToString(); + } + else + { + os = ReadEtcIssue(); + } + + if (os.Length > 45) + { + os = os.Substring(0, 45); + } + + return os; + } /// /// Is the given string a UUID? -- cgit v1.1 From c25a0ea7923aa390d30b8eebdbca4e599edf9b0d Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 17 Nov 2008 21:00:34 +0000 Subject: * Update libOMV to r2359. This is necessary for the progressive texture patch * Update libopenjpeg as well for this patch. * Appears to be okay on a very short sniff test * Source code will be placed in opensim-libs shortly --- OpenSim/Framework/Util.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f72797f..f0ad1d5 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -185,7 +185,7 @@ namespace OpenSim.Framework public static ulong UIntsToLong(uint X, uint Y) { - return Helpers.UIntsToLong(X, Y); + return Utils.UIntsToLong(X, Y); } public static T Clamp(T x, T min, T max) @@ -783,9 +783,9 @@ namespace OpenSim.Framework public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) { byte[] bytes = parcelID.GetBytes(); - regionHandle = Helpers.BytesToUInt64(bytes); - x = Helpers.BytesToUInt(bytes, 8); - y = Helpers.BytesToUInt(bytes, 12); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8); + y = Utils.BytesToUInt(bytes, 12); } public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) @@ -794,7 +794,7 @@ namespace OpenSim.Framework uint rx, ry; ParseFakeParcelID(parcelID, out regionHandle, out x, out y); - Helpers.LongToUInts(regionHandle, out rx, out ry); + Utils.LongToUInts(regionHandle, out rx, out ry); x += rx; y += ry; -- cgit v1.1 From 3234472d6203671a492a73042a0b56d6301903e0 Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 19 Nov 2008 06:15:21 +0000 Subject: Reverting the texture sending patch and the new libOMV. This makes this release a direct descendant of the stable 7364, with all the features and none of the issues. This omits the following patch chain: r7383 r7382 r7381 r7377 r7375 r7373 r7372 r7370 r7369 r7368 r7367 r7366 --- OpenSim/Framework/Util.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f0ad1d5..f72797f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -185,7 +185,7 @@ namespace OpenSim.Framework public static ulong UIntsToLong(uint X, uint Y) { - return Utils.UIntsToLong(X, Y); + return Helpers.UIntsToLong(X, Y); } public static T Clamp(T x, T min, T max) @@ -783,9 +783,9 @@ namespace OpenSim.Framework public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) { byte[] bytes = parcelID.GetBytes(); - regionHandle = Utils.BytesToUInt64(bytes); - x = Utils.BytesToUInt(bytes, 8); - y = Utils.BytesToUInt(bytes, 12); + regionHandle = Helpers.BytesToUInt64(bytes); + x = Helpers.BytesToUInt(bytes, 8); + y = Helpers.BytesToUInt(bytes, 12); } public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) @@ -794,7 +794,7 @@ namespace OpenSim.Framework uint rx, ry; ParseFakeParcelID(parcelID, out regionHandle, out x, out y); - Utils.LongToUInts(regionHandle, out rx, out ry); + Helpers.LongToUInts(regionHandle, out rx, out ry); x += rx; y += ry; -- cgit v1.1 From f518ca7feb33c0c1641ccb8f3956246b855f9b6c Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Wed, 19 Nov 2008 06:25:34 +0000 Subject: Reapply r7369 r7367 r7366 r7370 r7381. This brings it back up to the new libOMV. --- OpenSim/Framework/Util.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f72797f..f0ad1d5 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -185,7 +185,7 @@ namespace OpenSim.Framework public static ulong UIntsToLong(uint X, uint Y) { - return Helpers.UIntsToLong(X, Y); + return Utils.UIntsToLong(X, Y); } public static T Clamp(T x, T min, T max) @@ -783,9 +783,9 @@ namespace OpenSim.Framework public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) { byte[] bytes = parcelID.GetBytes(); - regionHandle = Helpers.BytesToUInt64(bytes); - x = Helpers.BytesToUInt(bytes, 8); - y = Helpers.BytesToUInt(bytes, 12); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8); + y = Utils.BytesToUInt(bytes, 12); } public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) @@ -794,7 +794,7 @@ namespace OpenSim.Framework uint rx, ry; ParseFakeParcelID(parcelID, out regionHandle, out x, out y); - Helpers.LongToUInts(regionHandle, out rx, out ry); + Utils.LongToUInts(regionHandle, out rx, out ry); x += rx; y += ry; -- cgit v1.1 From d1841ca94d382215a40a7433efcf24173967d80b Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sun, 30 Nov 2008 23:36:56 +0000 Subject: Mantis #2584 (again) Next step of diva's TP fixes and HG support --- OpenSim/Framework/Util.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f0ad1d5..c1429df 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -347,6 +347,12 @@ namespace OpenSim.Framework return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); } + public static bool IsOutsideView(uint oldx, uint newx, uint oldy, uint newy) + { + // Eventually this will be a function of the draw distance / camera position too. + return ((Math.Abs((int)(oldx - newx)) > 1) || (Math.Abs((int)(oldy - newy)) > 1)); + } + public static string FieldToString(byte[] bytes) { return FieldToString(bytes, String.Empty); -- cgit v1.1 From 888151833b1b08a6a8686d75a0385232b7fa90e9 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Tue, 9 Dec 2008 03:06:26 +0000 Subject: * Added primitive exception logging capabilities. * Disabled by default (see OpenSim.ini.example for how to enable) * Saves exceptions to a folder on disk (default "crashes") when enabled. * These reports can then be uploaded or posted to help debug an error. --- OpenSim/Framework/Util.cs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c1429df..23bdb94 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -560,6 +560,34 @@ namespace OpenSim.Framework return "."; } + // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html + public static string GetUniqueFilename(string FileName) + { + int count = 0; + string Name; + + if (File.Exists(FileName)) + { + FileInfo f = new FileInfo(FileName); + + if (!string.IsNullOrEmpty(f.Extension)) + { + Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); + } + else + { + Name = f.FullName; + } + + while (File.Exists(FileName)) + { + count++; + FileName = Name + count + f.Extension; + } + } + return FileName; + } + // Nini (config) related Methods public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) { -- cgit v1.1 From e6eb571c1d19972fe7eb4c3f7de113b1b91f5e02 Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Sun, 14 Dec 2008 02:17:12 +0000 Subject: Mantis#2725. Thank you kindly, Diva, for a patch that: Adds missing protocol pieces for EstablishAgentCommunication event which allows the client to activate CAPS and the EQ for child agents. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 23bdb94..4cc7134 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -350,7 +350,7 @@ namespace OpenSim.Framework public static bool IsOutsideView(uint oldx, uint newx, uint oldy, uint newy) { // Eventually this will be a function of the draw distance / camera position too. - return ((Math.Abs((int)(oldx - newx)) > 1) || (Math.Abs((int)(oldy - newy)) > 1)); + return (((int)Math.Abs((int)(oldx - newx)) > 1) || ((int)Math.Abs((int)(oldy - newy)) > 1)); } public static string FieldToString(byte[] bytes) -- cgit v1.1 From e7ac639f3a8a05858df03a8b5fd611826a56ae97 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Mon, 5 Jan 2009 19:36:48 +0000 Subject: * Centralize references to the well known blank texture 5748decc-f629-461c-9a36-a35a221fe21f to a constant in OpenSim.Framework.Util --- OpenSim/Framework/Util.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 4cc7134..396996a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -51,7 +51,7 @@ namespace OpenSim.Framework /// public class Util { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static uint nextXferID = 5000; private static Random randomClass = new Random(); @@ -66,6 +66,11 @@ namespace OpenSim.Framework public static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); + + /// + /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) + /// + public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); #region Vector Equations -- cgit v1.1 From b1c2cb3d8206b845a26fe04371dc1a1a6b2cbec2 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Tue, 6 Jan 2009 17:27:04 +0000 Subject: * minor: Move GetRandomCapsPath() to a CapsUtil class --- OpenSim/Framework/Util.cs | 8 -------- 1 file changed, 8 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 396996a..8e7eac7 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -334,14 +334,6 @@ namespace OpenSim.Framework return sb.ToString(); } - public static string GetRandomCapsPath() - { - UUID caps = UUID.Random(); - string capsPath = caps.ToString(); - capsPath = capsPath.Remove(capsPath.Length - 4, 4); - return capsPath; - } - public static int fast_distance2d(int x, int y) { x = Math.Abs(x); -- cgit v1.1 From 1c3542303c11b2186fe23268266c02e717cc5aae Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Tue, 13 Jan 2009 23:29:54 +0000 Subject: Change fake parcel ids to allow a Z coordinate. Change TP by lure to also transmit and use a Z coordinate. --- OpenSim/Framework/Util.cs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8e7eac7..7217ece 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -806,8 +806,19 @@ namespace OpenSim.Framework { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), - (byte)x, (byte)(x >> 8), (byte)(x >> 16), (byte)(x >> 24), - (byte)y, (byte)(y >> 8), (byte)(y >> 16), (byte)(y >> 24) }; + (byte)x, (byte)(x >> 8), 0, 0, + (byte)y, (byte)(y >> 8), 0, 0 }; + return new UUID(bytes, 0); + } + + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z) + { + byte[] bytes = + { + (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), + (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); } @@ -815,8 +826,17 @@ namespace OpenSim.Framework { byte[] bytes = parcelID.GetBytes(); regionHandle = Utils.BytesToUInt64(bytes); - x = Utils.BytesToUInt(bytes, 8); - y = Utils.BytesToUInt(bytes, 12); + x = Utils.BytesToUInt(bytes, 8) & 0xffff; + y = Utils.BytesToUInt(bytes, 12) & 0xffff; + } + + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) + { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8) & 0xffff; + z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16; + y = Utils.BytesToUInt(bytes, 12) & 0xffff; } public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) -- cgit v1.1 From ea6e4a95ce5e0fc8c5e3d049b43b9cc0ada65491 Mon Sep 17 00:00:00 2001 From: idb Date: Thu, 29 Jan 2009 19:47:55 +0000 Subject: Complete the implementation of llSHA1String. --- OpenSim/Framework/Util.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7217ece..df7a552 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -334,6 +334,17 @@ namespace OpenSim.Framework return sb.ToString(); } + /// + /// Return an SHA1 hash of the given string + /// + /// + /// + public static string SHA1Hash(string src) + { + SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); + return BitConverter.ToString(SHA1.ComputeHash(Encoding.Default.GetBytes(src))).Replace("-", String.Empty); + } + public static int fast_distance2d(int x, int y) { x = Math.Abs(x); -- cgit v1.1 From 801da4346aeb3c08969c4845f5c595135a64470a Mon Sep 17 00:00:00 2001 From: lbsa71 Date: Thu, 12 Feb 2009 09:53:12 +0000 Subject: * optimized usings. --- OpenSim/Framework/Util.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index df7a552..9949ad8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -194,7 +194,7 @@ namespace OpenSim.Framework } public static T Clamp(T x, T min, T max) - where T : System.IComparable + where T : IComparable { return x.CompareTo(max) > 0 ? max : x.CompareTo(min) < 0 ? min : @@ -758,8 +758,8 @@ namespace OpenSim.Framework memory.Read(compressed, 0, compressed.Length); byte[] compressedBuffer = new byte[compressed.Length + 4]; - System.Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); - System.Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); + Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); + Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); return Convert.ToBase64String(compressedBuffer); } @@ -872,9 +872,9 @@ namespace OpenSim.Framework { string os = String.Empty; - if (System.Environment.OSVersion.Platform != PlatformID.Unix) + if (Environment.OSVersion.Platform != PlatformID.Unix) { - os = System.Environment.OSVersion.ToString(); + os = Environment.OSVersion.ToString(); } else { -- cgit v1.1 From 93465df5e3cdab1774216fbf3f741af03aa609f7 Mon Sep 17 00:00:00 2001 From: lbsa71 Date: Tue, 17 Feb 2009 14:12:57 +0000 Subject: * Moved the nifty MySQLEstateData connectionstring password-stripper out into the Util project --- OpenSim/Framework/Util.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9949ad8..dcac9f1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -898,5 +898,25 @@ namespace OpenSim.Framework { return UUIDPattern.IsMatch(s); } + + public static string GetDisplayConnectionString(string connectionString) + { + int passPosition = 0; + int passEndPosition = 0; + string displayConnectionString = null; + + // hide the password in the connection string + passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); + passPosition = connectionString.IndexOf("=", passPosition); + if (passPosition < connectionString.Length) + passPosition += 1; + passEndPosition = connectionString.IndexOf(";", passPosition); + + displayConnectionString = connectionString.Substring(0, passPosition); + displayConnectionString += "***"; + displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition); + + return displayConnectionString; + } } } -- cgit v1.1 From 8f55b9d735fbc975ce7a4b54e972c17ffbfb1f49 Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Sun, 22 Feb 2009 20:52:55 +0000 Subject: Mantis#3218. Thank you kindly, TLaukkan (Tommil) for a patch that: * Added log4net dependency to physxplugin in prebuild.xml. * Added missing m_log fields to classes. * Replaced Console.WriteLine with appropriate m_log.Xxxx * Tested that nant test target runs succesfully. * Tested that local opensim sandbox starts up without errors. --- OpenSim/Framework/Util.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index dcac9f1..2718072 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -700,8 +700,7 @@ namespace OpenSim.Framework } catch (Exception e) { - System.Console.WriteLine(e.Message); - System.Console.WriteLine(e.StackTrace); + m_log.Error(e.ToString()); } finally { @@ -728,8 +727,7 @@ namespace OpenSim.Framework } catch (Exception e) { - System.Console.WriteLine(e.Message); - System.Console.WriteLine(e.StackTrace); + m_log.Error(e.ToString()); } finally { -- cgit v1.1 From c2f3ff872dd88b4382b41844a4faa632129d1760 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Mon, 23 Feb 2009 06:55:42 +0000 Subject: * Performance Changes: * Moves Entity Updates into a seperate thread, allowing for OpenSim to utilize a computers CPU more effectively in return for potentially greater user and prim capacity. * Removes an expensive Sqrt call performed during Update on each object. This should lower CPU requirements for high-prim regions with physics enabled. * MXP Changes: Centers the region around 0,0 for primitives instead of 128,128. Prim display should now look more correct for MXP viewers. --- OpenSim/Framework/Util.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2718072..4fce4ac 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -89,6 +89,21 @@ namespace OpenSim.Framework } /// + /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt. + /// + /// + /// + /// + /// + public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return (dx*dx + dy*dy + dz*dz) < (amount*amount); + } + + /// /// Get the magnitude of a 3d vector /// /// A 3d vector -- cgit v1.1 From 77b70759a69494d0d0cd1b978e8b136298ba8a5a Mon Sep 17 00:00:00 2001 From: MW Date: Sat, 28 Feb 2009 16:13:20 +0000 Subject: Copied the Util.ReadSettingsFromIniFile method from the branch to trunk. --- OpenSim/Framework/Util.cs | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 4fce4ac..a0f3567 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections.Generic; using System.Data; using System.Globalization; using System.IO; @@ -931,5 +932,65 @@ namespace OpenSim.Framework return displayConnectionString; } + + public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) + { + Type settingsType = settingsClass.GetType(); + + FieldInfo[] fieldInfos = settingsType.GetFields(); + foreach (FieldInfo fieldInfo in fieldInfos) + { + if (fieldInfo.FieldType == typeof(System.String)) + { + fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Boolean)) + { + fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Int32)) + { + fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Single)) + { + fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.UInt32)) + { + fieldInfo.SetValue(settingsClass, System.Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + } + } + + PropertyInfo[] propertyInfos = settingsType.GetProperties(); + foreach (PropertyInfo propInfo in propertyInfos) + { + if ((propInfo.CanRead) && (propInfo.CanWrite)) + { + if (propInfo.PropertyType == typeof(System.String)) + { + propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Boolean)) + { + propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Int32)) + { + propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Single)) + { + propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); + } + if (propInfo.PropertyType == typeof(System.UInt32)) + { + propInfo.SetValue(settingsClass, System.Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); + } + } + } + + return settingsClass; + } } } -- cgit v1.1 From 23a7af4538cb2b3c5b494259c5e36690c52572e0 Mon Sep 17 00:00:00 2001 From: MW Date: Sat, 28 Feb 2009 16:42:13 +0000 Subject: Added check so Util.ReadSettingsFromIniFile doesn't try to set static fields. --- OpenSim/Framework/Util.cs | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a0f3567..d978c4c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -940,25 +940,28 @@ namespace OpenSim.Framework FieldInfo[] fieldInfos = settingsType.GetFields(); foreach (FieldInfo fieldInfo in fieldInfos) { - if (fieldInfo.FieldType == typeof(System.String)) + if (!fieldInfo.IsStatic) { - fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Boolean)) - { - fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Int32)) - { - fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Single)) - { - fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.UInt32)) - { - fieldInfo.SetValue(settingsClass, System.Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + if (fieldInfo.FieldType == typeof(System.String)) + { + fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Boolean)) + { + fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Int32)) + { + fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Single)) + { + fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.UInt32)) + { + fieldInfo.SetValue(settingsClass, System.Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + } } } -- cgit v1.1 From 76133d07630d8a1547c034b28585a931f751ad1b Mon Sep 17 00:00:00 2001 From: MW Date: Tue, 3 Mar 2009 12:51:54 +0000 Subject: Refactoring of CreateCommsManagerPlugin. Plus some general cleanup of a few other files (deleting excess blank lines etc) --- OpenSim/Framework/Util.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d978c4c..ba19dc6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -766,8 +766,7 @@ namespace OpenSim.Framework } memory.Position = 0; - // MemoryStream outStream = new MemoryStream(); - + byte[] compressed = new byte[memory.Length]; memory.Read(compressed, 0, compressed.Length); -- cgit v1.1 From fb9a358b797418fbc4c38dd9ec67e12bb5b7c98a Mon Sep 17 00:00:00 2001 From: lbsa71 Date: Tue, 31 Mar 2009 05:51:28 +0000 Subject: * Refactored out and de-duplicated Base64ToString(string) * Fixed minor typo --- OpenSim/Framework/Util.cs | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ba19dc6..cce2adb 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -342,7 +342,7 @@ namespace OpenSim.Framework /// public static string Md5Hash(string pass) { - MD5 md5 = MD5CryptoServiceProvider.Create(); + MD5 md5 = MD5.Create(); byte[] dataMd5 = md5.ComputeHash(Encoding.Default.GetBytes(pass)); StringBuilder sb = new StringBuilder(); for (int i = 0; i < dataMd5.Length; i++) @@ -419,7 +419,7 @@ namespace OpenSim.Framework output.Append(": "); } - output.Append(CleanString(UTF8Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1))); + output.Append(CleanString(Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1))); } else { @@ -532,7 +532,7 @@ namespace OpenSim.Framework /// safe path public static string safePath(string path) { - return Regex.Replace(path, @regexInvalidPathChars, string.Empty); + return Regex.Replace(path, regexInvalidPathChars, String.Empty); } /// @@ -542,7 +542,7 @@ namespace OpenSim.Framework /// safe filename public static string safeFileName(string filename) { - return Regex.Replace(filename, @regexInvalidFileChars, string.Empty); + return Regex.Replace(filename, regexInvalidFileChars, String.Empty); ; } @@ -594,7 +594,7 @@ namespace OpenSim.Framework { FileInfo f = new FileInfo(FileName); - if (!string.IsNullOrEmpty(f.Extension)) + if (!String.IsNullOrEmpty(f.Extension)) { Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); } @@ -959,7 +959,7 @@ namespace OpenSim.Framework } else if (fieldInfo.FieldType == typeof(System.UInt32)) { - fieldInfo.SetValue(settingsClass, System.Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); } } } @@ -987,12 +987,25 @@ namespace OpenSim.Framework } if (propInfo.PropertyType == typeof(System.UInt32)) { - propInfo.SetValue(settingsClass, System.Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); + propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); } } } return settingsClass; } + + public static string Base64ToString(string str) + { + UTF8Encoding encoder = new UTF8Encoding(); + Decoder utf8Decode = encoder.GetDecoder(); + + byte[] todecode_byte = Convert.FromBase64String(str); + int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); + char[] decoded_char = new char[charCount]; + utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); + string result = new String(decoded_char); + return result; + } } } -- cgit v1.1 From 0266c344fb425e1338f988f542fc532e9b47aa1f Mon Sep 17 00:00:00 2001 From: lbsa71 Date: Wed, 1 Apr 2009 06:11:51 +0000 Subject: * Added NUnit tested utility function GetHashGuid() for future use. * Did some aligning refactoring of the MD5 and SHA-1 functions. --- OpenSim/Framework/Util.cs | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index cce2adb..a0cac96 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -338,29 +338,41 @@ namespace OpenSim.Framework /// /// Return an md5 hash of the given string /// - /// + /// /// - public static string Md5Hash(string pass) + public static string Md5Hash(string data) { - MD5 md5 = MD5.Create(); - byte[] dataMd5 = md5.ComputeHash(Encoding.Default.GetBytes(pass)); + byte[] dataMd5 = ComputeMD5Hash(data); StringBuilder sb = new StringBuilder(); for (int i = 0; i < dataMd5.Length; i++) sb.AppendFormat("{0:x2}", dataMd5[i]); return sb.ToString(); } + private static byte[] ComputeMD5Hash(string data) + { + MD5 md5 = MD5.Create(); + return md5.ComputeHash(Encoding.Default.GetBytes(data)); + } + /// /// Return an SHA1 hash of the given string /// - /// + /// /// - public static string SHA1Hash(string src) + public static string SHA1Hash(string data) + { + byte[] hash = ComputeSHA1Hash(data); + return BitConverter.ToString(hash).Replace("-", String.Empty); + } + + private static byte[] ComputeSHA1Hash(string src) { SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); - return BitConverter.ToString(SHA1.ComputeHash(Encoding.Default.GetBytes(src))).Replace("-", String.Empty); + return SHA1.ComputeHash(Encoding.Default.GetBytes(src)); } + public static int fast_distance2d(int x, int y) { x = Math.Abs(x); @@ -1007,5 +1019,16 @@ namespace OpenSim.Framework string result = new String(decoded_char); return result; } + + public static Guid GetHashGuid(string data, string salt) + { + byte[] hash = ComputeMD5Hash( data + salt ); + + string s = BitConverter.ToString(hash); + + Guid guid = new Guid( hash ); + + return guid; + } } } -- cgit v1.1 From c6283cacacd9c2a0992e233f54b6d9d272564449 Mon Sep 17 00:00:00 2001 From: Homer Horwitz Date: Sat, 4 Apr 2009 14:26:24 +0000 Subject: Remove some Mono warnings. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a0cac96..7019096 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1024,7 +1024,7 @@ namespace OpenSim.Framework { byte[] hash = ComputeMD5Hash( data + salt ); - string s = BitConverter.ToString(hash); + //string s = BitConverter.ToString(hash); Guid guid = new Guid( hash ); -- cgit v1.1 From 0413d052a3ec541164049e7d39278c57fb92ed06 Mon Sep 17 00:00:00 2001 From: diva Date: Tue, 14 Apr 2009 19:35:35 +0000 Subject: Adds session authentication upon NewUserConnections. Adds user key authentication (in safemode only) upon CreateChildAgents. All of this for Hypergrid users too. This addresses assorted spoofing vulnerabilities. --- OpenSim/Framework/Util.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7019096..f1993b2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -26,6 +26,7 @@ */ using System; +using System.Collections; using System.Collections.Generic; using System.Data; using System.Globalization; @@ -820,6 +821,21 @@ namespace OpenSim.Framework } /// + /// Returns an error message that the user could not be found in the database + /// + /// XML string consisting of a error element containing individual error(s) + public static XmlRpcResponse CreateUnknownUserErrorResponse() + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + responseData["error_type"] = "unknown_user"; + responseData["error_desc"] = "The user requested is not in the database"; + + response.Value = responseData; + return response; + } + + /// /// Converts a byte array in big endian order into an ulong. /// /// -- cgit v1.1 From 52d56288060caca4f92fee9549090390d7053549 Mon Sep 17 00:00:00 2001 From: Justin Clarke Casey Date: Tue, 28 Apr 2009 17:47:09 +0000 Subject: * Add preliminary code for resolving iar profile names * Not yet active --- OpenSim/Framework/Util.cs | 1 - 1 file changed, 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f1993b2..cad259d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -373,7 +373,6 @@ namespace OpenSim.Framework return SHA1.ComputeHash(Encoding.Default.GetBytes(src)); } - public static int fast_distance2d(int x, int y) { x = Math.Abs(x); -- cgit v1.1 From c1d680b6c3a5e3dc11cd1e7cc9b74d3d81317eee Mon Sep 17 00:00:00 2001 From: Charles Krinke Date: Tue, 12 May 2009 03:30:37 +0000 Subject: Thank you kindly, Patnad, for a patch that: This is to handle the changes in the v1.23 viewer of LL regarding the adult rating. With this patch a region can be changed to the adult rating from LL viewer v1.23 and above. --- OpenSim/Framework/Util.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index cad259d..35efa02 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1045,5 +1045,29 @@ namespace OpenSim.Framework return guid; } + + public static byte ConvertMaturityToAccessLevel(uint maturity) + { + byte retVal = 0; + switch (maturity) + { + case 0: //PG + retVal = 13; + break; + case 1: //Mature + retVal = 21; + break; + case 2: // Adult + retVal = 42; + break; + } + + return retVal; + + } + + + + } } -- cgit v1.1 From 2d0613516626960de5d7e3ea83b6386ce00dcb74 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sat, 23 May 2009 05:09:10 +0000 Subject: * Adds new NetworkUtil class, contains methods for handling IP resolution when located on the same subnet. (Eg, can be used to avoid NAT Loopback requirements if fully utilized.) * Adds a few new network-related methods to Util. --- OpenSim/Framework/Util.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 35efa02..0128735 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -517,6 +517,20 @@ namespace OpenSim.Framework return null; } + public static Uri GetURI(string protocol, string hostname, int port, string path) + { + return new UriBuilder(protocol, hostname, port, path).Uri; + } + + /// + /// Gets a list of all local system IP addresses + /// + /// + public static IPAddress[] GetLocalHosts() + { + return Dns.GetHostAddresses(Dns.GetHostName()); + } + public static IPAddress GetLocalHost() { string dnsAddress = "localhost"; -- cgit v1.1 From 70f6a2852eaea68bad0d26e5a5c1c7d8df3d8942 Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sat, 23 May 2009 07:51:29 +0000 Subject: * Fixes [irritating] edge case in Util.GetLocalHost which could return an IPv6 address if no non-loopback IPv4 address can be found. * Restores internal IPv6 support to NetworkUtil.* * Fixes bad login unit tests. --- OpenSim/Framework/Util.cs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0128735..ee47e0f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -546,7 +546,15 @@ namespace OpenSim.Framework } if (hosts.Length > 0) + { + foreach (IPAddress host in hosts) + { + if(host.AddressFamily == AddressFamily.InterNetwork) + return host; + } + // Well all else failed... return hosts[0]; + } return null; } -- cgit v1.1 From 896c20671887175255e5db205a721165810cf32e Mon Sep 17 00:00:00 2001 From: diva Date: Mon, 25 May 2009 19:20:27 +0000 Subject: One more utility. Not used yet. --- OpenSim/Framework/Util.cs | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ee47e0f..a188267 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -45,6 +45,7 @@ using log4net; using Nini.Config; using Nwc.XmlRpc; using OpenMetaverse; +using OpenMetaverse.StructuredData; namespace OpenSim.Framework { @@ -1088,8 +1089,27 @@ namespace OpenSim.Framework } - - + /// + /// Produces an OSDMap from its string representation on a stream + /// + /// The stream + /// The size of the data on the stream + /// The OSDMap or an exception + public static OSDMap GetOSDMap(Stream stream, int length) + { + byte[] data = new byte[length]; + stream.Read(data, 0, length); + string strdata = Encoding.UTF8.GetString(data); + OSDMap args = null; + OSD buffer; + buffer = OSDParser.DeserializeJson(strdata); + if (buffer.Type == OSDType.Map) + { + args = (OSDMap)buffer; + return args; + } + return null; + } } } -- cgit v1.1 From 35b450d41d2695aa6a82a6d8e6bda5e327f431e1 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Sun, 31 May 2009 18:35:00 +0000 Subject: Add copyright headers, formatting cleanup, ignore some generated files. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a188267..bc4af3f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -550,7 +550,7 @@ namespace OpenSim.Framework { foreach (IPAddress host in hosts) { - if(host.AddressFamily == AddressFamily.InterNetwork) + if (host.AddressFamily == AddressFamily.InterNetwork) return host; } // Well all else failed... -- cgit v1.1 From 840de6c036570d559ec6924cd8405d3f34a99fdd Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Mon, 1 Jun 2009 06:37:14 +0000 Subject: Minor: Change OpenSim to OpenSimulator in older copyright headers and LICENSE.txt. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index bc4af3f..d6202ea 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -9,7 +9,7 @@ * * 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 + * * 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. * -- cgit v1.1 From a23d64dec1cbf88abc3c7e84664a683dee534e4a Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Wed, 10 Jun 2009 04:28:56 +0000 Subject: Formatting cleanup. --- OpenSim/Framework/Util.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d6202ea..0a9b67d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1060,11 +1060,11 @@ namespace OpenSim.Framework public static Guid GetHashGuid(string data, string salt) { - byte[] hash = ComputeMD5Hash( data + salt ); + byte[] hash = ComputeMD5Hash(data + salt); //string s = BitConverter.ToString(hash); - Guid guid = new Guid( hash ); + Guid guid = new Guid(hash); return guid; } -- cgit v1.1 From efc57bc3d79e9c3c0971a2715a407ad08e030f02 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 6 Aug 2009 02:29:12 +0100 Subject: Allow arbitrary wildcards in config includes. Things like Include-Modules = "addin-modules/*/config/*.ini" will now work. Adds Util.Glob, which will resolve a globbed path into a string list. --- OpenSim/Framework/Util.cs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0a9b67d..65d4f4d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1111,5 +1111,56 @@ namespace OpenSim.Framework return null; } + public static string[] Glob(string path) + { + string vol=String.Empty; + + if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) + { + string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries); + + if (vcomps.Length > 1) + { + path = vcomps[1]; + vol = vcomps[0]; + } + } + + string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); + + // Glob + + path = vol; + if (vol != String.Empty) + path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar}); + else + path = new String(new char[] {Path.DirectorySeparatorChar}); + + List paths = new List(); + List found = new List(); + paths.Add(path); + + foreach (string c in comps) + { + List addpaths = new List(); + foreach (string p in paths) + { + string[] dirs = Directory.GetDirectories(p, c); + + if (dirs.Length != 0) + { + foreach (string dir in dirs) + addpaths.Add(Path.Combine(path, dir)); + } + + string[] files = Directory.GetFiles(p, c); + foreach (string f in files) + found.Add(f); + } + paths = addpaths; + } + + return found.ToArray(); + } } } -- cgit v1.1 From 178b40971a401307a827bc95abbe8d9d69566825 Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 7 Aug 2009 19:50:47 +0100 Subject: Add a method to init the OSSL Api's m_LSL_Api member back to the OSSL Api --- OpenSim/Framework/Util.cs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 65d4f4d..003c543 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1155,7 +1155,10 @@ namespace OpenSim.Framework string[] files = Directory.GetFiles(p, c); foreach (string f in files) + { + m_log.InfoFormat("Adding file {0} to include list", f); found.Add(f); + } } paths = addpaths; } -- cgit v1.1 From d10f1571831895fbdd0a818bf34590087078643a Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 7 Aug 2009 20:51:07 +0100 Subject: Remove GetFullPath call from config includes, because it barfs in Windoze --- OpenSim/Framework/Util.cs | 3 --- 1 file changed, 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 003c543..65d4f4d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1155,10 +1155,7 @@ namespace OpenSim.Framework string[] files = Directory.GetFiles(p, c); foreach (string f in files) - { - m_log.InfoFormat("Adding file {0} to include list", f); found.Add(f); - } } paths = addpaths; } -- cgit v1.1 From e97beb07c94571549da0c635d469190bff8ab918 Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 7 Aug 2009 21:59:54 +0100 Subject: Add extensive debug output to Util.Glob --- OpenSim/Framework/Util.cs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 65d4f4d..048de84 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1113,6 +1113,7 @@ namespace OpenSim.Framework public static string[] Glob(string path) { + m_log.DebugFormat("[GLOB]: Globbing {0}", path); string vol=String.Empty; if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) @@ -1145,17 +1146,25 @@ namespace OpenSim.Framework List addpaths = new List(); foreach (string p in paths) { + m_log.DebugFormat("[GLOB]: Getting directories (wildcard: {0}) from path {1}", c, p); string[] dirs = Directory.GetDirectories(p, c); if (dirs.Length != 0) { foreach (string dir in dirs) + { + m_log.DebugFormat("[GLOB]: Adding path {0} to search list", Path.Combine(path, dir)); addpaths.Add(Path.Combine(path, dir)); + } } + m_log.DebugFormat("[GLOB]: Getting files (wildcard: {0}) from path {1}", c, p); string[] files = Directory.GetFiles(p, c); foreach (string f in files) + { + m_log.DebugFormat("[GLOB]: Adding file {0} to result list", f); found.Add(f); + } } paths = addpaths; } -- cgit v1.1 From 257ed4c4ac2026b39c90d9f58d505dc2721e8df3 Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 7 Aug 2009 23:05:16 +0100 Subject: Remove debugging output frm ini file loading. Make it collect matching files only from last path component. --- OpenSim/Framework/Util.cs | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 048de84..bbb0ae2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1113,7 +1113,6 @@ namespace OpenSim.Framework public static string[] Glob(string path) { - m_log.DebugFormat("[GLOB]: Globbing {0}", path); string vol=String.Empty; if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) @@ -1141,29 +1140,28 @@ namespace OpenSim.Framework List found = new List(); paths.Add(path); + int compIndex = -1; foreach (string c in comps) { + compIndex++; + List addpaths = new List(); foreach (string p in paths) { - m_log.DebugFormat("[GLOB]: Getting directories (wildcard: {0}) from path {1}", c, p); string[] dirs = Directory.GetDirectories(p, c); if (dirs.Length != 0) { foreach (string dir in dirs) - { - m_log.DebugFormat("[GLOB]: Adding path {0} to search list", Path.Combine(path, dir)); addpaths.Add(Path.Combine(path, dir)); - } } - m_log.DebugFormat("[GLOB]: Getting files (wildcard: {0}) from path {1}", c, p); - string[] files = Directory.GetFiles(p, c); - foreach (string f in files) + // Only add files if that is the last path component + if (compIndex == comps.Length - 1) { - m_log.DebugFormat("[GLOB]: Adding file {0} to result list", f); - found.Add(f); + string[] files = Directory.GetFiles(p, c); + foreach (string f in files) + found.Add(f); } } paths = addpaths; -- cgit v1.1 From 584c1138361c6c5ed3ad18225760fb5f9e88093a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 1 Sep 2009 11:26:08 -0700 Subject: Added Util.FireAndForget(), to replace leaking calls to Delegate.BeginInvoke() --- OpenSim/Framework/Util.cs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index bbb0ae2..58344f3 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1169,5 +1169,27 @@ namespace OpenSim.Framework return found.ToArray(); } + + #region FireAndForget Threading Pattern + + public static void FireAndForget(System.Threading.WaitCallback callback) + { + callback.BeginInvoke(null, EndFireAndForget, callback); + } + + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + callback.BeginInvoke(obj, EndFireAndForget, callback); + } + + private static void EndFireAndForget(IAsyncResult ar) + { + System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; + + callback.EndInvoke(ar); + ar.AsyncWaitHandle.Close(); + } + + #endregion FireAndForget Threading Pattern } } -- cgit v1.1 From 71a4b02c7e9a2587759fd40092d1bdcfef648eff Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Thu, 24 Sep 2009 20:56:01 +1000 Subject: * Minor commit, added two new math utility functions. --- OpenSim/Framework/Util.cs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 58344f3..45b5a10 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -70,6 +70,39 @@ namespace OpenSim.Framework public static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); + /// + /// Linear interpolates B<->C using percent A + /// + /// + /// + /// + /// + public static double lerp(double a, double b, double c) + { + return (b*a) + (c*(1 - a)); + } + + /// + /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y. + /// Layout: + /// A B + /// C D + /// A<->C = Y + /// C<->D = X + /// + /// + /// + /// + /// + /// + /// + /// + public static double lerp2D(double x, double y, double a, double b, double c, double d) + { + return lerp(y, lerp(x, a, b), lerp(x, c, d)); + } + + /// /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) /// -- cgit v1.1 From f4bf581b96347b8d7f115eca74fa84a644eb729c Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 26 Sep 2009 21:00:51 -0700 Subject: Moved all HG1 operations to HGGridConnector.cs and HypergridServerConnector.cs/HypergridServiceConnector.cs, away from Region.Communications and HGNetworkServersInfo. Fixed small bugs with hyperlinked regions' map positions. --- OpenSim/Framework/Util.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 45b5a10..a28a617 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1203,6 +1203,32 @@ namespace OpenSim.Framework return found.ToArray(); } + public static string ServerURI(string uri) + { + if (uri == string.Empty) + return string.Empty; + + // Get rid of eventual slashes at the end + uri = uri.TrimEnd('/'); + + IPAddress ipaddr1 = null; + string port1 = ""; + try + { + ipaddr1 = Util.GetHostFromURL(uri); + } + catch { } + + try + { + port1 = uri.Split(new char[] { ':' })[2]; + } + catch { } + + // We tried our best to convert the domain names to IP addresses + return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; + } + #region FireAndForget Threading Pattern public static void FireAndForget(System.Threading.WaitCallback callback) -- cgit v1.1 From ee205e7e812e170f670e690a4e0fa9caa652f226 Mon Sep 17 00:00:00 2001 From: Jeff Ames Date: Thu, 1 Oct 2009 01:00:09 +0900 Subject: Formatting cleanup. --- OpenSim/Framework/Util.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a28a617..17fc58c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -54,7 +54,7 @@ namespace OpenSim.Framework /// public class Util { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static uint nextXferID = 5000; private static Random randomClass = new Random(); @@ -136,7 +136,7 @@ namespace OpenSim.Framework float dx = a.X - b.X; float dy = a.Y - b.Y; float dz = a.Z - b.Z; - return (dx*dx + dy*dy + dz*dz) < (amount*amount); + return (dx*dx + dy*dy + dz*dz) < (amount*amount); } /// @@ -975,7 +975,7 @@ namespace OpenSim.Framework else { os = ReadEtcIssue(); - } + } if (os.Length > 45) { -- cgit v1.1 From 387e9f7a7faeb412054383080afc3507a1522746 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 2 Oct 2009 18:31:08 -0700 Subject: * Creates Util.UTF8 and switches some references of Encoding.UTF8 to Util.UTF8 (not all references were switched since not all OpenSim libraries reference OpenSim.Framework) * Shrinks the largest in-memory object, the LLRAW.HeightmapLookupValue struct (only used for exporting to LLRAW terrain files), to the minimum possible size. This seems to have the odd side effect of cutting the size of the two double[256,256] terrain objects in half. Possibly an alignment optimization? --- OpenSim/Framework/Util.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 58344f3..59159a8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -69,7 +69,9 @@ namespace OpenSim.Framework public static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); - + + public static Encoding UTF8 = Encoding.UTF8; + /// /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) /// @@ -432,7 +434,7 @@ namespace OpenSim.Framework output.Append(": "); } - output.Append(CleanString(Encoding.UTF8.GetString(bytes, 0, bytes.Length - 1))); + output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1))); } else { @@ -793,7 +795,7 @@ namespace OpenSim.Framework public static string Compress(string text) { - byte[] buffer = Encoding.UTF8.GetBytes(text); + byte[] buffer = Util.UTF8.GetBytes(text); MemoryStream memory = new MemoryStream(); using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) { @@ -827,7 +829,7 @@ namespace OpenSim.Framework decompressor.Read(buffer, 0, buffer.Length); } - return Encoding.UTF8.GetString(buffer); + return Util.UTF8.GetString(buffer); } } @@ -1099,7 +1101,7 @@ namespace OpenSim.Framework { byte[] data = new byte[length]; stream.Read(data, 0, length); - string strdata = Encoding.UTF8.GetString(data); + string strdata = Util.UTF8.GetString(data); OSDMap args = null; OSD buffer; buffer = OSDParser.DeserializeJson(strdata); -- cgit v1.1 From e7c877407f2a72a9519eb53debca5aeef20cded9 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 6 Oct 2009 02:38:00 -0700 Subject: * Continued work on the new LLUDP implementation. Appears to be functioning, although not everything is reimplemented yet * Replaced logic in ThreadTracker with a call to System.Diagnostics that does the same thing * Added Util.StringToBytes256() and Util.StringToBytes1024() to clamp output at byte[256] and byte[1024], respectively * Fixed formatting for a MySQLAssetData error logging line --- OpenSim/Framework/Util.cs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0851d26..189fa38 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1231,6 +1231,42 @@ namespace OpenSim.Framework return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; } + public static byte[] StringToBytes256(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (str.Length > 254) str = str.Remove(254); + if (!str.EndsWith("\0")) { str += "\0"; } + + // Because this is UTF-8 encoding and not ASCII, it's possible we + // might have gotten an oversized array even after the string trim + byte[] data = UTF8.GetBytes(str); + if (data.Length > 256) + { + Array.Resize(ref data, 256); + data[255] = 0; + } + + return data; + } + + public static byte[] StringToBytes1024(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (str.Length > 1023) str = str.Remove(1023); + if (!str.EndsWith("\0")) { str += "\0"; } + + // Because this is UTF-8 encoding and not ASCII, it's possible we + // might have gotten an oversized array even after the string trim + byte[] data = UTF8.GetBytes(str); + if (data.Length > 1024) + { + Array.Resize(ref data, 1024); + data[1023] = 0; + } + + return data; + } + #region FireAndForget Threading Pattern public static void FireAndForget(System.Threading.WaitCallback callback) -- cgit v1.1 From fb19d1ca0a7c6e82c540c4e8d22c82c09b7bec98 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 6 Oct 2009 10:12:59 -0700 Subject: * Try/catch around EndInvoke() when Util.FireAndForget() returns to catch exceptions thrown in the async method * Added packet stats handling to the new LLUDP implementation * Attempting to avoid a race condition when creating a new LLUDPClient --- OpenSim/Framework/Util.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 189fa38..38729c6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1283,7 +1283,9 @@ namespace OpenSim.Framework { System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; - callback.EndInvoke(ar); + try { callback.EndInvoke(ar); } + catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } + ar.AsyncWaitHandle.Close(); } -- cgit v1.1 From 80a8a9c4a7c9f1f0351f70f944a69650e9eca930 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 16 Oct 2009 14:34:42 -0700 Subject: Converted FireAndForget methods to use a singleton pattern to attempt to work around a Mono bug with nested delegates --- OpenSim/Framework/Util.cs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 38729c6..3203fc1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -44,6 +44,7 @@ using System.Xml; using log4net; using Nini.Config; using Nwc.XmlRpc; +using BclExtras; using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -1269,14 +1270,32 @@ namespace OpenSim.Framework #region FireAndForget Threading Pattern + /// + /// Created to work around a limitation in Mono with nested delegates + /// + private class FireAndForgetWrapper + { + public void FireAndForget(System.Threading.WaitCallback callback) + { + callback.BeginInvoke(null, EndFireAndForget, callback); + } + + public void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + callback.BeginInvoke(obj, EndFireAndForget, callback); + } + } + public static void FireAndForget(System.Threading.WaitCallback callback) { - callback.BeginInvoke(null, EndFireAndForget, callback); + FireAndForgetWrapper wrapper = Singleton.GetInstance(); + wrapper.FireAndForget(callback); } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { - callback.BeginInvoke(obj, EndFireAndForget, callback); + FireAndForgetWrapper wrapper = Singleton.GetInstance(); + wrapper.FireAndForget(callback, obj); } private static void EndFireAndForget(IAsyncResult ar) -- cgit v1.1 From 142008121e2e9c5ca5fca5de07b8a14e37279800 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Mon, 19 Oct 2009 15:19:09 -0700 Subject: * Change Util.FireAndForget to use ThreadPool.UnsafeQueueUserWorkItem(). This avoids .NET remoting and a managed->unmanaged->managed jump. Overall, a night and day performance difference * Initialize the LLClientView prim full update queue to the number of prims in the scene for a big performance boost * Reordered some comparisons on hot code paths for a minor speed boost * Removed an unnecessary call to the expensive DateTime.Now function (if you *have* to get the current time as opposed to Environment.TickCount, always use DateTime.UtcNow) * Don't fire the queue empty callback for the Resend category * Run the outgoing packet handler thread loop for each client synchronously. It seems like more time was being spent doing the execution asynchronously, and it made deadlocks very difficult to track down * Rewrote some expensive math in LandObject.cs * Optimized EntityManager to only lock on operations that need locking, and use TryGetValue() where possible * Only update the attachment database when an object is attached or detached * Other small misc. performance improvements --- OpenSim/Framework/Util.cs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 3203fc1..d5ae3b7 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1273,7 +1273,7 @@ namespace OpenSim.Framework /// /// Created to work around a limitation in Mono with nested delegates /// - private class FireAndForgetWrapper + /*private class FireAndForgetWrapper { public void FireAndForget(System.Threading.WaitCallback callback) { @@ -1284,21 +1284,23 @@ namespace OpenSim.Framework { callback.BeginInvoke(obj, EndFireAndForget, callback); } - } + }*/ public static void FireAndForget(System.Threading.WaitCallback callback) { - FireAndForgetWrapper wrapper = Singleton.GetInstance(); - wrapper.FireAndForget(callback); + //FireAndForgetWrapper wrapper = Singleton.GetInstance(); + //wrapper.FireAndForget(callback); + System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null); } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { - FireAndForgetWrapper wrapper = Singleton.GetInstance(); - wrapper.FireAndForget(callback, obj); + //FireAndForgetWrapper wrapper = Singleton.GetInstance(); + //wrapper.FireAndForget(callback, obj); + System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); } - private static void EndFireAndForget(IAsyncResult ar) + /*private static void EndFireAndForget(IAsyncResult ar) { System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; @@ -1306,7 +1308,7 @@ namespace OpenSim.Framework catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } ar.AsyncWaitHandle.Close(); - } + }*/ #endregion FireAndForget Threading Pattern } -- cgit v1.1 From 8a336c6860d66b9fbba6922c32e7a57fd355c57e Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Oct 2009 02:28:53 +0100 Subject: Add MaxPoolThreads in startup to limit the size of the thread pool used for FireAndForget. This lets us limit concurrency to make OpenSim play nice --- OpenSim/Framework/Util.cs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d5ae3b7..9dfb75e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -41,12 +41,14 @@ using System.Security.Cryptography; using System.Text; using System.Text.RegularExpressions; using System.Xml; +using System.Threading; using log4net; using Nini.Config; using Nwc.XmlRpc; using BclExtras; using OpenMetaverse; using OpenMetaverse.StructuredData; +using Amib.Threading; namespace OpenSim.Framework { @@ -55,6 +57,8 @@ namespace OpenSim.Framework /// public class Util { + private static SmartThreadPool m_ThreadPool = null; + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static uint nextXferID = 5000; @@ -1293,22 +1297,28 @@ namespace OpenSim.Framework System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null); } - public static void FireAndForget(System.Threading.WaitCallback callback, object obj) + public static void SetMaxThreads(int maxThreads) { - //FireAndForgetWrapper wrapper = Singleton.GetInstance(); - //wrapper.FireAndForget(callback, obj); - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); - } + STPStartInfo startInfo = new STPStartInfo(); + startInfo.IdleTimeout = 2000; // 2 seconds + startInfo.MaxWorkerThreads = maxThreads; + startInfo.MinWorkerThreads = 5; + startInfo.StackSize = 524288; + startInfo.ThreadPriority = ThreadPriority.Normal; - /*private static void EndFireAndForget(IAsyncResult ar) - { - System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; + startInfo.StartSuspended = false; - try { callback.EndInvoke(ar); } - catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } + m_ThreadPool = new SmartThreadPool(startInfo); + } - ar.AsyncWaitHandle.Close(); - }*/ + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + m_ThreadPool.QueueWorkItem(new WorkItemCallback(delegate(object o) + { + callback(o); + return null; + }), obj); + } #endregion FireAndForget Threading Pattern } -- cgit v1.1 From 8ce4fd7234bd460652f6159a3b7a21d2bebee05d Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Oct 2009 04:02:26 +0100 Subject: Reduce the default pool threads to 15 (from 30) and the minimum from 5 to 2 --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9dfb75e..7dde6dd 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1302,7 +1302,7 @@ namespace OpenSim.Framework STPStartInfo startInfo = new STPStartInfo(); startInfo.IdleTimeout = 2000; // 2 seconds startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 5; + startInfo.MinWorkerThreads = 2; startInfo.StackSize = 524288; startInfo.ThreadPriority = ThreadPriority.Normal; -- cgit v1.1 From 32ccd5bb40447ea4d96f1181cf73edff3645a55a Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Wed, 21 Oct 2009 23:03:18 -0700 Subject: * Changed the misc. methods calling ThreadPool.UnsafeQueueUserWorkItem() to Util.FireAndForget() * Changed Util.FireAndForget() to use any of five different methods set with async_call_method in the [Startup] section of OpenSim.ini. Look at the example config for possible values --- OpenSim/Framework/Util.cs | 70 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 51 insertions(+), 19 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d5ae3b7..02f6d12 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -51,6 +51,18 @@ using OpenMetaverse.StructuredData; namespace OpenSim.Framework { /// + /// The method used by Util.FireAndForget for asynchronously firing events + /// + public enum FireAndForgetMethod + { + UnsafeQueueUserWorkItem, + QueueUserWorkItem, + BeginInvoke, + SmartThreadPool, + Thread, + } + + /// /// Miscellaneous utility functions /// public class Util @@ -70,7 +82,9 @@ namespace OpenSim.Framework public static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); - + + public static FireAndForgetMethod FireAndForgetMethod = FireAndForgetMethod.UnsafeQueueUserWorkItem; + /// /// Linear interpolates B<->C using percent A /// @@ -1273,7 +1287,7 @@ namespace OpenSim.Framework /// /// Created to work around a limitation in Mono with nested delegates /// - /*private class FireAndForgetWrapper + private class FireAndForgetWrapper { public void FireAndForget(System.Threading.WaitCallback callback) { @@ -1284,32 +1298,50 @@ namespace OpenSim.Framework { callback.BeginInvoke(obj, EndFireAndForget, callback); } - }*/ + + private static void EndFireAndForget(IAsyncResult ar) + { + System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; + + try { callback.EndInvoke(ar); } + catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } + + ar.AsyncWaitHandle.Close(); + } + } public static void FireAndForget(System.Threading.WaitCallback callback) { - //FireAndForgetWrapper wrapper = Singleton.GetInstance(); - //wrapper.FireAndForget(callback); - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null); + FireAndForget(callback, null); } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { - //FireAndForgetWrapper wrapper = Singleton.GetInstance(); - //wrapper.FireAndForget(callback, obj); - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + break; + case FireAndForgetMethod.QueueUserWorkItem: + System.Threading.ThreadPool.QueueUserWorkItem(callback, obj); + break; + case FireAndForgetMethod.BeginInvoke: + FireAndForgetWrapper wrapper = Singleton.GetInstance(); + wrapper.FireAndForget(callback, obj); + break; + case FireAndForgetMethod.SmartThreadPool: + Amib.Threading.SmartThreadPool stp = Singleton.GetInstance(); + stp.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); + break; + case FireAndForgetMethod.Thread: + System.Threading.Thread thread = new System.Threading.Thread(delegate(object o) { callback(o); }); + thread.Start(obj); + break; + default: + throw new NotImplementedException(); + } } - /*private static void EndFireAndForget(IAsyncResult ar) - { - System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; - - try { callback.EndInvoke(ar); } - catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } - - ar.AsyncWaitHandle.Close(); - }*/ - #endregion FireAndForget Threading Pattern } } -- cgit v1.1 From 2f394b7e7ebf991c7a70f93bf251d26d8043aaa2 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 01:30:12 -0700 Subject: * Allow SmartThreadPool to be initialized without setting max stack size (like the original implementation) * Only initialize Util's SmartThreadPool if it is actually being used * No longer initializing Util's SmartThreadPool with a custom max stack size. From MSDN: "Avoid using this constructor overload. The default stack size used by the Thread(ThreadStart) constructor overload is the recommended stack size for threads." --- OpenSim/Framework/Util.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d09bd6d..167e34d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -69,8 +69,6 @@ namespace OpenSim.Framework /// public class Util { - private static SmartThreadPool m_ThreadPool = null; - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static uint nextXferID = 5000; @@ -79,6 +77,9 @@ namespace OpenSim.Framework private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; private static object XferLock = new object(); + /// Thread pool used for Util.FireAndForget if + /// FireAndForgetMethod.SmartThreadPool is used + private static SmartThreadPool m_ThreadPool; // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. private static readonly DateTime unixEpoch = @@ -1319,8 +1320,11 @@ namespace OpenSim.Framework FireAndForget(callback, null); } - public static void SetMaxThreads(int maxThreads) + public static void InitThreadPool(int maxThreads) { + if (maxThreads < 2) + throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (m_ThreadPool != null) return; @@ -1328,9 +1332,7 @@ namespace OpenSim.Framework startInfo.IdleTimeout = 2000; // 2 seconds startInfo.MaxWorkerThreads = maxThreads; startInfo.MinWorkerThreads = 2; - startInfo.StackSize = 524288; startInfo.ThreadPriority = ThreadPriority.Normal; - startInfo.StartSuspended = false; m_ThreadPool = new SmartThreadPool(startInfo); -- cgit v1.1 From 6ca4b0f36622833688136e9ace7d5545063293ba Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 10:37:11 -0700 Subject: * Added a check if Util.m_ThreadPool is null before trying to use it, and if so initialize it to sane defaults * Simplified the InitThreadPool() function --- OpenSim/Framework/Util.cs | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 167e34d..a18a827 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1324,18 +1324,10 @@ namespace OpenSim.Framework { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); - if (m_ThreadPool != null) - return; - - STPStartInfo startInfo = new STPStartInfo(); - startInfo.IdleTimeout = 2000; // 2 seconds - startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 2; - startInfo.ThreadPriority = ThreadPriority.Normal; - startInfo.StartSuspended = false; + throw new InvalidOperationException("SmartThreadPool is already initialized"); - m_ThreadPool = new SmartThreadPool(startInfo); + m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); } public static void FireAndForget(System.Threading.WaitCallback callback, object obj) @@ -1343,20 +1335,22 @@ namespace OpenSim.Framework switch (FireAndForgetMethod) { case FireAndForgetMethod.UnsafeQueueUserWorkItem: - System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + ThreadPool.UnsafeQueueUserWorkItem(callback, obj); break; case FireAndForgetMethod.QueueUserWorkItem: - System.Threading.ThreadPool.QueueUserWorkItem(callback, obj); + ThreadPool.QueueUserWorkItem(callback, obj); break; case FireAndForgetMethod.BeginInvoke: FireAndForgetWrapper wrapper = Singleton.GetInstance(); wrapper.FireAndForget(callback, obj); break; case FireAndForgetMethod.SmartThreadPool: + if (m_ThreadPool != null) + m_ThreadPool = new SmartThreadPool(2000, 15, 2); m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); break; case FireAndForgetMethod.Thread: - System.Threading.Thread thread = new System.Threading.Thread(delegate(object o) { callback(o); }); + Thread thread = new Thread(delegate(object o) { callback(o); }); thread.Start(obj); break; default: -- cgit v1.1 From 36b0e5e1d3112212ef988a8b2e7c10284c7e9276 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Thu, 22 Oct 2009 11:07:23 -0700 Subject: Terrible typo in the previous commit! --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a18a827..b96367a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1345,7 +1345,7 @@ namespace OpenSim.Framework wrapper.FireAndForget(callback, obj); break; case FireAndForgetMethod.SmartThreadPool: - if (m_ThreadPool != null) + if (m_ThreadPool == null) m_ThreadPool = new SmartThreadPool(2000, 15, 2); m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); break; -- cgit v1.1 From 52a4534f7fe9e7b044a54f5a794391b54a1edb94 Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Fri, 23 Oct 2009 13:45:18 -0700 Subject: * Change the way Util.FireAndForget() calls SmartThreadPool to avoid using a delegate (which STP appears to hold on to). This removes the slow leak I was seeing when using async_call_method=SmartThreadPool and stabilizes allocated memory for an idle OpenSim instance --- OpenSim/Framework/Util.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b96367a..10f38ab 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1347,7 +1347,7 @@ namespace OpenSim.Framework case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) m_ThreadPool = new SmartThreadPool(2000, 15, 2); - m_ThreadPool.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj); + m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { callback, obj }); break; case FireAndForgetMethod.Thread: Thread thread = new Thread(delegate(object o) { callback(o); }); @@ -1358,6 +1358,16 @@ namespace OpenSim.Framework } } + private static object SmartThreadPoolCallback(object o) + { + object[] array = (object[])o; + WaitCallback callback = (WaitCallback)array[0]; + object obj = array[1]; + + callback(obj); + return null; + } + #endregion FireAndForget Threading Pattern } } -- cgit v1.1 From f89c2cac0fd3e9e1ae66552bbc2c3cc4bb17aaed Mon Sep 17 00:00:00 2001 From: John Hurliman Date: Tue, 27 Oct 2009 14:16:01 -0700 Subject: Experimental test to rate limit the incoming packet handler and try to always leave a worker thread available for other tasks --- OpenSim/Framework/Util.cs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 10f38ab..87ba5a8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1330,6 +1330,27 @@ namespace OpenSim.Framework m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); } + public static int FireAndForgetCount() + { + const int MAX_SYSTEM_THREADS = 200; + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + case FireAndForgetMethod.QueueUserWorkItem: + case FireAndForgetMethod.BeginInvoke: + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + return workerThreads; + case FireAndForgetMethod.SmartThreadPool: + return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads; + case FireAndForgetMethod.Thread: + return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count; + default: + throw new NotImplementedException(); + } + } + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { switch (FireAndForgetMethod) -- cgit v1.1 From 4338f4e1d7c841ba447eb2d7481daaa009182bc7 Mon Sep 17 00:00:00 2001 From: Teravus Ovares (Dan Olivares) Date: Sun, 29 Nov 2009 05:06:25 -0500 Subject: * Patch from Misterblue to fix Environment.TickCount for statistics purposes. Resolves the wrap-around of the 32 bit uint. * Teravus moved the Environment methods to the Util class --- OpenSim/Framework/Util.cs | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 87ba5a8..a459f8d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1389,6 +1389,30 @@ namespace OpenSim.Framework return null; } - #endregion FireAndForget Threading Pattern + #endregion FireAndForget Threading Pattern + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap + /// for the callers. + /// This trims it to a 12 day interval so don't let your frame time get too long. + /// + /// + public static Int32 EnvironmentTickCount() + { + return Environment.TickCount & EnvironmentTickCountMask; + } + const Int32 EnvironmentTickCountMask = 0x3fffffff; + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + { + Int32 diff = EnvironmentTickCount() - prevValue; + return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); + } } } -- cgit v1.1 From 4af77e84b1b26d1fb00fd9c7c3b5557cd9f744f3 Mon Sep 17 00:00:00 2001 From: Teravus Ovares (Dan Olivares) Date: Tue, 1 Dec 2009 10:21:22 -0500 Subject: * Fix Inconsistent line ending style in Util --- OpenSim/Framework/Util.cs | 48 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a459f8d..1112497 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1389,30 +1389,30 @@ namespace OpenSim.Framework return null; } - #endregion FireAndForget Threading Pattern - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap - /// for the callers. - /// This trims it to a 12 day interval so don't let your frame time get too long. - /// - /// - public static Int32 EnvironmentTickCount() - { - return Environment.TickCount & EnvironmentTickCountMask; - } - const Int32 EnvironmentTickCountMask = 0x3fffffff; - - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. Subtracts the passed value (previously fetched by - /// 'EnvironmentTickCount()') and accounts for any wrapping. - /// - /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) - { - Int32 diff = EnvironmentTickCount() - prevValue; - return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); + #endregion FireAndForget Threading Pattern + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap + /// for the callers. + /// This trims it to a 12 day interval so don't let your frame time get too long. + /// + /// + public static Int32 EnvironmentTickCount() + { + return Environment.TickCount & EnvironmentTickCountMask; + } + const Int32 EnvironmentTickCountMask = 0x3fffffff; + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + { + Int32 diff = EnvironmentTickCount() - prevValue; + return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); } } } -- cgit v1.1 From 963cf25813ad2bd6dceaa39757391fbf94d6f09e Mon Sep 17 00:00:00 2001 From: Adam Frisby Date: Sun, 13 Dec 2009 03:04:16 +1100 Subject: * Implements OSSL function: osGetSimulatorMemory - returns the current amount of memory allocated to the simulator process (Moderate Threat Level). * Cleans redundant information out of the Simulator Version. Versions now look like: "OpenSimulator 0.6.9(dev) Unix/Mono" * [Minor] additional log info for MySQLInventoryData --- OpenSim/Framework/Util.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 1112497..7215086 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1007,6 +1007,26 @@ namespace OpenSim.Framework return os; } + public static string GetRuntimeInformation() + { + string ru = String.Empty; + + if (Environment.OSVersion.Platform == PlatformID.Unix) + ru = "Unix/Mono"; + else + if (Environment.OSVersion.Platform == PlatformID.MacOSX) + ru = "OSX/Mono"; + else + { + if (Type.GetType("Mono.Runtime") != null) + ru = "Win/Mono"; + else + ru = "Win/.NET"; + } + + return ru; + } + /// /// Is the given string a UUID? /// -- cgit v1.1 From f4efa325bb8a1e4ae876ec5f080cf87c1f8c1de9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 31 Dec 2009 11:42:33 -0800 Subject: More progress on both the Simulation service and the Login service. Both still unfinished. --- OpenSim/Framework/Util.cs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7215086..234021c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1186,6 +1186,33 @@ namespace OpenSim.Framework return null; } + public static OSDMap GetOSDMap(string data) + { + OSDMap args = null; + try + { + OSD buffer; + // We should pay attention to the content-type, but let's assume we know it's Json + buffer = OSDParser.DeserializeJson(data); + if (buffer.Type == OSDType.Map) + { + args = (OSDMap)buffer; + return args; + } + else + { + // uh? + m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString())); + return null; + } + } + catch (Exception ex) + { + m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message); + return null; + } + } + public static string[] Glob(string path) { string vol=String.Empty; -- cgit v1.1 From 3112b04c85b9189a9ff1d1c98f8cd23b461a23b9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 30 Jan 2010 16:18:38 -0800 Subject: Changed an error message to w warning message. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 234021c..2fc7adc 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -553,7 +553,7 @@ namespace OpenSim.Framework } catch (Exception e) { - m_log.ErrorFormat("[UTIL]: An error occurred while resolving {0}, {1}", dnsAddress, e); + m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); // Still going to throw the exception on for now, since this was what was happening in the first place throw e; -- cgit v1.1 From 842b68eeff7571d3c82415c65065bec3c95f34ea Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 18 Feb 2010 04:19:33 +0000 Subject: Change handling of the SYSTEMIP constant to be more sane. This will now choose the first network interface IP address, or the loopback interface if no external interfaces are found. It will log the IP address used as [NETWORK]: Using x.x.x.x for SYSTEMIP. --- OpenSim/Framework/Util.cs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7215086..48435cb 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -589,11 +589,17 @@ namespace OpenSim.Framework public static IPAddress GetLocalHost() { - string dnsAddress = "localhost"; + IPAddress[] iplist = GetLocalHosts(); - IPAddress[] hosts = Dns.GetHostEntry(dnsAddress).AddressList; + if (iplist.Length == 0) // No accessible external interfaces + { + IPAddress[] loopback = Dns.GetHostAddresses("localhost"); + IPAddress localhost = loopback[0]; - foreach (IPAddress host in hosts) + return localhost; + } + + foreach (IPAddress host in iplist) { if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) { @@ -601,15 +607,15 @@ namespace OpenSim.Framework } } - if (hosts.Length > 0) + if (iplist.Length > 0) { - foreach (IPAddress host in hosts) + foreach (IPAddress host in iplist) { if (host.AddressFamily == AddressFamily.InterNetwork) return host; } // Well all else failed... - return hosts[0]; + return iplist[0]; } return null; -- cgit v1.1 From f4c165afe7003ad6276ad7d015fd1c9164a84328 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 6 Mar 2010 08:21:54 -0800 Subject: Bug fix: store correct position information upon logout. Fixes mantis #4608 --- OpenSim/Framework/Util.cs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 10af925..64f6118 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -29,6 +29,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Data; +using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; @@ -1443,6 +1444,7 @@ namespace OpenSim.Framework } #endregion FireAndForget Threading Pattern + /// /// Environment.TickCount is an int but it counts all 32 bits so it goes positive /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap @@ -1467,5 +1469,21 @@ namespace OpenSim.Framework Int32 diff = EnvironmentTickCount() - prevValue; return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); } + + /// + /// Prints the call stack at any given point. Useful for debugging. + /// + public static void PrintCallStack() + { + StackTrace stackTrace = new StackTrace(); // get call stack + StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + // write call stack method names + foreach (StackFrame stackFrame in stackFrames) + { + m_log.Debug(stackFrame.GetMethod().DeclaringType + "." + stackFrame.GetMethod().Name); // write method name + } + } + } } -- cgit v1.1 From 48f37339636f52392f698ae6036f970183ccae91 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Apr 2010 20:40:01 +0100 Subject: Fix http://opensimulator.org/mantis/view.php?id=4657 where OpenSim.Grid.UserServer.exe fails on startup if no previous config probably appears to occur because mono 2.4.2.3 (and possibly later) erroneously returns a value of 0 for BufferWidth and BufferHeight in some circumstances --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 64f6118..802cb37 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1486,4 +1486,4 @@ namespace OpenSim.Framework } } -} +} \ No newline at end of file -- cgit v1.1 From 00fd2e0446382af1a3581c8feec359cad5b939aa Mon Sep 17 00:00:00 2001 From: Melanie Thielker Date: Sat, 7 Aug 2010 05:45:52 +0200 Subject: Correct display of landmark about info. Also correct region maturity rating in LM info. Maturity is NOT the parcel's setting, that is only for the image and text. Parcel maturity is governed by region maturity. --- OpenSim/Framework/Util.cs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 802cb37..b5d025f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1171,6 +1171,16 @@ namespace OpenSim.Framework } + public static uint ConvertAccessLevelToMaturity(byte maturity) + { + if (maturity <= 13) + return 0; + else if (maturity <= 21) + return 1; + else + return 2; + } + /// /// Produces an OSDMap from its string representation on a stream /// @@ -1486,4 +1496,4 @@ namespace OpenSim.Framework } } -} \ No newline at end of file +} -- cgit v1.1 From 8fc68c6d9810a0d229e94a0cefb35086c65dec36 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 3 Sep 2010 17:18:53 -0700 Subject: Added XFF header processing. Untested, for lack of proxy. --- OpenSim/Framework/Util.cs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b5d025f..2ac4eb1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1495,5 +1495,33 @@ namespace OpenSim.Framework } } + /// + /// Gets the client IP address + /// + /// + /// + public static IPEndPoint GetClientIPFromXFF(string xff) + { + if (xff == string.Empty) + return null; + + string[] parts = xff.Split(new char[] { ',' }); + if (parts.Length > 0) + { + try + { + return new IPEndPoint(IPAddress.Parse(parts[0]), 0); + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message); + } + } + + return null; + } + + + } } -- cgit v1.1 From 9fd98368416ce9514e0926301a1fc20648d9ad59 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 4 Sep 2010 16:39:03 -0700 Subject: Make User Agent Service and Login Service separable. --- OpenSim/Framework/Util.cs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2ac4eb1..e7a7f49 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1521,7 +1521,23 @@ namespace OpenSim.Framework return null; } - + public static string GetCallerIP(Hashtable req) + { + if (req.ContainsKey("headers")) + { + try + { + Hashtable headers = (Hashtable)req["headers"]; + if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null) + return headers["remote_addr"].ToString(); + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message); + } + } + return string.Empty; + } } } -- cgit v1.1 From 0b13cfa4dd729b9142b1f7c5669390dae80d760a Mon Sep 17 00:00:00 2001 From: Melanie Date: Sun, 3 Oct 2010 16:50:50 +0100 Subject: Port ExecutingDirectory from omfOS Util class. --- OpenSim/Framework/Util.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e7a7f49..addfe5d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -92,6 +92,17 @@ namespace OpenSim.Framework public static FireAndForgetMethod FireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; /// + /// Gets the name of the directory where the current running executable + /// is located + /// + /// Filesystem path to the directory containing the current + /// executable + public static string ExecutingDirectory() + { + return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + } + + /// /// Linear interpolates B<->C using percent A /// /// -- cgit v1.1 From e6eeaaea6717f68c1ad622c4fbd308917b3d1408 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 17 Nov 2010 22:55:06 +0000 Subject: minor: add some method comments --- OpenSim/Framework/Util.cs | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index addfe5d..e8f8e01 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -451,6 +451,14 @@ namespace OpenSim.Framework return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); } + /// + /// Are the co-ordinates of the new region visible from the old region? + /// + /// Old region x-coord + /// New region x-coord + /// Old region y-coord + /// New region y-coord + /// public static bool IsOutsideView(uint oldx, uint newx, uint oldy, uint newy) { // Eventually this will be a function of the draw distance / camera position too. -- cgit v1.1 From ca8d0157333823b549c7ae36b40ea3c05045fc25 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 27 Nov 2010 11:40:54 -0800 Subject: Changed the parser for InventoryItem deserialization. Moved some utility functions around. --- OpenSim/Framework/Util.cs | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e8f8e01..101ece4 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1558,5 +1558,66 @@ namespace OpenSim.Framework return string.Empty; } + public static UUID ReadUUID(XmlTextReader reader, string name) + { + UUID id; + string idStr; + + reader.ReadStartElement(name); + + if (reader.Name == "Guid") + idStr = reader.ReadElementString("Guid"); + else if (reader.Name == "UUID") + idStr = reader.ReadElementString("UUID"); + else // no leading tag + idStr = reader.ReadContentAsString(); + UUID.TryParse(idStr, out id); + reader.ReadEndElement(); + + return id; + } + + public static Vector3 ReadVector(XmlTextReader reader, string name) + { + Vector3 vec; + + reader.ReadStartElement(name); + vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x + vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y + vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z + reader.ReadEndElement(); + + return vec; + } + + public static Quaternion ReadQuaternion(XmlTextReader reader, string name) + { + Quaternion quat = new Quaternion(); + + reader.ReadStartElement(name); + while (reader.NodeType != XmlNodeType.EndElement) + { + switch (reader.Name.ToLower()) + { + case "x": + quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "y": + quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "z": + quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "w": + quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + } + } + + reader.ReadEndElement(); + + return quat; + } + } } -- cgit v1.1 From f86c438653fc3c8356a8f0c43a055b1928183f02 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 29 Nov 2010 08:43:33 -0800 Subject: Preservation of creator information now also working in IARs. Cleaned up usage help. Moved Osp around, deleted unnecessary OspInventoryWrapperPlugin, added manipulation of SOP's xml representation in a generic ExternalRepresentationUtils function. --- OpenSim/Framework/Util.cs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 101ece4..8d1671a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1558,6 +1558,16 @@ namespace OpenSim.Framework return string.Empty; } + #region Xml Serialization Utilities + public static bool ReadBoolean(XmlTextReader reader) + { + reader.ReadStartElement(); + bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); + reader.ReadEndElement(); + + return result; + } + public static UUID ReadUUID(XmlTextReader reader, string name) { UUID id; @@ -1619,5 +1629,15 @@ namespace OpenSim.Framework return quat; } + public static T ReadEnum(XmlTextReader reader, string name) + { + string value = reader.ReadElementContentAsString(name, String.Empty); + // !!!!! to deal with flags without commas + if (value.Contains(" ") && !value.Contains(",")) + value = value.Replace(" ", ", "); + + return (T)Enum.Parse(typeof(T), value); ; + } + #endregion } } -- cgit v1.1 From 69c8cc787f0bcecd617aeeff3d2776ba159d82ee Mon Sep 17 00:00:00 2001 From: BlueWall Date: Thu, 13 Jan 2011 11:39:50 -0500 Subject: Make FireAndForgetWrapper a singleton class Made FireAndForgetWrapper a singleton class to allow us to drop dependancy on the BclExtras35 library. BclExtras is broken in Mono 2.8.2 and we used the library in only one function. --- OpenSim/Framework/Util.cs | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8d1671a..d1d8736 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -46,7 +46,7 @@ using System.Threading; using log4net; using Nini.Config; using Nwc.XmlRpc; -using BclExtras; +// using BclExtras; using OpenMetaverse; using OpenMetaverse.StructuredData; using Amib.Threading; @@ -1375,8 +1375,29 @@ namespace OpenSim.Framework /// /// Created to work around a limitation in Mono with nested delegates /// - private class FireAndForgetWrapper + private sealed class FireAndForgetWrapper { + private static volatile FireAndForgetWrapper instance; + private static object syncRoot = new Object(); + + public static FireAndForgetWrapper Instance { + get { + + if (instance == null) + { + lock (syncRoot) + { + if (instance == null) + { + instance = new FireAndForgetWrapper(); + } + } + } + + return instance; + } + } + public void FireAndForget(System.Threading.WaitCallback callback) { callback.BeginInvoke(null, EndFireAndForget, callback); @@ -1445,7 +1466,7 @@ namespace OpenSim.Framework ThreadPool.QueueUserWorkItem(callback, obj); break; case FireAndForgetMethod.BeginInvoke: - FireAndForgetWrapper wrapper = Singleton.GetInstance(); + FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; wrapper.FireAndForget(callback, obj); break; case FireAndForgetMethod.SmartThreadPool: -- cgit v1.1 From 722f0ba18cbea725235f1c31cf3bd3d6a66def29 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 4 Feb 2011 23:06:24 +0000 Subject: Put something in the ImprovedInstantMessage.BinaryBucket for llInstantMessage() to stop this crashing viewer 2.4.0 (1.23.5 was fine with this). We're putting in a string of format " which appears to be the expected value. This resolves http://opensimulator.org/mantis/view.php?id=5356 --- OpenSim/Framework/Util.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d1d8736..533e53a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1334,6 +1334,11 @@ namespace OpenSim.Framework return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; } + public static byte[] StringToBytes256(string str, params object[] args) + { + return StringToBytes256(string.Format(str, args)); + } + public static byte[] StringToBytes256(string str) { if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } @@ -1352,6 +1357,11 @@ namespace OpenSim.Framework return data; } + public static byte[] StringToBytes1024(string str, params object[] args) + { + return StringToBytes1024(string.Format(str, args)); + } + public static byte[] StringToBytes1024(string str) { if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } -- cgit v1.1 From 5a16fa882c0f1a6200bc3fdb63b0f4564acf0e6d Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Tue, 22 Feb 2011 13:23:54 -0800 Subject: Parameterizes the view distance used to compute and manage child agents in neighbor regions. This means you can extend the view on a simulator beyond the default 3x3 regions. This uses a region default draw distance and should be replaced at some point by the avatar specified draw distance. That will require more careful, dynamic recomputation of child agents every time the draw distance changes. WARNING: this is experimental and has known instabilities. specifically all regions "within site" should be running the same default draw distance or agents will not be closed correctly. --- OpenSim/Framework/Util.cs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 533e53a..5a5046e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -459,10 +459,17 @@ namespace OpenSim.Framework /// Old region y-coord /// New region y-coord /// - public static bool IsOutsideView(uint oldx, uint newx, uint oldy, uint newy) + public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) { - // Eventually this will be a function of the draw distance / camera position too. - return (((int)Math.Abs((int)(oldx - newx)) > 1) || ((int)Math.Abs((int)(oldy - newy)) > 1)); + int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); + + int startX = (int)oldx - dd; + int startY = (int)oldy - dd; + + int endX = (int)oldx + dd; + int endY = (int)oldy + dd; + + return (newx < startX || endX < newx || newy < startY || endY < newy); } public static string FieldToString(byte[] bytes) -- cgit v1.1 From 08d8a3e5808b790fbbd7ba3f460603db66aeaff2 Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Mon, 18 Apr 2011 16:48:49 -0700 Subject: Requeue unacknowledged entity updates rather than resend then "as is". Often, by the time the UDPServer realizes that an entity update packet has not been acknowledged, there is a newer update for the same entity already queued up or there is a higher priority update that should be sent first. This patch eliminates 1:1 packet resends for unacked entity update packets. Insteawd, unacked update packets are decomposed into the original entity updates and those updates are placed back into the priority queues based on their new priority but the original update timestamp. This will generally place them at the head of the line to be put back on the wire as a new outgoing packet but prevents the resend queue from filling up with multiple stale updates for the same entity. This new approach takes advantage of the UDP nature of the Linden protocol in that the intent of a reliable update packet is that if it goes unacknowledge, SOMETHING has to happen to get the update to the client. We are simply making sure that we are resending current object state rather than stale object state. Additionally, this patch includes a generalized callback mechanism so that any caller can specify their own method to call when a packet expires without being acknowledged. We use this mechanism to requeue update packets and otherwise use the UDPServer default method of just putting expired packets in the resend queue. --- OpenSim/Framework/Util.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5a5046e..aaa2724 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1537,6 +1537,23 @@ namespace OpenSim.Framework return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); } + // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount + // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). + // A positive return value indicates A occured later than B + public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) + { + // A, B and TC are all between 0 and 0x3fffffff + int tc = EnvironmentTickCount(); + + if (tc - tcA >= 0) + tcA += EnvironmentTickCountMask + 1; + + if (tc - tcB >= 0) + tcB += EnvironmentTickCountMask + 1; + + return tcA - tcB; + } + /// /// Prints the call stack at any given point. Useful for debugging. /// -- cgit v1.1 From d21e9c755f004d8fe03b11bc57b810dbd401435a Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 19 May 2011 16:54:46 -0700 Subject: HG Friends working to some extent: friendships offered and accepted correctly handled. Friends list showing correct foreign names. TODO: GrantRights. --- OpenSim/Framework/Util.cs | 61 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index aaa2724..af21cb5 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1694,5 +1694,66 @@ namespace OpenSim.Framework return (T)Enum.Parse(typeof(T), value); ; } #endregion + + #region Universal User Identifiers + /// + /// + /// uuid[;endpoint[;name]] + /// + /// + /// + /// + public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname) + { + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; + + string[] parts = value.Split(';'); + if (parts.Length >= 1) + if (!UUID.TryParse(parts[0], out uuid)) + return false; + + if (parts.Length >= 2) + url = parts[1]; + + if (parts.Length >= 3) + { + string[] name = parts[2].Split(); + if (name.Length == 2) + { + firstname = name[0]; + lastname = name[1]; + } + } + + return true; + } + + /// + /// + /// + /// + /// uuid[;endpoint[;name]] + public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) + { + if (acircuit.ServiceURLs.ContainsKey("HomeURI")) + { + string agentsURI = acircuit.ServiceURLs["HomeURI"].ToString(); + if (!agentsURI.EndsWith("/")) + agentsURI += "/"; + + // This is ugly, but there's no other way, given that the name is changed + // in the agent circuit data for foreigners + if (acircuit.lastname.Contains("@")) + { + string[] parts = acircuit.firstname.Split(new char[] { '.' }); + if (parts.Length == 2) + return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + } + return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + acircuit.firstname + " " + acircuit.lastname; + } + else + return acircuit.AgentID.ToString(); + } + #endregion } } -- cgit v1.1 From 336665e03532cf9d7a1ad65d5071e7050bf6ecd0 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 22 May 2011 16:51:03 -0700 Subject: More on HG Friends. Added Delete(string, string) across the board. Added security to friendship identifiers so that they can safely be deleted across worlds. Had to change Get(string) to use LIKE because the secret in the identifier is not always known -- affects only HG visitors. BOTTOM LINE SO FAR: HG friendships established and deleted safely across grids, local rights working but not (yet?) being transmitted back. --- OpenSim/Framework/Util.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index af21cb5..e5ff27a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1703,9 +1703,9 @@ namespace OpenSim.Framework /// /// /// - public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname) + public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; string[] parts = value.Split(';'); if (parts.Length >= 1) @@ -1724,6 +1724,8 @@ namespace OpenSim.Framework lastname = name[1]; } } + if (parts.Length >= 4) + secret = parts[3]; return true; } -- cgit v1.1 From b18ef976ff0e8bf2bc2fd8d8002007fcaafd0ed7 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 8 Jul 2011 19:43:22 +0100 Subject: Fix interpretation of physics mesh proxies from mesh data As per http://wiki.secondlife.com/wiki/Mesh/Mesh_Asset_Format, some submesh blocks may just have the flag "NoGeometry" to signal that they provide no mesh data. If a block contains this, ignore it for meshing purposes rather than suffer a ClassCastException This fixes physics proxy meshing, so you can now walk through mesh doorways, properly stand on the trailer of mesh trucks, etc. To get mesh physics proxy, the UseMeshiesPhysicsMesh must be true in a [Mesh] config section in OpenSim.ini (example in OpenSimDefaults.ini). Convex hull physics not currently supported. --- OpenSim/Framework/Util.cs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e5ff27a..039b926 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -324,10 +324,25 @@ namespace OpenSim.Framework } /// + /// Debug utility function to convert OSD into formatted XML for debugging purposes. + /// + /// + /// A + /// + /// + /// A + /// + public static string GetFormattedXml(OSD osd) + { + return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd)); + } + + /// /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. - /// - /// Please don't delete me even if I appear currently unused! /// + /// + /// Please don't delete me even if I appear currently unused! + /// /// /// public static string GetFormattedXml(string rawXml) -- cgit v1.1 From c3d82bdcb1ac2ee0e0bdad75fbf8779252ef31c4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 8 Jul 2011 22:53:19 +0100 Subject: When loading library asset set, only store an asset if it's different from an existing one with the same id. We compare existing and loaded asset by doing an SHA1 on both, so that a changed library asset will still update the store. This cuts asset library load time from 10 seconds to <1 sec. Note, a fix on the previous commit revealed a bug where a library script cannot be copied except on the first login after a cache clear. This is unrelated to this commit and needs to be fixed at some subsequent time. --- OpenSim/Framework/Util.cs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 039b926..fce8999 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -440,20 +440,30 @@ namespace OpenSim.Framework } /// - /// Return an SHA1 hash of the given string + /// Return an SHA1 hash /// /// /// public static string SHA1Hash(string data) { + return SHA1Hash(Encoding.Default.GetBytes(data)); + } + + /// + /// Return an SHA1 hash + /// + /// + /// + public static string SHA1Hash(byte[] data) + { byte[] hash = ComputeSHA1Hash(data); return BitConverter.ToString(hash).Replace("-", String.Empty); } - private static byte[] ComputeSHA1Hash(string src) + private static byte[] ComputeSHA1Hash(byte[] src) { SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); - return SHA1.ComputeHash(Encoding.Default.GetBytes(src)); + return SHA1.ComputeHash(src); } public static int fast_distance2d(int x, int y) -- cgit v1.1 From 9a5e0ede7c86b1fc213948332ae09a14a2d4729e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 29 Jul 2011 23:21:57 +0100 Subject: For all Util.FireAndForget invocations, set thread to en_US before continuing wtih the invocation. This is to avoid bugs where the locale is not manually set on the thread and bad data values get sent to the database or over the wire. Lots of code does this manually but as we've seen, a subtle change can hit code which has forgotton to do this. Since en_US show be used throughout the server at present, setting it at FireAndForget seems reasonable. Arguably, it would be better to do this where data is sent, but doing it here is much easier. All the manual BeginInvokes() remaining in the code should probably call FireAndForget instead. --- OpenSim/Framework/Util.cs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index fce8999..984a7a8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1499,25 +1499,30 @@ namespace OpenSim.Framework public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { + // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture + // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas + // for decimals places but is read by a culture that treats commas as number seperators. + WaitCallback realCallback = delegate(object o) { Culture.SetCurrentCulture(); callback(o); }; + switch (FireAndForgetMethod) { case FireAndForgetMethod.UnsafeQueueUserWorkItem: - ThreadPool.UnsafeQueueUserWorkItem(callback, obj); + ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); break; case FireAndForgetMethod.QueueUserWorkItem: - ThreadPool.QueueUserWorkItem(callback, obj); + ThreadPool.QueueUserWorkItem(realCallback, obj); break; case FireAndForgetMethod.BeginInvoke: FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; - wrapper.FireAndForget(callback, obj); + wrapper.FireAndForget(realCallback, obj); break; case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) m_ThreadPool = new SmartThreadPool(2000, 15, 2); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { callback, obj }); + m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); break; case FireAndForgetMethod.Thread: - Thread thread = new Thread(delegate(object o) { callback(o); }); + Thread thread = new Thread(delegate(object o) { realCallback(o); }); thread.Start(obj); break; default: -- cgit v1.1 From 57e54d84d641787d40a2b45549f6f2d373c5f2f2 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 16 Aug 2011 23:05:08 +0100 Subject: Add new FireAndForgetMethod.None. This executes the callback on the same thread that made the request. Designed for use only by regression tests that rely on a predicable event ordering. --- OpenSim/Framework/Util.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 984a7a8..51ced7b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -56,8 +56,13 @@ namespace OpenSim.Framework /// /// The method used by Util.FireAndForget for asynchronously firing events /// + /// + /// None is used to execute the method in the same thread that made the call. It should only be used by regression + /// test code that relies on predictable event ordering. + /// public enum FireAndForgetMethod { + None, UnsafeQueueUserWorkItem, QueueUserWorkItem, BeginInvoke, @@ -89,7 +94,8 @@ namespace OpenSim.Framework public static readonly Regex UUIDPattern = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); - public static FireAndForgetMethod FireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; + public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; + public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; /// /// Gets the name of the directory where the current running executable @@ -1506,6 +1512,9 @@ namespace OpenSim.Framework switch (FireAndForgetMethod) { + case FireAndForgetMethod.None: + realCallback.Invoke(obj); + break; case FireAndForgetMethod.UnsafeQueueUserWorkItem: ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); break; -- cgit v1.1 From 3aa86d22d16cbf82702024bdfc9846a4c3147232 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 31 Aug 2011 17:38:32 +0100 Subject: If a FireAndForget thread terminates with an exception, then catch and log rather than letting it terminate the simulator. Exceptions don't appear to do this with the SmartThreadPool but they do with UnsafeQueueUserWorkItem (and maybe others) --- OpenSim/Framework/Util.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 51ced7b..745da17 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1508,7 +1508,21 @@ namespace OpenSim.Framework // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas // for decimals places but is read by a culture that treats commas as number seperators. - WaitCallback realCallback = delegate(object o) { Culture.SetCurrentCulture(); callback(o); }; + WaitCallback realCallback = delegate(object o) + { + Culture.SetCurrentCulture(); + + try + { + callback(o); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", + e.Message, e.StackTrace); + } + }; switch (FireAndForgetMethod) { -- cgit v1.1 From 306af9934aac2aaf7fe9baa156b3cc57ff3f3f56 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 13 Sep 2011 17:13:42 +0100 Subject: In an object return message, send a null-terminated empty string in binary bucket to prevent a viewer 3 crash. This is the message sent to the client when the object is returned. We were sending byte[0] in the binary bucket. This didn't kill viewer 1 but did terminate viewer 3 (don't know about viewer 2). So sending "\0" instead. This is to address http://opensimulator.org/mantis/view.php?id=5683 --- OpenSim/Framework/Util.cs | 42 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 40 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 745da17..c4fc643 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1372,11 +1372,30 @@ namespace OpenSim.Framework return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; } + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// public static byte[] StringToBytes256(string str, params object[] args) { return StringToBytes256(string.Format(str, args)); } - + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// public static byte[] StringToBytes256(string str) { if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } @@ -1395,11 +1414,30 @@ namespace OpenSim.Framework return data; } + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// public static byte[] StringToBytes1024(string str, params object[] args) { return StringToBytes1024(string.Format(str, args)); } - + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// public static byte[] StringToBytes1024(string str) { if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } -- cgit v1.1 From ffdf59a57c936189e3b161b79b4a76a3a9b260bb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 22 Oct 2011 02:16:46 +0100 Subject: Get UUIDGatherer to scan notecards in the graph for asset uuids. This is to support npc baked texture saving in oars and iars. May address http://opensimulator.org/mantis/view.php?id=5743 --- OpenSim/Framework/Util.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c4fc643..21cfc09 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -46,7 +46,6 @@ using System.Threading; using log4net; using Nini.Config; using Nwc.XmlRpc; -// using BclExtras; using OpenMetaverse; using OpenMetaverse.StructuredData; using Amib.Threading; @@ -91,8 +90,10 @@ namespace OpenSim.Framework private static readonly DateTime unixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); - public static readonly Regex UUIDPattern - = new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"); + private static readonly string rawUUIDPattern + = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; + public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern); + public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern)); public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; -- cgit v1.1 From bc13855e6475ce2df051ad20acdd76756fb22555 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 8 Dec 2011 20:52:34 +0000 Subject: Reactivate BasicCircuitTests.TestAddClient() This checks that the initial UseCircuitCode packet is handled correctly for a normal client login. --- OpenSim/Framework/Util.cs | 45 +++++++++++++++++++++++++++++---------------- 1 file changed, 29 insertions(+), 16 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 21cfc09..ed92b2d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -58,10 +58,12 @@ namespace OpenSim.Framework /// /// None is used to execute the method in the same thread that made the call. It should only be used by regression /// test code that relies on predictable event ordering. + /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. /// public enum FireAndForgetMethod { None, + RegressionTest, UnsafeQueueUserWorkItem, QueueUserWorkItem, BeginInvoke, @@ -1544,27 +1546,38 @@ namespace OpenSim.Framework public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { - // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture - // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas - // for decimals places but is read by a culture that treats commas as number seperators. - WaitCallback realCallback = delegate(object o) - { - Culture.SetCurrentCulture(); + WaitCallback realCallback; - try - { - callback(o); - } - catch (Exception e) + if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + { + // If we're running regression tests, then we want any exceptions to rise up to the test code. + realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; + } + else + { + // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture + // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas + // for decimals places but is read by a culture that treats commas as number seperators. + realCallback = o => { - m_log.ErrorFormat( - "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", - e.Message, e.StackTrace); - } - }; + Culture.SetCurrentCulture(); + + try + { + callback(o); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", + e.Message, e.StackTrace); + } + }; + } switch (FireAndForgetMethod) { + case FireAndForgetMethod.RegressionTest: case FireAndForgetMethod.None: realCallback.Invoke(obj); break; -- cgit v1.1 From d80422eba7a4c75f6947ab9186d652b0a31b845e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 10 Feb 2012 23:39:32 +0000 Subject: Add line numbers to Util.PrintCallStack() --- OpenSim/Framework/Util.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ed92b2d..4b0b13c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1664,13 +1664,14 @@ namespace OpenSim.Framework /// public static void PrintCallStack() { - StackTrace stackTrace = new StackTrace(); // get call stack + StackTrace stackTrace = new StackTrace(true); // get call stack StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) // write call stack method names foreach (StackFrame stackFrame in stackFrames) { - m_log.Debug(stackFrame.GetMethod().DeclaringType + "." + stackFrame.GetMethod().Name); // write method name + MethodBase mb = stackFrame.GetMethod(); + m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name } } -- cgit v1.1 From b817c337dc2c5d8efda710f445114aa9a9344611 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 18 Feb 2012 00:33:52 +0000 Subject: On Windows automatically load the correct native ODE library depending on whether the process is 32-bit or 64-bit In theory, this means that a 64-bit Windows OS user can now run OpenSim.exe with ODE and use more than 2 (or 3) GB of memory. However, this is completely untested since I don't currently own a 64-bit Windows box. Feedback appreciated. Using OpenSim.32BitLaunch.exe should continue to work. Other platforms are unaffected. This will currently not work with sqlite - I will add that too if this works. --- OpenSim/Framework/Util.cs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 4b0b13c..b3ec5c2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -35,7 +35,8 @@ using System.IO; using System.IO.Compression; using System.Net; using System.Net.Sockets; -using System.Reflection; +using System.Reflection; +using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Security.Cryptography; @@ -375,6 +376,20 @@ namespace OpenSim.Framework } return sb.ToString(); + } + + /// + /// Is the platform Windows? + /// + /// true if so, false otherwise + public static bool IsWindows() + { + PlatformID platformId = Environment.OSVersion.Platform; + + return (platformId == PlatformID.Win32NT + || platformId == PlatformID.Win32S + || platformId == PlatformID.Win32Windows + || platformId == PlatformID.WinCE); } public static bool IsEnvironmentSupported(ref string reason) @@ -1457,6 +1472,27 @@ namespace OpenSim.Framework } return data; + } + + /// + /// Used to trigger an early library load on Windows systems. + /// + /// + /// Required to get 32-bit and 64-bit processes to automatically use the + /// appropriate native library. + /// + /// + /// + [DllImport("kernel32.dll")] + public static extern IntPtr LoadLibrary(string dllToLoad); + + /// + /// Determine whether the current process is 64 bit + /// + /// true if so, false if not + public static bool Is64BitProcess() + { + return IntPtr.Size == 8; } #region FireAndForget Threading Pattern -- cgit v1.1 From 68a4ef5ef62aef3d5e1ec5c20b03b3b4fa51743b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 Feb 2012 02:52:20 +0000 Subject: Add 64 bit Windows sqlite3.dll and use this if running a 64-bit windows process. --- OpenSim/Framework/Util.cs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b3ec5c2..efa4a7b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -392,6 +392,36 @@ namespace OpenSim.Framework || platformId == PlatformID.WinCE); } + public static bool LoadArchSpecificWindowsDll(string libraryName) + { + // We do this so that OpenSimulator on Windows loads the correct native library depending on whether + // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports + // will find it already loaded later on. + // + // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be + // controlled in config files. + string nativeLibraryPath; + + if (Util.Is64BitProcess()) + nativeLibraryPath = "lib64/" + libraryName; + else + nativeLibraryPath = "lib32/" + libraryName; + + m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); + + if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero) + { + m_log.ErrorFormat( + "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath); + + return false; + } + else + { + return true; + } + } + public static bool IsEnvironmentSupported(ref string reason) { // Must have .NET 2.0 (Generics / libsl) -- cgit v1.1 From 421b562a045c69c5d507ee33e0283613d133e376 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Mar 2012 02:43:33 +0000 Subject: Add process working memory to "show stats" memory statistics. This shows the actual amount of RAM being taken up by OpenSimulator (objects + vm overhead) --- OpenSim/Framework/Util.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index efa4a7b..31fa101 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -81,12 +81,15 @@ namespace OpenSim.Framework private static uint nextXferID = 5000; private static Random randomClass = new Random(); + // Get a list of invalid file characters (OS dependent) private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; private static object XferLock = new object(); - /// Thread pool used for Util.FireAndForget if - /// FireAndForgetMethod.SmartThreadPool is used + + /// + /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used + /// private static SmartThreadPool m_ThreadPool; // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. -- cgit v1.1 From 6e8f80f1ab933bbd00b892fa6d01f93f62a1bbbd Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Mar 2012 03:26:47 +0000 Subject: Improve threadpool reporting to "show threads" console command (also gets printed out periodically) --- OpenSim/Framework/Util.cs | 56 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 31fa101..9e0f138 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -147,7 +147,6 @@ namespace OpenSim.Framework return lerp(y, lerp(x, a, b), lerp(x, c, d)); } - public static Encoding UTF8 = Encoding.UTF8; /// @@ -1674,6 +1673,61 @@ namespace OpenSim.Framework } } + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = m_ThreadPool.MaxThreads; + minThreads = m_ThreadPool.MinThreads; + inUseThreads = m_ThreadPool.InUseThreads; + allocatedThreads = m_ThreadPool.ActiveThreads; + waitingCallbacks = m_ThreadPool.WaitingCallbacks; + } + else if ( + FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem + || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } + + return sb.ToString(); + } + private static object SmartThreadPoolCallback(object o) { object[] array = (object[])o; -- cgit v1.1 From 30b2a8c778d02926e038bc62977c4a4c9dbec5ee Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 20 Mar 2012 23:12:21 +0000 Subject: Move frame loop entirely within Scene.Update() for better future performance analysis and stat accuracy. Update() now accepts a frames parameter which can control the number of frames updated. -1 will update until shutdown. The watchdog updating moves above the maintc recalculation for any required sleep since it should be accounted for within the frame. --- OpenSim/Framework/Util.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9e0f138..b2e5c7b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1758,13 +1758,26 @@ namespace OpenSim.Framework /// and negative every 24.9 days. Subtracts the passed value (previously fetched by /// 'EnvironmentTickCount()') and accounts for any wrapping. /// + /// + /// /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue) { - Int32 diff = EnvironmentTickCount() - prevValue; + Int32 diff = newValue - prevValue; return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); } + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + { + return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue); + } + // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). // A positive return value indicates A occured later than B -- cgit v1.1 From d08ad6459a03a6a5a6a551fd2b275f1c7da94d8e Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 20 Mar 2012 17:14:19 -0700 Subject: HG Friends: allow the establishment of HG friendships without requiring co-presence in the same sim. Using avatar picker, users can now search for names such as "first.last@grid.com:9000", find them, and request friendship. Friendship requests are stored if target user is offline. TESTED ON STANDALONE ONLY. --- OpenSim/Framework/Util.cs | 3958 +++++++++++++++++++++++---------------------- 1 file changed, 1996 insertions(+), 1962 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9e0f138..0b9e0e7 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1,1509 +1,1509 @@ -/* - * 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.Collections; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Net; -using System.Net.Sockets; +/* + * 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.Collections; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Net; +using System.Net.Sockets; using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using System.Threading; -using log4net; -using Nini.Config; -using Nwc.XmlRpc; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using Amib.Threading; - -namespace OpenSim.Framework -{ - /// - /// The method used by Util.FireAndForget for asynchronously firing events - /// - /// - /// None is used to execute the method in the same thread that made the call. It should only be used by regression - /// test code that relies on predictable event ordering. - /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. - /// - public enum FireAndForgetMethod - { - None, - RegressionTest, - UnsafeQueueUserWorkItem, - QueueUserWorkItem, - BeginInvoke, - SmartThreadPool, - Thread, - } - - /// - /// Miscellaneous utility functions - /// - public class Util - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private static uint nextXferID = 5000; - private static Random randomClass = new Random(); - - // Get a list of invalid file characters (OS dependent) - private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; - private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; - private static object XferLock = new object(); - - /// - /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used - /// - private static SmartThreadPool m_ThreadPool; - - // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. - private static readonly DateTime unixEpoch = - DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); - - private static readonly string rawUUIDPattern - = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; - public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern); - public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern)); - - public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; - public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; - - /// - /// Gets the name of the directory where the current running executable - /// is located - /// - /// Filesystem path to the directory containing the current - /// executable - public static string ExecutingDirectory() - { - return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - } - - /// - /// Linear interpolates B<->C using percent A - /// - /// - /// - /// - /// - public static double lerp(double a, double b, double c) - { - return (b*a) + (c*(1 - a)); - } - - /// - /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y. - /// Layout: - /// A B - /// C D - /// A<->C = Y - /// C<->D = X - /// - /// - /// - /// - /// - /// - /// - /// - public static double lerp2D(double x, double y, double a, double b, double c, double d) - { - return lerp(y, lerp(x, a, b), lerp(x, c, d)); - } - - public static Encoding UTF8 = Encoding.UTF8; - - /// - /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) - /// - public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); - - #region Vector Equations - - /// - /// Get the distance between two 3d vectors - /// - /// A 3d vector - /// A 3d vector - /// The distance between the two vectors - public static double GetDistanceTo(Vector3 a, Vector3 b) - { - float dx = a.X - b.X; - float dy = a.Y - b.Y; - float dz = a.Z - b.Z; - return Math.Sqrt(dx * dx + dy * dy + dz * dz); - } - - /// - /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt. - /// - /// - /// - /// - /// - public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount) - { - float dx = a.X - b.X; - float dy = a.Y - b.Y; - float dz = a.Z - b.Z; - return (dx*dx + dy*dy + dz*dz) < (amount*amount); - } - - /// - /// Get the magnitude of a 3d vector - /// - /// A 3d vector - /// The magnitude of the vector - public static double GetMagnitude(Vector3 a) - { - return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); - } - - /// - /// Get a normalized form of a 3d vector - /// - /// A 3d vector - /// A new vector which is normalized form of the vector - /// The vector paramater cannot be <0,0,0> - public static Vector3 GetNormalizedVector(Vector3 a) - { - if (IsZeroVector(a)) - throw new ArgumentException("Vector paramater cannot be a zero vector."); - - float Mag = (float) GetMagnitude(a); - return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); - } - - /// - /// Returns if a vector is a zero vector (has all zero components) - /// - /// - public static bool IsZeroVector(Vector3 v) - { - if (v.X == 0 && v.Y == 0 && v.Z == 0) - { - return true; - } - - return false; - } - - # endregion - - public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up) - { - float s; - float tr = (float) (fwd.X + left.Y + up.Z + 1.0); - - if (tr >= 1.0) - { - s = (float) (0.5 / Math.Sqrt(tr)); - return new Quaternion( - (left.Z - up.Y) * s, - (up.X - fwd.Z) * s, - (fwd.Y - left.X) * s, - (float) 0.25 / s); - } - else - { - float max = (left.Y > up.Z) ? left.Y : up.Z; - - if (max < fwd.X) - { - s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0)); - float x = (float) (s * 0.5); - s = (float) (0.5 / s); - return new Quaternion( - x, - (fwd.Y + left.X) * s, - (up.X + fwd.Z) * s, - (left.Z - up.Y) * s); - } - else if (max == left.Y) - { - s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0)); - float y = (float) (s * 0.5); - s = (float) (0.5 / s); - return new Quaternion( - (fwd.Y + left.X) * s, - y, - (left.Z + up.Y) * s, - (up.X - fwd.Z) * s); - } - else - { - s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0)); - float z = (float) (s * 0.5); - s = (float) (0.5 / s); - return new Quaternion( - (up.X + fwd.Z) * s, - (left.Z + up.Y) * s, - z, - (fwd.Y - left.X) * s); - } - } - } - - public static Random RandomClass - { - get { return randomClass; } - } - - public static ulong UIntsToLong(uint X, uint Y) - { - return Utils.UIntsToLong(X, Y); - } - - public static T Clamp(T x, T min, T max) - where T : IComparable - { - return x.CompareTo(max) > 0 ? max : - x.CompareTo(min) < 0 ? min : - x; - } - - public static uint GetNextXferID() - { - uint id = 0; - lock (XferLock) - { - id = nextXferID; - nextXferID++; - } - return id; - } - - public static string GetFileName(string file) - { - // Return just the filename on UNIX platforms - // TODO: this should be customisable with a prefix, but that's something to do later. - if (Environment.OSVersion.Platform == PlatformID.Unix) - { - return file; - } - - // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA - // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - if (!Directory.Exists("%APPDATA%\\OpenSim\\")) - { - Directory.CreateDirectory("%APPDATA%\\OpenSim"); - } - - return "%APPDATA%\\OpenSim\\" + file; - } - - // Catch all - covers older windows versions - // (but those probably wont work anyway) - return file; - } - - /// - /// Debug utility function to convert OSD into formatted XML for debugging purposes. - /// - /// - /// A - /// - /// - /// A - /// - public static string GetFormattedXml(OSD osd) - { - return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd)); - } - - /// - /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. - /// - /// - /// Please don't delete me even if I appear currently unused! - /// - /// - /// - public static string GetFormattedXml(string rawXml) - { - XmlDocument xd = new XmlDocument(); - xd.LoadXml(rawXml); - - StringBuilder sb = new StringBuilder(); - StringWriter sw = new StringWriter(sb); - - XmlTextWriter xtw = new XmlTextWriter(sw); - xtw.Formatting = Formatting.Indented; - - try - { - xd.WriteTo(xtw); - } - finally - { - xtw.Close(); - } - - return sb.ToString(); +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Threading; +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using Amib.Threading; + +namespace OpenSim.Framework +{ + /// + /// The method used by Util.FireAndForget for asynchronously firing events + /// + /// + /// None is used to execute the method in the same thread that made the call. It should only be used by regression + /// test code that relies on predictable event ordering. + /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. + /// + public enum FireAndForgetMethod + { + None, + RegressionTest, + UnsafeQueueUserWorkItem, + QueueUserWorkItem, + BeginInvoke, + SmartThreadPool, + Thread, + } + + /// + /// Miscellaneous utility functions + /// + public class Util + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static uint nextXferID = 5000; + private static Random randomClass = new Random(); + + // Get a list of invalid file characters (OS dependent) + private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; + private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; + private static object XferLock = new object(); + + /// + /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used + /// + private static SmartThreadPool m_ThreadPool; + + // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. + private static readonly DateTime unixEpoch = + DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); + + private static readonly string rawUUIDPattern + = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; + public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern); + public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern)); + + public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; + public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; + + /// + /// Gets the name of the directory where the current running executable + /// is located + /// + /// Filesystem path to the directory containing the current + /// executable + public static string ExecutingDirectory() + { + return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + } + + /// + /// Linear interpolates B<->C using percent A + /// + /// + /// + /// + /// + public static double lerp(double a, double b, double c) + { + return (b*a) + (c*(1 - a)); + } + + /// + /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y. + /// Layout: + /// A B + /// C D + /// A<->C = Y + /// C<->D = X + /// + /// + /// + /// + /// + /// + /// + /// + public static double lerp2D(double x, double y, double a, double b, double c, double d) + { + return lerp(y, lerp(x, a, b), lerp(x, c, d)); + } + + public static Encoding UTF8 = Encoding.UTF8; + + /// + /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) + /// + public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); + + #region Vector Equations + + /// + /// Get the distance between two 3d vectors + /// + /// A 3d vector + /// A 3d vector + /// The distance between the two vectors + public static double GetDistanceTo(Vector3 a, Vector3 b) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return Math.Sqrt(dx * dx + dy * dy + dz * dz); + } + + /// + /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt. + /// + /// + /// + /// + /// + public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return (dx*dx + dy*dy + dz*dz) < (amount*amount); + } + + /// + /// Get the magnitude of a 3d vector + /// + /// A 3d vector + /// The magnitude of the vector + public static double GetMagnitude(Vector3 a) + { + return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); + } + + /// + /// Get a normalized form of a 3d vector + /// + /// A 3d vector + /// A new vector which is normalized form of the vector + /// The vector paramater cannot be <0,0,0> + public static Vector3 GetNormalizedVector(Vector3 a) + { + if (IsZeroVector(a)) + throw new ArgumentException("Vector paramater cannot be a zero vector."); + + float Mag = (float) GetMagnitude(a); + return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); + } + + /// + /// Returns if a vector is a zero vector (has all zero components) + /// + /// + public static bool IsZeroVector(Vector3 v) + { + if (v.X == 0 && v.Y == 0 && v.Z == 0) + { + return true; + } + + return false; + } + + # endregion + + public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up) + { + float s; + float tr = (float) (fwd.X + left.Y + up.Z + 1.0); + + if (tr >= 1.0) + { + s = (float) (0.5 / Math.Sqrt(tr)); + return new Quaternion( + (left.Z - up.Y) * s, + (up.X - fwd.Z) * s, + (fwd.Y - left.X) * s, + (float) 0.25 / s); + } + else + { + float max = (left.Y > up.Z) ? left.Y : up.Z; + + if (max < fwd.X) + { + s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0)); + float x = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + x, + (fwd.Y + left.X) * s, + (up.X + fwd.Z) * s, + (left.Z - up.Y) * s); + } + else if (max == left.Y) + { + s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0)); + float y = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + (fwd.Y + left.X) * s, + y, + (left.Z + up.Y) * s, + (up.X - fwd.Z) * s); + } + else + { + s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0)); + float z = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + (up.X + fwd.Z) * s, + (left.Z + up.Y) * s, + z, + (fwd.Y - left.X) * s); + } + } + } + + public static Random RandomClass + { + get { return randomClass; } + } + + public static ulong UIntsToLong(uint X, uint Y) + { + return Utils.UIntsToLong(X, Y); + } + + public static T Clamp(T x, T min, T max) + where T : IComparable + { + return x.CompareTo(max) > 0 ? max : + x.CompareTo(min) < 0 ? min : + x; + } + + public static uint GetNextXferID() + { + uint id = 0; + lock (XferLock) + { + id = nextXferID; + nextXferID++; + } + return id; + } + + public static string GetFileName(string file) + { + // Return just the filename on UNIX platforms + // TODO: this should be customisable with a prefix, but that's something to do later. + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + return file; + } + + // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA + // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + if (!Directory.Exists("%APPDATA%\\OpenSim\\")) + { + Directory.CreateDirectory("%APPDATA%\\OpenSim"); + } + + return "%APPDATA%\\OpenSim\\" + file; + } + + // Catch all - covers older windows versions + // (but those probably wont work anyway) + return file; + } + + /// + /// Debug utility function to convert OSD into formatted XML for debugging purposes. + /// + /// + /// A + /// + /// + /// A + /// + public static string GetFormattedXml(OSD osd) + { + return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd)); + } + + /// + /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. + /// + /// + /// Please don't delete me even if I appear currently unused! + /// + /// + /// + public static string GetFormattedXml(string rawXml) + { + XmlDocument xd = new XmlDocument(); + xd.LoadXml(rawXml); + + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + XmlTextWriter xtw = new XmlTextWriter(sw); + xtw.Formatting = Formatting.Indented; + + try + { + xd.WriteTo(xtw); + } + finally + { + xtw.Close(); + } + + return sb.ToString(); + } + + /// + /// Is the platform Windows? + /// + /// true if so, false otherwise + public static bool IsWindows() + { + PlatformID platformId = Environment.OSVersion.Platform; + + return (platformId == PlatformID.Win32NT + || platformId == PlatformID.Win32S + || platformId == PlatformID.Win32Windows + || platformId == PlatformID.WinCE); + } + + public static bool LoadArchSpecificWindowsDll(string libraryName) + { + // We do this so that OpenSimulator on Windows loads the correct native library depending on whether + // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports + // will find it already loaded later on. + // + // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be + // controlled in config files. + string nativeLibraryPath; + + if (Util.Is64BitProcess()) + nativeLibraryPath = "lib64/" + libraryName; + else + nativeLibraryPath = "lib32/" + libraryName; + + m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); + + if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero) + { + m_log.ErrorFormat( + "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath); + + return false; + } + else + { + return true; + } + } + + public static bool IsEnvironmentSupported(ref string reason) + { + // Must have .NET 2.0 (Generics / libsl) + if (Environment.Version.Major < 2) + { + reason = ".NET 1.0/1.1 lacks components that is used by OpenSim"; + return false; + } + + // Windows 95/98/ME are unsupported + if (Environment.OSVersion.Platform == PlatformID.Win32Windows && + Environment.OSVersion.Platform != PlatformID.Win32NT) + { + reason = "Windows 95/98/ME will not run OpenSim"; + return false; + } + + // Windows 2000 / Pre-SP2 XP + if (Environment.OSVersion.Version.Major == 5 && + Environment.OSVersion.Version.Minor == 0) + { + reason = "Please update to Windows XP Service Pack 2 or Server2003"; + return false; + } + + return true; + } + + public static int UnixTimeSinceEpoch() + { + return ToUnixTime(DateTime.UtcNow); + } + + public static int ToUnixTime(DateTime stamp) + { + TimeSpan t = stamp.ToUniversalTime() - unixEpoch; + return (int) t.TotalSeconds; + } + + public static DateTime ToDateTime(ulong seconds) + { + DateTime epoch = unixEpoch; + return epoch.AddSeconds(seconds); + } + + public static DateTime ToDateTime(int seconds) + { + DateTime epoch = unixEpoch; + return epoch.AddSeconds(seconds); + } + + /// + /// Return an md5 hash of the given string + /// + /// + /// + public static string Md5Hash(string data) + { + byte[] dataMd5 = ComputeMD5Hash(data); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < dataMd5.Length; i++) + sb.AppendFormat("{0:x2}", dataMd5[i]); + return sb.ToString(); + } + + private static byte[] ComputeMD5Hash(string data) + { + MD5 md5 = MD5.Create(); + return md5.ComputeHash(Encoding.Default.GetBytes(data)); + } + + /// + /// Return an SHA1 hash + /// + /// + /// + public static string SHA1Hash(string data) + { + return SHA1Hash(Encoding.Default.GetBytes(data)); + } + + /// + /// Return an SHA1 hash + /// + /// + /// + public static string SHA1Hash(byte[] data) + { + byte[] hash = ComputeSHA1Hash(data); + return BitConverter.ToString(hash).Replace("-", String.Empty); + } + + private static byte[] ComputeSHA1Hash(byte[] src) + { + SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); + return SHA1.ComputeHash(src); + } + + public static int fast_distance2d(int x, int y) + { + x = Math.Abs(x); + y = Math.Abs(y); + + int min = Math.Min(x, y); + + return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); + } + + /// + /// Are the co-ordinates of the new region visible from the old region? + /// + /// Old region x-coord + /// New region x-coord + /// Old region y-coord + /// New region y-coord + /// + public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) + { + int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); + + int startX = (int)oldx - dd; + int startY = (int)oldy - dd; + + int endX = (int)oldx + dd; + int endY = (int)oldy + dd; + + return (newx < startX || endX < newx || newy < startY || endY < newy); + } + + public static string FieldToString(byte[] bytes) + { + return FieldToString(bytes, String.Empty); + } + + /// + /// Convert a variable length field (byte array) to a string, with a + /// field name prepended to each line of the output + /// + /// If the byte array has unprintable characters in it, a + /// hex dump will be put in the string instead + /// The byte array to convert to a string + /// A field name to prepend to each line of output + /// An ASCII string or a string containing a hex dump, minus + /// the null terminator + public static string FieldToString(byte[] bytes, string fieldName) + { + // Check for a common case + if (bytes.Length == 0) return String.Empty; + + StringBuilder output = new StringBuilder(); + bool printable = true; + + for (int i = 0; i < bytes.Length; ++i) + { + // Check if there are any unprintable characters in the array + if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 + && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) + { + printable = false; + break; + } + } + + if (printable) + { + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1))); + } + else + { + for (int i = 0; i < bytes.Length; i += 16) + { + if (i != 0) + output.Append(Environment.NewLine); + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + for (int j = 0; j < 16; j++) + { + if ((i + j) < bytes.Length) + output.Append(String.Format("{0:X2} ", bytes[i + j])); + else + output.Append(" "); + } + + for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) + { + if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) + output.Append((char) bytes[i + j]); + else + output.Append("."); + } + } + } + + return output.ToString(); + } + + /// + /// Converts a URL to a IPAddress + /// + /// URL Standard Format + /// A resolved IP Address + public static IPAddress GetHostFromURL(string url) + { + return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); + } + + /// + /// Returns a IP address from a specified DNS, favouring IPv4 addresses. + /// + /// DNS Hostname + /// An IP address, or null + public static IPAddress GetHostFromDNS(string dnsAddress) + { + // Is it already a valid IP? No need to look it up. + IPAddress ipa; + if (IPAddress.TryParse(dnsAddress, out ipa)) + return ipa; + + IPAddress[] hosts = null; + + // Not an IP, lookup required + try + { + hosts = Dns.GetHostEntry(dnsAddress).AddressList; + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); + + // Still going to throw the exception on for now, since this was what was happening in the first place + throw e; + } + + foreach (IPAddress host in hosts) + { + if (host.AddressFamily == AddressFamily.InterNetwork) + { + return host; + } + } + + if (hosts.Length > 0) + return hosts[0]; + + return null; + } + + public static Uri GetURI(string protocol, string hostname, int port, string path) + { + return new UriBuilder(protocol, hostname, port, path).Uri; + } + + /// + /// Gets a list of all local system IP addresses + /// + /// + public static IPAddress[] GetLocalHosts() + { + return Dns.GetHostAddresses(Dns.GetHostName()); + } + + public static IPAddress GetLocalHost() + { + IPAddress[] iplist = GetLocalHosts(); + + if (iplist.Length == 0) // No accessible external interfaces + { + IPAddress[] loopback = Dns.GetHostAddresses("localhost"); + IPAddress localhost = loopback[0]; + + return localhost; + } + + foreach (IPAddress host in iplist) + { + if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) + { + return host; + } + } + + if (iplist.Length > 0) + { + foreach (IPAddress host in iplist) + { + if (host.AddressFamily == AddressFamily.InterNetwork) + return host; + } + // Well all else failed... + return iplist[0]; + } + + return null; + } + + /// + /// Removes all invalid path chars (OS dependent) + /// + /// path + /// safe path + public static string safePath(string path) + { + return Regex.Replace(path, regexInvalidPathChars, String.Empty); + } + + /// + /// Removes all invalid filename chars (OS dependent) + /// + /// filename + /// safe filename + public static string safeFileName(string filename) + { + return Regex.Replace(filename, regexInvalidFileChars, String.Empty); + ; + } + + // + // directory locations + // + + public static string homeDir() + { + string temp; + // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); + // temp = Path.Combine(personal,".OpenSim"); + temp = "."; + return temp; + } + + public static string assetsDir() + { + return Path.Combine(configDir(), "assets"); + } + + public static string inventoryDir() + { + return Path.Combine(configDir(), "inventory"); + } + + public static string configDir() + { + return "."; + } + + public static string dataDir() + { + return "."; + } + + public static string logDir() + { + return "."; + } + + // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html + public static string GetUniqueFilename(string FileName) + { + int count = 0; + string Name; + + if (File.Exists(FileName)) + { + FileInfo f = new FileInfo(FileName); + + if (!String.IsNullOrEmpty(f.Extension)) + { + Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); + } + else + { + Name = f.FullName; + } + + while (File.Exists(FileName)) + { + count++; + FileName = Name + count + f.Extension; + } + } + return FileName; + } + + // Nini (config) related Methods + public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) + { + if (!File.Exists(fileName)) + { + //create new file + } + XmlConfigSource config = new XmlConfigSource(fileName); + AddDataRowToConfig(config, row); + config.Save(); + + return config; + } + + public static void AddDataRowToConfig(IConfigSource config, DataRow row) + { + config.Configs.Add((string) row[0]); + for (int i = 0; i < row.Table.Columns.Count; i++) + { + config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); + } + } + + public static float Clip(float x, float min, float max) + { + return Math.Min(Math.Max(x, min), max); + } + + public static int Clip(int x, int min, int max) + { + return Math.Min(Math.Max(x, min), max); + } + + /// + /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. + /// + /// + /// + public static String ToRawUuidString(UUID UUID) + { + return UUID.Guid.ToString("n"); + } + + public static string CleanString(string input) + { + if (input.Length == 0) + return input; + + int clip = input.Length; + + // Test for ++ string terminator + int pos = input.IndexOf("\0"); + if (pos != -1 && pos < clip) + clip = pos; + + // Test for CR + pos = input.IndexOf("\r"); + if (pos != -1 && pos < clip) + clip = pos; + + // Test for LF + pos = input.IndexOf("\n"); + if (pos != -1 && pos < clip) + clip = pos; + + // Truncate string before first end-of-line character found + return input.Substring(0, clip); + } + + /// + /// returns the contents of /etc/issue on Unix Systems + /// Use this for where it's absolutely necessary to implement platform specific stuff + /// + /// + public static string ReadEtcIssue() + { + try + { + StreamReader sr = new StreamReader("/etc/issue.net"); + string issue = sr.ReadToEnd(); + sr.Close(); + return issue; + } + catch (Exception) + { + return ""; + } + } + + public static void SerializeToFile(string filename, Object obj) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + + try + { + stream = new FileStream( + filename, FileMode.Create, + FileAccess.Write, FileShare.None); + + formatter.Serialize(stream, obj); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + } + + public static Object DeserializeFromFile(string filename) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + Object ret = null; + + try + { + stream = new FileStream( + filename, FileMode.Open, + FileAccess.Read, FileShare.None); + + ret = formatter.Deserialize(stream); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + + return ret; + } + + public static string Compress(string text) + { + byte[] buffer = Util.UTF8.GetBytes(text); + MemoryStream memory = new MemoryStream(); + using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) + { + compressor.Write(buffer, 0, buffer.Length); + } + + memory.Position = 0; + + byte[] compressed = new byte[memory.Length]; + memory.Read(compressed, 0, compressed.Length); + + byte[] compressedBuffer = new byte[compressed.Length + 4]; + Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); + Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); + return Convert.ToBase64String(compressedBuffer); + } + + public static string Decompress(string compressedText) + { + byte[] compressedBuffer = Convert.FromBase64String(compressedText); + using (MemoryStream memory = new MemoryStream()) + { + int msgLength = BitConverter.ToInt32(compressedBuffer, 0); + memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); + + byte[] buffer = new byte[msgLength]; + + memory.Position = 0; + using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) + { + decompressor.Read(buffer, 0, buffer.Length); + } + + return Util.UTF8.GetString(buffer); + } + } + + public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) + { + return SendXmlRpcCommand(url, methodName, args); + } + + public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) + { + XmlRpcRequest client = new XmlRpcRequest(methodName, args); + return client.Send(url, 6000); + } + + /// + /// Returns an error message that the user could not be found in the database + /// + /// XML string consisting of a error element containing individual error(s) + public static XmlRpcResponse CreateUnknownUserErrorResponse() + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + responseData["error_type"] = "unknown_user"; + responseData["error_desc"] = "The user requested is not in the database"; + + response.Value = responseData; + return response; } /// - /// Is the platform Windows? + /// Converts a byte array in big endian order into an ulong. /// - /// true if so, false otherwise - public static bool IsWindows() + /// + /// The array of bytes + /// + /// + /// The extracted ulong + /// + public static ulong BytesToUInt64Big(byte[] bytes) { - PlatformID platformId = Environment.OSVersion.Platform; + if (bytes.Length < 8) return 0; + return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | + ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; + } - return (platformId == PlatformID.Win32NT - || platformId == PlatformID.Win32S - || platformId == PlatformID.Win32Windows - || platformId == PlatformID.WinCE); - } - - public static bool LoadArchSpecificWindowsDll(string libraryName) - { - // We do this so that OpenSimulator on Windows loads the correct native library depending on whether - // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports - // will find it already loaded later on. - // - // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be - // controlled in config files. - string nativeLibraryPath; - - if (Util.Is64BitProcess()) - nativeLibraryPath = "lib64/" + libraryName; - else - nativeLibraryPath = "lib32/" + libraryName; - - m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); - - if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero) - { - m_log.ErrorFormat( - "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath); - - return false; - } - else - { - return true; - } - } - - public static bool IsEnvironmentSupported(ref string reason) - { - // Must have .NET 2.0 (Generics / libsl) - if (Environment.Version.Major < 2) - { - reason = ".NET 1.0/1.1 lacks components that is used by OpenSim"; - return false; - } - - // Windows 95/98/ME are unsupported - if (Environment.OSVersion.Platform == PlatformID.Win32Windows && - Environment.OSVersion.Platform != PlatformID.Win32NT) - { - reason = "Windows 95/98/ME will not run OpenSim"; - return false; - } - - // Windows 2000 / Pre-SP2 XP - if (Environment.OSVersion.Version.Major == 5 && - Environment.OSVersion.Version.Minor == 0) - { - reason = "Please update to Windows XP Service Pack 2 or Server2003"; - return false; - } - - return true; - } - - public static int UnixTimeSinceEpoch() - { - return ToUnixTime(DateTime.UtcNow); - } - - public static int ToUnixTime(DateTime stamp) - { - TimeSpan t = stamp.ToUniversalTime() - unixEpoch; - return (int) t.TotalSeconds; - } - - public static DateTime ToDateTime(ulong seconds) - { - DateTime epoch = unixEpoch; - return epoch.AddSeconds(seconds); - } - - public static DateTime ToDateTime(int seconds) - { - DateTime epoch = unixEpoch; - return epoch.AddSeconds(seconds); - } - - /// - /// Return an md5 hash of the given string - /// - /// - /// - public static string Md5Hash(string data) - { - byte[] dataMd5 = ComputeMD5Hash(data); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < dataMd5.Length; i++) - sb.AppendFormat("{0:x2}", dataMd5[i]); - return sb.ToString(); - } - - private static byte[] ComputeMD5Hash(string data) - { - MD5 md5 = MD5.Create(); - return md5.ComputeHash(Encoding.Default.GetBytes(data)); - } - - /// - /// Return an SHA1 hash - /// - /// - /// - public static string SHA1Hash(string data) - { - return SHA1Hash(Encoding.Default.GetBytes(data)); - } - - /// - /// Return an SHA1 hash - /// - /// - /// - public static string SHA1Hash(byte[] data) - { - byte[] hash = ComputeSHA1Hash(data); - return BitConverter.ToString(hash).Replace("-", String.Empty); - } - - private static byte[] ComputeSHA1Hash(byte[] src) - { - SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); - return SHA1.ComputeHash(src); - } - - public static int fast_distance2d(int x, int y) - { - x = Math.Abs(x); - y = Math.Abs(y); - - int min = Math.Min(x, y); - - return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); - } - - /// - /// Are the co-ordinates of the new region visible from the old region? - /// - /// Old region x-coord - /// New region x-coord - /// Old region y-coord - /// New region y-coord - /// - public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) - { - int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); - - int startX = (int)oldx - dd; - int startY = (int)oldy - dd; - - int endX = (int)oldx + dd; - int endY = (int)oldy + dd; - - return (newx < startX || endX < newx || newy < startY || endY < newy); - } - - public static string FieldToString(byte[] bytes) - { - return FieldToString(bytes, String.Empty); - } - - /// - /// Convert a variable length field (byte array) to a string, with a - /// field name prepended to each line of the output - /// - /// If the byte array has unprintable characters in it, a - /// hex dump will be put in the string instead - /// The byte array to convert to a string - /// A field name to prepend to each line of output - /// An ASCII string or a string containing a hex dump, minus - /// the null terminator - public static string FieldToString(byte[] bytes, string fieldName) - { - // Check for a common case - if (bytes.Length == 0) return String.Empty; - - StringBuilder output = new StringBuilder(); - bool printable = true; - - for (int i = 0; i < bytes.Length; ++i) - { - // Check if there are any unprintable characters in the array - if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 - && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) - { - printable = false; - break; - } - } - - if (printable) - { - if (fieldName.Length > 0) - { - output.Append(fieldName); - output.Append(": "); - } - - output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1))); - } - else - { - for (int i = 0; i < bytes.Length; i += 16) - { - if (i != 0) - output.Append(Environment.NewLine); - if (fieldName.Length > 0) - { - output.Append(fieldName); - output.Append(": "); - } - - for (int j = 0; j < 16; j++) - { - if ((i + j) < bytes.Length) - output.Append(String.Format("{0:X2} ", bytes[i + j])); - else - output.Append(" "); - } - - for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) - { - if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) - output.Append((char) bytes[i + j]); - else - output.Append("."); - } - } - } - - return output.ToString(); - } - - /// - /// Converts a URL to a IPAddress - /// - /// URL Standard Format - /// A resolved IP Address - public static IPAddress GetHostFromURL(string url) - { - return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); - } - - /// - /// Returns a IP address from a specified DNS, favouring IPv4 addresses. - /// - /// DNS Hostname - /// An IP address, or null - public static IPAddress GetHostFromDNS(string dnsAddress) - { - // Is it already a valid IP? No need to look it up. - IPAddress ipa; - if (IPAddress.TryParse(dnsAddress, out ipa)) - return ipa; - - IPAddress[] hosts = null; - - // Not an IP, lookup required - try - { - hosts = Dns.GetHostEntry(dnsAddress).AddressList; - } - catch (Exception e) - { - m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); - - // Still going to throw the exception on for now, since this was what was happening in the first place - throw e; - } - - foreach (IPAddress host in hosts) - { - if (host.AddressFamily == AddressFamily.InterNetwork) - { - return host; - } - } - - if (hosts.Length > 0) - return hosts[0]; - - return null; - } - - public static Uri GetURI(string protocol, string hostname, int port, string path) - { - return new UriBuilder(protocol, hostname, port, path).Uri; - } - - /// - /// Gets a list of all local system IP addresses - /// - /// - public static IPAddress[] GetLocalHosts() - { - return Dns.GetHostAddresses(Dns.GetHostName()); - } - - public static IPAddress GetLocalHost() - { - IPAddress[] iplist = GetLocalHosts(); - - if (iplist.Length == 0) // No accessible external interfaces - { - IPAddress[] loopback = Dns.GetHostAddresses("localhost"); - IPAddress localhost = loopback[0]; - - return localhost; - } - - foreach (IPAddress host in iplist) - { - if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) - { - return host; - } - } - - if (iplist.Length > 0) - { - foreach (IPAddress host in iplist) - { - if (host.AddressFamily == AddressFamily.InterNetwork) - return host; - } - // Well all else failed... - return iplist[0]; - } - - return null; - } - - /// - /// Removes all invalid path chars (OS dependent) - /// - /// path - /// safe path - public static string safePath(string path) - { - return Regex.Replace(path, regexInvalidPathChars, String.Empty); - } - - /// - /// Removes all invalid filename chars (OS dependent) - /// - /// filename - /// safe filename - public static string safeFileName(string filename) - { - return Regex.Replace(filename, regexInvalidFileChars, String.Empty); - ; - } - - // - // directory locations - // - - public static string homeDir() - { - string temp; - // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); - // temp = Path.Combine(personal,".OpenSim"); - temp = "."; - return temp; - } - - public static string assetsDir() - { - return Path.Combine(configDir(), "assets"); - } - - public static string inventoryDir() - { - return Path.Combine(configDir(), "inventory"); - } - - public static string configDir() - { - return "."; - } - - public static string dataDir() - { - return "."; - } - - public static string logDir() - { - return "."; - } - - // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html - public static string GetUniqueFilename(string FileName) - { - int count = 0; - string Name; - - if (File.Exists(FileName)) - { - FileInfo f = new FileInfo(FileName); - - if (!String.IsNullOrEmpty(f.Extension)) - { - Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); - } - else - { - Name = f.FullName; - } - - while (File.Exists(FileName)) - { - count++; - FileName = Name + count + f.Extension; - } - } - return FileName; - } - - // Nini (config) related Methods - public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) - { - if (!File.Exists(fileName)) - { - //create new file - } - XmlConfigSource config = new XmlConfigSource(fileName); - AddDataRowToConfig(config, row); - config.Save(); - - return config; - } - - public static void AddDataRowToConfig(IConfigSource config, DataRow row) - { - config.Configs.Add((string) row[0]); - for (int i = 0; i < row.Table.Columns.Count; i++) - { - config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); - } - } - - public static float Clip(float x, float min, float max) - { - return Math.Min(Math.Max(x, min), max); - } - - public static int Clip(int x, int min, int max) - { - return Math.Min(Math.Max(x, min), max); - } - - /// - /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. - /// - /// - /// - public static String ToRawUuidString(UUID UUID) - { - return UUID.Guid.ToString("n"); - } - - public static string CleanString(string input) - { - if (input.Length == 0) - return input; - - int clip = input.Length; - - // Test for ++ string terminator - int pos = input.IndexOf("\0"); - if (pos != -1 && pos < clip) - clip = pos; - - // Test for CR - pos = input.IndexOf("\r"); - if (pos != -1 && pos < clip) - clip = pos; - - // Test for LF - pos = input.IndexOf("\n"); - if (pos != -1 && pos < clip) - clip = pos; - - // Truncate string before first end-of-line character found - return input.Substring(0, clip); - } - - /// - /// returns the contents of /etc/issue on Unix Systems - /// Use this for where it's absolutely necessary to implement platform specific stuff - /// - /// - public static string ReadEtcIssue() - { - try - { - StreamReader sr = new StreamReader("/etc/issue.net"); - string issue = sr.ReadToEnd(); - sr.Close(); - return issue; - } - catch (Exception) - { - return ""; - } - } - - public static void SerializeToFile(string filename, Object obj) - { - IFormatter formatter = new BinaryFormatter(); - Stream stream = null; - - try - { - stream = new FileStream( - filename, FileMode.Create, - FileAccess.Write, FileShare.None); - - formatter.Serialize(stream, obj); - } - catch (Exception e) - { - m_log.Error(e.ToString()); - } - finally - { - if (stream != null) - { - stream.Close(); - } - } - } - - public static Object DeserializeFromFile(string filename) - { - IFormatter formatter = new BinaryFormatter(); - Stream stream = null; - Object ret = null; - - try - { - stream = new FileStream( - filename, FileMode.Open, - FileAccess.Read, FileShare.None); - - ret = formatter.Deserialize(stream); - } - catch (Exception e) - { - m_log.Error(e.ToString()); - } - finally - { - if (stream != null) - { - stream.Close(); - } - } - - return ret; - } - - public static string Compress(string text) - { - byte[] buffer = Util.UTF8.GetBytes(text); - MemoryStream memory = new MemoryStream(); - using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) - { - compressor.Write(buffer, 0, buffer.Length); - } - - memory.Position = 0; - - byte[] compressed = new byte[memory.Length]; - memory.Read(compressed, 0, compressed.Length); - - byte[] compressedBuffer = new byte[compressed.Length + 4]; - Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); - Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); - return Convert.ToBase64String(compressedBuffer); - } - - public static string Decompress(string compressedText) - { - byte[] compressedBuffer = Convert.FromBase64String(compressedText); - using (MemoryStream memory = new MemoryStream()) - { - int msgLength = BitConverter.ToInt32(compressedBuffer, 0); - memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); - - byte[] buffer = new byte[msgLength]; - - memory.Position = 0; - using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) - { - decompressor.Read(buffer, 0, buffer.Length); - } - - return Util.UTF8.GetString(buffer); - } - } - - public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) - { - return SendXmlRpcCommand(url, methodName, args); - } - - public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) - { - XmlRpcRequest client = new XmlRpcRequest(methodName, args); - return client.Send(url, 6000); - } - - /// - /// Returns an error message that the user could not be found in the database - /// - /// XML string consisting of a error element containing individual error(s) - public static XmlRpcResponse CreateUnknownUserErrorResponse() - { - XmlRpcResponse response = new XmlRpcResponse(); - Hashtable responseData = new Hashtable(); - responseData["error_type"] = "unknown_user"; - responseData["error_desc"] = "The user requested is not in the database"; - - response.Value = responseData; - return response; - } - - /// - /// Converts a byte array in big endian order into an ulong. - /// - /// - /// The array of bytes - /// - /// - /// The extracted ulong - /// - public static ulong BytesToUInt64Big(byte[] bytes) - { - if (bytes.Length < 8) return 0; - return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | - ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; - } - - // used for RemoteParcelRequest (for "About Landmark") - public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) - { - byte[] bytes = - { - (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), - (byte)x, (byte)(x >> 8), 0, 0, - (byte)y, (byte)(y >> 8), 0, 0 }; - return new UUID(bytes, 0); - } - - public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z) - { - byte[] bytes = - { - (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), - (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), - (byte)y, (byte)(y >> 8), 0, 0 }; - return new UUID(bytes, 0); - } - - public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) - { - byte[] bytes = parcelID.GetBytes(); - regionHandle = Utils.BytesToUInt64(bytes); - x = Utils.BytesToUInt(bytes, 8) & 0xffff; - y = Utils.BytesToUInt(bytes, 12) & 0xffff; - } - - public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) - { - byte[] bytes = parcelID.GetBytes(); - regionHandle = Utils.BytesToUInt64(bytes); - x = Utils.BytesToUInt(bytes, 8) & 0xffff; - z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16; - y = Utils.BytesToUInt(bytes, 12) & 0xffff; - } - - public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) - { - ulong regionHandle; - uint rx, ry; - - ParseFakeParcelID(parcelID, out regionHandle, out x, out y); - Utils.LongToUInts(regionHandle, out rx, out ry); - - x += rx; - y += ry; - } - - /// - /// Get operating system information if available. Returns only the first 45 characters of information - /// - /// - /// Operating system information. Returns an empty string if none was available. - /// - public static string GetOperatingSystemInformation() - { - string os = String.Empty; - - if (Environment.OSVersion.Platform != PlatformID.Unix) - { - os = Environment.OSVersion.ToString(); - } - else - { - os = ReadEtcIssue(); - } - - if (os.Length > 45) - { - os = os.Substring(0, 45); - } - - return os; - } - - public static string GetRuntimeInformation() - { - string ru = String.Empty; - - if (Environment.OSVersion.Platform == PlatformID.Unix) - ru = "Unix/Mono"; - else - if (Environment.OSVersion.Platform == PlatformID.MacOSX) - ru = "OSX/Mono"; - else - { - if (Type.GetType("Mono.Runtime") != null) - ru = "Win/Mono"; - else - ru = "Win/.NET"; - } - - return ru; - } - - /// - /// Is the given string a UUID? - /// - /// - /// - public static bool isUUID(string s) - { - return UUIDPattern.IsMatch(s); - } - - public static string GetDisplayConnectionString(string connectionString) - { - int passPosition = 0; - int passEndPosition = 0; - string displayConnectionString = null; - - // hide the password in the connection string - passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); - passPosition = connectionString.IndexOf("=", passPosition); - if (passPosition < connectionString.Length) - passPosition += 1; - passEndPosition = connectionString.IndexOf(";", passPosition); - - displayConnectionString = connectionString.Substring(0, passPosition); - displayConnectionString += "***"; - displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition); - - return displayConnectionString; - } - - public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) - { - Type settingsType = settingsClass.GetType(); - - FieldInfo[] fieldInfos = settingsType.GetFields(); - foreach (FieldInfo fieldInfo in fieldInfos) - { - if (!fieldInfo.IsStatic) - { - if (fieldInfo.FieldType == typeof(System.String)) - { - fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Boolean)) - { - fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Int32)) - { - fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Single)) - { - fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.UInt32)) - { - fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); - } - } - } - - PropertyInfo[] propertyInfos = settingsType.GetProperties(); - foreach (PropertyInfo propInfo in propertyInfos) - { - if ((propInfo.CanRead) && (propInfo.CanWrite)) - { - if (propInfo.PropertyType == typeof(System.String)) - { - propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Boolean)) - { - propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Int32)) - { - propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Single)) - { - propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); - } - if (propInfo.PropertyType == typeof(System.UInt32)) - { - propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); - } - } - } - - return settingsClass; - } - - public static string Base64ToString(string str) - { - UTF8Encoding encoder = new UTF8Encoding(); - Decoder utf8Decode = encoder.GetDecoder(); - - byte[] todecode_byte = Convert.FromBase64String(str); - int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); - char[] decoded_char = new char[charCount]; - utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); - string result = new String(decoded_char); - return result; - } - - public static Guid GetHashGuid(string data, string salt) - { - byte[] hash = ComputeMD5Hash(data + salt); - - //string s = BitConverter.ToString(hash); - - Guid guid = new Guid(hash); - - return guid; - } - - public static byte ConvertMaturityToAccessLevel(uint maturity) - { - byte retVal = 0; - switch (maturity) - { - case 0: //PG - retVal = 13; - break; - case 1: //Mature - retVal = 21; - break; - case 2: // Adult - retVal = 42; - break; - } - - return retVal; - - } - - public static uint ConvertAccessLevelToMaturity(byte maturity) - { - if (maturity <= 13) - return 0; - else if (maturity <= 21) - return 1; - else - return 2; - } - - /// - /// Produces an OSDMap from its string representation on a stream - /// - /// The stream - /// The size of the data on the stream - /// The OSDMap or an exception - public static OSDMap GetOSDMap(Stream stream, int length) - { - byte[] data = new byte[length]; - stream.Read(data, 0, length); - string strdata = Util.UTF8.GetString(data); - OSDMap args = null; - OSD buffer; - buffer = OSDParser.DeserializeJson(strdata); - if (buffer.Type == OSDType.Map) - { - args = (OSDMap)buffer; - return args; - } - return null; - } - - public static OSDMap GetOSDMap(string data) - { - OSDMap args = null; - try - { - OSD buffer; - // We should pay attention to the content-type, but let's assume we know it's Json - buffer = OSDParser.DeserializeJson(data); - if (buffer.Type == OSDType.Map) - { - args = (OSDMap)buffer; - return args; - } - else - { - // uh? - m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString())); - return null; - } - } - catch (Exception ex) - { - m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message); - return null; - } - } - - public static string[] Glob(string path) - { - string vol=String.Empty; - - if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) - { - string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries); - - if (vcomps.Length > 1) - { - path = vcomps[1]; - vol = vcomps[0]; - } - } - - string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); - - // Glob - - path = vol; - if (vol != String.Empty) - path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar}); - else - path = new String(new char[] {Path.DirectorySeparatorChar}); - - List paths = new List(); - List found = new List(); - paths.Add(path); - - int compIndex = -1; - foreach (string c in comps) - { - compIndex++; - - List addpaths = new List(); - foreach (string p in paths) - { - string[] dirs = Directory.GetDirectories(p, c); - - if (dirs.Length != 0) - { - foreach (string dir in dirs) - addpaths.Add(Path.Combine(path, dir)); - } - - // Only add files if that is the last path component - if (compIndex == comps.Length - 1) - { - string[] files = Directory.GetFiles(p, c); - foreach (string f in files) - found.Add(f); - } - } - paths = addpaths; - } - - return found.ToArray(); - } - - public static string ServerURI(string uri) - { - if (uri == string.Empty) - return string.Empty; - - // Get rid of eventual slashes at the end - uri = uri.TrimEnd('/'); - - IPAddress ipaddr1 = null; - string port1 = ""; - try - { - ipaddr1 = Util.GetHostFromURL(uri); - } - catch { } - - try - { - port1 = uri.Split(new char[] { ':' })[2]; - } - catch { } - - // We tried our best to convert the domain names to IP addresses - return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - /// Arguments to substitute into the string via the {} mechanism. - /// - /// - public static byte[] StringToBytes256(string str, params object[] args) - { - return StringToBytes256(string.Format(str, args)); - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - public static byte[] StringToBytes256(string str) - { - if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } - if (str.Length > 254) str = str.Remove(254); - if (!str.EndsWith("\0")) { str += "\0"; } - - // Because this is UTF-8 encoding and not ASCII, it's possible we - // might have gotten an oversized array even after the string trim - byte[] data = UTF8.GetBytes(str); - if (data.Length > 256) - { - Array.Resize(ref data, 256); - data[255] = 0; - } - - return data; - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - /// Arguments to substitute into the string via the {} mechanism. - /// - /// - public static byte[] StringToBytes1024(string str, params object[] args) - { - return StringToBytes1024(string.Format(str, args)); - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - public static byte[] StringToBytes1024(string str) - { - if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } - if (str.Length > 1023) str = str.Remove(1023); - if (!str.EndsWith("\0")) { str += "\0"; } - - // Because this is UTF-8 encoding and not ASCII, it's possible we - // might have gotten an oversized array even after the string trim - byte[] data = UTF8.GetBytes(str); - if (data.Length > 1024) - { - Array.Resize(ref data, 1024); - data[1023] = 0; - } - - return data; + // used for RemoteParcelRequest (for "About Landmark") + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) + { + byte[] bytes = + { + (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)x, (byte)(x >> 8), 0, 0, + (byte)y, (byte)(y >> 8), 0, 0 }; + return new UUID(bytes, 0); + } + + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z) + { + byte[] bytes = + { + (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), + (byte)y, (byte)(y >> 8), 0, 0 }; + return new UUID(bytes, 0); + } + + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) + { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8) & 0xffff; + y = Utils.BytesToUInt(bytes, 12) & 0xffff; + } + + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) + { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8) & 0xffff; + z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16; + y = Utils.BytesToUInt(bytes, 12) & 0xffff; + } + + public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) + { + ulong regionHandle; + uint rx, ry; + + ParseFakeParcelID(parcelID, out regionHandle, out x, out y); + Utils.LongToUInts(regionHandle, out rx, out ry); + + x += rx; + y += ry; + } + + /// + /// Get operating system information if available. Returns only the first 45 characters of information + /// + /// + /// Operating system information. Returns an empty string if none was available. + /// + public static string GetOperatingSystemInformation() + { + string os = String.Empty; + + if (Environment.OSVersion.Platform != PlatformID.Unix) + { + os = Environment.OSVersion.ToString(); + } + else + { + os = ReadEtcIssue(); + } + + if (os.Length > 45) + { + os = os.Substring(0, 45); + } + + return os; + } + + public static string GetRuntimeInformation() + { + string ru = String.Empty; + + if (Environment.OSVersion.Platform == PlatformID.Unix) + ru = "Unix/Mono"; + else + if (Environment.OSVersion.Platform == PlatformID.MacOSX) + ru = "OSX/Mono"; + else + { + if (Type.GetType("Mono.Runtime") != null) + ru = "Win/Mono"; + else + ru = "Win/.NET"; + } + + return ru; + } + + /// + /// Is the given string a UUID? + /// + /// + /// + public static bool isUUID(string s) + { + return UUIDPattern.IsMatch(s); + } + + public static string GetDisplayConnectionString(string connectionString) + { + int passPosition = 0; + int passEndPosition = 0; + string displayConnectionString = null; + + // hide the password in the connection string + passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); + passPosition = connectionString.IndexOf("=", passPosition); + if (passPosition < connectionString.Length) + passPosition += 1; + passEndPosition = connectionString.IndexOf(";", passPosition); + + displayConnectionString = connectionString.Substring(0, passPosition); + displayConnectionString += "***"; + displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition); + + return displayConnectionString; + } + + public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) + { + Type settingsType = settingsClass.GetType(); + + FieldInfo[] fieldInfos = settingsType.GetFields(); + foreach (FieldInfo fieldInfo in fieldInfos) + { + if (!fieldInfo.IsStatic) + { + if (fieldInfo.FieldType == typeof(System.String)) + { + fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Boolean)) + { + fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Int32)) + { + fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Single)) + { + fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.UInt32)) + { + fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + } + } + } + + PropertyInfo[] propertyInfos = settingsType.GetProperties(); + foreach (PropertyInfo propInfo in propertyInfos) + { + if ((propInfo.CanRead) && (propInfo.CanWrite)) + { + if (propInfo.PropertyType == typeof(System.String)) + { + propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Boolean)) + { + propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Int32)) + { + propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Single)) + { + propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); + } + if (propInfo.PropertyType == typeof(System.UInt32)) + { + propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); + } + } + } + + return settingsClass; + } + + public static string Base64ToString(string str) + { + UTF8Encoding encoder = new UTF8Encoding(); + Decoder utf8Decode = encoder.GetDecoder(); + + byte[] todecode_byte = Convert.FromBase64String(str); + int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); + char[] decoded_char = new char[charCount]; + utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); + string result = new String(decoded_char); + return result; + } + + public static Guid GetHashGuid(string data, string salt) + { + byte[] hash = ComputeMD5Hash(data + salt); + + //string s = BitConverter.ToString(hash); + + Guid guid = new Guid(hash); + + return guid; + } + + public static byte ConvertMaturityToAccessLevel(uint maturity) + { + byte retVal = 0; + switch (maturity) + { + case 0: //PG + retVal = 13; + break; + case 1: //Mature + retVal = 21; + break; + case 2: // Adult + retVal = 42; + break; + } + + return retVal; + + } + + public static uint ConvertAccessLevelToMaturity(byte maturity) + { + if (maturity <= 13) + return 0; + else if (maturity <= 21) + return 1; + else + return 2; + } + + /// + /// Produces an OSDMap from its string representation on a stream + /// + /// The stream + /// The size of the data on the stream + /// The OSDMap or an exception + public static OSDMap GetOSDMap(Stream stream, int length) + { + byte[] data = new byte[length]; + stream.Read(data, 0, length); + string strdata = Util.UTF8.GetString(data); + OSDMap args = null; + OSD buffer; + buffer = OSDParser.DeserializeJson(strdata); + if (buffer.Type == OSDType.Map) + { + args = (OSDMap)buffer; + return args; + } + return null; + } + + public static OSDMap GetOSDMap(string data) + { + OSDMap args = null; + try + { + OSD buffer; + // We should pay attention to the content-type, but let's assume we know it's Json + buffer = OSDParser.DeserializeJson(data); + if (buffer.Type == OSDType.Map) + { + args = (OSDMap)buffer; + return args; + } + else + { + // uh? + m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString())); + return null; + } + } + catch (Exception ex) + { + m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message); + return null; + } + } + + public static string[] Glob(string path) + { + string vol=String.Empty; + + if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) + { + string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries); + + if (vcomps.Length > 1) + { + path = vcomps[1]; + vol = vcomps[0]; + } + } + + string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); + + // Glob + + path = vol; + if (vol != String.Empty) + path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar}); + else + path = new String(new char[] {Path.DirectorySeparatorChar}); + + List paths = new List(); + List found = new List(); + paths.Add(path); + + int compIndex = -1; + foreach (string c in comps) + { + compIndex++; + + List addpaths = new List(); + foreach (string p in paths) + { + string[] dirs = Directory.GetDirectories(p, c); + + if (dirs.Length != 0) + { + foreach (string dir in dirs) + addpaths.Add(Path.Combine(path, dir)); + } + + // Only add files if that is the last path component + if (compIndex == comps.Length - 1) + { + string[] files = Directory.GetFiles(p, c); + foreach (string f in files) + found.Add(f); + } + } + paths = addpaths; + } + + return found.ToArray(); + } + + public static string ServerURI(string uri) + { + if (uri == string.Empty) + return string.Empty; + + // Get rid of eventual slashes at the end + uri = uri.TrimEnd('/'); + + IPAddress ipaddr1 = null; + string port1 = ""; + try + { + ipaddr1 = Util.GetHostFromURL(uri); + } + catch { } + + try + { + port1 = uri.Split(new char[] { ':' })[2]; + } + catch { } + + // We tried our best to convert the domain names to IP addresses + return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// + public static byte[] StringToBytes256(string str, params object[] args) + { + return StringToBytes256(string.Format(str, args)); + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + public static byte[] StringToBytes256(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (str.Length > 254) str = str.Remove(254); + if (!str.EndsWith("\0")) { str += "\0"; } + + // Because this is UTF-8 encoding and not ASCII, it's possible we + // might have gotten an oversized array even after the string trim + byte[] data = UTF8.GetBytes(str); + if (data.Length > 256) + { + Array.Resize(ref data, 256); + data[255] = 0; + } + + return data; + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// + public static byte[] StringToBytes1024(string str, params object[] args) + { + return StringToBytes1024(string.Format(str, args)); + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + public static byte[] StringToBytes1024(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (str.Length > 1023) str = str.Remove(1023); + if (!str.EndsWith("\0")) { str += "\0"; } + + // Because this is UTF-8 encoding and not ASCII, it's possible we + // might have gotten an oversized array even after the string trim + byte[] data = UTF8.GetBytes(str); + if (data.Length > 1024) + { + Array.Resize(ref data, 1024); + data[1023] = 0; + } + + return data; } /// @@ -1525,466 +1525,500 @@ namespace OpenSim.Framework public static bool Is64BitProcess() { return IntPtr.Size == 8; - } - - #region FireAndForget Threading Pattern - - /// - /// Created to work around a limitation in Mono with nested delegates - /// - private sealed class FireAndForgetWrapper - { - private static volatile FireAndForgetWrapper instance; - private static object syncRoot = new Object(); - - public static FireAndForgetWrapper Instance { - get { - - if (instance == null) - { - lock (syncRoot) - { - if (instance == null) - { - instance = new FireAndForgetWrapper(); - } - } - } - - return instance; - } - } - - public void FireAndForget(System.Threading.WaitCallback callback) - { - callback.BeginInvoke(null, EndFireAndForget, callback); - } - - public void FireAndForget(System.Threading.WaitCallback callback, object obj) - { - callback.BeginInvoke(obj, EndFireAndForget, callback); - } - - private static void EndFireAndForget(IAsyncResult ar) - { - System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; - - try { callback.EndInvoke(ar); } - catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } - - ar.AsyncWaitHandle.Close(); - } - } - - public static void FireAndForget(System.Threading.WaitCallback callback) - { - FireAndForget(callback, null); - } - - public static void InitThreadPool(int maxThreads) - { - if (maxThreads < 2) - throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); - if (m_ThreadPool != null) - throw new InvalidOperationException("SmartThreadPool is already initialized"); - - m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); - } - - public static int FireAndForgetCount() - { - const int MAX_SYSTEM_THREADS = 200; - - switch (FireAndForgetMethod) - { - case FireAndForgetMethod.UnsafeQueueUserWorkItem: - case FireAndForgetMethod.QueueUserWorkItem: - case FireAndForgetMethod.BeginInvoke: - int workerThreads, iocpThreads; - ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); - return workerThreads; - case FireAndForgetMethod.SmartThreadPool: - return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads; - case FireAndForgetMethod.Thread: - return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count; - default: - throw new NotImplementedException(); - } - } - - public static void FireAndForget(System.Threading.WaitCallback callback, object obj) - { - WaitCallback realCallback; - - if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) - { - // If we're running regression tests, then we want any exceptions to rise up to the test code. - realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; - } - else - { - // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture - // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas - // for decimals places but is read by a culture that treats commas as number seperators. - realCallback = o => - { - Culture.SetCurrentCulture(); - - try - { - callback(o); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", - e.Message, e.StackTrace); - } - }; - } - - switch (FireAndForgetMethod) - { - case FireAndForgetMethod.RegressionTest: - case FireAndForgetMethod.None: - realCallback.Invoke(obj); - break; - case FireAndForgetMethod.UnsafeQueueUserWorkItem: - ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.QueueUserWorkItem: - ThreadPool.QueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.BeginInvoke: - FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; - wrapper.FireAndForget(realCallback, obj); - break; - case FireAndForgetMethod.SmartThreadPool: - if (m_ThreadPool == null) - m_ThreadPool = new SmartThreadPool(2000, 15, 2); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); - break; - case FireAndForgetMethod.Thread: - Thread thread = new Thread(delegate(object o) { realCallback(o); }); - thread.Start(obj); - break; - default: - throw new NotImplementedException(); - } - } - - /// - /// Get a thread pool report. - /// - /// - public static string GetThreadPoolReport() - { - string threadPoolUsed = null; - int maxThreads = 0; - int minThreads = 0; - int allocatedThreads = 0; - int inUseThreads = 0; - int waitingCallbacks = 0; - int completionPortThreads = 0; - - StringBuilder sb = new StringBuilder(); - if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; - } - else if ( - FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem - || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) - { - threadPoolUsed = "BuiltInThreadPool"; - ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); - ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); - int availableThreads; - ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); - inUseThreads = maxThreads - availableThreads; - allocatedThreads = -1; - waitingCallbacks = -1; - } - - if (threadPoolUsed != null) - { - sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); - sb.AppendFormat("Max threads : {0}\n", maxThreads); - sb.AppendFormat("Min threads : {0}\n", minThreads); - sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); - sb.AppendFormat("In use threads : {0}\n", inUseThreads); - sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); - } - else - { - sb.AppendFormat("Thread pool not used\n"); - } - - return sb.ToString(); - } - - private static object SmartThreadPoolCallback(object o) - { - object[] array = (object[])o; - WaitCallback callback = (WaitCallback)array[0]; - object obj = array[1]; - - callback(obj); - return null; - } - - #endregion FireAndForget Threading Pattern - - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap - /// for the callers. - /// This trims it to a 12 day interval so don't let your frame time get too long. - /// - /// - public static Int32 EnvironmentTickCount() - { - return Environment.TickCount & EnvironmentTickCountMask; - } - const Int32 EnvironmentTickCountMask = 0x3fffffff; - - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. Subtracts the passed value (previously fetched by - /// 'EnvironmentTickCount()') and accounts for any wrapping. - /// - /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) - { - Int32 diff = EnvironmentTickCount() - prevValue; - return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); - } - - // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount - // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). - // A positive return value indicates A occured later than B - public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) - { - // A, B and TC are all between 0 and 0x3fffffff - int tc = EnvironmentTickCount(); - - if (tc - tcA >= 0) - tcA += EnvironmentTickCountMask + 1; - - if (tc - tcB >= 0) - tcB += EnvironmentTickCountMask + 1; - - return tcA - tcB; - } - - /// - /// Prints the call stack at any given point. Useful for debugging. - /// - public static void PrintCallStack() - { - StackTrace stackTrace = new StackTrace(true); // get call stack - StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - // write call stack method names - foreach (StackFrame stackFrame in stackFrames) - { - MethodBase mb = stackFrame.GetMethod(); - m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name - } - } - - /// - /// Gets the client IP address - /// - /// - /// - public static IPEndPoint GetClientIPFromXFF(string xff) - { - if (xff == string.Empty) - return null; - - string[] parts = xff.Split(new char[] { ',' }); - if (parts.Length > 0) - { - try - { - return new IPEndPoint(IPAddress.Parse(parts[0]), 0); - } - catch (Exception e) - { - m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message); - } - } - - return null; - } - - public static string GetCallerIP(Hashtable req) - { - if (req.ContainsKey("headers")) - { - try - { - Hashtable headers = (Hashtable)req["headers"]; - if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null) - return headers["remote_addr"].ToString(); - } - catch (Exception e) - { - m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message); - } - } - return string.Empty; - } - - #region Xml Serialization Utilities - public static bool ReadBoolean(XmlTextReader reader) - { - reader.ReadStartElement(); - bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); - reader.ReadEndElement(); - - return result; - } - - public static UUID ReadUUID(XmlTextReader reader, string name) - { - UUID id; - string idStr; - - reader.ReadStartElement(name); - - if (reader.Name == "Guid") - idStr = reader.ReadElementString("Guid"); - else if (reader.Name == "UUID") - idStr = reader.ReadElementString("UUID"); - else // no leading tag - idStr = reader.ReadContentAsString(); - UUID.TryParse(idStr, out id); - reader.ReadEndElement(); - - return id; - } - - public static Vector3 ReadVector(XmlTextReader reader, string name) - { - Vector3 vec; - - reader.ReadStartElement(name); - vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x - vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y - vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z - reader.ReadEndElement(); - - return vec; - } - - public static Quaternion ReadQuaternion(XmlTextReader reader, string name) - { - Quaternion quat = new Quaternion(); - - reader.ReadStartElement(name); - while (reader.NodeType != XmlNodeType.EndElement) - { - switch (reader.Name.ToLower()) - { - case "x": - quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "y": - quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "z": - quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "w": - quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - } - } - - reader.ReadEndElement(); - - return quat; - } - - public static T ReadEnum(XmlTextReader reader, string name) - { - string value = reader.ReadElementContentAsString(name, String.Empty); - // !!!!! to deal with flags without commas - if (value.Contains(" ") && !value.Contains(",")) - value = value.Replace(" ", ", "); - - return (T)Enum.Parse(typeof(T), value); ; - } - #endregion - - #region Universal User Identifiers - /// - /// - /// uuid[;endpoint[;name]] - /// - /// - /// - /// - public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) - { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; - - string[] parts = value.Split(';'); - if (parts.Length >= 1) - if (!UUID.TryParse(parts[0], out uuid)) - return false; - - if (parts.Length >= 2) - url = parts[1]; - - if (parts.Length >= 3) - { - string[] name = parts[2].Split(); - if (name.Length == 2) - { - firstname = name[0]; - lastname = name[1]; - } - } - if (parts.Length >= 4) - secret = parts[3]; - - return true; - } - - /// - /// - /// - /// - /// uuid[;endpoint[;name]] - public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) - { - if (acircuit.ServiceURLs.ContainsKey("HomeURI")) - { - string agentsURI = acircuit.ServiceURLs["HomeURI"].ToString(); - if (!agentsURI.EndsWith("/")) - agentsURI += "/"; - - // This is ugly, but there's no other way, given that the name is changed - // in the agent circuit data for foreigners - if (acircuit.lastname.Contains("@")) - { - string[] parts = acircuit.firstname.Split(new char[] { '.' }); - if (parts.Length == 2) - return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; - } - return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + acircuit.firstname + " " + acircuit.lastname; - } - else - return acircuit.AgentID.ToString(); - } - #endregion - } -} + } + + #region FireAndForget Threading Pattern + + /// + /// Created to work around a limitation in Mono with nested delegates + /// + private sealed class FireAndForgetWrapper + { + private static volatile FireAndForgetWrapper instance; + private static object syncRoot = new Object(); + + public static FireAndForgetWrapper Instance { + get { + + if (instance == null) + { + lock (syncRoot) + { + if (instance == null) + { + instance = new FireAndForgetWrapper(); + } + } + } + + return instance; + } + } + + public void FireAndForget(System.Threading.WaitCallback callback) + { + callback.BeginInvoke(null, EndFireAndForget, callback); + } + + public void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + callback.BeginInvoke(obj, EndFireAndForget, callback); + } + + private static void EndFireAndForget(IAsyncResult ar) + { + System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; + + try { callback.EndInvoke(ar); } + catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } + + ar.AsyncWaitHandle.Close(); + } + } + + public static void FireAndForget(System.Threading.WaitCallback callback) + { + FireAndForget(callback, null); + } + + public static void InitThreadPool(int maxThreads) + { + if (maxThreads < 2) + throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (m_ThreadPool != null) + throw new InvalidOperationException("SmartThreadPool is already initialized"); + + m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); + } + + public static int FireAndForgetCount() + { + const int MAX_SYSTEM_THREADS = 200; + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + case FireAndForgetMethod.QueueUserWorkItem: + case FireAndForgetMethod.BeginInvoke: + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + return workerThreads; + case FireAndForgetMethod.SmartThreadPool: + return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads; + case FireAndForgetMethod.Thread: + return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count; + default: + throw new NotImplementedException(); + } + } + + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + WaitCallback realCallback; + + if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + { + // If we're running regression tests, then we want any exceptions to rise up to the test code. + realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; + } + else + { + // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture + // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas + // for decimals places but is read by a culture that treats commas as number seperators. + realCallback = o => + { + Culture.SetCurrentCulture(); + + try + { + callback(o); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", + e.Message, e.StackTrace); + } + }; + } + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.RegressionTest: + case FireAndForgetMethod.None: + realCallback.Invoke(obj); + break; + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.QueueUserWorkItem: + ThreadPool.QueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.BeginInvoke: + FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; + wrapper.FireAndForget(realCallback, obj); + break; + case FireAndForgetMethod.SmartThreadPool: + if (m_ThreadPool == null) + m_ThreadPool = new SmartThreadPool(2000, 15, 2); + m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); + break; + case FireAndForgetMethod.Thread: + Thread thread = new Thread(delegate(object o) { realCallback(o); }); + thread.Start(obj); + break; + default: + throw new NotImplementedException(); + } + } + + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = m_ThreadPool.MaxThreads; + minThreads = m_ThreadPool.MinThreads; + inUseThreads = m_ThreadPool.InUseThreads; + allocatedThreads = m_ThreadPool.ActiveThreads; + waitingCallbacks = m_ThreadPool.WaitingCallbacks; + } + else if ( + FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem + || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } + + return sb.ToString(); + } + + private static object SmartThreadPoolCallback(object o) + { + object[] array = (object[])o; + WaitCallback callback = (WaitCallback)array[0]; + object obj = array[1]; + + callback(obj); + return null; + } + + #endregion FireAndForget Threading Pattern + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap + /// for the callers. + /// This trims it to a 12 day interval so don't let your frame time get too long. + /// + /// + public static Int32 EnvironmentTickCount() + { + return Environment.TickCount & EnvironmentTickCountMask; + } + const Int32 EnvironmentTickCountMask = 0x3fffffff; + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + { + Int32 diff = EnvironmentTickCount() - prevValue; + return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); + } + + // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount + // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). + // A positive return value indicates A occured later than B + public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) + { + // A, B and TC are all between 0 and 0x3fffffff + int tc = EnvironmentTickCount(); + + if (tc - tcA >= 0) + tcA += EnvironmentTickCountMask + 1; + + if (tc - tcB >= 0) + tcB += EnvironmentTickCountMask + 1; + + return tcA - tcB; + } + + /// + /// Prints the call stack at any given point. Useful for debugging. + /// + public static void PrintCallStack() + { + StackTrace stackTrace = new StackTrace(true); // get call stack + StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + // write call stack method names + foreach (StackFrame stackFrame in stackFrames) + { + MethodBase mb = stackFrame.GetMethod(); + m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name + } + } + + /// + /// Gets the client IP address + /// + /// + /// + public static IPEndPoint GetClientIPFromXFF(string xff) + { + if (xff == string.Empty) + return null; + + string[] parts = xff.Split(new char[] { ',' }); + if (parts.Length > 0) + { + try + { + return new IPEndPoint(IPAddress.Parse(parts[0]), 0); + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message); + } + } + + return null; + } + + public static string GetCallerIP(Hashtable req) + { + if (req.ContainsKey("headers")) + { + try + { + Hashtable headers = (Hashtable)req["headers"]; + if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null) + return headers["remote_addr"].ToString(); + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message); + } + } + return string.Empty; + } + + #region Xml Serialization Utilities + public static bool ReadBoolean(XmlTextReader reader) + { + reader.ReadStartElement(); + bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); + reader.ReadEndElement(); + + return result; + } + + public static UUID ReadUUID(XmlTextReader reader, string name) + { + UUID id; + string idStr; + + reader.ReadStartElement(name); + + if (reader.Name == "Guid") + idStr = reader.ReadElementString("Guid"); + else if (reader.Name == "UUID") + idStr = reader.ReadElementString("UUID"); + else // no leading tag + idStr = reader.ReadContentAsString(); + UUID.TryParse(idStr, out id); + reader.ReadEndElement(); + + return id; + } + + public static Vector3 ReadVector(XmlTextReader reader, string name) + { + Vector3 vec; + + reader.ReadStartElement(name); + vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x + vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y + vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z + reader.ReadEndElement(); + + return vec; + } + + public static Quaternion ReadQuaternion(XmlTextReader reader, string name) + { + Quaternion quat = new Quaternion(); + + reader.ReadStartElement(name); + while (reader.NodeType != XmlNodeType.EndElement) + { + switch (reader.Name.ToLower()) + { + case "x": + quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "y": + quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "z": + quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "w": + quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + } + } + + reader.ReadEndElement(); + + return quat; + } + + public static T ReadEnum(XmlTextReader reader, string name) + { + string value = reader.ReadElementContentAsString(name, String.Empty); + // !!!!! to deal with flags without commas + if (value.Contains(" ") && !value.Contains(",")) + value = value.Replace(" ", ", "); + + return (T)Enum.Parse(typeof(T), value); ; + } + #endregion + + #region Universal User Identifiers + /// + /// + /// uuid[;endpoint[;first last[;secret]]] + /// the uuid part + /// the endpoint part (e.g. http://foo.com) + /// the first name part (e.g. Test) + /// the last name part (e.g User) + /// the secret part + public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) + { + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; + + string[] parts = value.Split(';'); + if (parts.Length >= 1) + if (!UUID.TryParse(parts[0], out uuid)) + return false; + + if (parts.Length >= 2) + url = parts[1]; + + if (parts.Length >= 3) + { + string[] name = parts[2].Split(); + if (name.Length == 2) + { + firstname = name[0]; + lastname = name[1]; + } + } + if (parts.Length >= 4) + secret = parts[3]; + + return true; + } + + /// + /// Produces a universal (HG) system-facing identifier given the information + /// + /// + /// uuid[;homeURI[;first last]] + public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) + { + if (acircuit.ServiceURLs.ContainsKey("HomeURI")) + return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString()); + else + return acircuit.AgentID.ToString(); + } + + /// + /// Produces a universal (HG) system-facing identifier given the information + /// + /// UUID of the user + /// first name (e.g Test) + /// last name (e.g. User) + /// homeURI (e.g. http://foo.com) + /// a string of the form uuid[;homeURI[;first last]] + public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI) + { + string agentsURI = homeURI; + if (!agentsURI.EndsWith("/")) + agentsURI += "/"; + + // This is ugly, but there's no other way, given that the name is changed + // in the agent circuit data for foreigners + if (lastName.Contains("@")) + { + string[] parts = firstName.Split(new char[] { '.' }); + if (parts.Length == 2) + return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + } + return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; + + } + + /// + /// Produces a universal (HG) user-facing name given the information + /// + /// + /// + /// + /// string of the form first.last @foo.com or first last + public static string UniversalName(String firstName, String lastName, String homeURI) + { + Uri uri = null; + try + { + uri = new Uri(homeURI); + } + catch (UriFormatException) + { + return firstName + " " + lastName; + } + return firstName + "." + lastName + " " + "@" + uri.Authority; + } + #endregion + } +} -- cgit v1.1 From 841b4232f691e90a977c5ed7e2ce20481da4781b Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 20 Mar 2012 17:19:55 -0700 Subject: Line endings --- OpenSim/Framework/Util.cs | 178 +++++++++++++++++++++++----------------------- 1 file changed, 89 insertions(+), 89 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 26b7070..ea1de80 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1758,26 +1758,26 @@ namespace OpenSim.Framework /// and negative every 24.9 days. Subtracts the passed value (previously fetched by /// 'EnvironmentTickCount()') and accounts for any wrapping. /// - /// - /// + /// + /// /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue) + public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue) { - Int32 diff = newValue - prevValue; + Int32 diff = newValue - prevValue; return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); } - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. Subtracts the passed value (previously fetched by - /// 'EnvironmentTickCount()') and accounts for any wrapping. - /// - /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) - { - return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue); - } - + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + { + return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue); + } + // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). // A positive return value indicates A occured later than B @@ -1940,12 +1940,12 @@ namespace OpenSim.Framework #region Universal User Identifiers /// /// - /// uuid[;endpoint[;first last[;secret]]] - /// the uuid part - /// the endpoint part (e.g. http://foo.com) - /// the first name part (e.g. Test) - /// the last name part (e.g User) - /// the secret part + /// uuid[;endpoint[;first last[;secret]]] + /// the uuid part + /// the endpoint part (e.g. http://foo.com) + /// the first name part (e.g. Test) + /// the last name part (e.g User) + /// the secret part public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) { uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; @@ -1974,79 +1974,79 @@ namespace OpenSim.Framework } /// - /// Produces a universal (HG) system-facing identifier given the information + /// Produces a universal (HG) system-facing identifier given the information /// /// - /// uuid[;homeURI[;first last]] + /// uuid[;homeURI[;first last]] public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) { if (acircuit.ServiceURLs.ContainsKey("HomeURI")) - return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString()); - else - return acircuit.AgentID.ToString(); - } - - /// - /// Produces a universal (HG) system-facing identifier given the information - /// - /// UUID of the user - /// first name (e.g Test) - /// last name (e.g. User) - /// homeURI (e.g. http://foo.com) - /// a string of the form uuid[;homeURI[;first last]] - public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI) - { - string agentsURI = homeURI; - if (!agentsURI.EndsWith("/")) - agentsURI += "/"; - - // This is ugly, but there's no other way, given that the name is changed - // in the agent circuit data for foreigners - if (lastName.Contains("@")) - { - string agentsURI = acircuit.ServiceURLs["HomeURI"].ToString(); - if (!agentsURI.EndsWith("/")) - agentsURI += "/"; - string[] parts = firstName.Split(new char[] { '.' }); - if (parts.Length == 2) - return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; - } - return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; - - } - - // This is ugly, but there's no other way, given that the name is changed - // in the agent circuit data for foreigners - if (acircuit.lastname.Contains("@")) - { - string[] parts = acircuit.firstname.Split(new char[] { '.' }); - if (parts.Length == 2) - return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; - } - return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + acircuit.firstname + " " + acircuit.lastname; - /// - /// Produces a universal (HG) user-facing name given the information - /// - /// - /// - /// - /// string of the form first.last @foo.com or first last - public static string UniversalName(String firstName, String lastName, String homeURI) - { - Uri uri = null; - try - { - uri = new Uri(homeURI); - } - else - return acircuit.AgentID.ToString(); - } - catch (UriFormatException) - { - return firstName + " " + lastName; - } - return firstName + "." + lastName + " " + "@" + uri.Authority; - } + return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString()); + else + return acircuit.AgentID.ToString(); + } + + /// + /// Produces a universal (HG) system-facing identifier given the information + /// + /// UUID of the user + /// first name (e.g Test) + /// last name (e.g. User) + /// homeURI (e.g. http://foo.com) + /// a string of the form uuid[;homeURI[;first last]] + public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI) + { + string agentsURI = homeURI; + if (!agentsURI.EndsWith("/")) + agentsURI += "/"; + + // This is ugly, but there's no other way, given that the name is changed + // in the agent circuit data for foreigners + if (lastName.Contains("@")) + { + string agentsURI = acircuit.ServiceURLs["HomeURI"].ToString(); + if (!agentsURI.EndsWith("/")) + agentsURI += "/"; + string[] parts = firstName.Split(new char[] { '.' }); + if (parts.Length == 2) + return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + } + return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; + + } + + // This is ugly, but there's no other way, given that the name is changed + // in the agent circuit data for foreigners + if (acircuit.lastname.Contains("@")) + { + string[] parts = acircuit.firstname.Split(new char[] { '.' }); + if (parts.Length == 2) + return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + } + return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + acircuit.firstname + " " + acircuit.lastname; + /// + /// Produces a universal (HG) user-facing name given the information + /// + /// + /// + /// + /// string of the form first.last @foo.com or first last + public static string UniversalName(String firstName, String lastName, String homeURI) + { + Uri uri = null; + try + { + uri = new Uri(homeURI); + } + else + return acircuit.AgentID.ToString(); + } + catch (UriFormatException) + { + return firstName + " " + lastName; + } + return firstName + "." + lastName + " " + "@" + uri.Authority; + } #endregion } } -- cgit v1.1 From f7c61790b7e88d6dd3ac2a226c77d5f43e1e6f05 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Tue, 20 Mar 2012 17:25:52 -0700 Subject: Fixed borkness with previous merge. --- OpenSim/Framework/Util.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ea1de80..deda62a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2004,26 +2004,14 @@ namespace OpenSim.Framework // in the agent circuit data for foreigners if (lastName.Contains("@")) { - string agentsURI = acircuit.ServiceURLs["HomeURI"].ToString(); - if (!agentsURI.EndsWith("/")) - agentsURI += "/"; string[] parts = firstName.Split(new char[] { '.' }); if (parts.Length == 2) return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; } return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; - + } - // This is ugly, but there's no other way, given that the name is changed - // in the agent circuit data for foreigners - if (acircuit.lastname.Contains("@")) - { - string[] parts = acircuit.firstname.Split(new char[] { '.' }); - if (parts.Length == 2) - return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; - } - return acircuit.AgentID.ToString() + ";" + agentsURI + ";" + acircuit.firstname + " " + acircuit.lastname; /// /// Produces a universal (HG) user-facing name given the information /// @@ -2038,9 +2026,6 @@ namespace OpenSim.Framework { uri = new Uri(homeURI); } - else - return acircuit.AgentID.ToString(); - } catch (UriFormatException) { return firstName + " " + lastName; -- cgit v1.1 From 7a0d7be44cbdea1f447e24d3fc3024e12875ffd8 Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 21 Mar 2012 00:17:58 +0000 Subject: Refix the fixed fix! --- OpenSim/Framework/Util.cs | 4074 ++++++++++++++++++++++----------------------- 1 file changed, 2037 insertions(+), 2037 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index deda62a..e03bb74 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1,2037 +1,2037 @@ -/* - * 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.Collections; -using System.Collections.Generic; -using System.Data; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.IO.Compression; -using System.Net; -using System.Net.Sockets; -using System.Reflection; -using System.Runtime.InteropServices; -using System.Runtime.Serialization; -using System.Runtime.Serialization.Formatters.Binary; -using System.Security.Cryptography; -using System.Text; -using System.Text.RegularExpressions; -using System.Xml; -using System.Threading; -using log4net; -using Nini.Config; -using Nwc.XmlRpc; -using OpenMetaverse; -using OpenMetaverse.StructuredData; -using Amib.Threading; - -namespace OpenSim.Framework -{ - /// - /// The method used by Util.FireAndForget for asynchronously firing events - /// - /// - /// None is used to execute the method in the same thread that made the call. It should only be used by regression - /// test code that relies on predictable event ordering. - /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. - /// - public enum FireAndForgetMethod - { - None, - RegressionTest, - UnsafeQueueUserWorkItem, - QueueUserWorkItem, - BeginInvoke, - SmartThreadPool, - Thread, - } - - /// - /// Miscellaneous utility functions - /// - public class Util - { - private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - - private static uint nextXferID = 5000; - private static Random randomClass = new Random(); - - // Get a list of invalid file characters (OS dependent) - private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; - private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; - private static object XferLock = new object(); - - /// - /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used - /// - private static SmartThreadPool m_ThreadPool; - - // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. - private static readonly DateTime unixEpoch = - DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); - - private static readonly string rawUUIDPattern - = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; - public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern); - public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern)); - - public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; - public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; - - /// - /// Gets the name of the directory where the current running executable - /// is located - /// - /// Filesystem path to the directory containing the current - /// executable - public static string ExecutingDirectory() - { - return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); - } - - /// - /// Linear interpolates B<->C using percent A - /// - /// - /// - /// - /// - public static double lerp(double a, double b, double c) - { - return (b*a) + (c*(1 - a)); - } - - /// - /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y. - /// Layout: - /// A B - /// C D - /// A<->C = Y - /// C<->D = X - /// - /// - /// - /// - /// - /// - /// - /// - public static double lerp2D(double x, double y, double a, double b, double c, double d) - { - return lerp(y, lerp(x, a, b), lerp(x, c, d)); - } - - public static Encoding UTF8 = Encoding.UTF8; - - /// - /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) - /// - public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); - - #region Vector Equations - - /// - /// Get the distance between two 3d vectors - /// - /// A 3d vector - /// A 3d vector - /// The distance between the two vectors - public static double GetDistanceTo(Vector3 a, Vector3 b) - { - float dx = a.X - b.X; - float dy = a.Y - b.Y; - float dz = a.Z - b.Z; - return Math.Sqrt(dx * dx + dy * dy + dz * dz); - } - - /// - /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt. - /// - /// - /// - /// - /// - public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount) - { - float dx = a.X - b.X; - float dy = a.Y - b.Y; - float dz = a.Z - b.Z; - return (dx*dx + dy*dy + dz*dz) < (amount*amount); - } - - /// - /// Get the magnitude of a 3d vector - /// - /// A 3d vector - /// The magnitude of the vector - public static double GetMagnitude(Vector3 a) - { - return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); - } - - /// - /// Get a normalized form of a 3d vector - /// - /// A 3d vector - /// A new vector which is normalized form of the vector - /// The vector paramater cannot be <0,0,0> - public static Vector3 GetNormalizedVector(Vector3 a) - { - if (IsZeroVector(a)) - throw new ArgumentException("Vector paramater cannot be a zero vector."); - - float Mag = (float) GetMagnitude(a); - return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); - } - - /// - /// Returns if a vector is a zero vector (has all zero components) - /// - /// - public static bool IsZeroVector(Vector3 v) - { - if (v.X == 0 && v.Y == 0 && v.Z == 0) - { - return true; - } - - return false; - } - - # endregion - - public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up) - { - float s; - float tr = (float) (fwd.X + left.Y + up.Z + 1.0); - - if (tr >= 1.0) - { - s = (float) (0.5 / Math.Sqrt(tr)); - return new Quaternion( - (left.Z - up.Y) * s, - (up.X - fwd.Z) * s, - (fwd.Y - left.X) * s, - (float) 0.25 / s); - } - else - { - float max = (left.Y > up.Z) ? left.Y : up.Z; - - if (max < fwd.X) - { - s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0)); - float x = (float) (s * 0.5); - s = (float) (0.5 / s); - return new Quaternion( - x, - (fwd.Y + left.X) * s, - (up.X + fwd.Z) * s, - (left.Z - up.Y) * s); - } - else if (max == left.Y) - { - s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0)); - float y = (float) (s * 0.5); - s = (float) (0.5 / s); - return new Quaternion( - (fwd.Y + left.X) * s, - y, - (left.Z + up.Y) * s, - (up.X - fwd.Z) * s); - } - else - { - s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0)); - float z = (float) (s * 0.5); - s = (float) (0.5 / s); - return new Quaternion( - (up.X + fwd.Z) * s, - (left.Z + up.Y) * s, - z, - (fwd.Y - left.X) * s); - } - } - } - - public static Random RandomClass - { - get { return randomClass; } - } - - public static ulong UIntsToLong(uint X, uint Y) - { - return Utils.UIntsToLong(X, Y); - } - - public static T Clamp(T x, T min, T max) - where T : IComparable - { - return x.CompareTo(max) > 0 ? max : - x.CompareTo(min) < 0 ? min : - x; - } - - public static uint GetNextXferID() - { - uint id = 0; - lock (XferLock) - { - id = nextXferID; - nextXferID++; - } - return id; - } - - public static string GetFileName(string file) - { - // Return just the filename on UNIX platforms - // TODO: this should be customisable with a prefix, but that's something to do later. - if (Environment.OSVersion.Platform == PlatformID.Unix) - { - return file; - } - - // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA - // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData - if (Environment.OSVersion.Platform == PlatformID.Win32NT) - { - if (!Directory.Exists("%APPDATA%\\OpenSim\\")) - { - Directory.CreateDirectory("%APPDATA%\\OpenSim"); - } - - return "%APPDATA%\\OpenSim\\" + file; - } - - // Catch all - covers older windows versions - // (but those probably wont work anyway) - return file; - } - - /// - /// Debug utility function to convert OSD into formatted XML for debugging purposes. - /// - /// - /// A - /// - /// - /// A - /// - public static string GetFormattedXml(OSD osd) - { - return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd)); - } - - /// - /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. - /// - /// - /// Please don't delete me even if I appear currently unused! - /// - /// - /// - public static string GetFormattedXml(string rawXml) - { - XmlDocument xd = new XmlDocument(); - xd.LoadXml(rawXml); - - StringBuilder sb = new StringBuilder(); - StringWriter sw = new StringWriter(sb); - - XmlTextWriter xtw = new XmlTextWriter(sw); - xtw.Formatting = Formatting.Indented; - - try - { - xd.WriteTo(xtw); - } - finally - { - xtw.Close(); - } - - return sb.ToString(); - } - - /// - /// Is the platform Windows? - /// - /// true if so, false otherwise - public static bool IsWindows() - { - PlatformID platformId = Environment.OSVersion.Platform; - - return (platformId == PlatformID.Win32NT - || platformId == PlatformID.Win32S - || platformId == PlatformID.Win32Windows - || platformId == PlatformID.WinCE); - } - - public static bool LoadArchSpecificWindowsDll(string libraryName) - { - // We do this so that OpenSimulator on Windows loads the correct native library depending on whether - // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports - // will find it already loaded later on. - // - // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be - // controlled in config files. - string nativeLibraryPath; - - if (Util.Is64BitProcess()) - nativeLibraryPath = "lib64/" + libraryName; - else - nativeLibraryPath = "lib32/" + libraryName; - - m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); - - if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero) - { - m_log.ErrorFormat( - "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath); - - return false; - } - else - { - return true; - } - } - - public static bool IsEnvironmentSupported(ref string reason) - { - // Must have .NET 2.0 (Generics / libsl) - if (Environment.Version.Major < 2) - { - reason = ".NET 1.0/1.1 lacks components that is used by OpenSim"; - return false; - } - - // Windows 95/98/ME are unsupported - if (Environment.OSVersion.Platform == PlatformID.Win32Windows && - Environment.OSVersion.Platform != PlatformID.Win32NT) - { - reason = "Windows 95/98/ME will not run OpenSim"; - return false; - } - - // Windows 2000 / Pre-SP2 XP - if (Environment.OSVersion.Version.Major == 5 && - Environment.OSVersion.Version.Minor == 0) - { - reason = "Please update to Windows XP Service Pack 2 or Server2003"; - return false; - } - - return true; - } - - public static int UnixTimeSinceEpoch() - { - return ToUnixTime(DateTime.UtcNow); - } - - public static int ToUnixTime(DateTime stamp) - { - TimeSpan t = stamp.ToUniversalTime() - unixEpoch; - return (int) t.TotalSeconds; - } - - public static DateTime ToDateTime(ulong seconds) - { - DateTime epoch = unixEpoch; - return epoch.AddSeconds(seconds); - } - - public static DateTime ToDateTime(int seconds) - { - DateTime epoch = unixEpoch; - return epoch.AddSeconds(seconds); - } - - /// - /// Return an md5 hash of the given string - /// - /// - /// - public static string Md5Hash(string data) - { - byte[] dataMd5 = ComputeMD5Hash(data); - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < dataMd5.Length; i++) - sb.AppendFormat("{0:x2}", dataMd5[i]); - return sb.ToString(); - } - - private static byte[] ComputeMD5Hash(string data) - { - MD5 md5 = MD5.Create(); - return md5.ComputeHash(Encoding.Default.GetBytes(data)); - } - - /// - /// Return an SHA1 hash - /// - /// - /// - public static string SHA1Hash(string data) - { - return SHA1Hash(Encoding.Default.GetBytes(data)); - } - - /// - /// Return an SHA1 hash - /// - /// - /// - public static string SHA1Hash(byte[] data) - { - byte[] hash = ComputeSHA1Hash(data); - return BitConverter.ToString(hash).Replace("-", String.Empty); - } - - private static byte[] ComputeSHA1Hash(byte[] src) - { - SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); - return SHA1.ComputeHash(src); - } - - public static int fast_distance2d(int x, int y) - { - x = Math.Abs(x); - y = Math.Abs(y); - - int min = Math.Min(x, y); - - return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); - } - - /// - /// Are the co-ordinates of the new region visible from the old region? - /// - /// Old region x-coord - /// New region x-coord - /// Old region y-coord - /// New region y-coord - /// - public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) - { - int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); - - int startX = (int)oldx - dd; - int startY = (int)oldy - dd; - - int endX = (int)oldx + dd; - int endY = (int)oldy + dd; - - return (newx < startX || endX < newx || newy < startY || endY < newy); - } - - public static string FieldToString(byte[] bytes) - { - return FieldToString(bytes, String.Empty); - } - - /// - /// Convert a variable length field (byte array) to a string, with a - /// field name prepended to each line of the output - /// - /// If the byte array has unprintable characters in it, a - /// hex dump will be put in the string instead - /// The byte array to convert to a string - /// A field name to prepend to each line of output - /// An ASCII string or a string containing a hex dump, minus - /// the null terminator - public static string FieldToString(byte[] bytes, string fieldName) - { - // Check for a common case - if (bytes.Length == 0) return String.Empty; - - StringBuilder output = new StringBuilder(); - bool printable = true; - - for (int i = 0; i < bytes.Length; ++i) - { - // Check if there are any unprintable characters in the array - if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 - && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) - { - printable = false; - break; - } - } - - if (printable) - { - if (fieldName.Length > 0) - { - output.Append(fieldName); - output.Append(": "); - } - - output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1))); - } - else - { - for (int i = 0; i < bytes.Length; i += 16) - { - if (i != 0) - output.Append(Environment.NewLine); - if (fieldName.Length > 0) - { - output.Append(fieldName); - output.Append(": "); - } - - for (int j = 0; j < 16; j++) - { - if ((i + j) < bytes.Length) - output.Append(String.Format("{0:X2} ", bytes[i + j])); - else - output.Append(" "); - } - - for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) - { - if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) - output.Append((char) bytes[i + j]); - else - output.Append("."); - } - } - } - - return output.ToString(); - } - - /// - /// Converts a URL to a IPAddress - /// - /// URL Standard Format - /// A resolved IP Address - public static IPAddress GetHostFromURL(string url) - { - return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); - } - - /// - /// Returns a IP address from a specified DNS, favouring IPv4 addresses. - /// - /// DNS Hostname - /// An IP address, or null - public static IPAddress GetHostFromDNS(string dnsAddress) - { - // Is it already a valid IP? No need to look it up. - IPAddress ipa; - if (IPAddress.TryParse(dnsAddress, out ipa)) - return ipa; - - IPAddress[] hosts = null; - - // Not an IP, lookup required - try - { - hosts = Dns.GetHostEntry(dnsAddress).AddressList; - } - catch (Exception e) - { - m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); - - // Still going to throw the exception on for now, since this was what was happening in the first place - throw e; - } - - foreach (IPAddress host in hosts) - { - if (host.AddressFamily == AddressFamily.InterNetwork) - { - return host; - } - } - - if (hosts.Length > 0) - return hosts[0]; - - return null; - } - - public static Uri GetURI(string protocol, string hostname, int port, string path) - { - return new UriBuilder(protocol, hostname, port, path).Uri; - } - - /// - /// Gets a list of all local system IP addresses - /// - /// - public static IPAddress[] GetLocalHosts() - { - return Dns.GetHostAddresses(Dns.GetHostName()); - } - - public static IPAddress GetLocalHost() - { - IPAddress[] iplist = GetLocalHosts(); - - if (iplist.Length == 0) // No accessible external interfaces - { - IPAddress[] loopback = Dns.GetHostAddresses("localhost"); - IPAddress localhost = loopback[0]; - - return localhost; - } - - foreach (IPAddress host in iplist) - { - if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) - { - return host; - } - } - - if (iplist.Length > 0) - { - foreach (IPAddress host in iplist) - { - if (host.AddressFamily == AddressFamily.InterNetwork) - return host; - } - // Well all else failed... - return iplist[0]; - } - - return null; - } - - /// - /// Removes all invalid path chars (OS dependent) - /// - /// path - /// safe path - public static string safePath(string path) - { - return Regex.Replace(path, regexInvalidPathChars, String.Empty); - } - - /// - /// Removes all invalid filename chars (OS dependent) - /// - /// filename - /// safe filename - public static string safeFileName(string filename) - { - return Regex.Replace(filename, regexInvalidFileChars, String.Empty); - ; - } - - // - // directory locations - // - - public static string homeDir() - { - string temp; - // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); - // temp = Path.Combine(personal,".OpenSim"); - temp = "."; - return temp; - } - - public static string assetsDir() - { - return Path.Combine(configDir(), "assets"); - } - - public static string inventoryDir() - { - return Path.Combine(configDir(), "inventory"); - } - - public static string configDir() - { - return "."; - } - - public static string dataDir() - { - return "."; - } - - public static string logDir() - { - return "."; - } - - // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html - public static string GetUniqueFilename(string FileName) - { - int count = 0; - string Name; - - if (File.Exists(FileName)) - { - FileInfo f = new FileInfo(FileName); - - if (!String.IsNullOrEmpty(f.Extension)) - { - Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); - } - else - { - Name = f.FullName; - } - - while (File.Exists(FileName)) - { - count++; - FileName = Name + count + f.Extension; - } - } - return FileName; - } - - // Nini (config) related Methods - public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) - { - if (!File.Exists(fileName)) - { - //create new file - } - XmlConfigSource config = new XmlConfigSource(fileName); - AddDataRowToConfig(config, row); - config.Save(); - - return config; - } - - public static void AddDataRowToConfig(IConfigSource config, DataRow row) - { - config.Configs.Add((string) row[0]); - for (int i = 0; i < row.Table.Columns.Count; i++) - { - config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); - } - } - - public static float Clip(float x, float min, float max) - { - return Math.Min(Math.Max(x, min), max); - } - - public static int Clip(int x, int min, int max) - { - return Math.Min(Math.Max(x, min), max); - } - - /// - /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. - /// - /// - /// - public static String ToRawUuidString(UUID UUID) - { - return UUID.Guid.ToString("n"); - } - - public static string CleanString(string input) - { - if (input.Length == 0) - return input; - - int clip = input.Length; - - // Test for ++ string terminator - int pos = input.IndexOf("\0"); - if (pos != -1 && pos < clip) - clip = pos; - - // Test for CR - pos = input.IndexOf("\r"); - if (pos != -1 && pos < clip) - clip = pos; - - // Test for LF - pos = input.IndexOf("\n"); - if (pos != -1 && pos < clip) - clip = pos; - - // Truncate string before first end-of-line character found - return input.Substring(0, clip); - } - - /// - /// returns the contents of /etc/issue on Unix Systems - /// Use this for where it's absolutely necessary to implement platform specific stuff - /// - /// - public static string ReadEtcIssue() - { - try - { - StreamReader sr = new StreamReader("/etc/issue.net"); - string issue = sr.ReadToEnd(); - sr.Close(); - return issue; - } - catch (Exception) - { - return ""; - } - } - - public static void SerializeToFile(string filename, Object obj) - { - IFormatter formatter = new BinaryFormatter(); - Stream stream = null; - - try - { - stream = new FileStream( - filename, FileMode.Create, - FileAccess.Write, FileShare.None); - - formatter.Serialize(stream, obj); - } - catch (Exception e) - { - m_log.Error(e.ToString()); - } - finally - { - if (stream != null) - { - stream.Close(); - } - } - } - - public static Object DeserializeFromFile(string filename) - { - IFormatter formatter = new BinaryFormatter(); - Stream stream = null; - Object ret = null; - - try - { - stream = new FileStream( - filename, FileMode.Open, - FileAccess.Read, FileShare.None); - - ret = formatter.Deserialize(stream); - } - catch (Exception e) - { - m_log.Error(e.ToString()); - } - finally - { - if (stream != null) - { - stream.Close(); - } - } - - return ret; - } - - public static string Compress(string text) - { - byte[] buffer = Util.UTF8.GetBytes(text); - MemoryStream memory = new MemoryStream(); - using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) - { - compressor.Write(buffer, 0, buffer.Length); - } - - memory.Position = 0; - - byte[] compressed = new byte[memory.Length]; - memory.Read(compressed, 0, compressed.Length); - - byte[] compressedBuffer = new byte[compressed.Length + 4]; - Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); - Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); - return Convert.ToBase64String(compressedBuffer); - } - - public static string Decompress(string compressedText) - { - byte[] compressedBuffer = Convert.FromBase64String(compressedText); - using (MemoryStream memory = new MemoryStream()) - { - int msgLength = BitConverter.ToInt32(compressedBuffer, 0); - memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); - - byte[] buffer = new byte[msgLength]; - - memory.Position = 0; - using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) - { - decompressor.Read(buffer, 0, buffer.Length); - } - - return Util.UTF8.GetString(buffer); - } - } - - public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) - { - return SendXmlRpcCommand(url, methodName, args); - } - - public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) - { - XmlRpcRequest client = new XmlRpcRequest(methodName, args); - return client.Send(url, 6000); - } - - /// - /// Returns an error message that the user could not be found in the database - /// - /// XML string consisting of a error element containing individual error(s) - public static XmlRpcResponse CreateUnknownUserErrorResponse() - { - XmlRpcResponse response = new XmlRpcResponse(); - Hashtable responseData = new Hashtable(); - responseData["error_type"] = "unknown_user"; - responseData["error_desc"] = "The user requested is not in the database"; - - response.Value = responseData; - return response; - } - - /// - /// Converts a byte array in big endian order into an ulong. - /// - /// - /// The array of bytes - /// - /// - /// The extracted ulong - /// - public static ulong BytesToUInt64Big(byte[] bytes) - { - if (bytes.Length < 8) return 0; - return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | - ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; - } - - // used for RemoteParcelRequest (for "About Landmark") - public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) - { - byte[] bytes = - { - (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), - (byte)x, (byte)(x >> 8), 0, 0, - (byte)y, (byte)(y >> 8), 0, 0 }; - return new UUID(bytes, 0); - } - - public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z) - { - byte[] bytes = - { - (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), - (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), - (byte)y, (byte)(y >> 8), 0, 0 }; - return new UUID(bytes, 0); - } - - public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) - { - byte[] bytes = parcelID.GetBytes(); - regionHandle = Utils.BytesToUInt64(bytes); - x = Utils.BytesToUInt(bytes, 8) & 0xffff; - y = Utils.BytesToUInt(bytes, 12) & 0xffff; - } - - public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) - { - byte[] bytes = parcelID.GetBytes(); - regionHandle = Utils.BytesToUInt64(bytes); - x = Utils.BytesToUInt(bytes, 8) & 0xffff; - z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16; - y = Utils.BytesToUInt(bytes, 12) & 0xffff; - } - - public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) - { - ulong regionHandle; - uint rx, ry; - - ParseFakeParcelID(parcelID, out regionHandle, out x, out y); - Utils.LongToUInts(regionHandle, out rx, out ry); - - x += rx; - y += ry; - } - - /// - /// Get operating system information if available. Returns only the first 45 characters of information - /// - /// - /// Operating system information. Returns an empty string if none was available. - /// - public static string GetOperatingSystemInformation() - { - string os = String.Empty; - - if (Environment.OSVersion.Platform != PlatformID.Unix) - { - os = Environment.OSVersion.ToString(); - } - else - { - os = ReadEtcIssue(); - } - - if (os.Length > 45) - { - os = os.Substring(0, 45); - } - - return os; - } - - public static string GetRuntimeInformation() - { - string ru = String.Empty; - - if (Environment.OSVersion.Platform == PlatformID.Unix) - ru = "Unix/Mono"; - else - if (Environment.OSVersion.Platform == PlatformID.MacOSX) - ru = "OSX/Mono"; - else - { - if (Type.GetType("Mono.Runtime") != null) - ru = "Win/Mono"; - else - ru = "Win/.NET"; - } - - return ru; - } - - /// - /// Is the given string a UUID? - /// - /// - /// - public static bool isUUID(string s) - { - return UUIDPattern.IsMatch(s); - } - - public static string GetDisplayConnectionString(string connectionString) - { - int passPosition = 0; - int passEndPosition = 0; - string displayConnectionString = null; - - // hide the password in the connection string - passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); - passPosition = connectionString.IndexOf("=", passPosition); - if (passPosition < connectionString.Length) - passPosition += 1; - passEndPosition = connectionString.IndexOf(";", passPosition); - - displayConnectionString = connectionString.Substring(0, passPosition); - displayConnectionString += "***"; - displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition); - - return displayConnectionString; - } - - public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) - { - Type settingsType = settingsClass.GetType(); - - FieldInfo[] fieldInfos = settingsType.GetFields(); - foreach (FieldInfo fieldInfo in fieldInfos) - { - if (!fieldInfo.IsStatic) - { - if (fieldInfo.FieldType == typeof(System.String)) - { - fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Boolean)) - { - fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Int32)) - { - fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Single)) - { - fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.UInt32)) - { - fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); - } - } - } - - PropertyInfo[] propertyInfos = settingsType.GetProperties(); - foreach (PropertyInfo propInfo in propertyInfos) - { - if ((propInfo.CanRead) && (propInfo.CanWrite)) - { - if (propInfo.PropertyType == typeof(System.String)) - { - propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Boolean)) - { - propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Int32)) - { - propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Single)) - { - propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); - } - if (propInfo.PropertyType == typeof(System.UInt32)) - { - propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); - } - } - } - - return settingsClass; - } - - public static string Base64ToString(string str) - { - UTF8Encoding encoder = new UTF8Encoding(); - Decoder utf8Decode = encoder.GetDecoder(); - - byte[] todecode_byte = Convert.FromBase64String(str); - int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); - char[] decoded_char = new char[charCount]; - utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); - string result = new String(decoded_char); - return result; - } - - public static Guid GetHashGuid(string data, string salt) - { - byte[] hash = ComputeMD5Hash(data + salt); - - //string s = BitConverter.ToString(hash); - - Guid guid = new Guid(hash); - - return guid; - } - - public static byte ConvertMaturityToAccessLevel(uint maturity) - { - byte retVal = 0; - switch (maturity) - { - case 0: //PG - retVal = 13; - break; - case 1: //Mature - retVal = 21; - break; - case 2: // Adult - retVal = 42; - break; - } - - return retVal; - - } - - public static uint ConvertAccessLevelToMaturity(byte maturity) - { - if (maturity <= 13) - return 0; - else if (maturity <= 21) - return 1; - else - return 2; - } - - /// - /// Produces an OSDMap from its string representation on a stream - /// - /// The stream - /// The size of the data on the stream - /// The OSDMap or an exception - public static OSDMap GetOSDMap(Stream stream, int length) - { - byte[] data = new byte[length]; - stream.Read(data, 0, length); - string strdata = Util.UTF8.GetString(data); - OSDMap args = null; - OSD buffer; - buffer = OSDParser.DeserializeJson(strdata); - if (buffer.Type == OSDType.Map) - { - args = (OSDMap)buffer; - return args; - } - return null; - } - - public static OSDMap GetOSDMap(string data) - { - OSDMap args = null; - try - { - OSD buffer; - // We should pay attention to the content-type, but let's assume we know it's Json - buffer = OSDParser.DeserializeJson(data); - if (buffer.Type == OSDType.Map) - { - args = (OSDMap)buffer; - return args; - } - else - { - // uh? - m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString())); - return null; - } - } - catch (Exception ex) - { - m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message); - return null; - } - } - - public static string[] Glob(string path) - { - string vol=String.Empty; - - if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) - { - string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries); - - if (vcomps.Length > 1) - { - path = vcomps[1]; - vol = vcomps[0]; - } - } - - string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); - - // Glob - - path = vol; - if (vol != String.Empty) - path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar}); - else - path = new String(new char[] {Path.DirectorySeparatorChar}); - - List paths = new List(); - List found = new List(); - paths.Add(path); - - int compIndex = -1; - foreach (string c in comps) - { - compIndex++; - - List addpaths = new List(); - foreach (string p in paths) - { - string[] dirs = Directory.GetDirectories(p, c); - - if (dirs.Length != 0) - { - foreach (string dir in dirs) - addpaths.Add(Path.Combine(path, dir)); - } - - // Only add files if that is the last path component - if (compIndex == comps.Length - 1) - { - string[] files = Directory.GetFiles(p, c); - foreach (string f in files) - found.Add(f); - } - } - paths = addpaths; - } - - return found.ToArray(); - } - - public static string ServerURI(string uri) - { - if (uri == string.Empty) - return string.Empty; - - // Get rid of eventual slashes at the end - uri = uri.TrimEnd('/'); - - IPAddress ipaddr1 = null; - string port1 = ""; - try - { - ipaddr1 = Util.GetHostFromURL(uri); - } - catch { } - - try - { - port1 = uri.Split(new char[] { ':' })[2]; - } - catch { } - - // We tried our best to convert the domain names to IP addresses - return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - /// Arguments to substitute into the string via the {} mechanism. - /// - /// - public static byte[] StringToBytes256(string str, params object[] args) - { - return StringToBytes256(string.Format(str, args)); - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - public static byte[] StringToBytes256(string str) - { - if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } - if (str.Length > 254) str = str.Remove(254); - if (!str.EndsWith("\0")) { str += "\0"; } - - // Because this is UTF-8 encoding and not ASCII, it's possible we - // might have gotten an oversized array even after the string trim - byte[] data = UTF8.GetBytes(str); - if (data.Length > 256) - { - Array.Resize(ref data, 256); - data[255] = 0; - } - - return data; - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - /// Arguments to substitute into the string via the {} mechanism. - /// - /// - public static byte[] StringToBytes1024(string str, params object[] args) - { - return StringToBytes1024(string.Format(str, args)); - } - - /// - /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. - /// - /// - /// If null or empty, then an bytes[0] is returned. - /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] - /// - /// - public static byte[] StringToBytes1024(string str) - { - if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } - if (str.Length > 1023) str = str.Remove(1023); - if (!str.EndsWith("\0")) { str += "\0"; } - - // Because this is UTF-8 encoding and not ASCII, it's possible we - // might have gotten an oversized array even after the string trim - byte[] data = UTF8.GetBytes(str); - if (data.Length > 1024) - { - Array.Resize(ref data, 1024); - data[1023] = 0; - } - - return data; - } - - /// - /// Used to trigger an early library load on Windows systems. - /// - /// - /// Required to get 32-bit and 64-bit processes to automatically use the - /// appropriate native library. - /// - /// - /// - [DllImport("kernel32.dll")] - public static extern IntPtr LoadLibrary(string dllToLoad); - - /// - /// Determine whether the current process is 64 bit - /// - /// true if so, false if not - public static bool Is64BitProcess() - { - return IntPtr.Size == 8; - } - - #region FireAndForget Threading Pattern - - /// - /// Created to work around a limitation in Mono with nested delegates - /// - private sealed class FireAndForgetWrapper - { - private static volatile FireAndForgetWrapper instance; - private static object syncRoot = new Object(); - - public static FireAndForgetWrapper Instance { - get { - - if (instance == null) - { - lock (syncRoot) - { - if (instance == null) - { - instance = new FireAndForgetWrapper(); - } - } - } - - return instance; - } - } - - public void FireAndForget(System.Threading.WaitCallback callback) - { - callback.BeginInvoke(null, EndFireAndForget, callback); - } - - public void FireAndForget(System.Threading.WaitCallback callback, object obj) - { - callback.BeginInvoke(obj, EndFireAndForget, callback); - } - - private static void EndFireAndForget(IAsyncResult ar) - { - System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; - - try { callback.EndInvoke(ar); } - catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } - - ar.AsyncWaitHandle.Close(); - } - } - - public static void FireAndForget(System.Threading.WaitCallback callback) - { - FireAndForget(callback, null); - } - - public static void InitThreadPool(int maxThreads) - { - if (maxThreads < 2) - throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); - if (m_ThreadPool != null) - throw new InvalidOperationException("SmartThreadPool is already initialized"); - - m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); - } - - public static int FireAndForgetCount() - { - const int MAX_SYSTEM_THREADS = 200; - - switch (FireAndForgetMethod) - { - case FireAndForgetMethod.UnsafeQueueUserWorkItem: - case FireAndForgetMethod.QueueUserWorkItem: - case FireAndForgetMethod.BeginInvoke: - int workerThreads, iocpThreads; - ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); - return workerThreads; - case FireAndForgetMethod.SmartThreadPool: - return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads; - case FireAndForgetMethod.Thread: - return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count; - default: - throw new NotImplementedException(); - } - } - - public static void FireAndForget(System.Threading.WaitCallback callback, object obj) - { - WaitCallback realCallback; - - if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) - { - // If we're running regression tests, then we want any exceptions to rise up to the test code. - realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; - } - else - { - // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture - // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas - // for decimals places but is read by a culture that treats commas as number seperators. - realCallback = o => - { - Culture.SetCurrentCulture(); - - try - { - callback(o); - } - catch (Exception e) - { - m_log.ErrorFormat( - "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", - e.Message, e.StackTrace); - } - }; - } - - switch (FireAndForgetMethod) - { - case FireAndForgetMethod.RegressionTest: - case FireAndForgetMethod.None: - realCallback.Invoke(obj); - break; - case FireAndForgetMethod.UnsafeQueueUserWorkItem: - ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.QueueUserWorkItem: - ThreadPool.QueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.BeginInvoke: - FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; - wrapper.FireAndForget(realCallback, obj); - break; - case FireAndForgetMethod.SmartThreadPool: - if (m_ThreadPool == null) - m_ThreadPool = new SmartThreadPool(2000, 15, 2); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); - break; - case FireAndForgetMethod.Thread: - Thread thread = new Thread(delegate(object o) { realCallback(o); }); - thread.Start(obj); - break; - default: - throw new NotImplementedException(); - } - } - - /// - /// Get a thread pool report. - /// - /// - public static string GetThreadPoolReport() - { - string threadPoolUsed = null; - int maxThreads = 0; - int minThreads = 0; - int allocatedThreads = 0; - int inUseThreads = 0; - int waitingCallbacks = 0; - int completionPortThreads = 0; - - StringBuilder sb = new StringBuilder(); - if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; - } - else if ( - FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem - || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) - { - threadPoolUsed = "BuiltInThreadPool"; - ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); - ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); - int availableThreads; - ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); - inUseThreads = maxThreads - availableThreads; - allocatedThreads = -1; - waitingCallbacks = -1; - } - - if (threadPoolUsed != null) - { - sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); - sb.AppendFormat("Max threads : {0}\n", maxThreads); - sb.AppendFormat("Min threads : {0}\n", minThreads); - sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); - sb.AppendFormat("In use threads : {0}\n", inUseThreads); - sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); - } - else - { - sb.AppendFormat("Thread pool not used\n"); - } - - return sb.ToString(); - } - - private static object SmartThreadPoolCallback(object o) - { - object[] array = (object[])o; - WaitCallback callback = (WaitCallback)array[0]; - object obj = array[1]; - - callback(obj); - return null; - } - - #endregion FireAndForget Threading Pattern - - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap - /// for the callers. - /// This trims it to a 12 day interval so don't let your frame time get too long. - /// - /// - public static Int32 EnvironmentTickCount() - { - return Environment.TickCount & EnvironmentTickCountMask; - } - const Int32 EnvironmentTickCountMask = 0x3fffffff; - - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. Subtracts the passed value (previously fetched by - /// 'EnvironmentTickCount()') and accounts for any wrapping. - /// - /// - /// - /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue) - { - Int32 diff = newValue - prevValue; - return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); - } - - /// - /// Environment.TickCount is an int but it counts all 32 bits so it goes positive - /// and negative every 24.9 days. Subtracts the passed value (previously fetched by - /// 'EnvironmentTickCount()') and accounts for any wrapping. - /// - /// subtraction of passed prevValue from current Environment.TickCount - public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) - { - return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue); - } - - // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount - // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). - // A positive return value indicates A occured later than B - public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) - { - // A, B and TC are all between 0 and 0x3fffffff - int tc = EnvironmentTickCount(); - - if (tc - tcA >= 0) - tcA += EnvironmentTickCountMask + 1; - - if (tc - tcB >= 0) - tcB += EnvironmentTickCountMask + 1; - - return tcA - tcB; - } - - /// - /// Prints the call stack at any given point. Useful for debugging. - /// - public static void PrintCallStack() - { - StackTrace stackTrace = new StackTrace(true); // get call stack - StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) - - // write call stack method names - foreach (StackFrame stackFrame in stackFrames) - { - MethodBase mb = stackFrame.GetMethod(); - m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name - } - } - - /// - /// Gets the client IP address - /// - /// - /// - public static IPEndPoint GetClientIPFromXFF(string xff) - { - if (xff == string.Empty) - return null; - - string[] parts = xff.Split(new char[] { ',' }); - if (parts.Length > 0) - { - try - { - return new IPEndPoint(IPAddress.Parse(parts[0]), 0); - } - catch (Exception e) - { - m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message); - } - } - - return null; - } - - public static string GetCallerIP(Hashtable req) - { - if (req.ContainsKey("headers")) - { - try - { - Hashtable headers = (Hashtable)req["headers"]; - if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null) - return headers["remote_addr"].ToString(); - } - catch (Exception e) - { - m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message); - } - } - return string.Empty; - } - - #region Xml Serialization Utilities - public static bool ReadBoolean(XmlTextReader reader) - { - reader.ReadStartElement(); - bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); - reader.ReadEndElement(); - - return result; - } - - public static UUID ReadUUID(XmlTextReader reader, string name) - { - UUID id; - string idStr; - - reader.ReadStartElement(name); - - if (reader.Name == "Guid") - idStr = reader.ReadElementString("Guid"); - else if (reader.Name == "UUID") - idStr = reader.ReadElementString("UUID"); - else // no leading tag - idStr = reader.ReadContentAsString(); - UUID.TryParse(idStr, out id); - reader.ReadEndElement(); - - return id; - } - - public static Vector3 ReadVector(XmlTextReader reader, string name) - { - Vector3 vec; - - reader.ReadStartElement(name); - vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x - vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y - vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z - reader.ReadEndElement(); - - return vec; - } - - public static Quaternion ReadQuaternion(XmlTextReader reader, string name) - { - Quaternion quat = new Quaternion(); - - reader.ReadStartElement(name); - while (reader.NodeType != XmlNodeType.EndElement) - { - switch (reader.Name.ToLower()) - { - case "x": - quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "y": - quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "z": - quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - case "w": - quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); - break; - } - } - - reader.ReadEndElement(); - - return quat; - } - - public static T ReadEnum(XmlTextReader reader, string name) - { - string value = reader.ReadElementContentAsString(name, String.Empty); - // !!!!! to deal with flags without commas - if (value.Contains(" ") && !value.Contains(",")) - value = value.Replace(" ", ", "); - - return (T)Enum.Parse(typeof(T), value); ; - } - #endregion - - #region Universal User Identifiers - /// - /// - /// uuid[;endpoint[;first last[;secret]]] - /// the uuid part - /// the endpoint part (e.g. http://foo.com) - /// the first name part (e.g. Test) - /// the last name part (e.g User) - /// the secret part - public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) - { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; - - string[] parts = value.Split(';'); - if (parts.Length >= 1) - if (!UUID.TryParse(parts[0], out uuid)) - return false; - - if (parts.Length >= 2) - url = parts[1]; - - if (parts.Length >= 3) - { - string[] name = parts[2].Split(); - if (name.Length == 2) - { - firstname = name[0]; - lastname = name[1]; - } - } - if (parts.Length >= 4) - secret = parts[3]; - - return true; - } - - /// - /// Produces a universal (HG) system-facing identifier given the information - /// - /// - /// uuid[;homeURI[;first last]] - public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) - { - if (acircuit.ServiceURLs.ContainsKey("HomeURI")) - return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString()); - else - return acircuit.AgentID.ToString(); - } - - /// - /// Produces a universal (HG) system-facing identifier given the information - /// - /// UUID of the user - /// first name (e.g Test) - /// last name (e.g. User) - /// homeURI (e.g. http://foo.com) - /// a string of the form uuid[;homeURI[;first last]] - public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI) - { - string agentsURI = homeURI; - if (!agentsURI.EndsWith("/")) - agentsURI += "/"; - - // This is ugly, but there's no other way, given that the name is changed - // in the agent circuit data for foreigners - if (lastName.Contains("@")) - { - string[] parts = firstName.Split(new char[] { '.' }); - if (parts.Length == 2) - return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; - } - return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; - - } - - /// - /// Produces a universal (HG) user-facing name given the information - /// - /// - /// - /// - /// string of the form first.last @foo.com or first last - public static string UniversalName(String firstName, String lastName, String homeURI) - { - Uri uri = null; - try - { - uri = new Uri(homeURI); - } - catch (UriFormatException) - { - return firstName + " " + lastName; - } - return firstName + "." + lastName + " " + "@" + uri.Authority; - } - #endregion - } -} +/* + * 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.Collections; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.IO.Compression; +using System.Net; +using System.Net.Sockets; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Runtime.Serialization.Formatters.Binary; +using System.Security.Cryptography; +using System.Text; +using System.Text.RegularExpressions; +using System.Xml; +using System.Threading; +using log4net; +using Nini.Config; +using Nwc.XmlRpc; +using OpenMetaverse; +using OpenMetaverse.StructuredData; +using Amib.Threading; + +namespace OpenSim.Framework +{ + /// + /// The method used by Util.FireAndForget for asynchronously firing events + /// + /// + /// None is used to execute the method in the same thread that made the call. It should only be used by regression + /// test code that relies on predictable event ordering. + /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions. + /// + public enum FireAndForgetMethod + { + None, + RegressionTest, + UnsafeQueueUserWorkItem, + QueueUserWorkItem, + BeginInvoke, + SmartThreadPool, + Thread, + } + + /// + /// Miscellaneous utility functions + /// + public class Util + { + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + private static uint nextXferID = 5000; + private static Random randomClass = new Random(); + + // Get a list of invalid file characters (OS dependent) + private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; + private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; + private static object XferLock = new object(); + + /// + /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used + /// + private static SmartThreadPool m_ThreadPool; + + // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. + private static readonly DateTime unixEpoch = + DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); + + private static readonly string rawUUIDPattern + = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}"; + public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern); + public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern)); + + public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; + public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; + + /// + /// Gets the name of the directory where the current running executable + /// is located + /// + /// Filesystem path to the directory containing the current + /// executable + public static string ExecutingDirectory() + { + return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); + } + + /// + /// Linear interpolates B<->C using percent A + /// + /// + /// + /// + /// + public static double lerp(double a, double b, double c) + { + return (b*a) + (c*(1 - a)); + } + + /// + /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y. + /// Layout: + /// A B + /// C D + /// A<->C = Y + /// C<->D = X + /// + /// + /// + /// + /// + /// + /// + /// + public static double lerp2D(double x, double y, double a, double b, double c, double d) + { + return lerp(y, lerp(x, a, b), lerp(x, c, d)); + } + + public static Encoding UTF8 = Encoding.UTF8; + + /// + /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) + /// + public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); + + #region Vector Equations + + /// + /// Get the distance between two 3d vectors + /// + /// A 3d vector + /// A 3d vector + /// The distance between the two vectors + public static double GetDistanceTo(Vector3 a, Vector3 b) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return Math.Sqrt(dx * dx + dy * dy + dz * dz); + } + + /// + /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt. + /// + /// + /// + /// + /// + public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount) + { + float dx = a.X - b.X; + float dy = a.Y - b.Y; + float dz = a.Z - b.Z; + return (dx*dx + dy*dy + dz*dz) < (amount*amount); + } + + /// + /// Get the magnitude of a 3d vector + /// + /// A 3d vector + /// The magnitude of the vector + public static double GetMagnitude(Vector3 a) + { + return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z)); + } + + /// + /// Get a normalized form of a 3d vector + /// + /// A 3d vector + /// A new vector which is normalized form of the vector + /// The vector paramater cannot be <0,0,0> + public static Vector3 GetNormalizedVector(Vector3 a) + { + if (IsZeroVector(a)) + throw new ArgumentException("Vector paramater cannot be a zero vector."); + + float Mag = (float) GetMagnitude(a); + return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); + } + + /// + /// Returns if a vector is a zero vector (has all zero components) + /// + /// + public static bool IsZeroVector(Vector3 v) + { + if (v.X == 0 && v.Y == 0 && v.Z == 0) + { + return true; + } + + return false; + } + + # endregion + + public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up) + { + float s; + float tr = (float) (fwd.X + left.Y + up.Z + 1.0); + + if (tr >= 1.0) + { + s = (float) (0.5 / Math.Sqrt(tr)); + return new Quaternion( + (left.Z - up.Y) * s, + (up.X - fwd.Z) * s, + (fwd.Y - left.X) * s, + (float) 0.25 / s); + } + else + { + float max = (left.Y > up.Z) ? left.Y : up.Z; + + if (max < fwd.X) + { + s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0)); + float x = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + x, + (fwd.Y + left.X) * s, + (up.X + fwd.Z) * s, + (left.Z - up.Y) * s); + } + else if (max == left.Y) + { + s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0)); + float y = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + (fwd.Y + left.X) * s, + y, + (left.Z + up.Y) * s, + (up.X - fwd.Z) * s); + } + else + { + s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0)); + float z = (float) (s * 0.5); + s = (float) (0.5 / s); + return new Quaternion( + (up.X + fwd.Z) * s, + (left.Z + up.Y) * s, + z, + (fwd.Y - left.X) * s); + } + } + } + + public static Random RandomClass + { + get { return randomClass; } + } + + public static ulong UIntsToLong(uint X, uint Y) + { + return Utils.UIntsToLong(X, Y); + } + + public static T Clamp(T x, T min, T max) + where T : IComparable + { + return x.CompareTo(max) > 0 ? max : + x.CompareTo(min) < 0 ? min : + x; + } + + public static uint GetNextXferID() + { + uint id = 0; + lock (XferLock) + { + id = nextXferID; + nextXferID++; + } + return id; + } + + public static string GetFileName(string file) + { + // Return just the filename on UNIX platforms + // TODO: this should be customisable with a prefix, but that's something to do later. + if (Environment.OSVersion.Platform == PlatformID.Unix) + { + return file; + } + + // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA + // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData + if (Environment.OSVersion.Platform == PlatformID.Win32NT) + { + if (!Directory.Exists("%APPDATA%\\OpenSim\\")) + { + Directory.CreateDirectory("%APPDATA%\\OpenSim"); + } + + return "%APPDATA%\\OpenSim\\" + file; + } + + // Catch all - covers older windows versions + // (but those probably wont work anyway) + return file; + } + + /// + /// Debug utility function to convert OSD into formatted XML for debugging purposes. + /// + /// + /// A + /// + /// + /// A + /// + public static string GetFormattedXml(OSD osd) + { + return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd)); + } + + /// + /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes. + /// + /// + /// Please don't delete me even if I appear currently unused! + /// + /// + /// + public static string GetFormattedXml(string rawXml) + { + XmlDocument xd = new XmlDocument(); + xd.LoadXml(rawXml); + + StringBuilder sb = new StringBuilder(); + StringWriter sw = new StringWriter(sb); + + XmlTextWriter xtw = new XmlTextWriter(sw); + xtw.Formatting = Formatting.Indented; + + try + { + xd.WriteTo(xtw); + } + finally + { + xtw.Close(); + } + + return sb.ToString(); + } + + /// + /// Is the platform Windows? + /// + /// true if so, false otherwise + public static bool IsWindows() + { + PlatformID platformId = Environment.OSVersion.Platform; + + return (platformId == PlatformID.Win32NT + || platformId == PlatformID.Win32S + || platformId == PlatformID.Win32Windows + || platformId == PlatformID.WinCE); + } + + public static bool LoadArchSpecificWindowsDll(string libraryName) + { + // We do this so that OpenSimulator on Windows loads the correct native library depending on whether + // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports + // will find it already loaded later on. + // + // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be + // controlled in config files. + string nativeLibraryPath; + + if (Util.Is64BitProcess()) + nativeLibraryPath = "lib64/" + libraryName; + else + nativeLibraryPath = "lib32/" + libraryName; + + m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); + + if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero) + { + m_log.ErrorFormat( + "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath); + + return false; + } + else + { + return true; + } + } + + public static bool IsEnvironmentSupported(ref string reason) + { + // Must have .NET 2.0 (Generics / libsl) + if (Environment.Version.Major < 2) + { + reason = ".NET 1.0/1.1 lacks components that is used by OpenSim"; + return false; + } + + // Windows 95/98/ME are unsupported + if (Environment.OSVersion.Platform == PlatformID.Win32Windows && + Environment.OSVersion.Platform != PlatformID.Win32NT) + { + reason = "Windows 95/98/ME will not run OpenSim"; + return false; + } + + // Windows 2000 / Pre-SP2 XP + if (Environment.OSVersion.Version.Major == 5 && + Environment.OSVersion.Version.Minor == 0) + { + reason = "Please update to Windows XP Service Pack 2 or Server2003"; + return false; + } + + return true; + } + + public static int UnixTimeSinceEpoch() + { + return ToUnixTime(DateTime.UtcNow); + } + + public static int ToUnixTime(DateTime stamp) + { + TimeSpan t = stamp.ToUniversalTime() - unixEpoch; + return (int) t.TotalSeconds; + } + + public static DateTime ToDateTime(ulong seconds) + { + DateTime epoch = unixEpoch; + return epoch.AddSeconds(seconds); + } + + public static DateTime ToDateTime(int seconds) + { + DateTime epoch = unixEpoch; + return epoch.AddSeconds(seconds); + } + + /// + /// Return an md5 hash of the given string + /// + /// + /// + public static string Md5Hash(string data) + { + byte[] dataMd5 = ComputeMD5Hash(data); + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < dataMd5.Length; i++) + sb.AppendFormat("{0:x2}", dataMd5[i]); + return sb.ToString(); + } + + private static byte[] ComputeMD5Hash(string data) + { + MD5 md5 = MD5.Create(); + return md5.ComputeHash(Encoding.Default.GetBytes(data)); + } + + /// + /// Return an SHA1 hash + /// + /// + /// + public static string SHA1Hash(string data) + { + return SHA1Hash(Encoding.Default.GetBytes(data)); + } + + /// + /// Return an SHA1 hash + /// + /// + /// + public static string SHA1Hash(byte[] data) + { + byte[] hash = ComputeSHA1Hash(data); + return BitConverter.ToString(hash).Replace("-", String.Empty); + } + + private static byte[] ComputeSHA1Hash(byte[] src) + { + SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); + return SHA1.ComputeHash(src); + } + + public static int fast_distance2d(int x, int y) + { + x = Math.Abs(x); + y = Math.Abs(y); + + int min = Math.Min(x, y); + + return (x + y - (min >> 1) - (min >> 2) + (min >> 4)); + } + + /// + /// Are the co-ordinates of the new region visible from the old region? + /// + /// Old region x-coord + /// New region x-coord + /// Old region y-coord + /// New region y-coord + /// + public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) + { + int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); + + int startX = (int)oldx - dd; + int startY = (int)oldy - dd; + + int endX = (int)oldx + dd; + int endY = (int)oldy + dd; + + return (newx < startX || endX < newx || newy < startY || endY < newy); + } + + public static string FieldToString(byte[] bytes) + { + return FieldToString(bytes, String.Empty); + } + + /// + /// Convert a variable length field (byte array) to a string, with a + /// field name prepended to each line of the output + /// + /// If the byte array has unprintable characters in it, a + /// hex dump will be put in the string instead + /// The byte array to convert to a string + /// A field name to prepend to each line of output + /// An ASCII string or a string containing a hex dump, minus + /// the null terminator + public static string FieldToString(byte[] bytes, string fieldName) + { + // Check for a common case + if (bytes.Length == 0) return String.Empty; + + StringBuilder output = new StringBuilder(); + bool printable = true; + + for (int i = 0; i < bytes.Length; ++i) + { + // Check if there are any unprintable characters in the array + if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09 + && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00) + { + printable = false; + break; + } + } + + if (printable) + { + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1))); + } + else + { + for (int i = 0; i < bytes.Length; i += 16) + { + if (i != 0) + output.Append(Environment.NewLine); + if (fieldName.Length > 0) + { + output.Append(fieldName); + output.Append(": "); + } + + for (int j = 0; j < 16; j++) + { + if ((i + j) < bytes.Length) + output.Append(String.Format("{0:X2} ", bytes[i + j])); + else + output.Append(" "); + } + + for (int j = 0; j < 16 && (i + j) < bytes.Length; j++) + { + if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E) + output.Append((char) bytes[i + j]); + else + output.Append("."); + } + } + } + + return output.ToString(); + } + + /// + /// Converts a URL to a IPAddress + /// + /// URL Standard Format + /// A resolved IP Address + public static IPAddress GetHostFromURL(string url) + { + return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); + } + + /// + /// Returns a IP address from a specified DNS, favouring IPv4 addresses. + /// + /// DNS Hostname + /// An IP address, or null + public static IPAddress GetHostFromDNS(string dnsAddress) + { + // Is it already a valid IP? No need to look it up. + IPAddress ipa; + if (IPAddress.TryParse(dnsAddress, out ipa)) + return ipa; + + IPAddress[] hosts = null; + + // Not an IP, lookup required + try + { + hosts = Dns.GetHostEntry(dnsAddress).AddressList; + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); + + // Still going to throw the exception on for now, since this was what was happening in the first place + throw e; + } + + foreach (IPAddress host in hosts) + { + if (host.AddressFamily == AddressFamily.InterNetwork) + { + return host; + } + } + + if (hosts.Length > 0) + return hosts[0]; + + return null; + } + + public static Uri GetURI(string protocol, string hostname, int port, string path) + { + return new UriBuilder(protocol, hostname, port, path).Uri; + } + + /// + /// Gets a list of all local system IP addresses + /// + /// + public static IPAddress[] GetLocalHosts() + { + return Dns.GetHostAddresses(Dns.GetHostName()); + } + + public static IPAddress GetLocalHost() + { + IPAddress[] iplist = GetLocalHosts(); + + if (iplist.Length == 0) // No accessible external interfaces + { + IPAddress[] loopback = Dns.GetHostAddresses("localhost"); + IPAddress localhost = loopback[0]; + + return localhost; + } + + foreach (IPAddress host in iplist) + { + if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork) + { + return host; + } + } + + if (iplist.Length > 0) + { + foreach (IPAddress host in iplist) + { + if (host.AddressFamily == AddressFamily.InterNetwork) + return host; + } + // Well all else failed... + return iplist[0]; + } + + return null; + } + + /// + /// Removes all invalid path chars (OS dependent) + /// + /// path + /// safe path + public static string safePath(string path) + { + return Regex.Replace(path, regexInvalidPathChars, String.Empty); + } + + /// + /// Removes all invalid filename chars (OS dependent) + /// + /// filename + /// safe filename + public static string safeFileName(string filename) + { + return Regex.Replace(filename, regexInvalidFileChars, String.Empty); + ; + } + + // + // directory locations + // + + public static string homeDir() + { + string temp; + // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal)); + // temp = Path.Combine(personal,".OpenSim"); + temp = "."; + return temp; + } + + public static string assetsDir() + { + return Path.Combine(configDir(), "assets"); + } + + public static string inventoryDir() + { + return Path.Combine(configDir(), "inventory"); + } + + public static string configDir() + { + return "."; + } + + public static string dataDir() + { + return "."; + } + + public static string logDir() + { + return "."; + } + + // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html + public static string GetUniqueFilename(string FileName) + { + int count = 0; + string Name; + + if (File.Exists(FileName)) + { + FileInfo f = new FileInfo(FileName); + + if (!String.IsNullOrEmpty(f.Extension)) + { + Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.')); + } + else + { + Name = f.FullName; + } + + while (File.Exists(FileName)) + { + count++; + FileName = Name + count + f.Extension; + } + } + return FileName; + } + + // Nini (config) related Methods + public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) + { + if (!File.Exists(fileName)) + { + //create new file + } + XmlConfigSource config = new XmlConfigSource(fileName); + AddDataRowToConfig(config, row); + config.Save(); + + return config; + } + + public static void AddDataRowToConfig(IConfigSource config, DataRow row) + { + config.Configs.Add((string) row[0]); + for (int i = 0; i < row.Table.Columns.Count; i++) + { + config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]); + } + } + + public static float Clip(float x, float min, float max) + { + return Math.Min(Math.Max(x, min), max); + } + + public static int Clip(int x, int min, int max) + { + return Math.Min(Math.Max(x, min), max); + } + + /// + /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. + /// + /// + /// + public static String ToRawUuidString(UUID UUID) + { + return UUID.Guid.ToString("n"); + } + + public static string CleanString(string input) + { + if (input.Length == 0) + return input; + + int clip = input.Length; + + // Test for ++ string terminator + int pos = input.IndexOf("\0"); + if (pos != -1 && pos < clip) + clip = pos; + + // Test for CR + pos = input.IndexOf("\r"); + if (pos != -1 && pos < clip) + clip = pos; + + // Test for LF + pos = input.IndexOf("\n"); + if (pos != -1 && pos < clip) + clip = pos; + + // Truncate string before first end-of-line character found + return input.Substring(0, clip); + } + + /// + /// returns the contents of /etc/issue on Unix Systems + /// Use this for where it's absolutely necessary to implement platform specific stuff + /// + /// + public static string ReadEtcIssue() + { + try + { + StreamReader sr = new StreamReader("/etc/issue.net"); + string issue = sr.ReadToEnd(); + sr.Close(); + return issue; + } + catch (Exception) + { + return ""; + } + } + + public static void SerializeToFile(string filename, Object obj) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + + try + { + stream = new FileStream( + filename, FileMode.Create, + FileAccess.Write, FileShare.None); + + formatter.Serialize(stream, obj); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + } + + public static Object DeserializeFromFile(string filename) + { + IFormatter formatter = new BinaryFormatter(); + Stream stream = null; + Object ret = null; + + try + { + stream = new FileStream( + filename, FileMode.Open, + FileAccess.Read, FileShare.None); + + ret = formatter.Deserialize(stream); + } + catch (Exception e) + { + m_log.Error(e.ToString()); + } + finally + { + if (stream != null) + { + stream.Close(); + } + } + + return ret; + } + + public static string Compress(string text) + { + byte[] buffer = Util.UTF8.GetBytes(text); + MemoryStream memory = new MemoryStream(); + using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) + { + compressor.Write(buffer, 0, buffer.Length); + } + + memory.Position = 0; + + byte[] compressed = new byte[memory.Length]; + memory.Read(compressed, 0, compressed.Length); + + byte[] compressedBuffer = new byte[compressed.Length + 4]; + Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); + Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); + return Convert.ToBase64String(compressedBuffer); + } + + public static string Decompress(string compressedText) + { + byte[] compressedBuffer = Convert.FromBase64String(compressedText); + using (MemoryStream memory = new MemoryStream()) + { + int msgLength = BitConverter.ToInt32(compressedBuffer, 0); + memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); + + byte[] buffer = new byte[msgLength]; + + memory.Position = 0; + using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) + { + decompressor.Read(buffer, 0, buffer.Length); + } + + return Util.UTF8.GetString(buffer); + } + } + + public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) + { + return SendXmlRpcCommand(url, methodName, args); + } + + public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args) + { + XmlRpcRequest client = new XmlRpcRequest(methodName, args); + return client.Send(url, 6000); + } + + /// + /// Returns an error message that the user could not be found in the database + /// + /// XML string consisting of a error element containing individual error(s) + public static XmlRpcResponse CreateUnknownUserErrorResponse() + { + XmlRpcResponse response = new XmlRpcResponse(); + Hashtable responseData = new Hashtable(); + responseData["error_type"] = "unknown_user"; + responseData["error_desc"] = "The user requested is not in the database"; + + response.Value = responseData; + return response; + } + + /// + /// Converts a byte array in big endian order into an ulong. + /// + /// + /// The array of bytes + /// + /// + /// The extracted ulong + /// + public static ulong BytesToUInt64Big(byte[] bytes) + { + if (bytes.Length < 8) return 0; + return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) | + ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7]; + } + + // used for RemoteParcelRequest (for "About Landmark") + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y) + { + byte[] bytes = + { + (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)x, (byte)(x >> 8), 0, 0, + (byte)y, (byte)(y >> 8), 0, 0 }; + return new UUID(bytes, 0); + } + + public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z) + { + byte[] bytes = + { + (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), + (byte)y, (byte)(y >> 8), 0, 0 }; + return new UUID(bytes, 0); + } + + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) + { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8) & 0xffff; + y = Utils.BytesToUInt(bytes, 12) & 0xffff; + } + + public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) + { + byte[] bytes = parcelID.GetBytes(); + regionHandle = Utils.BytesToUInt64(bytes); + x = Utils.BytesToUInt(bytes, 8) & 0xffff; + z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16; + y = Utils.BytesToUInt(bytes, 12) & 0xffff; + } + + public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y) + { + ulong regionHandle; + uint rx, ry; + + ParseFakeParcelID(parcelID, out regionHandle, out x, out y); + Utils.LongToUInts(regionHandle, out rx, out ry); + + x += rx; + y += ry; + } + + /// + /// Get operating system information if available. Returns only the first 45 characters of information + /// + /// + /// Operating system information. Returns an empty string if none was available. + /// + public static string GetOperatingSystemInformation() + { + string os = String.Empty; + + if (Environment.OSVersion.Platform != PlatformID.Unix) + { + os = Environment.OSVersion.ToString(); + } + else + { + os = ReadEtcIssue(); + } + + if (os.Length > 45) + { + os = os.Substring(0, 45); + } + + return os; + } + + public static string GetRuntimeInformation() + { + string ru = String.Empty; + + if (Environment.OSVersion.Platform == PlatformID.Unix) + ru = "Unix/Mono"; + else + if (Environment.OSVersion.Platform == PlatformID.MacOSX) + ru = "OSX/Mono"; + else + { + if (Type.GetType("Mono.Runtime") != null) + ru = "Win/Mono"; + else + ru = "Win/.NET"; + } + + return ru; + } + + /// + /// Is the given string a UUID? + /// + /// + /// + public static bool isUUID(string s) + { + return UUIDPattern.IsMatch(s); + } + + public static string GetDisplayConnectionString(string connectionString) + { + int passPosition = 0; + int passEndPosition = 0; + string displayConnectionString = null; + + // hide the password in the connection string + passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); + passPosition = connectionString.IndexOf("=", passPosition); + if (passPosition < connectionString.Length) + passPosition += 1; + passEndPosition = connectionString.IndexOf(";", passPosition); + + displayConnectionString = connectionString.Substring(0, passPosition); + displayConnectionString += "***"; + displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition); + + return displayConnectionString; + } + + public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) + { + Type settingsType = settingsClass.GetType(); + + FieldInfo[] fieldInfos = settingsType.GetFields(); + foreach (FieldInfo fieldInfo in fieldInfos) + { + if (!fieldInfo.IsStatic) + { + if (fieldInfo.FieldType == typeof(System.String)) + { + fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Boolean)) + { + fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Int32)) + { + fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Single)) + { + fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.UInt32)) + { + fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + } + } + } + + PropertyInfo[] propertyInfos = settingsType.GetProperties(); + foreach (PropertyInfo propInfo in propertyInfos) + { + if ((propInfo.CanRead) && (propInfo.CanWrite)) + { + if (propInfo.PropertyType == typeof(System.String)) + { + propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Boolean)) + { + propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Int32)) + { + propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Single)) + { + propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); + } + if (propInfo.PropertyType == typeof(System.UInt32)) + { + propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); + } + } + } + + return settingsClass; + } + + public static string Base64ToString(string str) + { + UTF8Encoding encoder = new UTF8Encoding(); + Decoder utf8Decode = encoder.GetDecoder(); + + byte[] todecode_byte = Convert.FromBase64String(str); + int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); + char[] decoded_char = new char[charCount]; + utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0); + string result = new String(decoded_char); + return result; + } + + public static Guid GetHashGuid(string data, string salt) + { + byte[] hash = ComputeMD5Hash(data + salt); + + //string s = BitConverter.ToString(hash); + + Guid guid = new Guid(hash); + + return guid; + } + + public static byte ConvertMaturityToAccessLevel(uint maturity) + { + byte retVal = 0; + switch (maturity) + { + case 0: //PG + retVal = 13; + break; + case 1: //Mature + retVal = 21; + break; + case 2: // Adult + retVal = 42; + break; + } + + return retVal; + + } + + public static uint ConvertAccessLevelToMaturity(byte maturity) + { + if (maturity <= 13) + return 0; + else if (maturity <= 21) + return 1; + else + return 2; + } + + /// + /// Produces an OSDMap from its string representation on a stream + /// + /// The stream + /// The size of the data on the stream + /// The OSDMap or an exception + public static OSDMap GetOSDMap(Stream stream, int length) + { + byte[] data = new byte[length]; + stream.Read(data, 0, length); + string strdata = Util.UTF8.GetString(data); + OSDMap args = null; + OSD buffer; + buffer = OSDParser.DeserializeJson(strdata); + if (buffer.Type == OSDType.Map) + { + args = (OSDMap)buffer; + return args; + } + return null; + } + + public static OSDMap GetOSDMap(string data) + { + OSDMap args = null; + try + { + OSD buffer; + // We should pay attention to the content-type, but let's assume we know it's Json + buffer = OSDParser.DeserializeJson(data); + if (buffer.Type == OSDType.Map) + { + args = (OSDMap)buffer; + return args; + } + else + { + // uh? + m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString())); + return null; + } + } + catch (Exception ex) + { + m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message); + return null; + } + } + + public static string[] Glob(string path) + { + string vol=String.Empty; + + if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar) + { + string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries); + + if (vcomps.Length > 1) + { + path = vcomps[1]; + vol = vcomps[0]; + } + } + + string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); + + // Glob + + path = vol; + if (vol != String.Empty) + path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar}); + else + path = new String(new char[] {Path.DirectorySeparatorChar}); + + List paths = new List(); + List found = new List(); + paths.Add(path); + + int compIndex = -1; + foreach (string c in comps) + { + compIndex++; + + List addpaths = new List(); + foreach (string p in paths) + { + string[] dirs = Directory.GetDirectories(p, c); + + if (dirs.Length != 0) + { + foreach (string dir in dirs) + addpaths.Add(Path.Combine(path, dir)); + } + + // Only add files if that is the last path component + if (compIndex == comps.Length - 1) + { + string[] files = Directory.GetFiles(p, c); + foreach (string f in files) + found.Add(f); + } + } + paths = addpaths; + } + + return found.ToArray(); + } + + public static string ServerURI(string uri) + { + if (uri == string.Empty) + return string.Empty; + + // Get rid of eventual slashes at the end + uri = uri.TrimEnd('/'); + + IPAddress ipaddr1 = null; + string port1 = ""; + try + { + ipaddr1 = Util.GetHostFromURL(uri); + } + catch { } + + try + { + port1 = uri.Split(new char[] { ':' })[2]; + } + catch { } + + // We tried our best to convert the domain names to IP addresses + return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// + public static byte[] StringToBytes256(string str, params object[] args) + { + return StringToBytes256(string.Format(str, args)); + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + public static byte[] StringToBytes256(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (str.Length > 254) str = str.Remove(254); + if (!str.EndsWith("\0")) { str += "\0"; } + + // Because this is UTF-8 encoding and not ASCII, it's possible we + // might have gotten an oversized array even after the string trim + byte[] data = UTF8.GetBytes(str); + if (data.Length > 256) + { + Array.Resize(ref data, 256); + data[255] = 0; + } + + return data; + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + /// Arguments to substitute into the string via the {} mechanism. + /// + /// + public static byte[] StringToBytes1024(string str, params object[] args) + { + return StringToBytes1024(string.Format(str, args)); + } + + /// + /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary. + /// + /// + /// If null or empty, then an bytes[0] is returned. + /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] + /// + /// + public static byte[] StringToBytes1024(string str) + { + if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; } + if (str.Length > 1023) str = str.Remove(1023); + if (!str.EndsWith("\0")) { str += "\0"; } + + // Because this is UTF-8 encoding and not ASCII, it's possible we + // might have gotten an oversized array even after the string trim + byte[] data = UTF8.GetBytes(str); + if (data.Length > 1024) + { + Array.Resize(ref data, 1024); + data[1023] = 0; + } + + return data; + } + + /// + /// Used to trigger an early library load on Windows systems. + /// + /// + /// Required to get 32-bit and 64-bit processes to automatically use the + /// appropriate native library. + /// + /// + /// + [DllImport("kernel32.dll")] + public static extern IntPtr LoadLibrary(string dllToLoad); + + /// + /// Determine whether the current process is 64 bit + /// + /// true if so, false if not + public static bool Is64BitProcess() + { + return IntPtr.Size == 8; + } + + #region FireAndForget Threading Pattern + + /// + /// Created to work around a limitation in Mono with nested delegates + /// + private sealed class FireAndForgetWrapper + { + private static volatile FireAndForgetWrapper instance; + private static object syncRoot = new Object(); + + public static FireAndForgetWrapper Instance { + get { + + if (instance == null) + { + lock (syncRoot) + { + if (instance == null) + { + instance = new FireAndForgetWrapper(); + } + } + } + + return instance; + } + } + + public void FireAndForget(System.Threading.WaitCallback callback) + { + callback.BeginInvoke(null, EndFireAndForget, callback); + } + + public void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + callback.BeginInvoke(obj, EndFireAndForget, callback); + } + + private static void EndFireAndForget(IAsyncResult ar) + { + System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState; + + try { callback.EndInvoke(ar); } + catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); } + + ar.AsyncWaitHandle.Close(); + } + } + + public static void FireAndForget(System.Threading.WaitCallback callback) + { + FireAndForget(callback, null); + } + + public static void InitThreadPool(int maxThreads) + { + if (maxThreads < 2) + throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (m_ThreadPool != null) + throw new InvalidOperationException("SmartThreadPool is already initialized"); + + m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); + } + + public static int FireAndForgetCount() + { + const int MAX_SYSTEM_THREADS = 200; + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + case FireAndForgetMethod.QueueUserWorkItem: + case FireAndForgetMethod.BeginInvoke: + int workerThreads, iocpThreads; + ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads); + return workerThreads; + case FireAndForgetMethod.SmartThreadPool: + return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads; + case FireAndForgetMethod.Thread: + return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count; + default: + throw new NotImplementedException(); + } + } + + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) + { + WaitCallback realCallback; + + if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + { + // If we're running regression tests, then we want any exceptions to rise up to the test code. + realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; + } + else + { + // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture + // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas + // for decimals places but is read by a culture that treats commas as number seperators. + realCallback = o => + { + Culture.SetCurrentCulture(); + + try + { + callback(o); + } + catch (Exception e) + { + m_log.ErrorFormat( + "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", + e.Message, e.StackTrace); + } + }; + } + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.RegressionTest: + case FireAndForgetMethod.None: + realCallback.Invoke(obj); + break; + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.QueueUserWorkItem: + ThreadPool.QueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.BeginInvoke: + FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; + wrapper.FireAndForget(realCallback, obj); + break; + case FireAndForgetMethod.SmartThreadPool: + if (m_ThreadPool == null) + m_ThreadPool = new SmartThreadPool(2000, 15, 2); + m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); + break; + case FireAndForgetMethod.Thread: + Thread thread = new Thread(delegate(object o) { realCallback(o); }); + thread.Start(obj); + break; + default: + throw new NotImplementedException(); + } + } + + /// + /// Get a thread pool report. + /// + /// + public static string GetThreadPoolReport() + { + string threadPoolUsed = null; + int maxThreads = 0; + int minThreads = 0; + int allocatedThreads = 0; + int inUseThreads = 0; + int waitingCallbacks = 0; + int completionPortThreads = 0; + + StringBuilder sb = new StringBuilder(); + if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = m_ThreadPool.MaxThreads; + minThreads = m_ThreadPool.MinThreads; + inUseThreads = m_ThreadPool.InUseThreads; + allocatedThreads = m_ThreadPool.ActiveThreads; + waitingCallbacks = m_ThreadPool.WaitingCallbacks; + } + else if ( + FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem + || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) + { + threadPoolUsed = "BuiltInThreadPool"; + ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); + ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); + int availableThreads; + ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); + inUseThreads = maxThreads - availableThreads; + allocatedThreads = -1; + waitingCallbacks = -1; + } + + if (threadPoolUsed != null) + { + sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); + sb.AppendFormat("Max threads : {0}\n", maxThreads); + sb.AppendFormat("Min threads : {0}\n", minThreads); + sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); + sb.AppendFormat("In use threads : {0}\n", inUseThreads); + sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); + } + else + { + sb.AppendFormat("Thread pool not used\n"); + } + + return sb.ToString(); + } + + private static object SmartThreadPoolCallback(object o) + { + object[] array = (object[])o; + WaitCallback callback = (WaitCallback)array[0]; + object obj = array[1]; + + callback(obj); + return null; + } + + #endregion FireAndForget Threading Pattern + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap + /// for the callers. + /// This trims it to a 12 day interval so don't let your frame time get too long. + /// + /// + public static Int32 EnvironmentTickCount() + { + return Environment.TickCount & EnvironmentTickCountMask; + } + const Int32 EnvironmentTickCountMask = 0x3fffffff; + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue) + { + Int32 diff = newValue - prevValue; + return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1); + } + + /// + /// Environment.TickCount is an int but it counts all 32 bits so it goes positive + /// and negative every 24.9 days. Subtracts the passed value (previously fetched by + /// 'EnvironmentTickCount()') and accounts for any wrapping. + /// + /// subtraction of passed prevValue from current Environment.TickCount + public static Int32 EnvironmentTickCountSubtract(Int32 prevValue) + { + return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue); + } + + // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount + // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount(). + // A positive return value indicates A occured later than B + public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB) + { + // A, B and TC are all between 0 and 0x3fffffff + int tc = EnvironmentTickCount(); + + if (tc - tcA >= 0) + tcA += EnvironmentTickCountMask + 1; + + if (tc - tcB >= 0) + tcB += EnvironmentTickCountMask + 1; + + return tcA - tcB; + } + + /// + /// Prints the call stack at any given point. Useful for debugging. + /// + public static void PrintCallStack() + { + StackTrace stackTrace = new StackTrace(true); // get call stack + StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) + + // write call stack method names + foreach (StackFrame stackFrame in stackFrames) + { + MethodBase mb = stackFrame.GetMethod(); + m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name + } + } + + /// + /// Gets the client IP address + /// + /// + /// + public static IPEndPoint GetClientIPFromXFF(string xff) + { + if (xff == string.Empty) + return null; + + string[] parts = xff.Split(new char[] { ',' }); + if (parts.Length > 0) + { + try + { + return new IPEndPoint(IPAddress.Parse(parts[0]), 0); + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message); + } + } + + return null; + } + + public static string GetCallerIP(Hashtable req) + { + if (req.ContainsKey("headers")) + { + try + { + Hashtable headers = (Hashtable)req["headers"]; + if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null) + return headers["remote_addr"].ToString(); + } + catch (Exception e) + { + m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message); + } + } + return string.Empty; + } + + #region Xml Serialization Utilities + public static bool ReadBoolean(XmlTextReader reader) + { + reader.ReadStartElement(); + bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); + reader.ReadEndElement(); + + return result; + } + + public static UUID ReadUUID(XmlTextReader reader, string name) + { + UUID id; + string idStr; + + reader.ReadStartElement(name); + + if (reader.Name == "Guid") + idStr = reader.ReadElementString("Guid"); + else if (reader.Name == "UUID") + idStr = reader.ReadElementString("UUID"); + else // no leading tag + idStr = reader.ReadContentAsString(); + UUID.TryParse(idStr, out id); + reader.ReadEndElement(); + + return id; + } + + public static Vector3 ReadVector(XmlTextReader reader, string name) + { + Vector3 vec; + + reader.ReadStartElement(name); + vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x + vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y + vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z + reader.ReadEndElement(); + + return vec; + } + + public static Quaternion ReadQuaternion(XmlTextReader reader, string name) + { + Quaternion quat = new Quaternion(); + + reader.ReadStartElement(name); + while (reader.NodeType != XmlNodeType.EndElement) + { + switch (reader.Name.ToLower()) + { + case "x": + quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "y": + quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "z": + quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + case "w": + quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty); + break; + } + } + + reader.ReadEndElement(); + + return quat; + } + + public static T ReadEnum(XmlTextReader reader, string name) + { + string value = reader.ReadElementContentAsString(name, String.Empty); + // !!!!! to deal with flags without commas + if (value.Contains(" ") && !value.Contains(",")) + value = value.Replace(" ", ", "); + + return (T)Enum.Parse(typeof(T), value); ; + } + #endregion + + #region Universal User Identifiers + /// + /// + /// uuid[;endpoint[;first last[;secret]]] + /// the uuid part + /// the endpoint part (e.g. http://foo.com) + /// the first name part (e.g. Test) + /// the last name part (e.g User) + /// the secret part + public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) + { + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; + + string[] parts = value.Split(';'); + if (parts.Length >= 1) + if (!UUID.TryParse(parts[0], out uuid)) + return false; + + if (parts.Length >= 2) + url = parts[1]; + + if (parts.Length >= 3) + { + string[] name = parts[2].Split(); + if (name.Length == 2) + { + firstname = name[0]; + lastname = name[1]; + } + } + if (parts.Length >= 4) + secret = parts[3]; + + return true; + } + + /// + /// Produces a universal (HG) system-facing identifier given the information + /// + /// + /// uuid[;homeURI[;first last]] + public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit) + { + if (acircuit.ServiceURLs.ContainsKey("HomeURI")) + return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString()); + else + return acircuit.AgentID.ToString(); + } + + /// + /// Produces a universal (HG) system-facing identifier given the information + /// + /// UUID of the user + /// first name (e.g Test) + /// last name (e.g. User) + /// homeURI (e.g. http://foo.com) + /// a string of the form uuid[;homeURI[;first last]] + public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI) + { + string agentsURI = homeURI; + if (!agentsURI.EndsWith("/")) + agentsURI += "/"; + + // This is ugly, but there's no other way, given that the name is changed + // in the agent circuit data for foreigners + if (lastName.Contains("@")) + { + string[] parts = firstName.Split(new char[] { '.' }); + if (parts.Length == 2) + return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + } + return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; + + } + + /// + /// Produces a universal (HG) user-facing name given the information + /// + /// + /// + /// + /// string of the form first.last @foo.com or first last + public static string UniversalName(String firstName, String lastName, String homeURI) + { + Uri uri = null; + try + { + uri = new Uri(homeURI); + } + catch (UriFormatException) + { + return firstName + " " + lastName; + } + return firstName + "." + lastName + " " + "@" + uri.Authority; + } + #endregion + } +} -- cgit v1.1 From 916e3bf886ee622e2f18d6eb74f90fee8c630471 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 11 Jul 2012 22:54:22 +0100 Subject: Where possible, use the system Encoding.ASCII and Encoding.UTF8 rather than constructing fresh copies. The encodings are thread-safe and already used in such a manner in other places. This isn't done where Byte Order Mark output is suppressed, since Encoding.UTF8 is constructed to output the BOM. --- OpenSim/Framework/Util.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e03bb74..fd9586c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1236,8 +1236,7 @@ namespace OpenSim.Framework public static string Base64ToString(string str) { - UTF8Encoding encoder = new UTF8Encoding(); - Decoder utf8Decode = encoder.GetDecoder(); + Decoder utf8Decode = Encoding.UTF8.GetDecoder(); byte[] todecode_byte = Convert.FromBase64String(str); int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length); -- cgit v1.1 From 884d603cac6c3fe0cdbd199e13e1514146ff82bc Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 13 Jul 2012 01:03:28 +0100 Subject: Rather than instantiating a UTF8 encoding everywhere when we want to supress the BOM, use a single Util.UTF8NoBomEncoding. This class is thread-safe (as evidenced by the provision of the system-wide Encoding.UTF8 which does not suppress BOM on output). --- OpenSim/Framework/Util.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index fd9586c..8cc29ee 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -148,6 +148,7 @@ namespace OpenSim.Framework } public static Encoding UTF8 = Encoding.UTF8; + public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false); /// /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) -- cgit v1.1 From e9ea911563362c4766d34cd948a2915beac06124 Mon Sep 17 00:00:00 2001 From: SignpostMarv Date: Fri, 17 Aug 2012 16:53:36 +0100 Subject: adding a clip method to handle Vector3 objects to enable a minor amount of refactoring --- OpenSim/Framework/Util.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cc29ee..38cb3a6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -850,6 +850,12 @@ namespace OpenSim.Framework return Math.Min(Math.Max(x, min), max); } + public static Vector3 Clip(Vector3 vec, float min, float max) + { + return new Vector3(Clip(vec.X, min, max), Clip(vec.Y, min, max), + Clip(vec.Z, min, max)); + } + /// /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens. /// -- cgit v1.1 From 25111e703f54d84c7c51e32db1f94332ea3ffd00 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 11 Sep 2012 21:48:02 +0100 Subject: Add levels 4 and 5 to "debug http" console command that will log a sample of incoming request data and the entire incoming data respectively. See "help debug http" for more details. --- OpenSim/Framework/Util.cs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 38cb3a6..1b9777f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1007,6 +1007,38 @@ namespace OpenSim.Framework } } + /// + /// Copy data from one stream to another, leaving the read position of both streams at the beginning. + /// + /// + /// Input stream. Must be seekable. + /// + /// + /// Thrown if the input stream is not seekable. + /// + public static Stream Copy(Stream inputStream) + { + if (!inputStream.CanSeek) + throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek"); + + const int readSize = 256; + byte[] buffer = new byte[readSize]; + MemoryStream ms = new MemoryStream(); + + int count = inputStream.Read(buffer, 0, readSize); + + while (count > 0) + { + ms.Write(buffer, 0, count); + count = inputStream.Read(buffer, 0, readSize); + } + + ms.Position = 0; + inputStream.Position = 0; + + return ms; + } + public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args) { return SendXmlRpcCommand(url, methodName, args); -- cgit v1.1 From 130768b16a35e307389e88d902f6e3a785dfb8ee Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 5 Oct 2012 03:52:42 +0100 Subject: Add "show object pos to " command to simulator console. This allows you to display details of all objects in a given bounding box. Values parts of the co-ord can be left out as appropriate (e.g. to get all objects between the ground and z=30. See "help show object pos" for more details. --- OpenSim/Framework/Util.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 1b9777f..5c7797a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -534,6 +534,19 @@ namespace OpenSim.Framework } /// + /// Determines whether a point is inside a bounding box. + /// + /// /param> + /// + /// + /// + public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max) + { + return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z + && v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z; + } + + /// /// Are the co-ordinates of the new region visible from the old region? /// /// Old region x-coord -- cgit v1.1 From 56965dd9599597bf5c51ab795f278db8291514c2 Mon Sep 17 00:00:00 2001 From: SignpostMarv Date: Tue, 16 Oct 2012 13:00:16 +0100 Subject: fixing poorly-formatted xml doc string for Util.IsInsideBox --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5c7797a..c369dbc 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -536,7 +536,7 @@ namespace OpenSim.Framework /// /// Determines whether a point is inside a bounding box. /// - /// /param> + /// /// /// /// -- cgit v1.1 From 999cb4b20cc20a24c7b9fbce4c31b13f8bf36cb5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 23 Nov 2012 04:40:49 +0000 Subject: Make "show threads" and "thread abort" console commands available on all servers --- OpenSim/Framework/Util.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c369dbc..a0c54a0 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1741,12 +1741,16 @@ namespace OpenSim.Framework StringBuilder sb = new StringBuilder(); if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; + // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. + if (m_ThreadPool != null) + { + threadPoolUsed = "SmartThreadPool"; + maxThreads = m_ThreadPool.MaxThreads; + minThreads = m_ThreadPool.MinThreads; + inUseThreads = m_ThreadPool.InUseThreads; + allocatedThreads = m_ThreadPool.ActiveThreads; + waitingCallbacks = m_ThreadPool.WaitingCallbacks; + } } else if ( FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem -- cgit v1.1 From 21dc5f4a1ada6fa7538627a81907054c619c0ebb Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 16 Dec 2012 17:53:44 -0800 Subject: Add stack dump function that takes an alternate printer outter. I've found that log4net can be slowish so, if one is generating A LOT of debug output, alternate printers are better --- OpenSim/Framework/Util.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a0c54a0..0c657c5 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1855,6 +1855,12 @@ namespace OpenSim.Framework /// public static void PrintCallStack() { + PrintCallStack(m_log.DebugFormat); + } + + public delegate void DebugPrinter(string msg, params Object[] parm); + public static void PrintCallStack(DebugPrinter printer) + { StackTrace stackTrace = new StackTrace(true); // get call stack StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames) @@ -1862,7 +1868,7 @@ namespace OpenSim.Framework foreach (StackFrame stackFrame in stackFrames) { MethodBase mb = stackFrame.GetMethod(); - m_log.DebugFormat("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name + printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name } } -- cgit v1.1 From 3e3c168987ba235ecb05079ed86e0ad3b6fe0dc8 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 22 Dec 2012 17:04:53 -0800 Subject: Add helper routine Util.InRange() --- OpenSim/Framework/Util.cs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0c657c5..ea2d28a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -299,6 +299,13 @@ namespace OpenSim.Framework x; } + // Inclusive, within range test (true if equal to the endpoints) + public static bool InRange(T x, T min, T max) + where T : IComparable + { + return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0; + } + public static uint GetNextXferID() { uint id = 0; -- cgit v1.1 From 416244051d248236cec142d3bda29d03f39f5606 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 1 Jan 2013 23:50:38 +0000 Subject: refactor: call Util.InitThreadPool() if we are initializing an uninitialized pool on first use rather than constructing it ourselves. No functional change. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ea2d28a..9bc9417 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1719,7 +1719,7 @@ namespace OpenSim.Framework break; case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) - m_ThreadPool = new SmartThreadPool(2000, 15, 2); + InitThreadPool(15); m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); break; case FireAndForgetMethod.Thread: -- cgit v1.1 From bc9a7ba0d6c0f7ad90a270c93acbb9b5c5f08645 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 1 Jan 2013 23:57:20 +0000 Subject: minor: Assign names to the different SmartThreadPools for debugging purposes. A different approach to the patch in http://opensimulator.org/mantis/view.php?id=6462 that doesn't involve further forking of SmartThreadPool --- OpenSim/Framework/Util.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9bc9417..4fd8a2d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1647,6 +1647,7 @@ namespace OpenSim.Framework throw new InvalidOperationException("SmartThreadPool is already initialized"); m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); + m_ThreadPool.Name = "Util"; } public static int FireAndForgetCount() -- cgit v1.1 From 1b826b487739220503458ccc6b07ec40c54e1164 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Sun, 16 Dec 2012 09:48:37 +0200 Subject: Allow registering regions whose names are equivalent under LIKE but not truly equal --- OpenSim/Framework/Util.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 4fd8a2d..f511494 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2102,5 +2102,16 @@ namespace OpenSim.Framework return firstName + "." + lastName + " " + "@" + uri.Authority; } #endregion + + /// + /// Escapes the special characters used in "LIKE". + /// + /// + /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz" + /// + public static string EscapeForLike(string str) + { + return str.Replace("_", "\\_").Replace("%", "\\%"); + } } } -- cgit v1.1 From caad1edabf755c2ef8e00f94f39a8b4c524012b4 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Thu, 17 Jan 2013 14:44:54 -0800 Subject: Add utility function to clamp a vector to a maximum magnitude. --- OpenSim/Framework/Util.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f511494..f6c9d15 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -299,6 +299,18 @@ namespace OpenSim.Framework x; } + // Clamp the maximum magnitude of a vector + public static Vector3 ClampV(Vector3 x, float max) + { + Vector3 ret = x; + float lenSq = x.LengthSquared(); + if (lenSq > (max * max)) + { + x = x / x.Length() * max; + } + return x; + } + // Inclusive, within range test (true if equal to the endpoints) public static bool InRange(T x, T min, T max) where T : IComparable -- cgit v1.1 From b77da5039eba6db0f904bfa9ca0852d640436055 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Fri, 4 Jan 2013 08:43:05 +0200 Subject: Assign the SmartThreadPool name in the constructor This is required because some threads are created in the constructor, so assigning the name afterwards would be too late. --- OpenSim/Framework/Util.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f6c9d15..9b1e97d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1658,8 +1658,13 @@ namespace OpenSim.Framework if (m_ThreadPool != null) throw new InvalidOperationException("SmartThreadPool is already initialized"); - m_ThreadPool = new SmartThreadPool(2000, maxThreads, 2); - m_ThreadPool.Name = "Util"; + STPStartInfo startInfo = new STPStartInfo(); + startInfo.ThreadPoolName = "Util"; + startInfo.IdleTimeout = 2000; + startInfo.MaxWorkerThreads = maxThreads; + startInfo.MinWorkerThreads = 2; + + m_ThreadPool = new SmartThreadPool(startInfo); } public static int FireAndForgetCount() -- cgit v1.1 From df37738ce7702774c4d3ff1f3835bfe87e0f1a5e Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Wed, 6 Feb 2013 16:42:55 -0800 Subject: WebStats will now use actual logfile as specified in OpenSim.exe.config rather than hardcoded ./OpenSim.log. This allows for rotating logs and other file appender types --- OpenSim/Framework/Util.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9b1e97d..d9148fb 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -45,6 +45,7 @@ using System.Text.RegularExpressions; using System.Xml; using System.Threading; using log4net; +using log4net.Appender; using Nini.Config; using Nwc.XmlRpc; using OpenMetaverse; @@ -816,9 +817,22 @@ namespace OpenSim.Framework return "."; } + public static string logFile() + { + foreach (IAppender appender in LogManager.GetRepository().GetAppenders()) + { + if (appender is FileAppender) + { + return ((FileAppender)appender).File; + } + } + + return "./OpenSim.log"; + } + public static string logDir() { - return "."; + return Path.GetDirectoryName(logFile()); } // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html -- cgit v1.1 From e515cdddec435e97e9ed4722de08ee410e94a7e6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 21 Feb 2013 17:26:19 -0800 Subject: Simplification of HG configs: HomeURI and GatekeeperURI now are defined as default under [Startup]. They can then be overwritten in the other sections (but probably shouldn't). I kept the existing code for backwards compatibility, so this should not cause any breaks from people's current configurations. But people should move to have these 2 vars under [Startup] -- see OpenSim.ini.example and Robust.HG.ini.example. And yes, both names now end with "URI" for consistency. --- OpenSim/Framework/Util.cs | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index d9148fb..1700d3e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -863,7 +863,7 @@ namespace OpenSim.Framework return FileName; } - // Nini (config) related Methods + #region Nini (config) related Methods public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) { if (!File.Exists(fileName)) @@ -886,6 +886,26 @@ namespace OpenSim.Framework } } + public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section) + { + // First, check the Startup section, the default section + IConfig cnf = config.Configs["Startup"]; + if (cnf == null) + return string.Empty; + string val = cnf.GetString(varname, string.Empty); + + // Then check for an overwrite of the default in the given section + if (!string.IsNullOrEmpty(section)) + { + cnf = config.Configs[section]; + if (cnf != null) + val = cnf.GetString(varname, val); + } + + return val; + } + #endregion + public static float Clip(float x, float min, float max) { return Math.Min(Math.Max(x, min), max); -- cgit v1.1 From 0e8289cd002b1947e172d1bfc77fdd0b16d92ffb Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Fri, 22 Feb 2013 15:57:33 -0800 Subject: Added new Util function for reading config vars that's more generic than the one I added yesterday -- this is for helping move config vars out of [Startup] --- OpenSim/Framework/Util.cs | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 1700d3e..8b8e507 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -904,6 +904,44 @@ namespace OpenSim.Framework return val; } + + /// + /// Gets the value of a configuration variable by looking into + /// multiple sections in order. The latter sections overwrite + /// any values previously found. + /// + /// Type of the variable + /// The configuration object + /// The configuration variable + /// Ordered sequence of sections to look at + /// + public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections) + { + object val = default(T); + foreach (string section in sections) + { + IConfig cnf = config.Configs[section]; + if (cnf == null) + continue; + + if (typeof(T) == typeof(String)) + { + if (val == null) // no null strings, please + val = string.Empty; + val = cnf.GetString(varname, (string)val); + } + else if (typeof(T) == typeof(Boolean)) + val = cnf.GetBoolean(varname, (bool)val); + else if (typeof(T) == typeof(Int32)) + val = cnf.GetInt(varname, (int)val); + else if (typeof(T) == typeof(float)) + val = cnf.GetFloat(varname, (int)val); + else + m_log.WarnFormat("[UTIL]: Unhandled type {0}", typeof(T)); + } + return (T)val; + } + #endregion public static float Clip(float x, float min, float max) -- cgit v1.1 From d0cb4fc3262df2afe2ef34396c7960f7afee6b89 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 25 Feb 2013 23:04:38 +0000 Subject: Move map related settings from [Startup] to a new [Map] section in OpenSim.ini Existing map settings in [Startup] will continue to work, and if present will override anything in [Map] However, the proper place for such settings would now be [Map] This is to reduce the use of [Startup] as a bag for non-generic settings which should really go in sections, in common with other settings. This commit also extends Diva's previous work to allow a default setting to be given when looking at multiple sections for settings. --- OpenSim/Framework/Util.cs | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8b8e507..0fa54b2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -917,7 +917,25 @@ namespace OpenSim.Framework /// public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections) { - object val = default(T); + return GetConfigVarFromSections(config, varname, sections, default(T)); + } + + /// + /// Gets the value of a configuration variable by looking into + /// multiple sections in order. The latter sections overwrite + /// any values previously found. + /// + /// + /// If no value is found then the given default value is returned + /// + /// Type of the variable + /// The configuration object + /// The configuration variable + /// Ordered sequence of sections to look at + /// Default value + /// + public static T GetConfigVarFromSections(IConfigSource config, string varname, string[] sections, object val) + { foreach (string section in sections) { IConfig cnf = config.Configs[section]; @@ -925,11 +943,7 @@ namespace OpenSim.Framework continue; if (typeof(T) == typeof(String)) - { - if (val == null) // no null strings, please - val = string.Empty; val = cnf.GetString(varname, (string)val); - } else if (typeof(T) == typeof(Boolean)) val = cnf.GetBoolean(varname, (bool)val); else if (typeof(T) == typeof(Int32)) @@ -937,8 +951,9 @@ namespace OpenSim.Framework else if (typeof(T) == typeof(float)) val = cnf.GetFloat(varname, (int)val); else - m_log.WarnFormat("[UTIL]: Unhandled type {0}", typeof(T)); + m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); } + return (T)val; } -- cgit v1.1 From 39a0928052bcaf4b81af326e129cbfd6329f9292 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 13 Mar 2013 23:17:27 +0000 Subject: minor: Remove some mono compiler warnings in OpenSim.Framework.dll --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0fa54b2..94a172c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -303,12 +303,12 @@ namespace OpenSim.Framework // Clamp the maximum magnitude of a vector public static Vector3 ClampV(Vector3 x, float max) { - Vector3 ret = x; float lenSq = x.LengthSquared(); if (lenSq > (max * max)) { x = x / x.Length() * max; } + return x; } -- cgit v1.1 From 5f4c4df227025c6b6156ce8238b56553dca4b5ae Mon Sep 17 00:00:00 2001 From: Melanie Date: Tue, 26 Mar 2013 03:40:06 +0000 Subject: Phase 1 of implementing a transfer permission. Overwrite libOMV's PermissionMask with our own and add export permissions as well as a new definition for "All" as meaning "all conventional permissions" rather than "all possible permissions" --- OpenSim/Framework/Util.cs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 94a172c..bde4673 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -54,6 +54,21 @@ using Amib.Threading; namespace OpenSim.Framework { + [Flags] + public enum PermissionMask : uint + { + None = 0, + Transfer = 1 << 13, + Modify = 1 << 14, + Copy = 1 << 15, + Export = 1 << 16, + Move = 1 << 19, + Damage = 1 << 20, + // All does not contain Export, which is special and must be + // explicitly given + All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) + } + /// /// The method used by Util.FireAndForget for asynchronously firing events /// -- cgit v1.1 From 206fb306a7820cf593570e35ddfa8e7c5a10e449 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 1 May 2013 19:01:43 +0100 Subject: Update SmartThreadPool to latest version 2.2.3 with a major and minor change. SmartThreadPool code comes from http://www.codeproject.com/Articles/7933/Smart-Thread-Pool This version implements thread abort (via WorkItem.Cancel(true)), threadpool naming, max thread stack, etc. so we no longer need to manually patch those. However, two changes have been made to stock 2.2.3. Major change: WorkItem.Cancel(bool abortExecution) in our version does not succeed if the work item was in progress and thread abort was not specified. This is to match previous behaviour where we handle co-operative termination via another mechanism rather than checking WorkItem.IsCanceled. Minor change: Did not add STP's StopWatch implementation as this is only used WinCE and Silverlight and causes a build clash with System.Diagnostics.StopWatch The reason for updating is to see if this improves http://opensimulator.org/mantis/view.php?id=6557 and http://opensimulator.org/mantis/view.php?id=6586 --- OpenSim/Framework/Util.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index bde4673..a3602e9 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1840,7 +1840,7 @@ namespace OpenSim.Framework case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) InitThreadPool(15); - m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); + m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); break; case FireAndForgetMethod.Thread: Thread thread = new Thread(delegate(object o) { realCallback(o); }); @@ -1910,15 +1910,15 @@ namespace OpenSim.Framework return sb.ToString(); } - private static object SmartThreadPoolCallback(object o) - { - object[] array = (object[])o; - WaitCallback callback = (WaitCallback)array[0]; - object obj = array[1]; - - callback(obj); - return null; - } +// private static object SmartThreadPoolCallback(object o) +// { +// object[] array = (object[])o; +// WaitCallback callback = (WaitCallback)array[0]; +// object obj = array[1]; +// +// callback(obj); +// return null; +// } #endregion FireAndForget Threading Pattern -- cgit v1.1 From 06ab16889744ab3f3cef7d698b19408368711194 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 21 May 2013 22:26:15 +0100 Subject: To further help with tracking down the apperance of too much "Unknown User" in chatlogs, etc. temporarily change each instance of this in OpenSimulator so we can identify where it's coming from For instance, the "Unknown User" in Util.ParseUniversalUserIdenitifer becaomes "Unknown UserUPUUI (class initials + method initials) This is to help with http://opensimulator.org/mantis/view.php?id=6625 --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index a3602e9..ada4e89 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2136,7 +2136,7 @@ namespace OpenSim.Framework /// the secret part public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) { - uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; + uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty; string[] parts = value.Split(';'); if (parts.Length >= 1) -- cgit v1.1 From a7dbafb0e383ca5043a71284cdc35569acc5e2be Mon Sep 17 00:00:00 2001 From: Melanie Date: Wed, 5 Jun 2013 23:42:50 +0100 Subject: Port Avination's inventory send throttling --- OpenSim/Framework/Util.cs | 108 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 108 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ada4e89..7f0850f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2233,4 +2233,112 @@ namespace OpenSim.Framework return str.Replace("_", "\\_").Replace("%", "\\%"); } } + + public class DoubleQueue where T:class + { + private Queue m_lowQueue = new Queue(); + private Queue m_highQueue = new Queue(); + + private object m_syncRoot = new object(); + private Semaphore m_s = new Semaphore(0, 1); + + public DoubleQueue() + { + } + + public virtual int Count + { + get { return m_highQueue.Count + m_lowQueue.Count; } + } + + public virtual void Enqueue(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueLow(T data) + { + Enqueue(m_lowQueue, data); + } + + public virtual void EnqueueHigh(T data) + { + Enqueue(m_highQueue, data); + } + + private void Enqueue(Queue q, T data) + { + lock (m_syncRoot) + { + m_lowQueue.Enqueue(data); + m_s.WaitOne(0); + m_s.Release(); + } + } + + public virtual T Dequeue() + { + return Dequeue(Timeout.Infinite); + } + + public virtual T Dequeue(int tmo) + { + return Dequeue(TimeSpan.FromMilliseconds(tmo)); + } + + public virtual T Dequeue(TimeSpan wait) + { + T res = null; + + if (!Dequeue(wait, ref res)) + return null; + + return res; + } + + public bool Dequeue(int timeout, ref T res) + { + return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res); + } + + public bool Dequeue(TimeSpan wait, ref T res) + { + if (!m_s.WaitOne(wait)) + return false; + + lock (m_syncRoot) + { + if (m_highQueue.Count > 0) + res = m_highQueue.Dequeue(); + else + res = m_lowQueue.Dequeue(); + + if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) + return true; + + try + { + m_s.Release(); + } + catch + { + } + + return true; + } + } + + public virtual void Clear() + { + + lock (m_syncRoot) + { + // Make sure sem count is 0 + m_s.WaitOne(0); + + m_lowQueue.Clear(); + m_highQueue.Clear(); + } + } + } } -- cgit v1.1 From c0a00cd7fd887190db61b1c69fb0e8f104a7e438 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 23:34:09 +0100 Subject: Fix bug where no threadpool data would be displayed in the "show threads" command if threadpool type was QueueUserWorkItem (Unsafe worked as expected) --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7f0850f..5e5eb7e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1880,7 +1880,7 @@ namespace OpenSim.Framework } } else if ( - FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem + FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) { threadPoolUsed = "BuiltInThreadPool"; -- cgit v1.1 From b7c9dee033bad425870540c08832058ac86d4ab5 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 17 Jun 2013 23:57:10 +0100 Subject: refactor: Move existing code to generate report information on the threadpool to the ServerBase rather than being in Util --- OpenSim/Framework/Util.cs | 104 ++++++++++++++++++---------------------------- 1 file changed, 41 insertions(+), 63 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5e5eb7e..ba6cc75 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -89,9 +89,30 @@ namespace OpenSim.Framework } /// + /// Class for delivering SmartThreadPool statistical information + /// + /// + /// We do it this way so that we do not directly expose STP. + /// + public class STPInfo + { + public string Name { get; set; } + public STPStartInfo STPStartInfo { get; set; } + public WIGStartInfo WIGStartInfo { get; set; } + public bool IsIdle { get; set; } + public bool IsShuttingDown { get; set; } + public int MaxThreads { get; set; } + public int MinThreads { get; set; } + public int InUseThreads { get; set; } + public int ActiveThreads { get; set; } + public int WaitingCallbacks { get; set; } + public int MaxConcurrentWorkItems { get; set; } + } + + /// /// Miscellaneous utility functions /// - public class Util + public static class Util { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); @@ -1852,74 +1873,31 @@ namespace OpenSim.Framework } /// - /// Get a thread pool report. + /// Get information about the current state of the smart thread pool. /// - /// - public static string GetThreadPoolReport() + /// + /// null if this isn't the pool being used for non-scriptengine threads. + /// + public static STPInfo GetSmartThreadPoolInfo() { - string threadPoolUsed = null; - int maxThreads = 0; - int minThreads = 0; - int allocatedThreads = 0; - int inUseThreads = 0; - int waitingCallbacks = 0; - int completionPortThreads = 0; - - StringBuilder sb = new StringBuilder(); - if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool) - { - // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool. - if (m_ThreadPool != null) - { - threadPoolUsed = "SmartThreadPool"; - maxThreads = m_ThreadPool.MaxThreads; - minThreads = m_ThreadPool.MinThreads; - inUseThreads = m_ThreadPool.InUseThreads; - allocatedThreads = m_ThreadPool.ActiveThreads; - waitingCallbacks = m_ThreadPool.WaitingCallbacks; - } - } - else if ( - FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem - || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem) - { - threadPoolUsed = "BuiltInThreadPool"; - ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads); - ThreadPool.GetMinThreads(out minThreads, out completionPortThreads); - int availableThreads; - ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads); - inUseThreads = maxThreads - availableThreads; - allocatedThreads = -1; - waitingCallbacks = -1; - } + if (m_ThreadPool == null) + return null; - if (threadPoolUsed != null) - { - sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed); - sb.AppendFormat("Max threads : {0}\n", maxThreads); - sb.AppendFormat("Min threads : {0}\n", minThreads); - sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString()); - sb.AppendFormat("In use threads : {0}\n", inUseThreads); - sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString()); - } - else - { - sb.AppendFormat("Thread pool not used\n"); - } + STPInfo stpi = new STPInfo(); + stpi.Name = m_ThreadPool.Name; + stpi.STPStartInfo = m_ThreadPool.STPStartInfo; + stpi.IsIdle = m_ThreadPool.IsIdle; + stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown; + stpi.MaxThreads = m_ThreadPool.MaxThreads; + stpi.MinThreads = m_ThreadPool.MinThreads; + stpi.InUseThreads = m_ThreadPool.InUseThreads; + stpi.ActiveThreads = m_ThreadPool.ActiveThreads; + stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks; + stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency; - return sb.ToString(); + return stpi; } -// private static object SmartThreadPoolCallback(object o) -// { -// object[] array = (object[])o; -// WaitCallback callback = (WaitCallback)array[0]; -// object obj = array[1]; -// -// callback(obj); -// return null; -// } - #endregion FireAndForget Threading Pattern /// -- cgit v1.1 From 44e9849ed1190dbc29ffa97fa5df286dc9794edb Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 11 Jul 2013 23:02:30 +0100 Subject: Fix regression where llHTTPRequests which did not get an OK response returned 499 and the exception message in the http_response event rather than the actual response code and body. This was a regression since commit 831e4c3 (Thu Apr 4 00:36:15 2013) This commit also adds a regression test for this case, though this currently only works with Mono This aims to address http://opensimulator.org/mantis/view.php?id=6704 --- OpenSim/Framework/Util.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ba6cc75..cafe103 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -141,6 +141,11 @@ namespace OpenSim.Framework public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; + public static bool IsPlatformMono + { + get { return Type.GetType("Mono.Runtime") != null; } + } + /// /// Gets the name of the directory where the current running executable /// is located @@ -1326,7 +1331,7 @@ namespace OpenSim.Framework ru = "OSX/Mono"; else { - if (Type.GetType("Mono.Runtime") != null) + if (IsPlatformMono) ru = "Win/Mono"; else ru = "Win/.NET"; -- cgit v1.1 From 60325f81d81f41ca6a23465468afa940aae397dd Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Mon, 15 Jul 2013 10:29:42 -0700 Subject: This might address the following observed exception: 17:14:28 - [APPLICATION]: APPLICATION EXCEPTION DETECTED: System.UnhandledExceptionEventArgs Exception: System.InvalidOperationException: Operation is not valid due to the current state of the object at System.Collections.Generic.Queue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Peek () [0x00011] in /root/install/mono-3.1.0/mono/mcs/class/System/System.Collections.Generic/Queue.cs:158 at System.Collections.Generic.Queue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Dequeue () [0x00000] in /root/install/mono-3.1.0/mono/mcs/class/System/System.Collections.Generic/Queue.cs:140 at OpenSim.Framework.DoubleQueue`1[OpenSim.Region.ClientStack.Linden.WebFetchInvDescModule+aPollRequest].Dequeue (TimeSpan wait, OpenSim.Region.ClientStack.Linden.aPollRequest& res) [0x0004e] in /home/avacon/opensim_2013-07-14/OpenSim/Framework/Util.cs:2297 --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index cafe103..8cfc4d4 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2293,7 +2293,7 @@ namespace OpenSim.Framework { if (m_highQueue.Count > 0) res = m_highQueue.Dequeue(); - else + else if (m_lowQueue.Count > 0) res = m_lowQueue.Dequeue(); if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) -- cgit v1.1 From 077be8b496f00c82353de02be192d2dcd920d6b3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 18 Jul 2013 01:23:33 +0100 Subject: Fix what apepars to be a bug in DoubleQueue.Enqueue(Queue q, T data) where the q parmater is ignored and everyghig is always placed on m_lowQueue. No actual impact presently since nothing ends up calling EnqueueHigh() --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cfc4d4..a39d860 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2253,7 +2253,7 @@ namespace OpenSim.Framework { lock (m_syncRoot) { - m_lowQueue.Enqueue(data); + q.Enqueue(data); m_s.WaitOne(0); m_s.Release(); } -- cgit v1.1 From 6572847518646f3f46959f613e602efc16210dcf Mon Sep 17 00:00:00 2001 From: Dan Lake Date: Thu, 18 Jul 2013 02:28:07 -0700 Subject: Added MinPoolThreads to ini [Startup] section to control SmartThreadPool. --- OpenSim/Framework/Util.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 8cfc4d4..27100e6 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1779,10 +1779,12 @@ namespace OpenSim.Framework FireAndForget(callback, null); } - public static void InitThreadPool(int maxThreads) + public static void InitThreadPool(int minThreads, int maxThreads) { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (minThreads > maxThreads || minThreads < 2) + throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); if (m_ThreadPool != null) throw new InvalidOperationException("SmartThreadPool is already initialized"); @@ -1790,7 +1792,7 @@ namespace OpenSim.Framework startInfo.ThreadPoolName = "Util"; startInfo.IdleTimeout = 2000; startInfo.MaxWorkerThreads = maxThreads; - startInfo.MinWorkerThreads = 2; + startInfo.MinWorkerThreads = minThreads; m_ThreadPool = new SmartThreadPool(startInfo); } @@ -1865,7 +1867,7 @@ namespace OpenSim.Framework break; case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) - InitThreadPool(15); + InitThreadPool(2, 15); m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); break; case FireAndForgetMethod.Thread: -- cgit v1.1 From 64216b34a49377f6999f6d2cf624d3c537d3f9d5 Mon Sep 17 00:00:00 2001 From: Kevin Cozens Date: Mon, 5 Aug 2013 19:30:46 -0400 Subject: Fixed error in BuildFakeParcelID() which was detected by regression tests. --- OpenSim/Framework/Util.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 6a15734..f0e5bc1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1247,7 +1247,7 @@ namespace OpenSim.Framework byte[] bytes = { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), (byte)x, (byte)(x >> 8), 0, 0, (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); @@ -1258,7 +1258,7 @@ namespace OpenSim.Framework byte[] bytes = { (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), - (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), + (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56), (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), (byte)y, (byte)(y >> 8), 0, 0 }; return new UUID(bytes, 0); -- cgit v1.1 From 4035badd20c00c766a1262afd7fa730ea6c53e98 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 00:04:12 +0100 Subject: Add experimental "show grid users online" console command to show grid users online from a standalone/robust instance. This is not guaranteed to be accurate since users may be left "online" in certain situations. For example, if a simulator crashes and they never login/logout again. To counter this somewhat, only users continuously online for less than 5 days are shown. --- OpenSim/Framework/Util.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f0e5bc1..52f5432 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -130,7 +130,7 @@ namespace OpenSim.Framework private static SmartThreadPool m_ThreadPool; // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. - private static readonly DateTime unixEpoch = + public static readonly DateTime UnixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); private static readonly string rawUUIDPattern @@ -521,19 +521,19 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { - TimeSpan t = stamp.ToUniversalTime() - unixEpoch; + TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; return (int) t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) { - DateTime epoch = unixEpoch; + DateTime epoch = UnixEpoch; return epoch.AddSeconds(seconds); } public static DateTime ToDateTime(int seconds) { - DateTime epoch = unixEpoch; + DateTime epoch = UnixEpoch; return epoch.AddSeconds(seconds); } -- cgit v1.1 From 431156f6c48944c79e3f56c54d64e7f3bc748f7b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 3 Sep 2013 00:17:50 +0100 Subject: minor simplification of some unix date functions in Util. No functional change. --- OpenSim/Framework/Util.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 52f5432..e8dfec1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -522,19 +522,17 @@ namespace OpenSim.Framework public static int ToUnixTime(DateTime stamp) { TimeSpan t = stamp.ToUniversalTime() - UnixEpoch; - return (int) t.TotalSeconds; + return (int)t.TotalSeconds; } public static DateTime ToDateTime(ulong seconds) { - DateTime epoch = UnixEpoch; - return epoch.AddSeconds(seconds); + return UnixEpoch.AddSeconds(seconds); } public static DateTime ToDateTime(int seconds) { - DateTime epoch = UnixEpoch; - return epoch.AddSeconds(seconds); + return UnixEpoch.AddSeconds(seconds); } /// -- cgit v1.1 From d9848943a96672b14fb9a6be58c4adc1e1552f3c Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sat, 4 Jan 2014 10:39:05 -0800 Subject: Add routines in Util.cs for conversion of region handles to region locations and for the conversion of region world location to region 'region' location. These routines will replace all the arithmatic scattered throughout OpenSimulator. --- OpenSim/Framework/Util.cs | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e8dfec1..b84673b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -333,6 +333,49 @@ namespace OpenSim.Framework return Utils.UIntsToLong(X, Y); } + // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong. + // Several places rely on the ability to extract a region's location from its handle. + // Note the location is in 'world coordinates' (see below). + // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0. + public static ulong RegionWorldLocToHandle(uint X, uint Y) + { + return Utils.UIntsToLong(X, Y); + } + + public static ulong RegionLocToHandle(uint X, uint Y) + { + return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y)); + } + + public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) + { + X = (uint)(handle >> 32); + Y = (uint)(handle & (ulong)uint.MaxValue); + } + + public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) + { + uint worldX, worldY; + RegionHandleToWorldLoc(handle, out worldX, out worldY); + X = WorldToRegionLoc(worldX); + Y = WorldToRegionLoc(worldY); + } + + // A region location can be 'world coordinates' (meters from zero) or 'region coordinates' + // (number of regions from zero). This measurement of regions relies on the legacy 256 region size. + // These routines exist to make what is being converted explicit so the next person knows what was meant. + // Convert a region's 'world coordinate' to its 'region coordinate'. + public static uint WorldToRegionLoc(uint worldCoord) + { + return worldCoord / Constants.RegionSize; + } + + // Convert a region's 'region coordinate' to its 'world coordinate'. + public static uint RegionToWorldLoc(uint regionCoord) + { + return regionCoord * Constants.RegionSize; + } + public static T Clamp(T x, T min, T max) where T : IComparable { -- cgit v1.1 From bc0ff5e7d43b873f8895f782c73170a84b5c35d6 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 2 May 2013 15:23:37 +0300 Subject: Allow Boolean nodes in XML to be specified as "0/1". AuroraSim does that. --- OpenSim/Framework/Util.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index e8dfec1..52635b2 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2029,8 +2029,10 @@ namespace OpenSim.Framework #region Xml Serialization Utilities public static bool ReadBoolean(XmlTextReader reader) { + // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. reader.ReadStartElement(); - bool result = Boolean.Parse(reader.ReadContentAsString().ToLower()); + string val = reader.ReadContentAsString().ToLower(); + bool result = val.Equals("true") || val.Equals("1"); reader.ReadEndElement(); return result; -- cgit v1.1 From 08fa0a6a8ae075742d321dd998187e85722650f8 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Sun, 19 Jan 2014 07:26:55 -0800 Subject: Fix casting error for float type INI file parameter parsing. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index cebba46..7bc8176 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1031,7 +1031,7 @@ namespace OpenSim.Framework else if (typeof(T) == typeof(Int32)) val = cnf.GetInt(varname, (int)val); else if (typeof(T) == typeof(float)) - val = cnf.GetFloat(varname, (int)val); + val = cnf.GetFloat(varname, (float)val); else m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T)); } -- cgit v1.1 From 733e067958bb2ddbb016b97272473b3372563fc3 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 14 Feb 2014 21:28:45 +0000 Subject: Log information about which function, request data and agent ID triggered an XmlRpcGroupsServiceConnector error --- OpenSim/Framework/Util.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 7bc8176..c7377b8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1746,6 +1746,30 @@ namespace OpenSim.Framework } /// + /// Pretty format the hashtable contents to a single line. + /// + /// + /// Used for debugging output. + /// + /// + public static string PrettyFormatToSingleLine(Hashtable ht) + { + StringBuilder sb = new StringBuilder(); + + int i = 0; + + foreach (string key in ht.Keys) + { + sb.AppendFormat("{0}:{1}", key, ht[key]); + + if (++i < ht.Count) + sb.AppendFormat(", "); + } + + return sb.ToString(); + } + + /// /// Used to trigger an early library load on Windows systems. /// /// -- cgit v1.1 From 6955190c7db2563927bc53fd47ed0b47094be45c Mon Sep 17 00:00:00 2001 From: Dev Random Date: Tue, 25 Feb 2014 08:24:22 -0500 Subject: Add Util method to load OpSys env vars --- OpenSim/Framework/Util.cs | 170 ++++++++++++++++++++++++---------------------- 1 file changed, 87 insertions(+), 83 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c7377b8..65cf177 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -946,11 +946,12 @@ namespace OpenSim.Framework } #region Nini (config) related Methods + public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName) { if (!File.Exists(fileName)) { - //create new file + // create new file } XmlConfigSource config = new XmlConfigSource(fileName); AddDataRowToConfig(config, row); @@ -968,25 +969,6 @@ namespace OpenSim.Framework } } - public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section) - { - // First, check the Startup section, the default section - IConfig cnf = config.Configs["Startup"]; - if (cnf == null) - return string.Empty; - string val = cnf.GetString(varname, string.Empty); - - // Then check for an overwrite of the default in the given section - if (!string.IsNullOrEmpty(section)) - { - cnf = config.Configs[section]; - if (cnf != null) - val = cnf.GetString(varname, val); - } - - return val; - } - /// /// Gets the value of a configuration variable by looking into /// multiple sections in order. The latter sections overwrite @@ -1039,6 +1021,91 @@ namespace OpenSim.Framework return (T)val; } + public static void MergeEnvironmentToConfig(IConfigSource ConfigSource) + { + IConfig enVars = ConfigSource.Configs["Environment"]; + // if section does not exist then user isn't expecting them, so don't bother. + if( enVars != null ) + { + // load the values from the environment + EnvConfigSource envConfigSource = new EnvConfigSource(); + // add the requested keys + string[] env_keys = enVars.GetKeys(); + foreach ( string key in env_keys ) + { + envConfigSource.AddEnv(key, string.Empty); + } + // load the values from environment + envConfigSource.LoadEnv(); + // add them in to the master + ConfigSource.Merge(envConfigSource); + ConfigSource.ExpandKeyValues(); + } + } + + public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) + { + Type settingsType = settingsClass.GetType(); + + FieldInfo[] fieldInfos = settingsType.GetFields(); + foreach (FieldInfo fieldInfo in fieldInfos) + { + if (!fieldInfo.IsStatic) + { + if (fieldInfo.FieldType == typeof(System.String)) + { + fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Boolean)) + { + fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Int32)) + { + fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.Single)) + { + fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); + } + else if (fieldInfo.FieldType == typeof(System.UInt32)) + { + fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); + } + } + } + + PropertyInfo[] propertyInfos = settingsType.GetProperties(); + foreach (PropertyInfo propInfo in propertyInfos) + { + if ((propInfo.CanRead) && (propInfo.CanWrite)) + { + if (propInfo.PropertyType == typeof(System.String)) + { + propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Boolean)) + { + propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Int32)) + { + propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); + } + else if (propInfo.PropertyType == typeof(System.Single)) + { + propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); + } + if (propInfo.PropertyType == typeof(System.UInt32)) + { + propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); + } + } + } + + return settingsClass; + } + #endregion public static float Clip(float x, float min, float max) @@ -1411,69 +1478,6 @@ namespace OpenSim.Framework return displayConnectionString; } - public static T ReadSettingsFromIniFile(IConfig config, T settingsClass) - { - Type settingsType = settingsClass.GetType(); - - FieldInfo[] fieldInfos = settingsType.GetFields(); - foreach (FieldInfo fieldInfo in fieldInfos) - { - if (!fieldInfo.IsStatic) - { - if (fieldInfo.FieldType == typeof(System.String)) - { - fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Boolean)) - { - fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Int32)) - { - fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.Single)) - { - fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass))); - } - else if (fieldInfo.FieldType == typeof(System.UInt32)) - { - fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString()))); - } - } - } - - PropertyInfo[] propertyInfos = settingsType.GetProperties(); - foreach (PropertyInfo propInfo in propertyInfos) - { - if ((propInfo.CanRead) && (propInfo.CanWrite)) - { - if (propInfo.PropertyType == typeof(System.String)) - { - propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Boolean)) - { - propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Int32)) - { - propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null); - } - else if (propInfo.PropertyType == typeof(System.Single)) - { - propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null); - } - if (propInfo.PropertyType == typeof(System.UInt32)) - { - propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null); - } - } - } - - return settingsClass; - } - public static string Base64ToString(string str) { Decoder utf8Decode = Encoding.UTF8.GetDecoder(); -- cgit v1.1 From c605c7a7b7f7e79147d1f32ab03ff244e375204e Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 18 Mar 2014 19:54:07 +0000 Subject: Lock m_syncRoot on DoubleQueue.Count. This is not documented as a thread-safe operation --- OpenSim/Framework/Util.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 65cf177..efaed62 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2304,7 +2304,11 @@ namespace OpenSim.Framework public virtual int Count { - get { return m_highQueue.Count + m_lowQueue.Count; } + get + { + lock (m_syncRoot) + return m_highQueue.Count + m_lowQueue.Count; + } } public virtual void Enqueue(T data) -- cgit v1.1 From 52b7b40034ddbb21d06b11ddc4eb6d766b0f616d Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 19 Mar 2014 00:48:13 +0000 Subject: Simplify DoubleQueue to eliminate redundant sempahore work. Exclusion is already guaranteed by the lock on m_syncRoot. Semaphore could not allow more than one thread in these sections anyway since the underlying SDK structures are not thread-safe. --- OpenSim/Framework/Util.cs | 34 +++++++--------------------------- 1 file changed, 7 insertions(+), 27 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index efaed62..f6e76dc 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2296,11 +2296,6 @@ namespace OpenSim.Framework private Queue m_highQueue = new Queue(); private object m_syncRoot = new object(); - private Semaphore m_s = new Semaphore(0, 1); - - public DoubleQueue() - { - } public virtual int Count { @@ -2329,11 +2324,7 @@ namespace OpenSim.Framework private void Enqueue(Queue q, T data) { lock (m_syncRoot) - { q.Enqueue(data); - m_s.WaitOne(0); - m_s.Release(); - } } public virtual T Dequeue() @@ -2363,42 +2354,31 @@ namespace OpenSim.Framework public bool Dequeue(TimeSpan wait, ref T res) { - if (!m_s.WaitOne(wait)) + if (!Monitor.TryEnter(m_syncRoot, wait)) return false; - lock (m_syncRoot) + try { if (m_highQueue.Count > 0) res = m_highQueue.Dequeue(); else if (m_lowQueue.Count > 0) res = m_lowQueue.Dequeue(); - if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) - return true; - - try - { - m_s.Release(); - } - catch - { - } - return true; } + finally + { + Monitor.Exit(m_syncRoot); + } } public virtual void Clear() { - lock (m_syncRoot) { - // Make sure sem count is 0 - m_s.WaitOne(0); - m_lowQueue.Clear(); m_highQueue.Clear(); } } } -} +} \ No newline at end of file -- cgit v1.1 From cf97535d9e6c1b54994edd5cb646fe891187d33b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 19 Mar 2014 01:40:56 +0000 Subject: Revert "Simplify DoubleQueue to eliminate redundant sempahore work." This reverts commit 52b7b40034ddbb21d06b11ddc4eb6d766b0f616d. Got the semantics wrong - the sempahore is required so that the blocking thread waits for a signal. --- OpenSim/Framework/Util.cs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index f6e76dc..efaed62 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2296,6 +2296,11 @@ namespace OpenSim.Framework private Queue m_highQueue = new Queue(); private object m_syncRoot = new object(); + private Semaphore m_s = new Semaphore(0, 1); + + public DoubleQueue() + { + } public virtual int Count { @@ -2324,7 +2329,11 @@ namespace OpenSim.Framework private void Enqueue(Queue q, T data) { lock (m_syncRoot) + { q.Enqueue(data); + m_s.WaitOne(0); + m_s.Release(); + } } public virtual T Dequeue() @@ -2354,31 +2363,42 @@ namespace OpenSim.Framework public bool Dequeue(TimeSpan wait, ref T res) { - if (!Monitor.TryEnter(m_syncRoot, wait)) + if (!m_s.WaitOne(wait)) return false; - try + lock (m_syncRoot) { if (m_highQueue.Count > 0) res = m_highQueue.Dequeue(); else if (m_lowQueue.Count > 0) res = m_lowQueue.Dequeue(); + if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) + return true; + + try + { + m_s.Release(); + } + catch + { + } + return true; } - finally - { - Monitor.Exit(m_syncRoot); - } } public virtual void Clear() { + lock (m_syncRoot) { + // Make sure sem count is 0 + m_s.WaitOne(0); + m_lowQueue.Clear(); m_highQueue.Clear(); } } } -} \ No newline at end of file +} -- cgit v1.1 From 921f0052f43e0e4553e970a8d560c5635fcd3ca6 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Sun, 8 Dec 2013 16:50:24 +0200 Subject: Get the full viewer name even if it's (incorrectly) sent in the 'Channel' field Recent versions of Firestorm and Singularity have started sending the viewer name in the 'Channel' field, leaving only their version number in the 'Viewer' field. So we need to search both of these fields for the viewer name. This resolves http://opensimulator.org/mantis/view.php?id=6952 --- OpenSim/Framework/Util.cs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index efaed62..5805dc8 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2288,6 +2288,38 @@ namespace OpenSim.Framework { return str.Replace("_", "\\_").Replace("%", "\\%"); } + + /// + /// Returns the name of the user's viewer. + /// + /// + /// This method handles two ways that viewers specify their name: + /// 1. Viewer = "Firestorm-Release 4.4.2.34167", Channel = "(don't care)" -> "Firestorm-Release 4.4.2.34167" + /// 2. Viewer = "4.5.1.38838", Channel = "Firestorm-Beta" -> "Firestorm-Beta 4.5.1.38838" + /// + public static string GetViewerName(AgentCircuitData agent) + { + string name = agent.Viewer; + if (name == null) + name = ""; + else + name = name.Trim(); + + // Check if 'Viewer' is just a version number. If it's *not*, then we + // assume that it contains the real viewer name, and we return it. + foreach (char c in name) + { + if (Char.IsLetter(c)) + return name; + } + + // The 'Viewer' string contains just a version number. If there's anything in + // 'Channel' then assume that it's the viewer name. + if ((agent.Channel != null) && (agent.Channel.Length > 0)) + name = agent.Channel.Trim() + " " + name; + + return name; + } } public class DoubleQueue where T:class -- cgit v1.1 From 89945f8829dcc1ee889aad1bafd1d6c2938a6cc7 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 31 Oct 2013 13:02:57 +0200 Subject: Refactored: ExternalRepresentationUtils should be the only place where the "CreatorData" field is calculated, to ensure uniformity Resolves http://opensimulator.org/mantis/view.php?id=6933 --- OpenSim/Framework/Util.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5805dc8..c2c9698 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2250,10 +2250,15 @@ namespace OpenSim.Framework { string[] parts = firstName.Split(new char[] { '.' }); if (parts.Length == 2) - return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1]; + return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]); } - return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName; + + return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName); + } + private static string CalcUniversalIdentifier(UUID id, string agentsURI, string name) + { + return id.ToString() + ";" + agentsURI + ";" + name; } /// -- cgit v1.1 From 7c0ebcb984be1ffe66654fc2c566e56125596b21 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Mon, 25 Nov 2013 13:00:13 +0200 Subject: Added debug flag: LogThreadPool. It makes us log every use of the main threadpool. Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 143 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 114 insertions(+), 29 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c2c9698..ed94c6f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -116,6 +116,16 @@ namespace OpenSim.Framework { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// + /// Log every invocation of a thread using the threadpool. + /// + public static bool LogThreadPool { get; set; } + + static Util() + { + LogThreadPool = false; + } + private static uint nextXferID = 5000; private static Random randomClass = new Random(); @@ -1887,10 +1897,17 @@ namespace OpenSim.Framework } } + + private static long nextThreadFuncNum = 0; + private static long numQueuedThreadFuncs = 0; + private static long numRunningThreadFuncs = 0; + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { WaitCallback realCallback; + long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); + if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { // If we're running regression tests, then we want any exceptions to rise up to the test code. @@ -1903,49 +1920,117 @@ namespace OpenSim.Framework // for decimals places but is read by a culture that treats commas as number seperators. realCallback = o => { - Culture.SetCurrentCulture(); + long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs); + long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs); try { + if (LogThreadPool) + m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1); + + Culture.SetCurrentCulture(); + callback(o); } catch (Exception e) { - m_log.ErrorFormat( - "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}", - e.Message, e.StackTrace); + m_log.Error("[UTIL]: FireAndForget thread terminated with error ", e); + } + finally + { + Interlocked.Decrement(ref numRunningThreadFuncs); + if (LogThreadPool) + m_log.Debug("Exit threadfunc " + threadFuncNum); } }; } - switch (FireAndForgetMethod) + long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs); + try { - case FireAndForgetMethod.RegressionTest: - case FireAndForgetMethod.None: - realCallback.Invoke(obj); - break; - case FireAndForgetMethod.UnsafeQueueUserWorkItem: - ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.QueueUserWorkItem: - ThreadPool.QueueUserWorkItem(realCallback, obj); - break; - case FireAndForgetMethod.BeginInvoke: - FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; - wrapper.FireAndForget(realCallback, obj); - break; - case FireAndForgetMethod.SmartThreadPool: - if (m_ThreadPool == null) - InitThreadPool(2, 15); - m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); - break; - case FireAndForgetMethod.Thread: - Thread thread = new Thread(delegate(object o) { realCallback(o); }); - thread.Start(obj); + if (LogThreadPool) + m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}", + threadFuncNum, numQueued, numRunningThreadFuncs, GetFireAndForgetStackTrace(true)); + + switch (FireAndForgetMethod) + { + case FireAndForgetMethod.RegressionTest: + case FireAndForgetMethod.None: + realCallback.Invoke(obj); + break; + case FireAndForgetMethod.UnsafeQueueUserWorkItem: + ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.QueueUserWorkItem: + ThreadPool.QueueUserWorkItem(realCallback, obj); + break; + case FireAndForgetMethod.BeginInvoke: + FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance; + wrapper.FireAndForget(realCallback, obj); + break; + case FireAndForgetMethod.SmartThreadPool: + if (m_ThreadPool == null) + InitThreadPool(2, 15); + m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); + break; + case FireAndForgetMethod.Thread: + Thread thread = new Thread(delegate(object o) { realCallback(o); }); + thread.Start(obj); + break; + default: + throw new NotImplementedException(); + } + } + catch (Exception) + { + Interlocked.Decrement(ref numQueuedThreadFuncs); + throw; + } + } + + /// + /// Returns a stack trace for a thread added using FireAndForget(). + /// + /// True: return full stack trace; False: return only the first frame + private static string GetFireAndForgetStackTrace(bool full) + { + string src = Environment.StackTrace; + string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); + + StringBuilder dest = new StringBuilder(src.Length); + + bool started = false; + bool first = true; + + for (int i = 0; i < lines.Length; i++) + { + string line = lines[i]; + + if (!started) + { + // Skip the initial stack frames, because they're of no interest for debugging + if (line.Contains("StackTrace") || line.Contains("FireAndForget")) + continue; + started = true; + } + + if (first) + { + line = line.TrimStart(); + first = false; + } + + bool last = (i == lines.Length - 1) || !full; + if (last) + dest.Append(line); + else + dest.AppendLine(line); + + if (!full) break; - default: - throw new NotImplementedException(); } + + return dest.ToString(); } /// -- cgit v1.1 From 8555e54e22f6d15375b9279a59ec8695a883dc11 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 5 Dec 2013 08:40:41 +0200 Subject: Automatically start logging FireAndForget activity if the threadpool is full Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ed94c6f..0dfee71 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1901,11 +1901,14 @@ namespace OpenSim.Framework private static long nextThreadFuncNum = 0; private static long numQueuedThreadFuncs = 0; private static long numRunningThreadFuncs = 0; + private static Int32 threadFuncOverloadMode = 0; public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { WaitCallback realCallback; + bool loggingEnabled = LogThreadPool; + long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) @@ -1925,7 +1928,7 @@ namespace OpenSim.Framework try { - if (LogThreadPool) + if (loggingEnabled || (threadFuncOverloadMode == 1)) m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1); Culture.SetCurrentCulture(); @@ -1939,7 +1942,7 @@ namespace OpenSim.Framework finally { Interlocked.Decrement(ref numRunningThreadFuncs); - if (LogThreadPool) + if (loggingEnabled || (threadFuncOverloadMode == 1)) m_log.Debug("Exit threadfunc " + threadFuncNum); } }; @@ -1948,9 +1951,21 @@ namespace OpenSim.Framework long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs); try { - if (LogThreadPool) + long numRunning = numRunningThreadFuncs; + if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads)) + { + if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0) + m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + } + else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads*2)/3)) + { + if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1) + m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + } + + if (loggingEnabled || (threadFuncOverloadMode == 1)) m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}", - threadFuncNum, numQueued, numRunningThreadFuncs, GetFireAndForgetStackTrace(true)); + threadFuncNum, numQueued, numRunningThreadFuncs, GetFireAndForgetStackTrace(loggingEnabled)); switch (FireAndForgetMethod) { -- cgit v1.1 From 4031933475a8df81629862bfcdc497ac57d01223 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Wed, 27 Nov 2013 14:15:21 +0200 Subject: Refactored DebugFlagsEnum Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 0dfee71..225d360 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -67,7 +67,7 @@ namespace OpenSim.Framework // All does not contain Export, which is special and must be // explicitly given All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) - } + } /// /// The method used by Util.FireAndForget for asynchronously firing events @@ -109,6 +109,15 @@ namespace OpenSim.Framework public int MaxConcurrentWorkItems { get; set; } } + [Flags] + public enum DebugFlagsEnum : uint + { + None = 0, + + // Log every invocation of a thread using the threadpool + LogThreadPool = 0x01 + } + /// /// Miscellaneous utility functions /// @@ -117,13 +126,13 @@ namespace OpenSim.Framework private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// - /// Log every invocation of a thread using the threadpool. + /// Flags that enable additional debugging. /// - public static bool LogThreadPool { get; set; } + public static DebugFlagsEnum DebugFlags { get; set; } static Util() { - LogThreadPool = false; + DebugFlags = DebugFlagsEnum.None; } private static uint nextXferID = 5000; @@ -1907,7 +1916,7 @@ namespace OpenSim.Framework { WaitCallback realCallback; - bool loggingEnabled = LogThreadPool; + bool loggingEnabled = (DebugFlags & DebugFlagsEnum.LogThreadPool) != 0; long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); -- cgit v1.1 From e735f765539dc2f9a6b5d072b114a5b0116dba9f Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 19 Dec 2013 10:51:10 +0200 Subject: LogThreadPool: when the thread is for ProcessPacketMethod, also log the packet type Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 225d360..6be1722 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1864,7 +1864,7 @@ namespace OpenSim.Framework public static void FireAndForget(System.Threading.WaitCallback callback) { - FireAndForget(callback, null); + FireAndForget(callback, null, null); } public static void InitThreadPool(int minThreads, int maxThreads) @@ -1914,6 +1914,11 @@ namespace OpenSim.Framework public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { + FireAndForget(callback, obj, null); + } + + public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) + { WaitCallback realCallback; bool loggingEnabled = (DebugFlags & DebugFlagsEnum.LogThreadPool) != 0; @@ -1973,8 +1978,12 @@ namespace OpenSim.Framework } if (loggingEnabled || (threadFuncOverloadMode == 1)) - m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}", - threadFuncNum, numQueued, numRunningThreadFuncs, GetFireAndForgetStackTrace(loggingEnabled)); + { + m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", + threadFuncNum, numQueued, numRunningThreadFuncs, + (context == null) ? "" : ("(" + context + ") "), + GetFireAndForgetStackTrace(loggingEnabled)); + } switch (FireAndForgetMethod) { -- cgit v1.1 From b13214af273f826699e97bd1f4dd2e49bfe43f5e Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 14 Jan 2014 09:55:19 +0200 Subject: Added a watchdog to abort slow threads in the main thread pool If a task in the thread pool hangs then it will permanently take up one of the threads. If this happens repeatedly then the thread pool will become exhausted and OpenSim will fail. This watchdog terminates threads in the thread pool that have been executing for over a minute (which probably means they're hung). Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 280 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 269 insertions(+), 11 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 6be1722..2de596e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -51,6 +51,7 @@ using Nwc.XmlRpc; using OpenMetaverse; using OpenMetaverse.StructuredData; using Amib.Threading; +using System.Collections.Concurrent; namespace OpenSim.Framework { @@ -148,6 +149,9 @@ namespace OpenSim.Framework /// private static SmartThreadPool m_ThreadPool; + // Watchdog timer that aborts threads that have timed-out + private static Timer m_threadPoolWatchdog; + // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. public static readonly DateTime UnixEpoch = DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); @@ -1883,6 +1887,7 @@ namespace OpenSim.Framework startInfo.MinWorkerThreads = minThreads; m_ThreadPool = new SmartThreadPool(startInfo); + m_threadPoolWatchdog = new Timer(ThreadPoolWatchdog, null, 0, 1000); } public static int FireAndForgetCount() @@ -1907,16 +1912,117 @@ namespace OpenSim.Framework } + /// + /// Additional information about threads in the main thread pool. Used to time how long the + /// thread has been running, and abort it if it has timed-out. + /// + private class ThreadInfo + { + public long ThreadFuncNum { get; set; } + public string StackTrace { get; set; } + private string context; + + public IWorkItemResult WorkItem { get; set; } + public Thread Thread { get; set; } + public bool Running { get; set; } + public bool Aborted { get; set; } + private int started; + + public ThreadInfo(long threadFuncNum, string context) + { + ThreadFuncNum = threadFuncNum; + this.context = context; + Thread = null; + Running = false; + Aborted = false; + } + + public void Started() + { + Thread = Thread.CurrentThread; + started = EnvironmentTickCount(); + Running = true; + } + + public void Ended() + { + Running = false; + } + + public int Elapsed() + { + return EnvironmentTickCountSubtract(started); + } + + public void Abort() + { + Aborted = true; + WorkItem.Cancel(true); + } + + /// + /// Returns the thread's stack trace. + /// + /// + /// May return one of two stack traces. First, tries to get the thread's active stack + /// trace. But this can fail, so as a fallback this method will return the stack + /// trace that was active when the task was queued. + /// + public string GetStackTrace() + { + string ret = (context == null) ? "" : ("(" + context + ") "); + + StackTrace activeStackTrace = Util.GetStackTrace(Thread); + if (activeStackTrace != null) + ret += activeStackTrace.ToString(); + else if (StackTrace != null) + ret += "(Stack trace when queued) " + StackTrace; + // else, no stack trace available + + return ret; + } + } + + private static long nextThreadFuncNum = 0; private static long numQueuedThreadFuncs = 0; private static long numRunningThreadFuncs = 0; private static Int32 threadFuncOverloadMode = 0; + // Maps (ThreadFunc number -> Thread) + private static ConcurrentDictionary activeThreads = new ConcurrentDictionary(); + + private static readonly int THREAD_TIMEOUT = 60 * 1000; + + /// + /// Finds threads in the main thread pool that have timed-out, and aborts them. + /// + private static void ThreadPoolWatchdog(object state) + { + foreach (KeyValuePair entry in activeThreads) + { + ThreadInfo t = entry.Value; + if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT)) + { + m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace()); + t.Abort(); + + ThreadInfo dummy; + activeThreads.TryRemove(entry.Key, out dummy); + + // It's possible that the thread won't abort. To make sure the thread pool isn't + // depleted, increase the pool size. + m_ThreadPool.MaxThreads++; + } + } + } + + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { FireAndForget(callback, obj, null); } - + public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) { WaitCallback realCallback; @@ -1924,6 +2030,7 @@ namespace OpenSim.Framework bool loggingEnabled = (DebugFlags & DebugFlagsEnum.LogThreadPool) != 0; long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); + ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context); if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { @@ -1939,6 +2046,8 @@ namespace OpenSim.Framework { long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs); long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs); + threadInfo.Started(); + activeThreads[threadFuncNum] = threadInfo; try { @@ -1949,15 +2058,22 @@ namespace OpenSim.Framework callback(o); } + catch (ThreadAbortException e) + { + m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e); + } catch (Exception e) { - m_log.Error("[UTIL]: FireAndForget thread terminated with error ", e); + m_log.Error(string.Format("[UTIL]: Util STP threadfunc {0} terminated with error ", threadFuncNum), e); } finally { Interlocked.Decrement(ref numRunningThreadFuncs); + threadInfo.Ended(); + ThreadInfo dummy; + activeThreads.TryRemove(threadFuncNum, out dummy); if (loggingEnabled || (threadFuncOverloadMode == 1)) - m_log.Debug("Exit threadfunc " + threadFuncNum); + m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); } }; } @@ -1979,10 +2095,13 @@ namespace OpenSim.Framework if (loggingEnabled || (threadFuncOverloadMode == 1)) { + string full, partial; + GetFireAndForgetStackTrace(out full, out partial); m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", threadFuncNum, numQueued, numRunningThreadFuncs, (context == null) ? "" : ("(" + context + ") "), - GetFireAndForgetStackTrace(loggingEnabled)); + loggingEnabled ? full : partial); + threadInfo.StackTrace = full; } switch (FireAndForgetMethod) @@ -2004,7 +2123,7 @@ namespace OpenSim.Framework case FireAndForgetMethod.SmartThreadPool: if (m_ThreadPool == null) InitThreadPool(2, 15); - m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); + threadInfo.WorkItem = m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj); break; case FireAndForgetMethod.Thread: Thread thread = new Thread(delegate(object o) { realCallback(o); }); @@ -2017,6 +2136,8 @@ namespace OpenSim.Framework catch (Exception) { Interlocked.Decrement(ref numQueuedThreadFuncs); + ThreadInfo dummy; + activeThreads.TryRemove(threadFuncNum, out dummy); throw; } } @@ -2024,8 +2145,9 @@ namespace OpenSim.Framework /// /// Returns a stack trace for a thread added using FireAndForget(). /// - /// True: return full stack trace; False: return only the first frame - private static string GetFireAndForgetStackTrace(bool full) + /// Will contain the full stack trace + /// Will contain only the first frame of the stack trace + private static void GetFireAndForgetStackTrace(out string full, out string partial) { string src = Environment.StackTrace; string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); @@ -2034,6 +2156,7 @@ namespace OpenSim.Framework bool started = false; bool first = true; + partial = ""; for (int i = 0; i < lines.Length; i++) { @@ -2051,20 +2174,101 @@ namespace OpenSim.Framework { line = line.TrimStart(); first = false; + partial = line; } - bool last = (i == lines.Length - 1) || !full; + bool last = (i == lines.Length - 1); if (last) dest.Append(line); else dest.AppendLine(line); + } - if (!full) - break; + full = dest.ToString(); + } + +#pragma warning disable 0618 + /// + /// Return the stack trace of a different thread. + /// + /// + /// This is complicated because the thread needs to be paused in order to get its stack + /// trace. And pausing another thread can cause a deadlock. This method attempts to + /// avoid deadlock by using a short timeout (200ms), after which it gives up and + /// returns 'null' instead of the stack trace. + /// + /// Take from: http://stackoverflow.com/a/14935378 + /// + /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691 + /// + /// + /// The stack trace, or null if failed to get it + private static StackTrace GetStackTrace(Thread targetThread) + { + if (IsPlatformMono) + { + // This doesn't work in Mono + return null; } - return dest.ToString(); + ManualResetEventSlim fallbackThreadReady = new ManualResetEventSlim(); + ManualResetEventSlim exitedSafely = new ManualResetEventSlim(); + + try + { + new Thread(delegate() + { + fallbackThreadReady.Set(); + while (!exitedSafely.Wait(200)) + { + try + { + targetThread.Resume(); + } + catch (Exception) + { + // Whatever happens, do never stop to resume the main-thread regularly until the main-thread has exited safely. + } + } + }).Start(); + + fallbackThreadReady.Wait(); + // From here, you have about 200ms to get the stack-trace + + targetThread.Suspend(); + + StackTrace trace = null; + try + { + trace = new StackTrace(targetThread, true); + } + catch (ThreadStateException) + { + //failed to get stack trace, since the fallback-thread resumed the thread + //possible reasons: + //1.) This thread was just too slow + //2.) A deadlock ocurred + //Automatic retry seems too risky here, so just return null. + } + + try + { + targetThread.Resume(); + } + catch (ThreadStateException) + { + // Thread is running again already + } + + return trace; + } + finally + { + // Signal the fallack-thread to stop + exitedSafely.Set(); + } } +#pragma warning restore 0618 /// /// Get information about the current state of the smart thread pool. @@ -2150,6 +2354,60 @@ namespace OpenSim.Framework } /// + /// Formats a duration (given in milliseconds). + /// + public static string FormatDuration(int ms) + { + TimeSpan span = new TimeSpan(ms * TimeSpan.TicksPerMillisecond); + + string str = ""; + string suffix = null; + + int hours = (int)span.TotalHours; + if (hours > 0) + { + str += hours.ToString(str.Length == 0 ? "0" : "00"); + suffix = "hours"; + } + + if ((hours > 0) || (span.Minutes > 0)) + { + if (str.Length > 0) + str += ":"; + str += span.Minutes.ToString(str.Length == 0 ? "0" : "00"); + if (suffix == null) + suffix = "min"; + } + + if ((hours > 0) || (span.Minutes > 0) || (span.Seconds > 0)) + { + if (str.Length > 0) + str += ":"; + str += span.Seconds.ToString(str.Length == 0 ? "0" : "00"); + if (suffix == null) + suffix = "sec"; + } + + if (suffix == null) + suffix = "ms"; + + if (span.TotalMinutes < 1) + { + int ms1 = span.Milliseconds; + if (str.Length > 0) + { + ms1 /= 100; + str += "."; + } + str += ms1.ToString("0"); + } + + str += " " + suffix; + + return str; + } + + /// /// Prints the call stack at any given point. Useful for debugging. /// public static void PrintCallStack() -- cgit v1.1 From 84d7227dfd8fc7e673b3015e2b5495d1752e16a3 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 16 Jan 2014 15:08:45 +0200 Subject: Changed LogThreadPool to have 4 logging levels. Added console command "debug threadpool level" to set the logging level. Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 59 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 19 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2de596e..b39dc5f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -110,15 +110,6 @@ namespace OpenSim.Framework public int MaxConcurrentWorkItems { get; set; } } - [Flags] - public enum DebugFlagsEnum : uint - { - None = 0, - - // Log every invocation of a thread using the threadpool - LogThreadPool = 0x01 - } - /// /// Miscellaneous utility functions /// @@ -127,13 +118,19 @@ namespace OpenSim.Framework private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); /// - /// Flags that enable additional debugging. + /// Log-level for the thread pool: + /// 0 = no logging + /// 1 = only first line of stack trace; don't log common threads + /// 2 = full stack trace; don't log common threads + /// 3 = full stack trace, including common threads /// - public static DebugFlagsEnum DebugFlags { get; set; } + public static int LogThreadPool { get; set; } + + public static readonly int MAX_THREADPOOL_LEVEL = 3; static Util() { - DebugFlags = DebugFlagsEnum.None; + LogThreadPool = 0; } private static uint nextXferID = 5000; @@ -1921,6 +1918,7 @@ namespace OpenSim.Framework public long ThreadFuncNum { get; set; } public string StackTrace { get; set; } private string context; + public bool LogThread { get; set; } public IWorkItemResult WorkItem { get; set; } public Thread Thread { get; set; } @@ -1932,6 +1930,7 @@ namespace OpenSim.Framework { ThreadFuncNum = threadFuncNum; this.context = context; + LogThread = true; Thread = null; Running = false; Aborted = false; @@ -2027,7 +2026,7 @@ namespace OpenSim.Framework { WaitCallback realCallback; - bool loggingEnabled = (DebugFlags & DebugFlagsEnum.LogThreadPool) != 0; + bool loggingEnabled = LogThreadPool > 0; long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context); @@ -2051,7 +2050,7 @@ namespace OpenSim.Framework try { - if (loggingEnabled || (threadFuncOverloadMode == 1)) + if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1); Culture.SetCurrentCulture(); @@ -2072,7 +2071,7 @@ namespace OpenSim.Framework threadInfo.Ended(); ThreadInfo dummy; activeThreads.TryRemove(threadFuncNum, out dummy); - if (loggingEnabled || (threadFuncOverloadMode == 1)) + if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); } }; @@ -2097,11 +2096,16 @@ namespace OpenSim.Framework { string full, partial; GetFireAndForgetStackTrace(out full, out partial); - m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", - threadFuncNum, numQueued, numRunningThreadFuncs, - (context == null) ? "" : ("(" + context + ") "), - loggingEnabled ? full : partial); threadInfo.StackTrace = full; + threadInfo.LogThread = ShouldLogThread(partial); + + if (threadInfo.LogThread) + { + m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", + threadFuncNum, numQueued, numRunningThreadFuncs, + (context == null) ? "" : ("(" + context + ") "), + (LogThreadPool >= 2) ? full : partial); + } } switch (FireAndForgetMethod) @@ -2143,6 +2147,23 @@ namespace OpenSim.Framework } /// + /// Returns whether the thread should be logged. Some very common threads aren't logged, + /// to avoid filling up the log. + /// + /// A partial stack trace of where the thread was queued + /// Whether to log this thread + private static bool ShouldLogThread(string stackTrace) + { + if (LogThreadPool < 3) + { + if (stackTrace.Contains("BeginFireQueueEmpty")) + return false; + } + + return true; + } + + /// /// Returns a stack trace for a thread added using FireAndForget(). /// /// Will contain the full stack trace -- cgit v1.1 From e131e73652cf6ed2407e41c7d83dc67f49ca23ee Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Wed, 29 Jan 2014 16:14:27 +0200 Subject: Run slow operations in a separate thread, instead of using FireAndForget (which has a 1-minute timeout) Resolves http://opensimulator.org/mantis/view.php?id=6945 --- OpenSim/Framework/Util.cs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b39dc5f..c9930fb 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2320,6 +2320,29 @@ namespace OpenSim.Framework #endregion FireAndForget Threading Pattern /// + /// Run the callback on a different thread, outside the thread pool. This is used for tasks + /// that may take a long time. + /// + public static void RunThreadNoTimeout(WaitCallback callback, string name, object obj) + { + Thread t = new Thread(delegate() + { + try + { + Culture.SetCurrentCulture(); + callback(obj); + } + catch (Exception e) + { + m_log.Error("Exception in thread " + name, e); + } + }); + + t.Name = name; + t.Start(); + } + + /// /// Environment.TickCount is an int but it counts all 32 bits so it goes positive /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap /// for the callers. -- cgit v1.1 From 4289b7114198ea8dfb5b5d5134ada1e5582528d9 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Tue, 25 Mar 2014 10:04:52 +0200 Subject: Fixed unit tests due to changes in the threadpool --- OpenSim/Framework/Util.cs | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c9930fb..ae720f1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2081,15 +2081,19 @@ namespace OpenSim.Framework try { long numRunning = numRunningThreadFuncs; - if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads)) - { - if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0) - m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning); - } - else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads*2)/3)) + + if (m_ThreadPool != null) { - if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1) - m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads)) + { + if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0) + m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + } + else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads * 2) / 3)) + { + if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1) + m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning); + } } if (loggingEnabled || (threadFuncOverloadMode == 1)) @@ -2325,6 +2329,13 @@ namespace OpenSim.Framework /// public static void RunThreadNoTimeout(WaitCallback callback, string name, object obj) { + if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) + { + Culture.SetCurrentCulture(); + callback(obj); + return; + } + Thread t = new Thread(delegate() { try -- cgit v1.1 From f901a3820497e0d99accb6f5f60f6517e07c2c8f Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 28 Nov 2013 23:07:14 +0200 Subject: Improved logging of HTTP requests - MemoryBuffer isn't seekable, so we can't log it. Log the string instead. - Handle compressed streams - Don't attempt to dump binary data. Either don't log it at all (if we know it's binary), or at least convert non-ASCII characters to ASCII. - Log responses to HTTP requests - Use the same log prefix for all of these log messages ("[LOGHTTP]"), to make them easy to see at a glance - Increased the snippet length to 200 (80 doesn't show enough), and add "..." only if the message was actually truncated Resolves http://opensimulator.org/mantis/view.php?id=6949 --- OpenSim/Framework/Util.cs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ae720f1..ce4af8b 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1510,6 +1510,46 @@ namespace OpenSim.Framework return result; } + public static void BinaryToASCII(char[] chars) + { + for (int i = 0; i < chars.Length; i++) + { + char ch = chars[i]; + if (ch < 32 || ch > 127) + chars[i] = '.'; + } + } + + public static string BinaryToASCII(string src) + { + char[] chars = src.ToCharArray(); + BinaryToASCII(chars); + return new String(chars); + } + + /// + /// Reads a known number of bytes from a stream. + /// Throws EndOfStreamException if the stream doesn't contain enough data. + /// + /// The stream to read data from + /// The array to write bytes into. The array + /// will be completely filled from the stream, so an appropriate + /// size must be given. + public static void ReadStream(Stream stream, byte[] data) + { + int offset = 0; + int remaining = data.Length; + + while (remaining > 0) + { + int read = stream.Read(data, offset, remaining); + if (read <= 0) + throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining)); + remaining -= read; + offset += read; + } + } + public static Guid GetHashGuid(string data, string salt) { byte[] hash = ComputeMD5Hash(data + salt); -- cgit v1.1 From 7a47c15edbbebd93fc3355dfed68c2d5f635c897 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Wed, 26 Mar 2014 21:31:16 +0200 Subject: - Increased the threadpool timeout to 10 minutes - Changed a few places that launch long-lasting threads to skip the timeout altogether --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index ce4af8b..c7a7341 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2031,7 +2031,7 @@ namespace OpenSim.Framework // Maps (ThreadFunc number -> Thread) private static ConcurrentDictionary activeThreads = new ConcurrentDictionary(); - private static readonly int THREAD_TIMEOUT = 60 * 1000; + private static readonly int THREAD_TIMEOUT = 10 * 60 * 1000; // 10 minutes /// /// Finds threads in the main thread pool that have timed-out, and aborts them. -- cgit v1.1 From d1c3f8eef58b29eb8760eeb1ac03852a2387f927 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Mon, 31 Mar 2014 11:53:12 +0300 Subject: Added assets service method AssetsExist(), which returns whether the given list of assets exist. This method is used to optimize sending assets with embedded assets: e.g., when a Hypergrid visitor takes an item into the inventory. --- OpenSim/Framework/Util.cs | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c7a7341..b133ff3 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -52,6 +52,8 @@ using OpenMetaverse; using OpenMetaverse.StructuredData; using Amib.Threading; using System.Collections.Concurrent; +using System.Collections.Specialized; +using System.Web; namespace OpenSim.Framework { @@ -866,6 +868,54 @@ namespace OpenSim.Framework } /// + /// Parses a foreign asset ID. + /// + /// A possibly-foreign asset ID: http://grid.example.com:8002/00000000-0000-0000-0000-000000000000 + /// The URL: http://grid.example.com:8002 + /// The asset ID: 00000000-0000-0000-0000-000000000000. Returned even if 'id' isn't foreign. + /// True: this is a foreign asset ID; False: it isn't + public static bool ParseForeignAssetID(string id, out string url, out string assetID) + { + url = String.Empty; + assetID = String.Empty; + + UUID uuid; + if (UUID.TryParse(id, out uuid)) + { + assetID = uuid.ToString(); + return false; + } + + if ((id.Length == 0) || (id[0] != 'h' && id[0] != 'H')) + return false; + + Uri assetUri; + if (!Uri.TryCreate(id, UriKind.Absolute, out assetUri) || assetUri.Scheme != Uri.UriSchemeHttp) + return false; + + // Simian + if (assetUri.Query != string.Empty) + { + NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query); + assetID = qscoll["id"]; + if (assetID != null) + url = id.Replace(assetID, ""); // Malformed again, as simian expects + else + url = id; // !!! best effort + } + else // robust + { + url = "http://" + assetUri.Authority; + assetID = assetUri.LocalPath.Trim(new char[] { '/' }); + } + + if (!UUID.TryParse(assetID, out uuid)) + return false; + + return true; + } + + /// /// Removes all invalid path chars (OS dependent) /// /// path -- cgit v1.1 From 5dc0298f8336b93d565f8ffb17367b02ebfd706f Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 24 Apr 2014 01:44:11 +0100 Subject: Apply logging flag to a spammy message that may have been overlooked. No one needs to see every thread launch..... --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b133ff3..c8a0c68 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2193,7 +2193,7 @@ namespace OpenSim.Framework threadInfo.StackTrace = full; threadInfo.LogThread = ShouldLogThread(partial); - if (threadInfo.LogThread) + if (loggingEnabled && threadInfo.LogThread) { m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", threadFuncNum, numQueued, numRunningThreadFuncs, -- cgit v1.1 From a108fcac957dd2283fb8904207addda6dc7582f0 Mon Sep 17 00:00:00 2001 From: Melanie Date: Fri, 25 Apr 2014 21:34:29 +0100 Subject: Restore overload mode accidentally disabled in a prior commit. Add a new config option, LogOverloads, to log when a thread pool overload occurs. This option defaults to "True" because the logging data is useful for diagnosing threading issues. --- OpenSim/Framework/Util.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index c8a0c68..740e55a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -127,12 +127,14 @@ namespace OpenSim.Framework /// 3 = full stack trace, including common threads /// public static int LogThreadPool { get; set; } + public static bool LogOverloads { get; set; } public static readonly int MAX_THREADPOOL_LEVEL = 3; static Util() { LogThreadPool = 0; + LogOverloads = true; } private static uint nextXferID = 5000; @@ -2172,7 +2174,7 @@ namespace OpenSim.Framework { long numRunning = numRunningThreadFuncs; - if (m_ThreadPool != null) + if (m_ThreadPool != null && LogOverloads) { if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads)) { @@ -2193,7 +2195,7 @@ namespace OpenSim.Framework threadInfo.StackTrace = full; threadInfo.LogThread = ShouldLogThread(partial); - if (loggingEnabled && threadInfo.LogThread) + if (threadInfo.LogThread) { m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}", threadFuncNum, numQueued, numRunningThreadFuncs, -- cgit v1.1 From 889194db63016ad4b9ecb0c6ae82d3d9c7632c95 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 2 Jul 2014 23:48:44 +0100 Subject: Actually call Close() for shared region modules when the simulator is being shutdown. Adds regression test for this case. --- OpenSim/Framework/Util.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 740e55a..729281c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1964,10 +1964,15 @@ namespace OpenSim.Framework { if (maxThreads < 2) throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); + if (minThreads > maxThreads || minThreads < 2) throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads"); + if (m_ThreadPool != null) - throw new InvalidOperationException("SmartThreadPool is already initialized"); + { + m_log.Warn("SmartThreadPool is already initialized. Ignoring request."); + return; + } STPStartInfo startInfo = new STPStartInfo(); startInfo.ThreadPoolName = "Util"; -- cgit v1.1 From 0c8f3dddd89bb1578797ada8f23bc1ed07d1afff Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 14 Jul 2014 20:08:11 +0100 Subject: Use thread-safe version of .NET Random as the SDK class is not thread-safe. As per http://msdn.microsoft.com/en-us/library/system.random%28v=vs.100%29.aspx, the .NET Random class is not thread-safe. If called by multiple threads at once, methods may return 0. Except for llRand(), other OpenSimulator code did not lock before calling a shared Random instance. This commit adds a ThreadSafeRandom class that extends Random but does internal locking so that it is thread-safe. This change is invisible to existing callers and the explicit locking in the llFrand() implementation is now redundant. --- OpenSim/Framework/Util.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 729281c..9d7de97 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -138,7 +138,7 @@ namespace OpenSim.Framework } private static uint nextXferID = 5000; - private static Random randomClass = new Random(); + private static Random randomClass = new ThreadSafeRandom(); // Get a list of invalid file characters (OS dependent) private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; -- cgit v1.1 From 99ac770abbe3a95887c4b10c82f3985aa878eeef Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Sun, 1 Jun 2014 17:39:11 +0300 Subject: Close streams immediately when we finish using them --- OpenSim/Framework/Util.cs | 53 ++++++++++++----------------------------------- 1 file changed, 13 insertions(+), 40 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 9d7de97..5c429ee 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -509,6 +509,19 @@ namespace OpenSim.Framework return sb.ToString(); } + public static byte[] DocToBytes(XmlDocument doc) + { + using (MemoryStream ms = new MemoryStream()) + using (XmlTextWriter xw = new XmlTextWriter(ms, null)) + { + xw.Formatting = Formatting.Indented; + doc.WriteTo(xw); + xw.Flush(); + + return ms.ToArray(); + } + } + /// /// Is the platform Windows? /// @@ -1307,46 +1320,6 @@ namespace OpenSim.Framework return ret; } - public static string Compress(string text) - { - byte[] buffer = Util.UTF8.GetBytes(text); - MemoryStream memory = new MemoryStream(); - using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) - { - compressor.Write(buffer, 0, buffer.Length); - } - - memory.Position = 0; - - byte[] compressed = new byte[memory.Length]; - memory.Read(compressed, 0, compressed.Length); - - byte[] compressedBuffer = new byte[compressed.Length + 4]; - Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); - Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); - return Convert.ToBase64String(compressedBuffer); - } - - public static string Decompress(string compressedText) - { - byte[] compressedBuffer = Convert.FromBase64String(compressedText); - using (MemoryStream memory = new MemoryStream()) - { - int msgLength = BitConverter.ToInt32(compressedBuffer, 0); - memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); - - byte[] buffer = new byte[msgLength]; - - memory.Position = 0; - using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) - { - decompressor.Read(buffer, 0, buffer.Length); - } - - return Util.UTF8.GetString(buffer); - } - } - /// /// Copy data from one stream to another, leaving the read position of both streams at the beginning. /// -- cgit v1.1 From 48d1cca30338f087ccb26ec2d00dea183a32fff8 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 12 Jun 2014 15:02:25 +0300 Subject: Better logging of threadpool activity in Overload mode: if we didn't log "Queue threadfunc" for a particular thread then don't log "Run threadfunc" or "End threadfunc" for that thread either. --- OpenSim/Framework/Util.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 5c429ee..2d0178e 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2000,7 +2000,7 @@ namespace OpenSim.Framework { ThreadFuncNum = threadFuncNum; this.context = context; - LogThread = true; + LogThread = false; Thread = null; Running = false; Aborted = false; @@ -2181,6 +2181,12 @@ namespace OpenSim.Framework (LogThreadPool >= 2) ? full : partial); } } + else + { + // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either. + // Those log lines aren't useful when we don't know which function is running in the thread. + threadInfo.LogThread = false; + } switch (FireAndForgetMethod) { -- cgit v1.1 From 1b75ec5647afeb9fbdad78f70c0c90a829bba076 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 29 Aug 2014 19:08:23 +0100 Subject: Ignore whitespace when reading serialized XML objects. This was previously effectively being done by XmlDocument in the multiple passes through the XML. This change tells XmlReader to ignore whitespace. This also means changing arguments to use XmlReader instead of XmlTextReader (a descendent of XmlReader) directly. XmlReader.Create() has been the recommend way to create XML readers since .NET 2.0 as per MS SDK and is the only way to specific ignore whitespace settings. --- OpenSim/Framework/Util.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2d0178e..2c38571 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2605,7 +2605,7 @@ namespace OpenSim.Framework } #region Xml Serialization Utilities - public static bool ReadBoolean(XmlTextReader reader) + public static bool ReadBoolean(XmlReader reader) { // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this. reader.ReadStartElement(); @@ -2616,7 +2616,7 @@ namespace OpenSim.Framework return result; } - public static UUID ReadUUID(XmlTextReader reader, string name) + public static UUID ReadUUID(XmlReader reader, string name) { UUID id; string idStr; @@ -2635,7 +2635,7 @@ namespace OpenSim.Framework return id; } - public static Vector3 ReadVector(XmlTextReader reader, string name) + public static Vector3 ReadVector(XmlReader reader, string name) { Vector3 vec; @@ -2648,7 +2648,7 @@ namespace OpenSim.Framework return vec; } - public static Quaternion ReadQuaternion(XmlTextReader reader, string name) + public static Quaternion ReadQuaternion(XmlReader reader, string name) { Quaternion quat = new Quaternion(); @@ -2677,7 +2677,7 @@ namespace OpenSim.Framework return quat; } - public static T ReadEnum(XmlTextReader reader, string name) + public static T ReadEnum(XmlReader reader, string name) { string value = reader.ReadElementContentAsString(name, String.Empty); // !!!!! to deal with flags without commas -- cgit v1.1 From 41f2f3132bdcbfb8020c7fd6e5f3b7e48c75b1cf Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 5 Sep 2014 23:20:59 +0100 Subject: For monitoring purposes, start non-timeout tasks (which do not currently use a threadpool) via Watchdog.RunInThread() rather than Util.RunThreadNoTimeout() The functionality is the same but this allow us to monitor such tasks via "show threads" and abort them for test purposes, etc. Also extends thread names to provide more info (e.g. SendInitialDataToClient says what client the task is for). --- OpenSim/Framework/Util.cs | 30 ------------------------------ 1 file changed, 30 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2c38571..fefa050 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2400,36 +2400,6 @@ namespace OpenSim.Framework #endregion FireAndForget Threading Pattern /// - /// Run the callback on a different thread, outside the thread pool. This is used for tasks - /// that may take a long time. - /// - public static void RunThreadNoTimeout(WaitCallback callback, string name, object obj) - { - if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) - { - Culture.SetCurrentCulture(); - callback(obj); - return; - } - - Thread t = new Thread(delegate() - { - try - { - Culture.SetCurrentCulture(); - callback(obj); - } - catch (Exception e) - { - m_log.Error("Exception in thread " + name, e); - } - }); - - t.Name = name; - t.Start(); - } - - /// /// Environment.TickCount is an int but it counts all 32 bits so it goes positive /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap /// for the callers. -- cgit v1.1 From 72cb1cc7d6b1dc69e959581817c70e92435d002f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Mon, 3 Nov 2014 23:49:11 +0000 Subject: Add "show threadpool calls" command to show count of all labelled smartthreadpool calls --- OpenSim/Framework/Util.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index fefa050..53bbb06 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2086,14 +2086,28 @@ namespace OpenSim.Framework } } + public static Dictionary GetFireAndForgetCallsMade() + { + return new Dictionary(m_fireAndForgetCallsMade); + } + + private static Dictionary m_fireAndForgetCallsMade = new Dictionary(); public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { FireAndForget(callback, obj, null); } - + public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) { + if (context != null) + { + if (!m_fireAndForgetCallsMade.ContainsKey(context)) + m_fireAndForgetCallsMade[context] = 1; + else + m_fireAndForgetCallsMade[context]++; + } + WaitCallback realCallback; bool loggingEnabled = LogThreadPool > 0; -- cgit v1.1 From ec8d21c434a39f46518ee9cf9f5539d1790eacc0 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 4 Nov 2014 00:55:48 +0000 Subject: Label all threadpool calls being made in core OpenSimulator. This is to add problem diagnosis. "show threadpool calls" now also returns named (labelled), anonymous (unlabelled) and total call stats. --- OpenSim/Framework/Util.cs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 53bbb06..baad0b9 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1928,11 +1928,6 @@ namespace OpenSim.Framework } } - public static void FireAndForget(System.Threading.WaitCallback callback) - { - FireAndForget(callback, null, null); - } - public static void InitThreadPool(int minThreads, int maxThreads) { if (maxThreads < 2) @@ -1977,8 +1972,7 @@ namespace OpenSim.Framework throw new NotImplementedException(); } } - - + /// /// Additional information about threads in the main thread pool. Used to time how long the /// thread has been running, and abort it if it has timed-out. @@ -2052,10 +2046,10 @@ namespace OpenSim.Framework } } - private static long nextThreadFuncNum = 0; private static long numQueuedThreadFuncs = 0; private static long numRunningThreadFuncs = 0; + private static long numTotalThreadFuncsCalled = 0; private static Int32 threadFuncOverloadMode = 0; // Maps (ThreadFunc number -> Thread) @@ -2086,20 +2080,29 @@ namespace OpenSim.Framework } } + public static long TotalFireAndForgetCallsMade { get { return numTotalThreadFuncsCalled; } } + public static Dictionary GetFireAndForgetCallsMade() { return new Dictionary(m_fireAndForgetCallsMade); - } + } private static Dictionary m_fireAndForgetCallsMade = new Dictionary(); + public static void FireAndForget(System.Threading.WaitCallback callback) + { + FireAndForget(callback, null, null); + } + public static void FireAndForget(System.Threading.WaitCallback callback, object obj) { FireAndForget(callback, obj, null); } - + public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) { + Interlocked.Increment(ref numTotalThreadFuncsCalled); + if (context != null) { if (!m_fireAndForgetCallsMade.ContainsKey(context)) -- cgit v1.1 From f54c70741b4008c242aa8f088be7551bfe41ac1f Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Tue, 4 Nov 2014 17:21:22 +0000 Subject: Add "show threadpool calls active" console debug command. This shows named threadpool calls (excluding timer and network calls) that are currently queued or running. Also shows total of labelled and any anonymous calls. --- OpenSim/Framework/Util.cs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index baad0b9..97c958a 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2052,6 +2052,9 @@ namespace OpenSim.Framework private static long numTotalThreadFuncsCalled = 0; private static Int32 threadFuncOverloadMode = 0; + public static long TotalQueuedFireAndForgetCalls { get { return numQueuedThreadFuncs; } } + public static long TotalRunningFireAndForgetCalls { get { return numRunningThreadFuncs; } } + // Maps (ThreadFunc number -> Thread) private static ConcurrentDictionary activeThreads = new ConcurrentDictionary(); @@ -2089,6 +2092,13 @@ namespace OpenSim.Framework private static Dictionary m_fireAndForgetCallsMade = new Dictionary(); + public static Dictionary GetFireAndForgetCallsInProgress() + { + return new Dictionary(m_fireAndForgetCallsInProgress); + } + + private static Dictionary m_fireAndForgetCallsInProgress = new Dictionary(); + public static void FireAndForget(System.Threading.WaitCallback callback) { FireAndForget(callback, null, null); @@ -2109,6 +2119,11 @@ namespace OpenSim.Framework m_fireAndForgetCallsMade[context] = 1; else m_fireAndForgetCallsMade[context]++; + + if (!m_fireAndForgetCallsInProgress.ContainsKey(context)) + m_fireAndForgetCallsInProgress[context] = 1; + else + m_fireAndForgetCallsInProgress[context]++; } WaitCallback realCallback; @@ -2121,7 +2136,15 @@ namespace OpenSim.Framework if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) { // If we're running regression tests, then we want any exceptions to rise up to the test code. - realCallback = o => { Culture.SetCurrentCulture(); callback(o); }; + realCallback = + o => + { + Culture.SetCurrentCulture(); + callback(o); + + if (context != null) + m_fireAndForgetCallsInProgress[context]--; + }; } else { @@ -2160,6 +2183,9 @@ namespace OpenSim.Framework activeThreads.TryRemove(threadFuncNum, out dummy); if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); + + if (context != null) + m_fireAndForgetCallsInProgress[context]--; } }; } -- cgit v1.1 From 53c8318124b7750f2d8a6e6b67ba447a0b99c2cf Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sat, 3 Jan 2015 21:53:18 -0800 Subject: Added utility function that simplifies configuration loading of all addins. --- OpenSim/Framework/Util.cs | 57 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 97c958a..6f2e7c3 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -1191,6 +1191,63 @@ namespace OpenSim.Framework return settingsClass; } + /// + /// Reads a configuration file, configFile, merging it with the main configuration, config. + /// If the file doesn't exist, it copies a given exampleConfigFile onto configFile, and then + /// merges it. + /// + /// The main configuration data + /// The name of a configuration file in ConfigDirectory variable, no path + /// Full path to an example configuration file + /// Full path ConfigDirectory/configFileName + /// True if the file was created in ConfigDirectory, false if it existed + /// True if success + public static bool MergeConfigurationFile(IConfigSource config, string configFileName, string exampleConfigFile, out string configFilePath, out bool created) + { + created = false; + configFilePath = string.Empty; + + IConfig cnf = config.Configs["Startup"]; + if (cnf == null) + { + m_log.WarnFormat("[UTILS]: Startup section doesn't exist"); + return false; + } + + string configDirectory = cnf.GetString("ConfigDirectory", "."); + string configFile = Path.Combine(configDirectory, configFileName); + + if (!File.Exists(configFile) && !string.IsNullOrEmpty(exampleConfigFile)) + { + // We need to copy the example onto it + + if (!Directory.Exists(configDirectory)) + Directory.CreateDirectory(configDirectory); + + try + { + File.Copy(exampleConfigFile, configFile); + created = true; + } + catch (Exception e) + { + m_log.WarnFormat("[UTILS]: Exception copying configuration file {0} to {1}: {2}", configFile, exampleConfigFile, e.Message); + return false; + } + } + + if (File.Exists(configFile)) + { + // Merge + config.Merge(new IniConfigSource(configFile)); + config.ExpandKeyValues(); + configFilePath = configFile; + return true; + } + else + return false; + } + #endregion public static float Clip(float x, float min, float max) -- cgit v1.1 From ce1a87b7843ed05e8d827c230c9860e7bf7d75b6 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Sun, 4 Jan 2015 19:06:49 -0800 Subject: Added overloaded LoadArchSpecificWindowsDll, to help addins load native libraries. --- OpenSim/Framework/Util.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 6f2e7c3..836fa5f 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -538,6 +538,11 @@ namespace OpenSim.Framework public static bool LoadArchSpecificWindowsDll(string libraryName) { + return LoadArchSpecificWindowsDll(libraryName, string.Empty); + } + + public static bool LoadArchSpecificWindowsDll(string libraryName, string path) + { // We do this so that OpenSimulator on Windows loads the correct native library depending on whether // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports // will find it already loaded later on. @@ -547,9 +552,9 @@ namespace OpenSim.Framework string nativeLibraryPath; if (Util.Is64BitProcess()) - nativeLibraryPath = "lib64/" + libraryName; + nativeLibraryPath = Path.Combine(Path.Combine(path, "lib64"), libraryName); else - nativeLibraryPath = "lib32/" + libraryName; + nativeLibraryPath = Path.Combine(Path.Combine(path, "lib32"), libraryName); m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath); -- cgit v1.1 From 8b2af1071f37e45dc330524a4731581867616b21 Mon Sep 17 00:00:00 2001 From: dahlia Date: Mon, 16 Feb 2015 23:51:37 -0800 Subject: Add NaN and Infinity tests for SOP Velocity and Acceleration setters. --- OpenSim/Framework/Util.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 836fa5f..56a90b1 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -420,6 +420,22 @@ namespace OpenSim.Framework return x; } + /// + /// Check if any of the values in a Vector3 are NaN or Infinity + /// + /// Vector3 to check + /// + public static bool IsNanOrInfinity(Vector3 v) + { + if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z)) + return true; + + if (float.IsInfinity(v.X) || float.IsInfinity(v.Y) || float.IsNaN(v.Z)) + return true; + + return false; + } + // Inclusive, within range test (true if equal to the endpoints) public static bool InRange(T x, T min, T max) where T : IComparable -- cgit v1.1 From 0af17c94848724c0d56d4be12c01983b4793b8bf Mon Sep 17 00:00:00 2001 From: Cinder Date: Wed, 27 May 2015 08:55:49 -0600 Subject: llListRandomize() wasn't very random Signed-off-by: Diva Canto --- OpenSim/Framework/Util.cs | 51 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 56a90b1..2d0b280 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -3036,4 +3036,55 @@ namespace OpenSim.Framework } } } + + public class BetterRandom + { + private const int BufferSize = 1024; // must be a multiple of 4 + private byte[] RandomBuffer; + private int BufferOffset; + private RNGCryptoServiceProvider rng; + public BetterRandom() + { + RandomBuffer = new byte[BufferSize]; + rng = new RNGCryptoServiceProvider(); + BufferOffset = RandomBuffer.Length; + } + private void FillBuffer() + { + rng.GetBytes(RandomBuffer); + BufferOffset = 0; + } + public int Next() + { + if (BufferOffset >= RandomBuffer.Length) + { + FillBuffer(); + } + int val = BitConverter.ToInt32(RandomBuffer, BufferOffset) & 0x7fffffff; + BufferOffset += sizeof(int); + return val; + } + public int Next(int maxValue) + { + return Next() % maxValue; + } + public int Next(int minValue, int maxValue) + { + if (maxValue < minValue) + { + throw new ArgumentOutOfRangeException("maxValue must be greater than or equal to minValue"); + } + int range = maxValue - minValue; + return minValue + Next(range); + } + public double NextDouble() + { + int val = Next(); + return (double)val / int.MaxValue; + } + public void GetBytes(byte[] buff) + { + rng.GetBytes(buff); + } + } } -- cgit v1.1 From 83da58226114ddda41c984fed8298908ed012c8b Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Thu, 23 Jul 2015 14:50:50 +0300 Subject: Removed unused code related to DNS lookups --- OpenSim/Framework/Util.cs | 36 ------------------------------------ 1 file changed, 36 deletions(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 2d0b280..4e75a5c 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -805,16 +805,6 @@ namespace OpenSim.Framework } /// - /// Converts a URL to a IPAddress - /// - /// URL Standard Format - /// A resolved IP Address - public static IPAddress GetHostFromURL(string url) - { - return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); - } - - /// /// Returns a IP address from a specified DNS, favouring IPv4 addresses. /// /// DNS Hostname @@ -1802,32 +1792,6 @@ namespace OpenSim.Framework return found.ToArray(); } - public static string ServerURI(string uri) - { - if (uri == string.Empty) - return string.Empty; - - // Get rid of eventual slashes at the end - uri = uri.TrimEnd('/'); - - IPAddress ipaddr1 = null; - string port1 = ""; - try - { - ipaddr1 = Util.GetHostFromURL(uri); - } - catch { } - - try - { - port1 = uri.Split(new char[] { ':' })[2]; - } - catch { } - - // We tried our best to convert the domain names to IP addresses - return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; - } - /// /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. /// -- cgit v1.1 From 2153a01cc7eb8667fa0c9fc76a36b178566bf444 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Fri, 7 Aug 2015 11:34:52 +0300 Subject: Have osAvatarName2Key check the cache first, even for foreign users Another change: removed the second call to userManager.AddUser(). UserManagementModule won't modify an existing record. --- OpenSim/Framework/Util.cs | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 4e75a5c..875f4ad 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2744,7 +2744,9 @@ namespace OpenSim.Framework #endregion #region Universal User Identifiers - /// + + /// + /// Attempts to parse a UUI into its components: UUID, name and URL. /// /// uuid[;endpoint[;first last[;secret]]] /// the uuid part @@ -2780,6 +2782,27 @@ namespace OpenSim.Framework } /// + /// For foreign avatars, extracts their original name and Server URL from their First Name and Last Name. + /// + public static bool ParseForeignAvatarName(string firstname, string lastname, + out string realFirstName, out string realLastName, out string serverURI) + { + realFirstName = realLastName = serverURI = string.Empty; + + if (!lastname.Contains("@")) + return false; + + if (!firstname.Contains(".")) + return false; + + realFirstName = firstname.Split('.')[0]; + realLastName = firstname.Split('.')[1]; + serverURI = new Uri("http://" + lastname.Replace("@", "")).ToString(); + + return true; + } + + /// /// Produces a universal (HG) system-facing identifier given the information /// /// -- cgit v1.1 From 4ad1468165b80f67439399e36688d36944996312 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Sun, 5 Jul 2015 16:05:01 +0300 Subject: Better handling of invalid XML: a) prevent infinite loop on EOF; b) better logging If the XML was truncated for some reason then ExecuteReadProcessors() would get into an infinite loop, using high CPU. Now it detects EOF (and several other error cases) and aborts. The rest of the changes just improve logging of XML in case of errors, so that we can see what the bad XML is. --- OpenSim/Framework/Util.cs | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'OpenSim/Framework/Util.cs') diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index 875f4ad..a5f798d 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -2910,6 +2910,16 @@ namespace OpenSim.Framework return name; } + + public static void LogFailedXML(string message, string xml) + { + int length = xml.Length; + if (length > 2000) + xml = xml.Substring(0, 2000) + "..."; + + m_log.ErrorFormat("{0} Failed XML ({1} bytes) = {2}", message, length, xml); + } + } public class DoubleQueue where T:class -- cgit v1.1