From 749c3fef8ad2d3af97fcd9ab9c72740675e46715 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Thu, 8 Mar 2012 01:51:37 +0000 Subject: Change "help" to display categories/module list then "help " to display commands in a category. This is to deal with the hundred lines of command splurge when one previously typed "help" Modelled somewhat on the mysql console One can still type help to get per command help at any point. Categories capitalized to avoid conflict with the all-lowercase commands (except for commander system, as of yet). Does not affect command parsing or any other aspects of the console apart from the help system. Backwards compatible with existing modules. --- OpenSim/Framework/Console/CommandConsole.cs | 114 ++++++++++++++++++++----- OpenSim/Framework/ICommandConsole.cs | 2 +- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 20 ++--- 3 files changed, 103 insertions(+), 33 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index 0d6288b..2bb7de1 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs @@ -29,6 +29,7 @@ using System; using System.Xml; using System.Collections.Generic; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Text; using System.Text.RegularExpressions; @@ -40,6 +41,8 @@ namespace OpenSim.Framework.Console { public class Commands : ICommands { +// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + /// /// Encapsulates a command that can be invoked from the console /// @@ -76,6 +79,8 @@ namespace OpenSim.Framework.Console public List fn; } + public const string GeneralHelpText = "For more information, type 'help ' where is one of the following categories:"; + /// /// Commands organized by keyword in a tree /// @@ -83,6 +88,11 @@ namespace OpenSim.Framework.Console new Dictionary(); /// + /// Commands organized by module + /// + private Dictionary> m_modulesCommands = new Dictionary>(); + + /// /// Get help for the given help string /// /// Parsed parts of the help string. If empty then general help is returned. @@ -98,8 +108,8 @@ namespace OpenSim.Framework.Console // General help if (helpParts.Count == 0) { - help.AddRange(CollectHelp(tree)); - help.Sort(); + help.Add(GeneralHelpText); + help.AddRange(CollectModulesHelp(tree)); } else { @@ -118,6 +128,13 @@ namespace OpenSim.Framework.Console { string originalHelpRequest = string.Join(" ", helpParts.ToArray()); List help = new List(); + + // Check modules first to see if we just need to display a list of those commands + if (TryCollectModuleHelp(originalHelpRequest, help)) + { + help.Insert(0, GeneralHelpText); + return help; + } Dictionary dict = tree; while (helpParts.Count > 0) @@ -161,25 +178,61 @@ namespace OpenSim.Framework.Console return help; } - private List CollectHelp(Dictionary dict) + /// + /// Try to collect help for the given module if that module exists. + /// + /// + /// /param> + /// true if there was the module existed, false otherwise. + private bool TryCollectModuleHelp(string moduleName, List helpText) { - List result = new List(); - - foreach (KeyValuePair kvp in dict) + lock (m_modulesCommands) { - if (kvp.Value is Dictionary) + if (m_modulesCommands.ContainsKey(moduleName)) { - result.AddRange(CollectHelp((Dictionary)kvp.Value)); + List commands = m_modulesCommands[moduleName]; + var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help)); + ourHelpText.Sort(); + helpText.AddRange(ourHelpText); + + return true; } else { - if (((CommandInfo)kvp.Value).long_help != String.Empty) - result.Add(((CommandInfo)kvp.Value).help_text+" - "+ - ((CommandInfo)kvp.Value).long_help); + return false; } } - return result; } + + private List CollectModulesHelp(Dictionary dict) + { + lock (m_modulesCommands) + { + List helpText = new List(m_modulesCommands.Keys); + helpText.Sort(); + return helpText; + } + } + +// private List CollectHelp(Dictionary dict) +// { +// List result = new List(); +// +// foreach (KeyValuePair kvp in dict) +// { +// if (kvp.Value is Dictionary) +// { +// result.AddRange(CollectHelp((Dictionary)kvp.Value)); +// } +// else +// { +// if (((CommandInfo)kvp.Value).long_help != String.Empty) +// result.Add(((CommandInfo)kvp.Value).help_text+" - "+ +// ((CommandInfo)kvp.Value).long_help); +// } +// } +// return result; +// } /// /// Add a command to those which can be invoked from the console. @@ -212,21 +265,19 @@ namespace OpenSim.Framework.Console Dictionary current = tree; - foreach (string s in parts) + foreach (string part in parts) { - if (current.ContainsKey(s)) + if (current.ContainsKey(part)) { - if (current[s] is Dictionary) - { - current = (Dictionary)current[s]; - } + if (current[part] is Dictionary) + current = (Dictionary)current[part]; else return; } else { - current[s] = new Dictionary(); - current = (Dictionary)current[s]; + current[part] = new Dictionary(); + current = (Dictionary)current[part]; } } @@ -250,6 +301,24 @@ namespace OpenSim.Framework.Console info.fn = new List(); info.fn.Add(fn); current[String.Empty] = info; + + // Now add command to modules dictionary + lock (m_modulesCommands) + { + List commands; + if (m_modulesCommands.ContainsKey(module)) + { + commands = m_modulesCommands[module]; + } + else + { + commands = new List(); + m_modulesCommands[module] = commands; + } + +// m_log.DebugFormat("[COMMAND CONSOLE]: Adding to category {0} command {1}", module, command); + commands.Add(info); + } } public string[] FindNextOption(string[] cmd, bool term) @@ -607,8 +676,9 @@ namespace OpenSim.Framework.Console { Commands = new Commands(); - Commands.AddCommand("console", false, "help", "help []", - "Get general command list or more detailed help on a specific command", Help); + Commands.AddCommand( + "Help", false, "help", "help []", + "Display help on a particular command or on a list of commands in a category", Help); } private void Help(string module, string[] cmd) diff --git a/OpenSim/Framework/ICommandConsole.cs b/OpenSim/Framework/ICommandConsole.cs index d33b9b5..ca0ff93 100644 --- a/OpenSim/Framework/ICommandConsole.cs +++ b/OpenSim/Framework/ICommandConsole.cs @@ -40,7 +40,7 @@ namespace OpenSim.Framework /// /// Get help for the given help string /// - /// Parsed parts of the help string. If empty then general help is returned. + /// Parsed parts of the help string. If empty then general help is returned. /// List GetHelp(string[] cmd); diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 6a3135e..d5c2515 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -161,43 +161,43 @@ namespace OpenSim.Framework.Servers Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold)); } - m_console.Commands.AddCommand("base", false, "quit", + m_console.Commands.AddCommand("General", false, "quit", "quit", "Quit the application", HandleQuit); - m_console.Commands.AddCommand("base", false, "shutdown", + m_console.Commands.AddCommand("General", false, "shutdown", "shutdown", "Quit the application", HandleQuit); - m_console.Commands.AddCommand("base", false, "set log level", + m_console.Commands.AddCommand("General", false, "set log level", "set log level ", "Set the console logging level", HandleLogLevel); - m_console.Commands.AddCommand("base", false, "show info", + m_console.Commands.AddCommand("General", false, "show info", "show info", "Show general information about the server", HandleShow); - m_console.Commands.AddCommand("base", false, "show stats", + m_console.Commands.AddCommand("General", false, "show stats", "show stats", "Show statistics", HandleShow); - m_console.Commands.AddCommand("base", false, "show threads", + m_console.Commands.AddCommand("General", false, "show threads", "show threads", "Show thread status", HandleShow); - m_console.Commands.AddCommand("base", false, "show uptime", + m_console.Commands.AddCommand("General", false, "show uptime", "show uptime", "Show server uptime", HandleShow); - m_console.Commands.AddCommand("base", false, "show version", + m_console.Commands.AddCommand("General", false, "show version", "show version", "Show server version", HandleShow); - m_console.Commands.AddCommand("base", false, "threads abort", + m_console.Commands.AddCommand("General", false, "threads abort", "threads abort ", "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); - m_console.Commands.AddCommand("base", false, "threads show", + m_console.Commands.AddCommand("General", false, "threads show", "threads show", "Show thread status. Synonym for \"show threads\"", (string module, string[] args) => Notice(GetThreadsReport())); -- cgit v1.1 From bdc968f1fcd4008e9f2a6099a7d30edb075ca0f1 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 9 Mar 2012 23:57:24 +0000 Subject: Factor out common default animations code into SLUtil. LLClientView now makes use of the SLUtil copy via a method rather than each LLClientView loading a separate copy. As per opensim-users mailing list discussion. --- OpenSim/Framework/SLUtil.cs | 52 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index b337e03..f9cb851 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -28,6 +28,7 @@ using System; using System.Collections.Generic; using System.Reflection; +using System.Xml; using log4net; using OpenMetaverse; @@ -39,6 +40,13 @@ namespace OpenSim.Framework #region SL / file extension / content-type conversions + public static Dictionary DefaultAvatarAnimations = new Dictionary(); + + static SLUtil() + { + DefaultAvatarAnimations = LoadDefaultAvatarAnimations("data/avataranimations.xml"); + } + public static string SLAssetTypeToContentType(int assetType) { switch ((AssetType)assetType) @@ -374,5 +382,47 @@ namespace OpenSim.Framework return output; } + + /// + /// Load the default SL avatar animations. + /// + /// + public static Dictionary LoadDefaultAvatarAnimations(string path) + { + Dictionary animations = new Dictionary(); + + using (XmlTextReader reader = new XmlTextReader(path)) + { + XmlDocument doc = new XmlDocument(); + doc.Load(reader); + if (doc.DocumentElement != null) + { + foreach (XmlNode nod in doc.DocumentElement.ChildNodes) + { + if (nod.Attributes["name"] != null) + { + string name = nod.Attributes["name"].Value.ToLower(); + string id = nod.InnerText; + animations.Add(name, (UUID)id); + } + } + } + } + + return animations; + } + + /// + /// Get the default SL avatar animation with the given name. + /// + /// + /// + public static UUID GetDefaultAvatarAnimation(string name) + { + if (DefaultAvatarAnimations.ContainsKey(name)) + return DefaultAvatarAnimations[name]; + + return UUID.Zero; + } } -} +} \ No newline at end of file -- cgit v1.1 From 7b8e9d88e38ed0f7e50c6bfca6e2bbf82855ef09 Mon Sep 17 00:00:00 2001 From: Mic Bowman Date: Mon, 27 Feb 2012 20:04:11 -0800 Subject: Serialize all web requests to a particular host:port pair; only applied to the PostToService variants. --- OpenSim/Framework/WebUtil.cs | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index af25da9..77f3d9b 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -63,6 +63,31 @@ namespace OpenSim.Framework // a "long" call for warning & debugging purposes public const int LongCallTime = 500; + // dictionary of end points + private static Dictionary m_endpointSerializer = new Dictionary(); + + + private static object EndPointLock(string url) + { + System.Uri uri = new System.Uri(url); + string endpoint = string.Format("{0}:{1}",uri.Host,uri.Port); + + lock (m_endpointSerializer) + { + object eplock = null; + + if (! m_endpointSerializer.TryGetValue(endpoint,out eplock)) + { + eplock = new object(); + m_endpointSerializer.Add(endpoint,eplock); + // m_log.WarnFormat("[WEB UTIL] add a new host to end point serializer {0}",endpoint); + } + + return eplock; + } + } + + #region JSONRequest /// @@ -96,6 +121,14 @@ namespace OpenSim.Framework public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) { + lock (EndPointLock(url)) + { + return ServiceOSDRequestWorker(url,data,method,timeout,compressed); + } + } + + private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) + { int reqnum = m_requestNumber++; // m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method); @@ -248,6 +281,14 @@ namespace OpenSim.Framework public static OSDMap ServiceFormRequest(string url, NameValueCollection data, int timeout) { + lock (EndPointLock(url)) + { + return ServiceFormRequestWorker(url,data,timeout); + } + } + + private static OSDMap ServiceFormRequestWorker(string url, NameValueCollection data, int timeout) + { int reqnum = m_requestNumber++; string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown"; // m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method); -- cgit v1.1 From e0dd38f6722e891cfc91c8d795604b7b78c0bc81 Mon Sep 17 00:00:00 2001 From: Robert Adams Date: Mon, 12 Mar 2012 10:07:04 -0700 Subject: Rename the stream extension method WebUtil.CopyTo() to WebUtil.CopyStream(). .NET 4.0 added the method Stream.CopyTo(stream, bufferSize). For .NET 3.5 and before, WebUtil defined an extension method for Stream with the signature Stream.CopyTo(stream, maxBytesToCopy). The meaning of the second parameter is different in the two forms and depending on which compiler and/or runtime you use, you could get one form or the other. Crashes ensue. This change renames the WebUtil stream copy method to something that cannot be confused with the new CopyTo method defined in .NET 4.0. --- OpenSim/Framework/MultipartForm.cs | 2 +- OpenSim/Framework/WebUtil.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/MultipartForm.cs b/OpenSim/Framework/MultipartForm.cs index 90c4007..7a13e8b 100644 --- a/OpenSim/Framework/MultipartForm.cs +++ b/OpenSim/Framework/MultipartForm.cs @@ -119,7 +119,7 @@ namespace OpenSim.Framework // Copy the temporary stream to the network stream formDataStream.Seek(0, SeekOrigin.Begin); using (Stream requestStream = request.GetRequestStream()) - formDataStream.CopyTo(requestStream, (int)formDataStream.Length); + formDataStream.CopyStream(requestStream, (int)formDataStream.Length); } #endregion Stream Writing diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs index 77f3d9b..ead8f46 100644 --- a/OpenSim/Framework/WebUtil.cs +++ b/OpenSim/Framework/WebUtil.cs @@ -510,8 +510,13 @@ namespace OpenSim.Framework /// /// Copying begins at the streams' current positions. The positions are /// NOT reset after copying is complete. + /// NOTE!! .NET 4.0 adds the method 'Stream.CopyTo(stream, bufferSize)'. + /// This function could be replaced with that method once we move + /// totally to .NET 4.0. For versions before, this routine exists. + /// This routine used to be named 'CopyTo' but the int parameter has + /// a different meaning so this method was renamed to avoid any confusion. /// - public static int CopyTo(this Stream copyFrom, Stream copyTo, int maximumBytesToCopy) + public static int CopyStream(this Stream copyFrom, Stream copyTo, int maximumBytesToCopy) { byte[] buffer = new byte[4096]; int readBytes; -- 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/Statistics/BaseStatsCollector.cs | 8 ++++++-- OpenSim/Framework/Util.cs | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Statistics/BaseStatsCollector.cs b/OpenSim/Framework/Statistics/BaseStatsCollector.cs index a1841c5..c9e57ce 100644 --- a/OpenSim/Framework/Statistics/BaseStatsCollector.cs +++ b/OpenSim/Framework/Statistics/BaseStatsCollector.cs @@ -26,8 +26,8 @@ */ using System; +using System.Diagnostics; using System.Text; - using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -46,8 +46,12 @@ namespace OpenSim.Framework.Statistics sb.Append(Environment.NewLine); sb.Append( string.Format( - "Allocated to OpenSim : {0} MB" + Environment.NewLine, + "Allocated to OpenSim objects: {0} MB\n", Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0))); + sb.Append( + string.Format( + "Process memory : {0} MB\n", + Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0))); return sb.ToString(); } 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/Servers/BaseOpenSimServer.cs | 8 +--- OpenSim/Framework/Util.cs | 56 +++++++++++++++++++++++++- 2 files changed, 57 insertions(+), 7 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index d5c2515..5c74ac9 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -272,12 +272,8 @@ namespace OpenSim.Framework.Servers sb.Append(Environment.NewLine); } - int workers = 0, ports = 0, maxWorkers = 0, maxPorts = 0; - ThreadPool.GetAvailableThreads(out workers, out ports); - ThreadPool.GetMaxThreads(out maxWorkers, out maxPorts); - - sb.Append(Environment.NewLine + "*** ThreadPool threads ***" + Environment.NewLine); - sb.Append("workers: " + (maxWorkers - workers) + " (" + maxWorkers + "); ports: " + (maxPorts - ports) + " (" + maxPorts + ")" + Environment.NewLine); + sb.Append("\n*** Main threadpool (excluding script engine)***\n"); + sb.Append(Util.GetThreadPoolReport()); return sb.ToString(); } 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 bece2023e754d3d2c09753ad853f68c84243505c Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Mar 2012 03:52:13 +0000 Subject: Add total scripts count to "show threads" However, this returns 0 on Mono (at least on 2.6.7)! So not showing if it is zero. --- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 5c74ac9..6da1436 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -269,10 +269,18 @@ namespace OpenSim.Framework.Servers t.Priority, t.ThreadState); - sb.Append(Environment.NewLine); + sb.Append("\n"); } - sb.Append("\n*** Main threadpool (excluding script engine)***\n"); + sb.Append("\n"); + + // For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting + // zero active threads. + int totalThreads = Process.GetCurrentProcess().Threads.Count; + if (totalThreads > 0) + sb.AppendFormat("Total threads active: {0}\n\n", Process.GetCurrentProcess().Threads.Count); + + sb.Append("Main threadpool (excluding script engine pools)\n"); sb.Append(Util.GetThreadPoolReport()); return sb.ToString(); -- cgit v1.1 From 59b6f6a6e03417360d9ea94b8e9cabc8569ffe89 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Fri, 16 Mar 2012 03:56:56 +0000 Subject: minor: reuse threadpool count we just fetched instead of fetching it again --- OpenSim/Framework/Servers/BaseOpenSimServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs index 6da1436..06a8021 100644 --- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs +++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs @@ -278,7 +278,7 @@ namespace OpenSim.Framework.Servers // zero active threads. int totalThreads = Process.GetCurrentProcess().Threads.Count; if (totalThreads > 0) - sb.AppendFormat("Total threads active: {0}\n\n", Process.GetCurrentProcess().Threads.Count); + sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); sb.Append("Main threadpool (excluding script engine pools)\n"); sb.Append(Util.GetThreadPoolReport()); -- 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') 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') 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') 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') 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') 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 54a8a5baba4d7d3992cfe2c777c65eac812f7229 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 21 Mar 2012 02:02:14 +0000 Subject: If "debug scene updates true" then print out to log when a garbage collection occurs. --- OpenSim/Framework/GcNotify.cs | 62 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 OpenSim/Framework/GcNotify.cs (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/GcNotify.cs b/OpenSim/Framework/GcNotify.cs new file mode 100644 index 0000000..14a22a6 --- /dev/null +++ b/OpenSim/Framework/GcNotify.cs @@ -0,0 +1,62 @@ +/* + * Copyright (c) Contributors, http://opensimulator.org/ + * See CONTRIBUTORS.TXT for a full list of copyright holders. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the OpenSimulator Project nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +using System; +using System.Reflection; +using log4net; + +public class GcNotify +{ + private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); + + public static bool Enabled + { + get { return s_initialized; } + set + { + if (!s_initialized && value) + new GcNotify(); + + s_initialized = value; + } + } + + private static bool s_initialized = false; + + private GcNotify() {} + + ~GcNotify() + { + if (!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload()) + { + m_log.DebugFormat("[GC NOTIFY]: Garbage collection triggered."); + + if (Enabled) + new GcNotify(); + } + } +} \ No newline at end of file -- cgit v1.1 From 1a8769e6eff0eab750a528f27d127637edbd292b Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Wed, 21 Mar 2012 23:57:39 +0000 Subject: Instead of loading default avatar animations in both SLUtil and AvatarAnimations, load just in AvatarAnimations instead. This lets us remove the dependency of OpenSim.Framework.dll on data/avataranimations.xml, which is not necessary for ROBUST. This commit also takes care of the odd situation where animations are stored and used internally with uppercase names (e.g. "STAND") but scripts refer to them with lowercase names (e.g. "sit"). --- OpenSim/Framework/IClientAPI.cs | 3 +-- OpenSim/Framework/SLUtil.cs | 50 +---------------------------------------- 2 files changed, 2 insertions(+), 51 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs index c85e599..3f560d0 100644 --- a/OpenSim/Framework/IClientAPI.cs +++ b/OpenSim/Framework/IClientAPI.cs @@ -1215,10 +1215,9 @@ namespace OpenSim.Framework /// The orbital position is given in radians, and must be "adjusted" for the linden client, see LLClientView void SendSunPos(Vector3 sunPos, Vector3 sunVel, ulong CurrentTime, uint SecondsPerSunCycle, uint SecondsPerYear, float OrbitalPosition); - + void SendViewerEffect(ViewerEffectPacket.EffectBlock[] effectBlocks); void SendViewerTime(int phase); - UUID GetDefaultAnimation(string name); void SendAvatarProperties(UUID avatarID, string aboutText, string bornOn, Byte[] charterMember, string flAbout, uint flags, UUID flImageID, UUID imageID, string profileURL, UUID partnerID); diff --git a/OpenSim/Framework/SLUtil.cs b/OpenSim/Framework/SLUtil.cs index f9cb851..db4541e 100644 --- a/OpenSim/Framework/SLUtil.cs +++ b/OpenSim/Framework/SLUtil.cs @@ -27,6 +27,7 @@ using System; using System.Collections.Generic; +using System.IO; using System.Reflection; using System.Xml; using log4net; @@ -40,13 +41,6 @@ namespace OpenSim.Framework #region SL / file extension / content-type conversions - public static Dictionary DefaultAvatarAnimations = new Dictionary(); - - static SLUtil() - { - DefaultAvatarAnimations = LoadDefaultAvatarAnimations("data/avataranimations.xml"); - } - public static string SLAssetTypeToContentType(int assetType) { switch ((AssetType)assetType) @@ -382,47 +376,5 @@ namespace OpenSim.Framework return output; } - - /// - /// Load the default SL avatar animations. - /// - /// - public static Dictionary LoadDefaultAvatarAnimations(string path) - { - Dictionary animations = new Dictionary(); - - using (XmlTextReader reader = new XmlTextReader(path)) - { - XmlDocument doc = new XmlDocument(); - doc.Load(reader); - if (doc.DocumentElement != null) - { - foreach (XmlNode nod in doc.DocumentElement.ChildNodes) - { - if (nod.Attributes["name"] != null) - { - string name = nod.Attributes["name"].Value.ToLower(); - string id = nod.InnerText; - animations.Add(name, (UUID)id); - } - } - } - } - - return animations; - } - - /// - /// Get the default SL avatar animation with the given name. - /// - /// - /// - public static UUID GetDefaultAvatarAnimation(string name) - { - if (DefaultAvatarAnimations.ContainsKey(name)) - return DefaultAvatarAnimations[name]; - - return UUID.Zero; - } } } \ No newline at end of file -- cgit v1.1 From 6146e7ef258b10888ad7464b72b75cca701e02c9 Mon Sep 17 00:00:00 2001 From: Diva Canto Date: Thu, 22 Mar 2012 12:57:12 -0700 Subject: Simple build permissions feature. NOTE: EXPERIMENTAL, DISABLED BY DEFAULT. Turns out that this can't be expressed by cascading Permission modules, so I did it as per this patch. --- OpenSim/Framework/ILandObject.cs | 2 ++ 1 file changed, 2 insertions(+) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index dd73b3f..33aad9b 100644 --- a/OpenSim/Framework/ILandObject.cs +++ b/OpenSim/Framework/ILandObject.cs @@ -63,6 +63,7 @@ namespace OpenSim.Framework bool ContainsPoint(int x, int y); ILandObject Copy(); + ILandObject MemberwiseCopy(); void SendLandUpdateToAvatarsOverMe(); @@ -70,6 +71,7 @@ namespace OpenSim.Framework void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client); bool IsEitherBannedOrRestricted(UUID avatar); bool IsBannedFromLand(UUID avatar); + bool IsAllowedInLand(UUID avatar); bool IsRestrictedFromLand(UUID avatar); void SendLandUpdateToClient(IClientAPI remote_client); void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client); -- cgit v1.1 From 45b588cf008c514f461bf43c168dcdc9902b7bb9 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Mar 2012 20:10:38 +0000 Subject: Revert "Simple build permissions feature. NOTE: EXPERIMENTAL, DISABLED BY DEFAULT. Turns out that this can't be expressed by cascading Permission modules, so I did it as per this patch." This reverts commit 6146e7ef258b10888ad7464b72b75cca701e02c9. --- OpenSim/Framework/ILandObject.cs | 2 -- 1 file changed, 2 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index 33aad9b..dd73b3f 100644 --- a/OpenSim/Framework/ILandObject.cs +++ b/OpenSim/Framework/ILandObject.cs @@ -63,7 +63,6 @@ namespace OpenSim.Framework bool ContainsPoint(int x, int y); ILandObject Copy(); - ILandObject MemberwiseCopy(); void SendLandUpdateToAvatarsOverMe(); @@ -71,7 +70,6 @@ namespace OpenSim.Framework void UpdateLandProperties(LandUpdateArgs args, IClientAPI remote_client); bool IsEitherBannedOrRestricted(UUID avatar); bool IsBannedFromLand(UUID avatar); - bool IsAllowedInLand(UUID avatar); bool IsRestrictedFromLand(UUID avatar); void SendLandUpdateToClient(IClientAPI remote_client); void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client); -- cgit v1.1 From b5d0bc24887e177e7b6e982789bfd86f27b84cf0 Mon Sep 17 00:00:00 2001 From: Melanie Date: Thu, 22 Mar 2012 20:25:20 +0000 Subject: Rework Diva's patch to simplify it --- OpenSim/Framework/ILandObject.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/ILandObject.cs b/OpenSim/Framework/ILandObject.cs index dd73b3f..4f98d7b 100644 --- a/OpenSim/Framework/ILandObject.cs +++ b/OpenSim/Framework/ILandObject.cs @@ -71,6 +71,7 @@ namespace OpenSim.Framework bool IsEitherBannedOrRestricted(UUID avatar); bool IsBannedFromLand(UUID avatar); bool IsRestrictedFromLand(UUID avatar); + bool IsInLandAccessList(UUID avatar); void SendLandUpdateToClient(IClientAPI remote_client); void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client); List CreateAccessListArrayByFlag(AccessList flag); -- cgit v1.1 From cf61c74e90324e07cb4b15f9c597fef00c047c75 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 24 Mar 2012 02:16:44 +0000 Subject: Give feedback when "terrain save-tile" is not successfully invoked. --- OpenSim/Framework/RegionInfo.cs | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/RegionInfo.cs b/OpenSim/Framework/RegionInfo.cs index 5ba3863..a505524 100644 --- a/OpenSim/Framework/RegionInfo.cs +++ b/OpenSim/Framework/RegionInfo.cs @@ -421,12 +421,18 @@ namespace OpenSim.Framework set { m_internalEndPoint = value; } } + /// + /// The x co-ordinate of this region in map tiles (e.g. 1000). + /// public uint RegionLocX { get { return m_regionLocX.Value; } set { m_regionLocX = value; } } + /// + /// The y co-ordinate of this region in map tiles (e.g. 1000). + /// public uint RegionLocY { get { return m_regionLocY.Value; } -- cgit v1.1 From 4f17537555856823cd3c3cc80708cc1d8bc574b4 Mon Sep 17 00:00:00 2001 From: Justin Clark-Casey (justincc) Date: Sat, 24 Mar 2012 03:07:01 +0000 Subject: Allow the user to enter help topics in upper or lowercase. Forcing uppercase (e.g. help Assets) is too annoying. Thanks to WhiteStar for pointing this out. --- OpenSim/Framework/Console/CommandConsole.cs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs index 2bb7de1..c5d6b78 100644 --- a/OpenSim/Framework/Console/CommandConsole.cs +++ b/OpenSim/Framework/Console/CommandConsole.cs @@ -188,19 +188,21 @@ namespace OpenSim.Framework.Console { lock (m_modulesCommands) { - if (m_modulesCommands.ContainsKey(moduleName)) + foreach (string key in m_modulesCommands.Keys) { - List commands = m_modulesCommands[moduleName]; - var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help)); - ourHelpText.Sort(); - helpText.AddRange(ourHelpText); + // Allow topic help requests to succeed whether they are upper or lowercase. + if (moduleName.ToLower() == key.ToLower()) + { + List commands = m_modulesCommands[key]; + var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help)); + ourHelpText.Sort(); + helpText.AddRange(ourHelpText); - return true; - } - else - { - return false; + return true; + } } + + return false; } } -- cgit v1.1