OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
Util.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections;
30 using System.Collections.Generic;
31 using System.Data;
32 using System.Diagnostics;
33 using System.Globalization;
34 using System.IO;
35 using System.IO.Compression;
36 using System.Net;
37 using System.Net.Sockets;
38 using System.Reflection;
39 using System.Runtime.InteropServices;
40 using System.Runtime.Serialization;
41 using System.Runtime.Serialization.Formatters.Binary;
42 using System.Security.Cryptography;
43 using System.Text;
44 using System.Text.RegularExpressions;
45 using System.Xml;
46 using System.Threading;
47 using log4net;
48 using log4net.Appender;
49 using Nini.Config;
50 using Nwc.XmlRpc;
51 using OpenMetaverse;
52 using OpenMetaverse.StructuredData;
53 using Amib.Threading;
54 using System.Collections.Concurrent;
55 using System.Collections.Specialized;
56 using System.Web;
57 
58 namespace OpenSim.Framework
59 {
60  [Flags]
61  public enum PermissionMask : uint
62  {
63  None = 0,
64 
65  // folded perms
66  foldedTransfer = 1,
67  foldedModify = 1 << 1,
68  foldedCopy = 1 << 2,
69 
70  foldedMask = 0x07,
71 
72  //
73  Transfer = 1 << 13,
74  Modify = 1 << 14,
75  Copy = 1 << 15,
76  Export = 1 << 16,
77  Move = 1 << 19,
78  Damage = 1 << 20,
79  // All does not contain Export, which is special and must be
80  // explicitly given
81  All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19)
82  }
83 
92  public enum FireAndForgetMethod
93  {
94  None,
100  Thread,
101  }
102 
109  public class STPInfo
110  {
111  public string Name { get; set; }
112  public STPStartInfo STPStartInfo { get; set; }
113  public WIGStartInfo WIGStartInfo { get; set; }
114  public bool IsIdle { get; set; }
115  public bool IsShuttingDown { get; set; }
116  public int MaxThreads { get; set; }
117  public int MinThreads { get; set; }
118  public int InUseThreads { get; set; }
119  public int ActiveThreads { get; set; }
120  public int WaitingCallbacks { get; set; }
121  public int MaxConcurrentWorkItems { get; set; }
122  }
123 
127  public static class Util
128  {
129  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
130 
138  public static int LogThreadPool { get; set; }
139  public static bool LogOverloads { get; set; }
140 
141  public static readonly int MAX_THREADPOOL_LEVEL = 3;
142 
143  public static double TimeStampClockPeriodMS;
144 
145  static Util()
146  {
147  LogThreadPool = 0;
148  LogOverloads = true;
149  TimeStampClockPeriodMS = 1000.0D / (double)Stopwatch.Frequency;
150  m_log.InfoFormat("[UTIL] TimeStamp clock with period of {0}ms", Math.Round(TimeStampClockPeriodMS,6,MidpointRounding.AwayFromZero));
151  }
152 
153  private static uint nextXferID = 5000;
154  private static Random randomClass = new ThreadSafeRandom();
155 
156  // Get a list of invalid file characters (OS dependent)
157  private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
158  private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]";
159  private static object XferLock = new object();
160 
164  private static SmartThreadPool m_ThreadPool;
165 
166  // Watchdog timer that aborts threads that have timed-out
167  private static Timer m_threadPoolWatchdog;
168 
169  // 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.
170  public static readonly DateTime UnixEpoch =
171  DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
172 
173  private static readonly string rawUUIDPattern
174  = "[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}";
175  public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern);
176  public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern));
177 
178  public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
179  public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
180 
181  public static bool IsPlatformMono
182  {
183  get { return Type.GetType("Mono.Runtime") != null; }
184  }
185 
192  public static string ExecutingDirectory()
193  {
194  return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
195  }
196 
204  public static double lerp(double a, double b, double c)
205  {
206  return (b*a) + (c*(1 - a));
207  }
208 
224  public static double lerp2D(double x, double y, double a, double b, double c, double d)
225  {
226  return lerp(y, lerp(x, a, b), lerp(x, c, d));
227  }
228 
229  public static Encoding UTF8 = Encoding.UTF8;
230  public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false);
231 
235  public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
236 
237  #region Vector Equations
238 
245  public static double GetDistanceTo(Vector3 a, Vector3 b)
246  {
247  float dx = a.X - b.X;
248  float dy = a.Y - b.Y;
249  float dz = a.Z - b.Z;
250  return Math.Sqrt(dx * dx + dy * dy + dz * dz);
251  }
252 
260  public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount)
261  {
262  float dx = a.X - b.X;
263  float dy = a.Y - b.Y;
264  float dz = a.Z - b.Z;
265  return (dx*dx + dy*dy + dz*dz) < (amount*amount);
266  }
267 
273  public static double GetMagnitude(Vector3 a)
274  {
275  return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z));
276  }
277 
283 
284  public static Vector3 GetNormalizedVector(Vector3 a)
285  {
286  Vector3 v = new Vector3(a.X, a.Y, a.Z);
287  v.Normalize();
288  return v;
289  }
290 
295  public static bool IsZeroVector(Vector3 v)
296  {
297  if (v.X == 0 && v.Y == 0 && v.Z == 0)
298  {
299  return true;
300  }
301 
302  return false;
303  }
304 
305  # endregion
306 
307  public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up)
308  {
309  float s;
310  float tr = (float) (fwd.X + left.Y + up.Z + 1.0);
311 
312  if (tr >= 1.0)
313  {
314  s = (float) (0.5 / Math.Sqrt(tr));
315  return new Quaternion(
316  (left.Z - up.Y) * s,
317  (up.X - fwd.Z) * s,
318  (fwd.Y - left.X) * s,
319  (float) 0.25 / s);
320  }
321  else
322  {
323  float max = (left.Y > up.Z) ? left.Y : up.Z;
324 
325  if (max < fwd.X)
326  {
327  s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0));
328  float x = (float) (s * 0.5);
329  s = (float) (0.5 / s);
330  return new Quaternion(
331  x,
332  (fwd.Y + left.X) * s,
333  (up.X + fwd.Z) * s,
334  (left.Z - up.Y) * s);
335  }
336  else if (max == left.Y)
337  {
338  s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0));
339  float y = (float) (s * 0.5);
340  s = (float) (0.5 / s);
341  return new Quaternion(
342  (fwd.Y + left.X) * s,
343  y,
344  (left.Z + up.Y) * s,
345  (up.X - fwd.Z) * s);
346  }
347  else
348  {
349  s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0));
350  float z = (float) (s * 0.5);
351  s = (float) (0.5 / s);
352  return new Quaternion(
353  (up.X + fwd.Z) * s,
354  (left.Z + up.Y) * s,
355  z,
356  (fwd.Y - left.X) * s);
357  }
358  }
359  }
360 
361  public static Random RandomClass
362  {
363  get { return randomClass; }
364  }
365 
366  public static ulong UIntsToLong(uint X, uint Y)
367  {
368  return Utils.UIntsToLong(X, Y);
369  }
370 
371  // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong.
372  // Several places rely on the ability to extract a region's location from its handle.
373  // Note the location is in 'world coordinates' (see below).
374  // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0.
375  public static ulong RegionWorldLocToHandle(uint X, uint Y)
376  {
377  return Utils.UIntsToLong(X, Y);
378  }
379 
380  public static ulong RegionLocToHandle(uint X, uint Y)
381  {
382  return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y));
383  }
384 
385  public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y)
386  {
387  X = (uint)(handle >> 32);
388  Y = (uint)(handle & (ulong)uint.MaxValue);
389  }
390 
391  public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y)
392  {
393  uint worldX, worldY;
394  RegionHandleToWorldLoc(handle, out worldX, out worldY);
395  X = WorldToRegionLoc(worldX);
396  Y = WorldToRegionLoc(worldY);
397  }
398 
399  // A region location can be 'world coordinates' (meters from zero) or 'region coordinates'
400  // (number of regions from zero). This measurement of regions relies on the legacy 256 region size.
401  // These routines exist to make what is being converted explicit so the next person knows what was meant.
402  // Convert a region's 'world coordinate' to its 'region coordinate'.
403  public static uint WorldToRegionLoc(uint worldCoord)
404  {
405  return worldCoord / Constants.RegionSize;
406  }
407 
408  // Convert a region's 'region coordinate' to its 'world coordinate'.
409  public static uint RegionToWorldLoc(uint regionCoord)
410  {
411  return regionCoord * Constants.RegionSize;
412  }
413 
414  public static T Clamp<T>(T x, T min, T max)
415  where T : IComparable<T>
416  {
417  return x.CompareTo(max) > 0 ? max :
418  x.CompareTo(min) < 0 ? min :
419  x;
420  }
421 
422  // Clamp the maximum magnitude of a vector
423  public static Vector3 ClampV(Vector3 x, float max)
424  {
425  float lenSq = x.LengthSquared();
426  if (lenSq > (max * max))
427  {
428  x = x / x.Length() * max;
429  }
430 
431  return x;
432  }
433 
439  public static bool IsNanOrInfinity(Vector3 v)
440  {
441  if (float.IsNaN(v.X) || float.IsNaN(v.Y) || float.IsNaN(v.Z))
442  return true;
443 
444  if (float.IsInfinity(v.X) || float.IsInfinity(v.Y) || float.IsNaN(v.Z))
445  return true;
446 
447  return false;
448  }
449 
450  // Inclusive, within range test (true if equal to the endpoints)
451  public static bool InRange<T>(T x, T min, T max)
452  where T : IComparable<T>
453  {
454  return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0;
455  }
456 
457  public static uint GetNextXferID()
458  {
459  uint id = 0;
460  lock (XferLock)
461  {
462  id = nextXferID;
463  nextXferID++;
464  }
465  return id;
466  }
467 
468  public static string GetFileName(string file)
469  {
470  // Return just the filename on UNIX platforms
471  // TODO: this should be customisable with a prefix, but that's something to do later.
472  if (Environment.OSVersion.Platform == PlatformID.Unix)
473  {
474  return file;
475  }
476 
477  // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA
478  // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData
479  if (Environment.OSVersion.Platform == PlatformID.Win32NT)
480  {
481  if (!Directory.Exists("%APPDATA%\\OpenSim\\"))
482  {
483  Directory.CreateDirectory("%APPDATA%\\OpenSim");
484  }
485 
486  return "%APPDATA%\\OpenSim\\" + file;
487  }
488 
489  // Catch all - covers older windows versions
490  // (but those probably wont work anyway)
491  return file;
492  }
493 
503  public static string GetFormattedXml(OSD osd)
504  {
505  return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd));
506  }
507 
516  public static string GetFormattedXml(string rawXml)
517  {
518  XmlDocument xd = new XmlDocument();
519  xd.LoadXml(rawXml);
520 
521  StringBuilder sb = new StringBuilder();
522  StringWriter sw = new StringWriter(sb);
523 
524  XmlTextWriter xtw = new XmlTextWriter(sw);
525  xtw.Formatting = Formatting.Indented;
526 
527  try
528  {
529  xd.WriteTo(xtw);
530  }
531  finally
532  {
533  xtw.Close();
534  }
535 
536  return sb.ToString();
537  }
538 
539  public static byte[] DocToBytes(XmlDocument doc)
540  {
541  using (MemoryStream ms = new MemoryStream())
542  using (XmlTextWriter xw = new XmlTextWriter(ms, null))
543  {
544  xw.Formatting = Formatting.Indented;
545  doc.WriteTo(xw);
546  xw.Flush();
547 
548  return ms.ToArray();
549  }
550  }
551 
556  public static bool IsWindows()
557  {
558  PlatformID platformId = Environment.OSVersion.Platform;
559 
560  return (platformId == PlatformID.Win32NT
561  || platformId == PlatformID.Win32S
562  || platformId == PlatformID.Win32Windows
563  || platformId == PlatformID.WinCE);
564  }
565 
566  public static bool LoadArchSpecificWindowsDll(string libraryName)
567  {
568  return LoadArchSpecificWindowsDll(libraryName, string.Empty);
569  }
570 
571  public static bool LoadArchSpecificWindowsDll(string libraryName, string path)
572  {
573  // We do this so that OpenSimulator on Windows loads the correct native library depending on whether
574  // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
575  // will find it already loaded later on.
576  //
577  // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be
578  // controlled in config files.
579  string nativeLibraryPath;
580 
581  if (Util.Is64BitProcess())
582  nativeLibraryPath = Path.Combine(Path.Combine(path, "lib64"), libraryName);
583  else
584  nativeLibraryPath = Path.Combine(Path.Combine(path, "lib32"), libraryName);
585 
586  m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath);
587 
588  if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero)
589  {
590  m_log.ErrorFormat(
591  "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath);
592 
593  return false;
594  }
595  else
596  {
597  return true;
598  }
599  }
600 
601  public static bool IsEnvironmentSupported(ref string reason)
602  {
603  // Must have .NET 2.0 (Generics / libsl)
604  if (Environment.Version.Major < 2)
605  {
606  reason = ".NET 1.0/1.1 lacks components that is used by OpenSim";
607  return false;
608  }
609 
610  // Windows 95/98/ME are unsupported
611  if (Environment.OSVersion.Platform == PlatformID.Win32Windows &&
612  Environment.OSVersion.Platform != PlatformID.Win32NT)
613  {
614  reason = "Windows 95/98/ME will not run OpenSim";
615  return false;
616  }
617 
618  // Windows 2000 / Pre-SP2 XP
619  if (Environment.OSVersion.Version.Major == 5 &&
620  Environment.OSVersion.Version.Minor == 0)
621  {
622  reason = "Please update to Windows XP Service Pack 2 or Server2003";
623  return false;
624  }
625 
626  return true;
627  }
628 
629  public static int UnixTimeSinceEpoch()
630  {
631  return ToUnixTime(DateTime.UtcNow);
632  }
633 
634  public static int ToUnixTime(DateTime stamp)
635  {
636  TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
637  return (int)t.TotalSeconds;
638  }
639 
640  public static DateTime ToDateTime(ulong seconds)
641  {
642  return UnixEpoch.AddSeconds(seconds);
643  }
644 
645  public static DateTime ToDateTime(int seconds)
646  {
647  return UnixEpoch.AddSeconds(seconds);
648  }
649 
655 
656  public static string Md5Hash(string data)
657  {
658  return Md5Hash(data, Encoding.Default);
659  }
660 
661  public static string Md5Hash(string data, Encoding encoding)
662  {
663  byte[] dataMd5 = ComputeMD5Hash(data, encoding);
664  StringBuilder sb = new StringBuilder();
665  for (int i = 0; i < dataMd5.Length; i++)
666  sb.AppendFormat("{0:x2}", dataMd5[i]);
667  return sb.ToString();
668  }
669 
670  private static byte[] ComputeMD5Hash(string data, Encoding encoding)
671  {
672  MD5 md5 = MD5.Create();
673  return md5.ComputeHash(encoding.GetBytes(data));
674  }
675 
681 
682  public static string SHA1Hash(string data, Encoding enc)
683  {
684  return SHA1Hash(enc.GetBytes(data));
685  }
686 
687  public static string SHA1Hash(string data)
688  {
689  return SHA1Hash(Encoding.Default.GetBytes(data));
690  }
691 
697  public static string SHA1Hash(byte[] data)
698  {
699  byte[] hash = ComputeSHA1Hash(data);
700  return BitConverter.ToString(hash).Replace("-", String.Empty);
701  }
702 
703  private static byte[] ComputeSHA1Hash(byte[] src)
704  {
705  SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();
706  return SHA1.ComputeHash(src);
707  }
708 
709  public static int fast_distance2d(int x, int y)
710  {
711  x = Math.Abs(x);
712  y = Math.Abs(y);
713 
714  int min = Math.Min(x, y);
715 
716  return (x + y - (min >> 1) - (min >> 2) + (min >> 4));
717  }
718 
726  public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max)
727  {
728  return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z
729  && v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z;
730  }
731 
740  public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy,
741  int oldsizex, int oldsizey, int newsizex, int newsizey)
742  {
743  // we still need to make sure we see new region 1stNeighbors
744  drawdist--;
745  oldx *= Constants.RegionSize;
746  newx *= Constants.RegionSize;
747  if (oldx + oldsizex + drawdist < newx)
748  return true;
749  if (newx + newsizex + drawdist < oldx)
750  return true;
751 
752  oldy *= Constants.RegionSize;
753  newy *= Constants.RegionSize;
754  if (oldy + oldsizey + drawdist < newy)
755  return true;
756  if (newy + newsizey + drawdist < oldy)
757  return true;
758 
759  return false;
760  }
761 
762  public static string FieldToString(byte[] bytes)
763  {
764  return FieldToString(bytes, String.Empty);
765  }
766 
777  public static string FieldToString(byte[] bytes, string fieldName)
778  {
779  // Check for a common case
780  if (bytes.Length == 0) return String.Empty;
781 
782  StringBuilder output = new StringBuilder();
783  bool printable = true;
784 
785  for (int i = 0; i < bytes.Length; ++i)
786  {
787  // Check if there are any unprintable characters in the array
788  if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09
789  && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00)
790  {
791  printable = false;
792  break;
793  }
794  }
795 
796  if (printable)
797  {
798  if (fieldName.Length > 0)
799  {
800  output.Append(fieldName);
801  output.Append(": ");
802  }
803 
804  output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1)));
805  }
806  else
807  {
808  for (int i = 0; i < bytes.Length; i += 16)
809  {
810  if (i != 0)
811  output.Append(Environment.NewLine);
812  if (fieldName.Length > 0)
813  {
814  output.Append(fieldName);
815  output.Append(": ");
816  }
817 
818  for (int j = 0; j < 16; j++)
819  {
820  if ((i + j) < bytes.Length)
821  output.Append(String.Format("{0:X2} ", bytes[i + j]));
822  else
823  output.Append(" ");
824  }
825 
826  for (int j = 0; j < 16 && (i + j) < bytes.Length; j++)
827  {
828  if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E)
829  output.Append((char) bytes[i + j]);
830  else
831  output.Append(".");
832  }
833  }
834  }
835 
836  return output.ToString();
837  }
838 
844  public static IPAddress GetHostFromURL(string url)
845  {
846  return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]);
847  }
848 
854  public static IPAddress GetHostFromDNS(string dnsAddress)
855  {
856  // Is it already a valid IP? No need to look it up.
857  IPAddress ipa;
858  if (IPAddress.TryParse(dnsAddress, out ipa))
859  return ipa;
860 
861  IPAddress[] hosts = null;
862 
863  // Not an IP, lookup required
864  try
865  {
866  hosts = Dns.GetHostEntry(dnsAddress).AddressList;
867  }
868  catch (Exception e)
869  {
870  m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e);
871 
872  // Still going to throw the exception on for now, since this was what was happening in the first place
873  throw e;
874  }
875 
876  foreach (IPAddress host in hosts)
877  {
878  if (host.AddressFamily == AddressFamily.InterNetwork)
879  {
880  return host;
881  }
882  }
883 
884  if (hosts.Length > 0)
885  return hosts[0];
886 
887  return null;
888  }
889 
890  public static Uri GetURI(string protocol, string hostname, int port, string path)
891  {
892  return new UriBuilder(protocol, hostname, port, path).Uri;
893  }
894 
899  public static IPAddress[] GetLocalHosts()
900  {
901  return Dns.GetHostAddresses(Dns.GetHostName());
902  }
903 
904  public static IPAddress GetLocalHost()
905  {
906  IPAddress[] iplist = GetLocalHosts();
907 
908  if (iplist.Length == 0) // No accessible external interfaces
909  {
910  IPAddress[] loopback = Dns.GetHostAddresses("localhost");
911  IPAddress localhost = loopback[0];
912 
913  return localhost;
914  }
915 
916  foreach (IPAddress host in iplist)
917  {
918  if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork)
919  {
920  return host;
921  }
922  }
923 
924  if (iplist.Length > 0)
925  {
926  foreach (IPAddress host in iplist)
927  {
928  if (host.AddressFamily == AddressFamily.InterNetwork)
929  return host;
930  }
931  // Well all else failed...
932  return iplist[0];
933  }
934 
935  return null;
936  }
937 
945  public static bool ParseForeignAssetID(string id, out string url, out string assetID)
946  {
947  url = String.Empty;
948  assetID = String.Empty;
949 
950  UUID uuid;
951  if (UUID.TryParse(id, out uuid))
952  {
953  assetID = uuid.ToString();
954  return false;
955  }
956 
957  if ((id.Length == 0) || (id[0] != 'h' && id[0] != 'H'))
958  return false;
959 
960  Uri assetUri;
961  if (!Uri.TryCreate(id, UriKind.Absolute, out assetUri) || assetUri.Scheme != Uri.UriSchemeHttp)
962  return false;
963 
964  // Simian
965  if (assetUri.Query != string.Empty)
966  {
967  NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query);
968  assetID = qscoll["id"];
969  if (assetID != null)
970  url = id.Replace(assetID, ""); // Malformed again, as simian expects
971  else
972  url = id; // !!! best effort
973  }
974  else // robust
975  {
976  url = "http://" + assetUri.Authority;
977  assetID = assetUri.LocalPath.Trim(new char[] { '/' });
978  }
979 
980  if (!UUID.TryParse(assetID, out uuid))
981  return false;
982 
983  return true;
984  }
985 
991  public static string safePath(string path)
992  {
993  return Regex.Replace(path, regexInvalidPathChars, String.Empty);
994  }
995 
1001  public static string safeFileName(string filename)
1002  {
1003  return Regex.Replace(filename, regexInvalidFileChars, String.Empty);
1004  ;
1005  }
1006 
1007  //
1008  // directory locations
1009  //
1010 
1011  public static string homeDir()
1012  {
1013  string temp;
1014  // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
1015  // temp = Path.Combine(personal,".OpenSim");
1016  temp = ".";
1017  return temp;
1018  }
1019 
1020  public static string assetsDir()
1021  {
1022  return Path.Combine(configDir(), "assets");
1023  }
1024 
1025  public static string inventoryDir()
1026  {
1027  return Path.Combine(configDir(), "inventory");
1028  }
1029 
1030  public static string configDir()
1031  {
1032  return ".";
1033  }
1034 
1035  public static string dataDir()
1036  {
1037  return ".";
1038  }
1039 
1040  public static string logFile()
1041  {
1042  foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
1043  {
1044  if (appender is FileAppender)
1045  {
1046  return ((FileAppender)appender).File;
1047  }
1048  }
1049 
1050  return "./OpenSim.log";
1051  }
1052 
1053  public static string logDir()
1054  {
1055  return Path.GetDirectoryName(logFile());
1056  }
1057 
1058  // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
1059  public static string GetUniqueFilename(string FileName)
1060  {
1061  int count = 0;
1062  string Name;
1063 
1064  if (File.Exists(FileName))
1065  {
1066  FileInfo f = new FileInfo(FileName);
1067 
1068  if (!String.IsNullOrEmpty(f.Extension))
1069  {
1070  Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.'));
1071  }
1072  else
1073  {
1074  Name = f.FullName;
1075  }
1076 
1077  while (File.Exists(FileName))
1078  {
1079  count++;
1080  FileName = Name + count + f.Extension;
1081  }
1082  }
1083  return FileName;
1084  }
1085 
1086  #region Nini (config) related Methods
1087 
1088  public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName)
1089  {
1090  if (!File.Exists(fileName))
1091  {
1092  // create new file
1093  }
1094  XmlConfigSource config = new XmlConfigSource(fileName);
1095  AddDataRowToConfig(config, row);
1096  config.Save();
1097 
1098  return config;
1099  }
1100 
1101  public static void AddDataRowToConfig(IConfigSource config, DataRow row)
1102  {
1103  config.Configs.Add((string) row[0]);
1104  for (int i = 0; i < row.Table.Columns.Count; i++)
1105  {
1106  config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]);
1107  }
1108  }
1109 
1110  public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section)
1111  {
1112  // First, check the Startup section, the default section
1113  IConfig cnf = config.Configs["Startup"];
1114  if (cnf == null)
1115  return string.Empty;
1116  string val = cnf.GetString(varname, string.Empty);
1117 
1118  // Then check for an overwrite of the default in the given section
1119  if (!string.IsNullOrEmpty(section))
1120  {
1121  cnf = config.Configs[section];
1122  if (cnf != null)
1123  val = cnf.GetString(varname, val);
1124  }
1125 
1126  return val;
1127  }
1128 
1139  public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections)
1140  {
1141  return GetConfigVarFromSections<T>(config, varname, sections, default(T));
1142  }
1143 
1158  public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections, object val)
1159  {
1160  foreach (string section in sections)
1161  {
1162  IConfig cnf = config.Configs[section];
1163  if (cnf == null)
1164  continue;
1165 
1166  if (typeof(T) == typeof(String))
1167  val = cnf.GetString(varname, (string)val);
1168  else if (typeof(T) == typeof(Boolean))
1169  val = cnf.GetBoolean(varname, (bool)val);
1170  else if (typeof(T) == typeof(Int32))
1171  val = cnf.GetInt(varname, (int)val);
1172  else if (typeof(T) == typeof(float))
1173  val = cnf.GetFloat(varname, (float)val);
1174  else
1175  m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T));
1176  }
1177 
1178  return (T)val;
1179  }
1180 
1181  public static void MergeEnvironmentToConfig(IConfigSource ConfigSource)
1182  {
1183  IConfig enVars = ConfigSource.Configs["Environment"];
1184  // if section does not exist then user isn't expecting them, so don't bother.
1185  if( enVars != null )
1186  {
1187  // load the values from the environment
1188  EnvConfigSource envConfigSource = new EnvConfigSource();
1189  // add the requested keys
1190  string[] env_keys = enVars.GetKeys();
1191  foreach ( string key in env_keys )
1192  {
1193  envConfigSource.AddEnv(key, string.Empty);
1194  }
1195  // load the values from environment
1196  envConfigSource.LoadEnv();
1197  // add them in to the master
1198  ConfigSource.Merge(envConfigSource);
1199  ConfigSource.ExpandKeyValues();
1200  }
1201  }
1202 
1203  public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass)
1204  {
1205  Type settingsType = settingsClass.GetType();
1206 
1207  FieldInfo[] fieldInfos = settingsType.GetFields();
1208  foreach (FieldInfo fieldInfo in fieldInfos)
1209  {
1210  if (!fieldInfo.IsStatic)
1211  {
1212  if (fieldInfo.FieldType == typeof(System.String))
1213  {
1214  fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
1215  }
1216  else if (fieldInfo.FieldType == typeof(System.Boolean))
1217  {
1218  fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
1219  }
1220  else if (fieldInfo.FieldType == typeof(System.Int32))
1221  {
1222  fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
1223  }
1224  else if (fieldInfo.FieldType == typeof(System.Single))
1225  {
1226  fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
1227  }
1228  else if (fieldInfo.FieldType == typeof(System.UInt32))
1229  {
1230  fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
1231  }
1232  }
1233  }
1234 
1235  PropertyInfo[] propertyInfos = settingsType.GetProperties();
1236  foreach (PropertyInfo propInfo in propertyInfos)
1237  {
1238  if ((propInfo.CanRead) && (propInfo.CanWrite))
1239  {
1240  if (propInfo.PropertyType == typeof(System.String))
1241  {
1242  propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
1243  }
1244  else if (propInfo.PropertyType == typeof(System.Boolean))
1245  {
1246  propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
1247  }
1248  else if (propInfo.PropertyType == typeof(System.Int32))
1249  {
1250  propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
1251  }
1252  else if (propInfo.PropertyType == typeof(System.Single))
1253  {
1254  propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
1255  }
1256  if (propInfo.PropertyType == typeof(System.UInt32))
1257  {
1258  propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
1259  }
1260  }
1261  }
1262 
1263  return settingsClass;
1264  }
1265 
1277  public static bool MergeConfigurationFile(IConfigSource config, string configFileName, string exampleConfigFile, out string configFilePath, out bool created)
1278  {
1279  created = false;
1280  configFilePath = string.Empty;
1281 
1282  IConfig cnf = config.Configs["Startup"];
1283  if (cnf == null)
1284  {
1285  m_log.WarnFormat("[UTILS]: Startup section doesn't exist");
1286  return false;
1287  }
1288 
1289  string configDirectory = cnf.GetString("ConfigDirectory", ".");
1290  string configFile = Path.Combine(configDirectory, configFileName);
1291 
1292  if (!File.Exists(configFile) && !string.IsNullOrEmpty(exampleConfigFile))
1293  {
1294  // We need to copy the example onto it
1295 
1296  if (!Directory.Exists(configDirectory))
1297  Directory.CreateDirectory(configDirectory);
1298 
1299  try
1300  {
1301  File.Copy(exampleConfigFile, configFile);
1302  created = true;
1303  }
1304  catch (Exception e)
1305  {
1306  m_log.WarnFormat("[UTILS]: Exception copying configuration file {0} to {1}: {2}", configFile, exampleConfigFile, e.Message);
1307  return false;
1308  }
1309  }
1310 
1311  if (File.Exists(configFile))
1312  {
1313  // Merge
1314  config.Merge(new IniConfigSource(configFile));
1315  config.ExpandKeyValues();
1316  configFilePath = configFile;
1317  return true;
1318  }
1319  else
1320  return false;
1321  }
1322 
1323  #endregion
1324 
1325  public static float Clip(float x, float min, float max)
1326  {
1327  return Math.Min(Math.Max(x, min), max);
1328  }
1329 
1330  public static int Clip(int x, int min, int max)
1331  {
1332  return Math.Min(Math.Max(x, min), max);
1333  }
1334 
1335  public static Vector3 Clip(Vector3 vec, float min, float max)
1336  {
1337  return new Vector3(Clip(vec.X, min, max), Clip(vec.Y, min, max),
1338  Clip(vec.Z, min, max));
1339  }
1340 
1346  public static String ToRawUuidString(UUID UUID)
1347  {
1348  return UUID.Guid.ToString("n");
1349  }
1350 
1351  public static string CleanString(string input)
1352  {
1353  if (input.Length == 0)
1354  return input;
1355 
1356  int clip = input.Length;
1357 
1358  // Test for ++ string terminator
1359  int pos = input.IndexOf("\0");
1360  if (pos != -1 && pos < clip)
1361  clip = pos;
1362 
1363  // Test for CR
1364  pos = input.IndexOf("\r");
1365  if (pos != -1 && pos < clip)
1366  clip = pos;
1367 
1368  // Test for LF
1369  pos = input.IndexOf("\n");
1370  if (pos != -1 && pos < clip)
1371  clip = pos;
1372 
1373  // Truncate string before first end-of-line character found
1374  return input.Substring(0, clip);
1375  }
1376 
1382  public static string ReadEtcIssue()
1383  {
1384  try
1385  {
1386  StreamReader sr = new StreamReader("/etc/issue.net");
1387  string issue = sr.ReadToEnd();
1388  sr.Close();
1389  return issue;
1390  }
1391  catch (Exception)
1392  {
1393  return "";
1394  }
1395  }
1396 
1397  public static void SerializeToFile(string filename, Object obj)
1398  {
1399  IFormatter formatter = new BinaryFormatter();
1400  Stream stream = null;
1401 
1402  try
1403  {
1404  stream = new FileStream(
1405  filename, FileMode.Create,
1406  FileAccess.Write, FileShare.None);
1407 
1408  formatter.Serialize(stream, obj);
1409  }
1410  catch (Exception e)
1411  {
1412  m_log.Error(e.ToString());
1413  }
1414  finally
1415  {
1416  if (stream != null)
1417  {
1418  stream.Close();
1419  }
1420  }
1421  }
1422 
1423  public static Object DeserializeFromFile(string filename)
1424  {
1425  IFormatter formatter = new BinaryFormatter();
1426  Stream stream = null;
1427  Object ret = null;
1428 
1429  try
1430  {
1431  stream = new FileStream(
1432  filename, FileMode.Open,
1433  FileAccess.Read, FileShare.None);
1434 
1435  ret = formatter.Deserialize(stream);
1436  }
1437  catch (Exception e)
1438  {
1439  m_log.Error(e.ToString());
1440  }
1441  finally
1442  {
1443  if (stream != null)
1444  {
1445  stream.Close();
1446  }
1447  }
1448 
1449  return ret;
1450  }
1451 
1452  public static string Compress(string text)
1453  {
1454  byte[] buffer = Util.UTF8.GetBytes(text);
1455  MemoryStream memory = new MemoryStream();
1456  using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true))
1457  {
1458  compressor.Write(buffer, 0, buffer.Length);
1459  }
1460 
1461  memory.Position = 0;
1462 
1463  byte[] compressed = new byte[memory.Length];
1464  memory.Read(compressed, 0, compressed.Length);
1465 
1466  byte[] compressedBuffer = new byte[compressed.Length + 4];
1467  Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length);
1468  Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4);
1469  return Convert.ToBase64String(compressedBuffer);
1470  }
1471 
1472  public static string Decompress(string compressedText)
1473  {
1474  byte[] compressedBuffer = Convert.FromBase64String(compressedText);
1475  using (MemoryStream memory = new MemoryStream())
1476  {
1477  int msgLength = BitConverter.ToInt32(compressedBuffer, 0);
1478  memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4);
1479 
1480  byte[] buffer = new byte[msgLength];
1481 
1482  memory.Position = 0;
1483  using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress))
1484  {
1485  decompressor.Read(buffer, 0, buffer.Length);
1486  }
1487 
1488  return Util.UTF8.GetString(buffer);
1489  }
1490  }
1491 
1501  public static Stream Copy(Stream inputStream)
1502  {
1503  if (!inputStream.CanSeek)
1504  throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek");
1505 
1506  const int readSize = 256;
1507  byte[] buffer = new byte[readSize];
1508  MemoryStream ms = new MemoryStream();
1509 
1510  int count = inputStream.Read(buffer, 0, readSize);
1511 
1512  while (count > 0)
1513  {
1514  ms.Write(buffer, 0, count);
1515  count = inputStream.Read(buffer, 0, readSize);
1516  }
1517 
1518  ms.Position = 0;
1519  inputStream.Position = 0;
1520 
1521  return ms;
1522  }
1523 
1524  public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
1525  {
1526  return SendXmlRpcCommand(url, methodName, args);
1527  }
1528 
1529  public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args)
1530  {
1531  XmlRpcRequest client = new XmlRpcRequest(methodName, args);
1532  return client.Send(url, 6000);
1533  }
1534 
1539  public static XmlRpcResponse CreateUnknownUserErrorResponse()
1540  {
1541  XmlRpcResponse response = new XmlRpcResponse();
1542  Hashtable responseData = new Hashtable();
1543  responseData["error_type"] = "unknown_user";
1544  responseData["error_desc"] = "The user requested is not in the database";
1545 
1546  response.Value = responseData;
1547  return response;
1548  }
1549 
1559  public static ulong BytesToUInt64Big(byte[] bytes)
1560  {
1561  if (bytes.Length < 8) return 0;
1562  return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) |
1563  ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7];
1564  }
1565 
1566  // used for RemoteParcelRequest (for "About Landmark")
1567  public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y)
1568  {
1569  byte[] bytes =
1570  {
1571  (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1572  (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1573  (byte)x, (byte)(x >> 8), 0, 0,
1574  (byte)y, (byte)(y >> 8), 0, 0 };
1575  return new UUID(bytes, 0);
1576  }
1577 
1578  public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z)
1579  {
1580  byte[] bytes =
1581  {
1582  (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1583  (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1584  (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
1585  (byte)y, (byte)(y >> 8), 0, 0 };
1586  return new UUID(bytes, 0);
1587  }
1588 
1589  public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y)
1590  {
1591  byte[] bytes = parcelID.GetBytes();
1592  regionHandle = Utils.BytesToUInt64(bytes);
1593  x = Utils.BytesToUInt(bytes, 8) & 0xffff;
1594  y = Utils.BytesToUInt(bytes, 12) & 0xffff;
1595  }
1596 
1597  public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z)
1598  {
1599  byte[] bytes = parcelID.GetBytes();
1600  regionHandle = Utils.BytesToUInt64(bytes);
1601  x = Utils.BytesToUInt(bytes, 8) & 0xffff;
1602  z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16;
1603  y = Utils.BytesToUInt(bytes, 12) & 0xffff;
1604  }
1605 
1606  public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y)
1607  {
1608  ulong regionHandle;
1609  uint rx, ry;
1610 
1611  ParseFakeParcelID(parcelID, out regionHandle, out x, out y);
1612  Utils.LongToUInts(regionHandle, out rx, out ry);
1613 
1614  x += rx;
1615  y += ry;
1616  }
1617 
1624  public static string GetOperatingSystemInformation()
1625  {
1626  string os = String.Empty;
1627 
1628 // if (Environment.OSVersion.Platform != PlatformID.Unix)
1629 // {
1630 // os = Environment.OSVersion.ToString();
1631 // }
1632 // else
1633 // {
1634 // os = ReadEtcIssue();
1635 // }
1636 //
1637 // if (os.Length > 45)
1638 // {
1639 // os = os.Substring(0, 45);
1640 // }
1641 
1642  return os;
1643  }
1644 
1645  public static string GetRuntimeInformation()
1646  {
1647  string ru = String.Empty;
1648 
1649  if (Environment.OSVersion.Platform == PlatformID.Unix)
1650  ru = "Unix/Mono";
1651  else
1652  if (Environment.OSVersion.Platform == PlatformID.MacOSX)
1653  ru = "OSX/Mono";
1654  else
1655  {
1656  if (IsPlatformMono)
1657  ru = "Win/Mono";
1658  else
1659  ru = "Win/.NET";
1660  }
1661 
1662  return ru;
1663  }
1664 
1670  public static bool isUUID(string s)
1671  {
1672  return UUIDPattern.IsMatch(s);
1673  }
1674 
1675  public static string GetDisplayConnectionString(string connectionString)
1676  {
1677  int passPosition = 0;
1678  int passEndPosition = 0;
1679  string displayConnectionString = null;
1680 
1681  // hide the password in the connection string
1682  passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase);
1683  passPosition = connectionString.IndexOf("=", passPosition);
1684  if (passPosition < connectionString.Length)
1685  passPosition += 1;
1686  passEndPosition = connectionString.IndexOf(";", passPosition);
1687 
1688  displayConnectionString = connectionString.Substring(0, passPosition);
1689  displayConnectionString += "***";
1690  displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition);
1691 
1692  return displayConnectionString;
1693  }
1694 
1695  public static string Base64ToString(string str)
1696  {
1697  Decoder utf8Decode = Encoding.UTF8.GetDecoder();
1698 
1699  byte[] todecode_byte = Convert.FromBase64String(str);
1700  int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
1701  char[] decoded_char = new char[charCount];
1702  utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
1703  string result = new String(decoded_char);
1704  return result;
1705  }
1706 
1707  public static void BinaryToASCII(char[] chars)
1708  {
1709  for (int i = 0; i < chars.Length; i++)
1710  {
1711  char ch = chars[i];
1712  if (ch < 32 || ch > 127)
1713  chars[i] = '.';
1714  }
1715  }
1716 
1717  public static string BinaryToASCII(string src)
1718  {
1719  char[] chars = src.ToCharArray();
1720  BinaryToASCII(chars);
1721  return new String(chars);
1722  }
1723 
1732  public static void ReadStream(Stream stream, byte[] data)
1733  {
1734  int offset = 0;
1735  int remaining = data.Length;
1736 
1737  while (remaining > 0)
1738  {
1739  int read = stream.Read(data, offset, remaining);
1740  if (read <= 0)
1741  throw new EndOfStreamException(String.Format("End of stream reached with {0} bytes left to read", remaining));
1742  remaining -= read;
1743  offset += read;
1744  }
1745  }
1746 
1747  public static Guid GetHashGuid(string data, string salt)
1748  {
1749  byte[] hash = ComputeMD5Hash(data + salt, Encoding.Default);
1750 
1751  //string s = BitConverter.ToString(hash);
1752 
1753  Guid guid = new Guid(hash);
1754 
1755  return guid;
1756  }
1757 
1758  public static byte ConvertMaturityToAccessLevel(uint maturity)
1759  {
1760  byte retVal = 0;
1761  switch (maturity)
1762  {
1763  case 0: //PG
1764  retVal = 13;
1765  break;
1766  case 1: //Mature
1767  retVal = 21;
1768  break;
1769  case 2: // Adult
1770  retVal = 42;
1771  break;
1772  }
1773 
1774  return retVal;
1775 
1776  }
1777 
1778  public static uint ConvertAccessLevelToMaturity(byte maturity)
1779  {
1780  if (maturity <= 13)
1781  return 0;
1782  else if (maturity <= 21)
1783  return 1;
1784  else
1785  return 2;
1786  }
1787 
1794  public static OSDMap GetOSDMap(Stream stream, int length)
1795  {
1796  byte[] data = new byte[length];
1797  stream.Read(data, 0, length);
1798  string strdata = Util.UTF8.GetString(data);
1799  OSDMap args = null;
1800  OSD buffer;
1801  buffer = OSDParser.DeserializeJson(strdata);
1802  if (buffer.Type == OSDType.Map)
1803  {
1804  args = (OSDMap)buffer;
1805  return args;
1806  }
1807  return null;
1808  }
1809 
1810  public static OSDMap GetOSDMap(string data)
1811  {
1812  OSDMap args = null;
1813  try
1814  {
1815  OSD buffer;
1816  // We should pay attention to the content-type, but let's assume we know it's Json
1817  buffer = OSDParser.DeserializeJson(data);
1818  if (buffer.Type == OSDType.Map)
1819  {
1820  args = (OSDMap)buffer;
1821  return args;
1822  }
1823  else
1824  {
1825  // uh?
1826  m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString()));
1827  return null;
1828  }
1829  }
1830  catch (Exception ex)
1831  {
1832  m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message);
1833  return null;
1834  }
1835  }
1836 
1837  public static string[] Glob(string path)
1838  {
1839  string vol=String.Empty;
1840 
1841  if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar)
1842  {
1843  string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries);
1844 
1845  if (vcomps.Length > 1)
1846  {
1847  path = vcomps[1];
1848  vol = vcomps[0];
1849  }
1850  }
1851 
1852  string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
1853 
1854  // Glob
1855 
1856  path = vol;
1857  if (vol != String.Empty)
1858  path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar});
1859  else
1860  path = new String(new char[] {Path.DirectorySeparatorChar});
1861 
1862  List<string> paths = new List<string>();
1863  List<string> found = new List<string>();
1864  paths.Add(path);
1865 
1866  int compIndex = -1;
1867  foreach (string c in comps)
1868  {
1869  compIndex++;
1870 
1871  List<string> addpaths = new List<string>();
1872  foreach (string p in paths)
1873  {
1874  string[] dirs = Directory.GetDirectories(p, c);
1875 
1876  if (dirs.Length != 0)
1877  {
1878  foreach (string dir in dirs)
1879  addpaths.Add(Path.Combine(path, dir));
1880  }
1881 
1882  // Only add files if that is the last path component
1883  if (compIndex == comps.Length - 1)
1884  {
1885  string[] files = Directory.GetFiles(p, c);
1886  foreach (string f in files)
1887  found.Add(f);
1888  }
1889  }
1890  paths = addpaths;
1891  }
1892 
1893  return found.ToArray();
1894  }
1895 
1896  public static string ServerURI(string uri)
1897  {
1898  if (uri == string.Empty)
1899  return string.Empty;
1900 
1901  // Get rid of eventual slashes at the end
1902  uri = uri.TrimEnd('/');
1903 
1904  IPAddress ipaddr1 = null;
1905  string port1 = "";
1906  try
1907  {
1908  ipaddr1 = Util.GetHostFromURL(uri);
1909  }
1910  catch { }
1911 
1912  try
1913  {
1914  port1 = uri.Split(new char[] { ':' })[2];
1915  }
1916  catch { }
1917 
1918  // We tried our best to convert the domain names to IP addresses
1919  return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
1920  }
1921 
1933  public static byte[] StringToBytes256(string str, params object[] args)
1934  {
1935  return StringToBytes256(string.Format(str, args));
1936  }
1937 
1946  public static byte[] StringToBytes256(string str)
1947  {
1948  if (String.IsNullOrEmpty(str))
1949  return Utils.EmptyBytes;
1950 
1951  if (!str.EndsWith("\0"))
1952  str += "\0";
1953 
1954  // Because this is UTF-8 encoding and not ASCII, it's possible we
1955  // might have gotten an oversized array even after the string trim
1956  byte[] data = UTF8.GetBytes(str);
1957 
1958  if (data.Length > 256)
1959  {
1960  int cut = 255;
1961  if((data[cut] & 0x80 ) != 0 )
1962  {
1963  while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
1964  cut--;
1965  }
1966  Array.Resize<byte>(ref data, cut + 1);
1967  data[cut] = 0;
1968  }
1969 
1970  return data;
1971  }
1972 
1984  public static byte[] StringToBytes1024(string str, params object[] args)
1985  {
1986  return StringToBytes1024(string.Format(str, args));
1987  }
1988 
1997  public static byte[] StringToBytes1024(string str)
1998  {
1999  if (String.IsNullOrEmpty(str))
2000  return Utils.EmptyBytes;
2001 
2002  if (!str.EndsWith("\0"))
2003  str += "\0";
2004 
2005  // Because this is UTF-8 encoding and not ASCII, it's possible we
2006  // might have gotten an oversized array even after the string trim
2007  byte[] data = UTF8.GetBytes(str);
2008 
2009  if (data.Length > 1024)
2010  {
2011  int cut = 1023;
2012  if((data[cut] & 0x80 ) != 0 )
2013  {
2014  while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
2015  cut--;
2016  }
2017  Array.Resize<byte>(ref data, cut + 1);
2018  data[cut] = 0;
2019  }
2020 
2021  return data;
2022  }
2023 
2035  public static byte[] StringToBytes(string str, int MaxLength, params object[] args)
2036  {
2037  return StringToBytes1024(string.Format(str, args), MaxLength);
2038  }
2039 
2048  public static byte[] StringToBytes(string str, int MaxLength)
2049  {
2050  if (String.IsNullOrEmpty(str))
2051  return Utils.EmptyBytes;
2052 
2053  if (!str.EndsWith("\0"))
2054  str += "\0";
2055 
2056  // Because this is UTF-8 encoding and not ASCII, it's possible we
2057  // might have gotten an oversized array even after the string trim
2058  byte[] data = UTF8.GetBytes(str);
2059 
2060  if (data.Length > MaxLength)
2061  {
2062  int cut = MaxLength -1 ;
2063  if((data[cut] & 0x80 ) != 0 )
2064  {
2065  while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
2066  cut--;
2067  }
2068  Array.Resize<byte>(ref data, cut + 1);
2069  data[cut] = 0;
2070  }
2071 
2072  return data;
2073  }
2081  public static string PrettyFormatToSingleLine(Hashtable ht)
2082  {
2083  StringBuilder sb = new StringBuilder();
2084 
2085  int i = 0;
2086 
2087  foreach (string key in ht.Keys)
2088  {
2089  sb.AppendFormat("{0}:{1}", key, ht[key]);
2090 
2091  if (++i < ht.Count)
2092  sb.AppendFormat(", ");
2093  }
2094 
2095  return sb.ToString();
2096  }
2097 
2107  [DllImport("kernel32.dll")]
2108  public static extern IntPtr LoadLibrary(string dllToLoad);
2109 
2114  public static bool Is64BitProcess()
2115  {
2116  return IntPtr.Size == 8;
2117  }
2118 
2119  #region FireAndForget Threading Pattern
2120 
2124  private sealed class FireAndForgetWrapper
2125  {
2126  private static volatile FireAndForgetWrapper instance;
2127  private static object syncRoot = new Object();
2128 
2129  public static FireAndForgetWrapper Instance {
2130  get {
2131 
2132  if (instance == null)
2133  {
2134  lock (syncRoot)
2135  {
2136  if (instance == null)
2137  {
2138  instance = new FireAndForgetWrapper();
2139  }
2140  }
2141  }
2142 
2143  return instance;
2144  }
2145  }
2146 
2147  public void FireAndForget(System.Threading.WaitCallback callback)
2148  {
2149  callback.BeginInvoke(null, EndFireAndForget, callback);
2150  }
2151 
2152  public void FireAndForget(System.Threading.WaitCallback callback, object obj)
2153  {
2154  callback.BeginInvoke(obj, EndFireAndForget, callback);
2155  }
2156 
2157  private static void EndFireAndForget(IAsyncResult ar)
2158  {
2159  System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
2160 
2161  try { callback.EndInvoke(ar); }
2162  catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
2163 
2164  ar.AsyncWaitHandle.Close();
2165  }
2166  }
2167 
2168  public static void InitThreadPool(int minThreads, int maxThreads)
2169  {
2170  if (maxThreads < 2)
2171  throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
2172 
2173  if (minThreads > maxThreads || minThreads < 2)
2174  throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads");
2175 
2176  if (m_ThreadPool != null)
2177  {
2178  m_log.Warn("SmartThreadPool is already initialized. Ignoring request.");
2179  return;
2180  }
2181 
2182  STPStartInfo startInfo = new STPStartInfo();
2183  startInfo.ThreadPoolName = "Util";
2184  startInfo.IdleTimeout = 20000;
2185  startInfo.MaxWorkerThreads = maxThreads;
2186  startInfo.MinWorkerThreads = minThreads;
2187 
2188  m_ThreadPool = new SmartThreadPool(startInfo);
2189  m_threadPoolWatchdog = new Timer(ThreadPoolWatchdog, null, 0, 1000);
2190  }
2191 
2192  public static int FireAndForgetCount()
2193  {
2194  const int MAX_SYSTEM_THREADS = 200;
2195 
2196  switch (FireAndForgetMethod)
2197  {
2198  case FireAndForgetMethod.UnsafeQueueUserWorkItem:
2199  case FireAndForgetMethod.QueueUserWorkItem:
2200  case FireAndForgetMethod.BeginInvoke:
2201  int workerThreads, iocpThreads;
2202  ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
2203  return workerThreads;
2204  case FireAndForgetMethod.SmartThreadPool:
2205  return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads;
2206  case FireAndForgetMethod.Thread:
2207  return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count;
2208  default:
2209  throw new NotImplementedException();
2210  }
2211  }
2212 
2217  private class ThreadInfo
2218  {
2219  public long ThreadFuncNum { get; set; }
2220  public string StackTrace { get; set; }
2221  private string context;
2222  public bool LogThread { get; set; }
2223 
2224  public IWorkItemResult WorkItem { get; set; }
2225  public Thread Thread { get; set; }
2226  public bool Running { get; set; }
2227  public bool Aborted { get; set; }
2228  private int started;
2229 
2230  public ThreadInfo(long threadFuncNum, string context)
2231  {
2232  ThreadFuncNum = threadFuncNum;
2233  this.context = context;
2234  LogThread = false;
2235  Thread = null;
2236  Running = false;
2237  Aborted = false;
2238  }
2239 
2240  public void Started()
2241  {
2242  Thread = Thread.CurrentThread;
2243  started = EnvironmentTickCount();
2244  Running = true;
2245  }
2246 
2247  public void Ended()
2248  {
2249  Running = false;
2250  }
2251 
2252  public int Elapsed()
2253  {
2254  return EnvironmentTickCountSubtract(started);
2255  }
2256 
2257  public void Abort()
2258  {
2259  Aborted = true;
2260  WorkItem.Cancel(true);
2261  }
2262 
2271  public string GetStackTrace()
2272  {
2273  string ret = (context == null) ? "" : ("(" + context + ") ");
2274 
2275  StackTrace activeStackTrace = Util.GetStackTrace(Thread);
2276  if (activeStackTrace != null)
2277  ret += activeStackTrace.ToString();
2278  else if (StackTrace != null)
2279  ret += "(Stack trace when queued) " + StackTrace;
2280  // else, no stack trace available
2281 
2282  return ret;
2283  }
2284  }
2285 
2286  private static long nextThreadFuncNum = 0;
2287  private static long numQueuedThreadFuncs = 0;
2288  private static long numRunningThreadFuncs = 0;
2289  private static long numTotalThreadFuncsCalled = 0;
2290  private static Int32 threadFuncOverloadMode = 0;
2291 
2292  public static long TotalQueuedFireAndForgetCalls { get { return numQueuedThreadFuncs; } }
2293  public static long TotalRunningFireAndForgetCalls { get { return numRunningThreadFuncs; } }
2294 
2295  // Maps (ThreadFunc number -> Thread)
2296  private static ConcurrentDictionary<long, ThreadInfo> activeThreads = new ConcurrentDictionary<long, ThreadInfo>();
2297 
2298  private static readonly int THREAD_TIMEOUT = 10 * 60 * 1000; // 10 minutes
2299 
2303  private static void ThreadPoolWatchdog(object state)
2304  {
2305  foreach (KeyValuePair<long, ThreadInfo> entry in activeThreads)
2306  {
2307  ThreadInfo t = entry.Value;
2308  if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT))
2309  {
2310  m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace());
2311  t.Abort();
2312 
2313  ThreadInfo dummy;
2314  activeThreads.TryRemove(entry.Key, out dummy);
2315 
2316  // It's possible that the thread won't abort. To make sure the thread pool isn't
2317  // depleted, increase the pool size.
2318 // m_ThreadPool.MaxThreads++;
2319  }
2320  }
2321  }
2322 
2323  public static long TotalFireAndForgetCallsMade { get { return numTotalThreadFuncsCalled; } }
2324 
2325  public static Dictionary<string, int> GetFireAndForgetCallsMade()
2326  {
2327  return new Dictionary<string, int>(m_fireAndForgetCallsMade);
2328  }
2329 
2330  private static Dictionary<string, int> m_fireAndForgetCallsMade = new Dictionary<string, int>();
2331 
2332  public static Dictionary<string, int> GetFireAndForgetCallsInProgress()
2333  {
2334  return new Dictionary<string, int>(m_fireAndForgetCallsInProgress);
2335  }
2336 
2337  private static Dictionary<string, int> m_fireAndForgetCallsInProgress = new Dictionary<string, int>();
2338 
2339  public static void FireAndForget(System.Threading.WaitCallback callback)
2340  {
2341  FireAndForget(callback, null, null);
2342  }
2343 
2344  public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
2345  {
2346  FireAndForget(callback, obj, null);
2347  }
2348 
2349  public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context)
2350  {
2351  Interlocked.Increment(ref numTotalThreadFuncsCalled);
2352 
2353  if (context != null)
2354  {
2355  if (!m_fireAndForgetCallsMade.ContainsKey(context))
2356  m_fireAndForgetCallsMade[context] = 1;
2357  else
2358  m_fireAndForgetCallsMade[context]++;
2359 
2360  if (!m_fireAndForgetCallsInProgress.ContainsKey(context))
2361  m_fireAndForgetCallsInProgress[context] = 1;
2362  else
2363  m_fireAndForgetCallsInProgress[context]++;
2364  }
2365 
2366  WaitCallback realCallback;
2367 
2368  bool loggingEnabled = LogThreadPool > 0;
2369 
2370  long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum);
2371  ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context);
2372 
2373  if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
2374  {
2375  // If we're running regression tests, then we want any exceptions to rise up to the test code.
2376  realCallback =
2377  o =>
2378  {
2379  Culture.SetCurrentCulture();
2380  callback(o);
2381 
2382  if (context != null)
2383  m_fireAndForgetCallsInProgress[context]--;
2384  };
2385  }
2386  else
2387  {
2388  // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture
2389  // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas
2390  // for decimals places but is read by a culture that treats commas as number seperators.
2391  realCallback = o =>
2392  {
2393  long numQueued1 = Interlocked.Decrement(ref numQueuedThreadFuncs);
2394  long numRunning1 = Interlocked.Increment(ref numRunningThreadFuncs);
2395  threadInfo.Started();
2396  activeThreads[threadFuncNum] = threadInfo;
2397 
2398  try
2399  {
2400  if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
2401  m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1);
2402 
2403  Culture.SetCurrentCulture();
2404 
2405  callback(o);
2406  }
2407  catch (ThreadAbortException e)
2408  {
2409  m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e);
2410  }
2411  catch (Exception e)
2412  {
2413  m_log.Error(string.Format("[UTIL]: Util STP threadfunc {0} terminated with error ", threadFuncNum), e);
2414  }
2415  finally
2416  {
2417  Interlocked.Decrement(ref numRunningThreadFuncs);
2418  threadInfo.Ended();
2419  ThreadInfo dummy;
2420  activeThreads.TryRemove(threadFuncNum, out dummy);
2421  if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
2422  m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed()));
2423 
2424  if (context != null)
2425  m_fireAndForgetCallsInProgress[context]--;
2426  }
2427  };
2428  }
2429 
2430  long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs);
2431  try
2432  {
2433 /*
2434  long numRunning = numRunningThreadFuncs;
2435 
2436  if (m_ThreadPool != null && LogOverloads)
2437  {
2438  if ((threadFuncOverloadMode == 0) && (numRunning >= m_ThreadPool.MaxThreads))
2439  {
2440  if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 1, 0) == 0)
2441  m_log.DebugFormat("Threadfunc: enable overload mode (Queued {0}, Running {1})", numQueued, numRunning);
2442  }
2443  else if ((threadFuncOverloadMode == 1) && (numRunning <= (m_ThreadPool.MaxThreads * 2) / 3))
2444  {
2445  if (Interlocked.CompareExchange(ref threadFuncOverloadMode, 0, 1) == 1)
2446  m_log.DebugFormat("Threadfunc: disable overload mode (Queued {0}, Running {1})", numQueued, numRunning);
2447  }
2448  }
2449 
2450  if (loggingEnabled || (threadFuncOverloadMode == 1))
2451  {
2452  string full, partial;
2453  GetFireAndForgetStackTrace(out full, out partial);
2454  threadInfo.StackTrace = full;
2455  threadInfo.LogThread = ShouldLogThread(partial);
2456 
2457  if (threadInfo.LogThread)
2458  {
2459  m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}",
2460  threadFuncNum, numQueued, numRunningThreadFuncs,
2461  (context == null) ? "" : ("(" + context + ") "),
2462  (LogThreadPool >= 2) ? full : partial);
2463  }
2464  }
2465  else
2466 */
2467  {
2468  // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either.
2469  // Those log lines aren't useful when we don't know which function is running in the thread.
2470  threadInfo.LogThread = false;
2471  }
2472 
2473  switch (FireAndForgetMethod)
2474  {
2475  case FireAndForgetMethod.RegressionTest:
2476  case FireAndForgetMethod.None:
2477  realCallback.Invoke(obj);
2478  break;
2479  case FireAndForgetMethod.UnsafeQueueUserWorkItem:
2480  ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj);
2481  break;
2482  case FireAndForgetMethod.QueueUserWorkItem:
2483  ThreadPool.QueueUserWorkItem(realCallback, obj);
2484  break;
2485  case FireAndForgetMethod.BeginInvoke:
2486  FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance;
2487  wrapper.FireAndForget(realCallback, obj);
2488  break;
2489  case FireAndForgetMethod.SmartThreadPool:
2490  if (m_ThreadPool == null)
2491  InitThreadPool(2, 15);
2492  threadInfo.WorkItem = m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
2493  break;
2494  case FireAndForgetMethod.Thread:
2495  Thread thread = new Thread(delegate(object o) { realCallback(o); });
2496  thread.Start(obj);
2497  break;
2498  default:
2499  throw new NotImplementedException();
2500  }
2501  }
2502  catch (Exception)
2503  {
2504  Interlocked.Decrement(ref numQueuedThreadFuncs);
2505  ThreadInfo dummy;
2506  activeThreads.TryRemove(threadFuncNum, out dummy);
2507  throw;
2508  }
2509  }
2510 
2517  private static bool ShouldLogThread(string stackTrace)
2518  {
2519  if (LogThreadPool < 3)
2520  {
2521  if (stackTrace.Contains("BeginFireQueueEmpty"))
2522  return false;
2523  }
2524 
2525  return true;
2526  }
2527 
2533  private static void GetFireAndForgetStackTrace(out string full, out string partial)
2534  {
2535  string src = Environment.StackTrace;
2536  string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
2537 
2538  StringBuilder dest = new StringBuilder(src.Length);
2539 
2540  bool started = false;
2541  bool first = true;
2542  partial = "";
2543 
2544  for (int i = 0; i < lines.Length; i++)
2545  {
2546  string line = lines[i];
2547 
2548  if (!started)
2549  {
2550  // Skip the initial stack frames, because they're of no interest for debugging
2551  if (line.Contains("StackTrace") || line.Contains("FireAndForget"))
2552  continue;
2553  started = true;
2554  }
2555 
2556  if (first)
2557  {
2558  line = line.TrimStart();
2559  first = false;
2560  partial = line;
2561  }
2562 
2563  bool last = (i == lines.Length - 1);
2564  if (last)
2565  dest.Append(line);
2566  else
2567  dest.AppendLine(line);
2568  }
2569 
2570  full = dest.ToString();
2571  }
2572 
2573 #pragma warning disable 0618
2574  private static StackTrace GetStackTrace(Thread targetThread)
2590  {
2591  if (IsPlatformMono)
2592  {
2593  // This doesn't work in Mono
2594  return null;
2595  }
2596 
2597  ManualResetEventSlim fallbackThreadReady = new ManualResetEventSlim();
2598  ManualResetEventSlim exitedSafely = new ManualResetEventSlim();
2599 
2600  try
2601  {
2602  new Thread(delegate()
2603  {
2604  fallbackThreadReady.Set();
2605  while (!exitedSafely.Wait(200))
2606  {
2607  try
2608  {
2609  targetThread.Resume();
2610  }
2611  catch (Exception)
2612  {
2613  // Whatever happens, do never stop to resume the main-thread regularly until the main-thread has exited safely.
2614  }
2615  }
2616  }).Start();
2617 
2618  fallbackThreadReady.Wait();
2619  // From here, you have about 200ms to get the stack-trace
2620 
2621  targetThread.Suspend();
2622 
2623  StackTrace trace = null;
2624  try
2625  {
2626  trace = new StackTrace(targetThread, true);
2627  }
2628  catch (ThreadStateException)
2629  {
2630  //failed to get stack trace, since the fallback-thread resumed the thread
2631  //possible reasons:
2632  //1.) This thread was just too slow
2633  //2.) A deadlock ocurred
2634  //Automatic retry seems too risky here, so just return null.
2635  }
2636 
2637  try
2638  {
2639  targetThread.Resume();
2640  }
2641  catch (ThreadStateException)
2642  {
2643  // Thread is running again already
2644  }
2645 
2646  return trace;
2647  }
2648  finally
2649  {
2650  // Signal the fallack-thread to stop
2651  exitedSafely.Set();
2652  }
2653  }
2654 #pragma warning restore 0618
2655 
2662  public static STPInfo GetSmartThreadPoolInfo()
2663  {
2664  if (m_ThreadPool == null)
2665  return null;
2666 
2667  STPInfo stpi = new STPInfo();
2668  stpi.Name = m_ThreadPool.Name;
2669  stpi.STPStartInfo = m_ThreadPool.STPStartInfo;
2670  stpi.IsIdle = m_ThreadPool.IsIdle;
2671  stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown;
2672  stpi.MaxThreads = m_ThreadPool.MaxThreads;
2673  stpi.MinThreads = m_ThreadPool.MinThreads;
2674  stpi.InUseThreads = m_ThreadPool.InUseThreads;
2675  stpi.ActiveThreads = m_ThreadPool.ActiveThreads;
2676  stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks;
2677  stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency;
2678 
2679  return stpi;
2680  }
2681 
2682  #endregion FireAndForget Threading Pattern
2683 
2691  public static Int32 EnvironmentTickCount()
2692  {
2693  return Environment.TickCount & EnvironmentTickCountMask;
2694  }
2695  const Int32 EnvironmentTickCountMask = 0x3fffffff;
2696 
2705  public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue)
2706  {
2707  Int32 diff = newValue - prevValue;
2708  return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
2709  }
2710 
2717  public static Int32 EnvironmentTickCountSubtract(Int32 prevValue)
2718  {
2719  return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue);
2720  }
2721 
2722  // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount
2723  // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount().
2724  // A positive return value indicates A occured later than B
2725  public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB)
2726  {
2727  // A, B and TC are all between 0 and 0x3fffffff
2728  int tc = EnvironmentTickCount();
2729 
2730  if (tc - tcA >= 0)
2731  tcA += EnvironmentTickCountMask + 1;
2732 
2733  if (tc - tcB >= 0)
2734  tcB += EnvironmentTickCountMask + 1;
2735 
2736  return tcA - tcB;
2737  }
2738 
2739  // returns a timestamp in ms as double
2740  // using the time resolution avaiable to StopWatch
2741  public static double GetTimeStampMS()
2742  {
2743  return (double)Stopwatch.GetTimestamp() * TimeStampClockPeriodMS;
2744  }
2745 
2749  public static string FormatDuration(int ms)
2750  {
2751  TimeSpan span = new TimeSpan(ms * TimeSpan.TicksPerMillisecond);
2752 
2753  string str = "";
2754  string suffix = null;
2755 
2756  int hours = (int)span.TotalHours;
2757  if (hours > 0)
2758  {
2759  str += hours.ToString(str.Length == 0 ? "0" : "00");
2760  suffix = "hours";
2761  }
2762 
2763  if ((hours > 0) || (span.Minutes > 0))
2764  {
2765  if (str.Length > 0)
2766  str += ":";
2767  str += span.Minutes.ToString(str.Length == 0 ? "0" : "00");
2768  if (suffix == null)
2769  suffix = "min";
2770  }
2771 
2772  if ((hours > 0) || (span.Minutes > 0) || (span.Seconds > 0))
2773  {
2774  if (str.Length > 0)
2775  str += ":";
2776  str += span.Seconds.ToString(str.Length == 0 ? "0" : "00");
2777  if (suffix == null)
2778  suffix = "sec";
2779  }
2780 
2781  if (suffix == null)
2782  suffix = "ms";
2783 
2784  if (span.TotalMinutes < 1)
2785  {
2786  int ms1 = span.Milliseconds;
2787  if (str.Length > 0)
2788  {
2789  ms1 /= 100;
2790  str += ".";
2791  }
2792  str += ms1.ToString("0");
2793  }
2794 
2795  str += " " + suffix;
2796 
2797  return str;
2798  }
2799 
2803  public static void PrintCallStack()
2804  {
2805  PrintCallStack(m_log.DebugFormat);
2806  }
2807 
2808  public delegate void DebugPrinter(string msg, params Object[] parm);
2809  public static void PrintCallStack(DebugPrinter printer)
2810  {
2811  StackTrace stackTrace = new StackTrace(true); // get call stack
2812  StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
2813 
2814  // write call stack method names
2815  foreach (StackFrame stackFrame in stackFrames)
2816  {
2817  MethodBase mb = stackFrame.GetMethod();
2818  printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
2819  }
2820  }
2821 
2827  public static IPEndPoint GetClientIPFromXFF(string xff)
2828  {
2829  if (xff == string.Empty)
2830  return null;
2831 
2832  string[] parts = xff.Split(new char[] { ',' });
2833  if (parts.Length > 0)
2834  {
2835  try
2836  {
2837  return new IPEndPoint(IPAddress.Parse(parts[0]), 0);
2838  }
2839  catch (Exception e)
2840  {
2841  m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message);
2842  }
2843  }
2844 
2845  return null;
2846  }
2847 
2848  public static string GetCallerIP(Hashtable req)
2849  {
2850  if (req.ContainsKey("headers"))
2851  {
2852  try
2853  {
2854  Hashtable headers = (Hashtable)req["headers"];
2855  if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null)
2856  return headers["remote_addr"].ToString();
2857  }
2858  catch (Exception e)
2859  {
2860  m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message);
2861  }
2862  }
2863  return string.Empty;
2864  }
2865 
2866  #region Xml Serialization Utilities
2867  public static bool ReadBoolean(XmlReader reader)
2868  {
2869  // AuroraSim uses "int" for some fields that are boolean in OpenSim, e.g. "PassCollisions". Don't fail because of this.
2870  reader.ReadStartElement();
2871  string val = reader.ReadContentAsString().ToLower();
2872  bool result = val.Equals("true") || val.Equals("1");
2873  reader.ReadEndElement();
2874 
2875  return result;
2876  }
2877 
2878  public static UUID ReadUUID(XmlReader reader, string name)
2879  {
2880  UUID id;
2881  string idStr;
2882 
2883  reader.ReadStartElement(name);
2884 
2885  if (reader.Name == "Guid")
2886  idStr = reader.ReadElementString("Guid");
2887  else if (reader.Name == "UUID")
2888  idStr = reader.ReadElementString("UUID");
2889  else // no leading tag
2890  idStr = reader.ReadContentAsString();
2891  UUID.TryParse(idStr, out id);
2892  reader.ReadEndElement();
2893 
2894  return id;
2895  }
2896 
2897  public static Vector3 ReadVector(XmlReader reader, string name)
2898  {
2899  Vector3 vec;
2900 
2901  reader.ReadStartElement(name);
2902  vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x
2903  vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y
2904  vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z
2905  reader.ReadEndElement();
2906 
2907  return vec;
2908  }
2909 
2910  public static Quaternion ReadQuaternion(XmlReader reader, string name)
2911  {
2912  Quaternion quat = new Quaternion();
2913 
2914  reader.ReadStartElement(name);
2915  while (reader.NodeType != XmlNodeType.EndElement)
2916  {
2917  switch (reader.Name.ToLower())
2918  {
2919  case "x":
2920  quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2921  break;
2922  case "y":
2923  quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2924  break;
2925  case "z":
2926  quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2927  break;
2928  case "w":
2929  quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2930  break;
2931  }
2932  }
2933 
2934  reader.ReadEndElement();
2935 
2936  return quat;
2937  }
2938 
2939  public static T ReadEnum<T>(XmlReader reader, string name)
2940  {
2941  string value = reader.ReadElementContentAsString(name, String.Empty);
2942  // !!!!! to deal with flags without commas
2943  if (value.Contains(" ") && !value.Contains(","))
2944  value = value.Replace(" ", ", ");
2945 
2946  return (T)Enum.Parse(typeof(T), value); ;
2947  }
2948  #endregion
2949 
2950  #region Universal User Identifiers
2951 
2961  public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret)
2962  {
2963  uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty;
2964 
2965  string[] parts = value.Split(';');
2966  if (parts.Length >= 1)
2967  if (!UUID.TryParse(parts[0], out uuid))
2968  return false;
2969 
2970  if (parts.Length >= 2)
2971  url = parts[1];
2972 
2973  if (parts.Length >= 3)
2974  {
2975  string[] name = parts[2].Split();
2976  if (name.Length == 2)
2977  {
2978  firstname = name[0];
2979  lastname = name[1];
2980  }
2981  }
2982  if (parts.Length >= 4)
2983  secret = parts[3];
2984 
2985  return true;
2986  }
2987 
2991  public static bool ParseForeignAvatarName(string firstname, string lastname,
2992  out string realFirstName, out string realLastName, out string serverURI)
2993  {
2994  realFirstName = realLastName = serverURI = string.Empty;
2995 
2996  if (!lastname.Contains("@"))
2997  return false;
2998 
2999  if (!firstname.Contains("."))
3000  return false;
3001 
3002  realFirstName = firstname.Split('.')[0];
3003  realLastName = firstname.Split('.')[1];
3004  serverURI = new Uri("http://" + lastname.Replace("@", "")).ToString();
3005 
3006  return true;
3007  }
3008 
3014  public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit)
3015  {
3016  if (acircuit.ServiceURLs.ContainsKey("HomeURI"))
3017  return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString());
3018  else
3019  return acircuit.AgentID.ToString();
3020  }
3021 
3030  public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI)
3031  {
3032  string agentsURI = homeURI;
3033  if (!agentsURI.EndsWith("/"))
3034  agentsURI += "/";
3035 
3036  // This is ugly, but there's no other way, given that the name is changed
3037  // in the agent circuit data for foreigners
3038  if (lastName.Contains("@"))
3039  {
3040  string[] parts = firstName.Split(new char[] { '.' });
3041  if (parts.Length == 2)
3042  return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]);
3043  }
3044 
3045  return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName);
3046  }
3047 
3048  private static string CalcUniversalIdentifier(UUID id, string agentsURI, string name)
3049  {
3050  return id.ToString() + ";" + agentsURI + ";" + name;
3051  }
3052 
3060  public static string UniversalName(String firstName, String lastName, String homeURI)
3061  {
3062  Uri uri = null;
3063  try
3064  {
3065  uri = new Uri(homeURI);
3066  }
3067  catch (UriFormatException)
3068  {
3069  return firstName + " " + lastName;
3070  }
3071  return firstName + "." + lastName + " " + "@" + uri.Authority;
3072  }
3073  #endregion
3074 
3081  public static string EscapeForLike(string str)
3082  {
3083  return str.Replace("_", "\\_").Replace("%", "\\%");
3084  }
3085 
3094  public static string GetViewerName(AgentCircuitData agent)
3095  {
3096  string name = agent.Viewer;
3097  if (name == null)
3098  name = "";
3099  else
3100  name = name.Trim();
3101 
3102  // Check if 'Viewer' is just a version number. If it's *not*, then we
3103  // assume that it contains the real viewer name, and we return it.
3104  foreach (char c in name)
3105  {
3106  if (Char.IsLetter(c))
3107  return name;
3108  }
3109 
3110  // The 'Viewer' string contains just a version number. If there's anything in
3111  // 'Channel' then assume that it's the viewer name.
3112  if ((agent.Channel != null) && (agent.Channel.Length > 0))
3113  name = agent.Channel.Trim() + " " + name;
3114 
3115  return name;
3116  }
3117 
3118  public static void LogFailedXML(string message, string xml)
3119  {
3120  int length = xml.Length;
3121  if (length > 2000)
3122  xml = xml.Substring(0, 2000) + "...";
3123 
3124  m_log.ErrorFormat("{0} Failed XML ({1} bytes) = {2}", message, length, xml);
3125  }
3126 
3127  }
3128 
3129 /* don't like this code
3130  public class DoubleQueue<T> where T:class
3131  {
3132  private Queue<T> m_lowQueue = new Queue<T>();
3133  private Queue<T> m_highQueue = new Queue<T>();
3134 
3135  private object m_syncRoot = new object();
3136  private Semaphore m_s = new Semaphore(0, 1);
3137 
3138  public DoubleQueue()
3139  {
3140  }
3141 
3142  public virtual int Count
3143  {
3144  get
3145  {
3146  lock (m_syncRoot)
3147  return m_highQueue.Count + m_lowQueue.Count;
3148  }
3149  }
3150 
3151  public virtual void Enqueue(T data)
3152  {
3153  Enqueue(m_lowQueue, data);
3154  }
3155 
3156  public virtual void EnqueueLow(T data)
3157  {
3158  Enqueue(m_lowQueue, data);
3159  }
3160 
3161  public virtual void EnqueueHigh(T data)
3162  {
3163  Enqueue(m_highQueue, data);
3164  }
3165 
3166  private void Enqueue(Queue<T> q, T data)
3167  {
3168  lock (m_syncRoot)
3169  {
3170  q.Enqueue(data);
3171  m_s.WaitOne(0);
3172  m_s.Release();
3173  }
3174  }
3175 
3176  public virtual T Dequeue()
3177  {
3178  return Dequeue(Timeout.Infinite);
3179  }
3180 
3181  public virtual T Dequeue(int tmo)
3182  {
3183  return Dequeue(TimeSpan.FromMilliseconds(tmo));
3184  }
3185 
3186  public virtual T Dequeue(TimeSpan wait)
3187  {
3188  T res = null;
3189 
3190  if (!Dequeue(wait, ref res))
3191  return null;
3192 
3193  return res;
3194  }
3195 
3196  public bool Dequeue(int timeout, ref T res)
3197  {
3198  return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
3199  }
3200 
3201  public bool Dequeue(TimeSpan wait, ref T res)
3202  {
3203  if (!m_s.WaitOne(wait))
3204  return false;
3205 
3206  lock (m_syncRoot)
3207  {
3208  if (m_highQueue.Count > 0)
3209  res = m_highQueue.Dequeue();
3210  else if (m_lowQueue.Count > 0)
3211  res = m_lowQueue.Dequeue();
3212 
3213  if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
3214  return true;
3215 
3216  try
3217  {
3218  m_s.Release();
3219  }
3220  catch
3221  {
3222  }
3223 
3224  return true;
3225  }
3226  }
3227 
3228  public virtual void Clear()
3229  {
3230 
3231  lock (m_syncRoot)
3232  {
3233  // Make sure sem count is 0
3234  m_s.WaitOne(0);
3235 
3236  m_lowQueue.Clear();
3237  m_highQueue.Clear();
3238  }
3239  }
3240  }
3241 */
3242  public class BetterRandom
3243  {
3244  private const int BufferSize = 1024; // must be a multiple of 4
3245  private byte[] RandomBuffer;
3246  private int BufferOffset;
3247  private RNGCryptoServiceProvider rng;
3248  public BetterRandom()
3249  {
3250  RandomBuffer = new byte[BufferSize];
3251  rng = new RNGCryptoServiceProvider();
3252  BufferOffset = RandomBuffer.Length;
3253  }
3254  private void FillBuffer()
3255  {
3256  rng.GetBytes(RandomBuffer);
3257  BufferOffset = 0;
3258  }
3259  public int Next()
3260  {
3261  if (BufferOffset >= RandomBuffer.Length)
3262  {
3263  FillBuffer();
3264  }
3265  int val = BitConverter.ToInt32(RandomBuffer, BufferOffset) & 0x7fffffff;
3266  BufferOffset += sizeof(int);
3267  return val;
3268  }
3269  public int Next(int maxValue)
3270  {
3271  return Next() % maxValue;
3272  }
3273  public int Next(int minValue, int maxValue)
3274  {
3275  if (maxValue < minValue)
3276  {
3277  throw new ArgumentOutOfRangeException("maxValue must be greater than or equal to minValue");
3278  }
3279  int range = maxValue - minValue;
3280  return minValue + Next(range);
3281  }
3282  public double NextDouble()
3283  {
3284  int val = Next();
3285  return (double)val / int.MaxValue;
3286  }
3287  public void GetBytes(byte[] buff)
3288  {
3289  rng.GetBytes(buff);
3290  }
3291  }
3292 }
FireAndForgetMethod
The method used by Util.FireAndForget for asynchronously firing events
Definition: Util.cs:92
OpenSim.Server.Handlers.Simulation.Utils Utils
void GetBytes(byte[] buff)
Definition: Util.cs:3287
Class for delivering SmartThreadPool statistical information
Definition: Util.cs:109
OpenMetaverse.StructuredData.OSDMap OSDMap
Ionic.Zlib.GZipStream GZipStream
System.Timers.Timer Timer
OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString key
Definition: ICM_Api.cs:31
int Next(int maxValue)
Definition: Util.cs:3269
int Next(int minValue, int maxValue)
Definition: Util.cs:3273
OpenMetaverse.StructuredData.OSD OSD
Ionic.Zlib.CompressionMode CompressionMode