clockwerk-opensim-stable – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 vero 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  
55 namespace OpenSim.Framework
56 {
57 [Flags]
58 public enum PermissionMask : uint
59 {
60 None = 0,
61 Transfer = 1 << 13,
62 Modify = 1 << 14,
63 Copy = 1 << 15,
64 Export = 1 << 16,
65 Move = 1 << 19,
66 Damage = 1 << 20,
67 // All does not contain Export, which is special and must be
68 // explicitly given
69 All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19)
70 }
71  
72 /// <summary>
73 /// The method used by Util.FireAndForget for asynchronously firing events
74 /// </summary>
75 /// <remarks>
76 /// None is used to execute the method in the same thread that made the call. It should only be used by regression
77 /// test code that relies on predictable event ordering.
78 /// RegressionTest is used by regression tests. It fires the call synchronously and does not catch any exceptions.
79 /// </remarks>
80 public enum FireAndForgetMethod
81 {
82 None,
83 RegressionTest,
84 UnsafeQueueUserWorkItem,
85 QueueUserWorkItem,
86 BeginInvoke,
87 SmartThreadPool,
88 Thread,
89 }
90  
91 /// <summary>
92 /// Class for delivering SmartThreadPool statistical information
93 /// </summary>
94 /// <remarks>
95 /// We do it this way so that we do not directly expose STP.
96 /// </remarks>
97 public class STPInfo
98 {
99 public string Name { get; set; }
100 public STPStartInfo STPStartInfo { get; set; }
101 public WIGStartInfo WIGStartInfo { get; set; }
102 public bool IsIdle { get; set; }
103 public bool IsShuttingDown { get; set; }
104 public int MaxThreads { get; set; }
105 public int MinThreads { get; set; }
106 public int InUseThreads { get; set; }
107 public int ActiveThreads { get; set; }
108 public int WaitingCallbacks { get; set; }
109 public int MaxConcurrentWorkItems { get; set; }
110 }
111  
112 /// <summary>
113 /// Miscellaneous utility functions
114 /// </summary>
115 public static class Util
116 {
117 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
118  
119 private static uint nextXferID = 5000;
120 private static Random randomClass = new Random();
121  
122 // Get a list of invalid file characters (OS dependent)
123 private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
124 private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]";
125 private static object XferLock = new object();
126  
127 /// <summary>
128 /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used
129 /// </summary>
130 private static SmartThreadPool m_ThreadPool;
131  
132 // 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.
133 public static readonly DateTime UnixEpoch =
134 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
135  
136 private static readonly string rawUUIDPattern
137 = "[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}";
138 public static readonly Regex PermissiveUUIDPattern = new Regex(rawUUIDPattern);
139 public static readonly Regex UUIDPattern = new Regex(string.Format("^{0}$", rawUUIDPattern));
140  
141 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
142 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
143  
144 public static bool IsPlatformMono
145 {
146 get { return Type.GetType("Mono.Runtime") != null; }
147 }
148  
149 /// <summary>
150 /// Gets the name of the directory where the current running executable
151 /// is located
152 /// </summary>
153 /// <returns>Filesystem path to the directory containing the current
154 /// executable</returns>
155 public static string ExecutingDirectory()
156 {
157 return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
158 }
159  
160 /// <summary>
161 /// Linear interpolates B<->C using percent A
162 /// </summary>
163 /// <param name="a"></param>
164 /// <param name="b"></param>
165 /// <param name="c"></param>
166 /// <returns></returns>
167 public static double lerp(double a, double b, double c)
168 {
169 return (b*a) + (c*(1 - a));
170 }
171  
172 /// <summary>
173 /// Bilinear Interpolate, see Lerp but for 2D using 'percents' X & Y.
174 /// Layout:
175 /// A B
176 /// C D
177 /// A<->C = Y
178 /// C<->D = X
179 /// </summary>
180 /// <param name="x"></param>
181 /// <param name="y"></param>
182 /// <param name="a"></param>
183 /// <param name="b"></param>
184 /// <param name="c"></param>
185 /// <param name="d"></param>
186 /// <returns></returns>
187 public static double lerp2D(double x, double y, double a, double b, double c, double d)
188 {
189 return lerp(y, lerp(x, a, b), lerp(x, c, d));
190 }
191  
192 public static Encoding UTF8 = Encoding.UTF8;
193 public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false);
194  
195 /// <value>
196 /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards)
197 /// </value>
198 public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
199  
200 #region Vector Equations
201  
202 /// <summary>
203 /// Get the distance between two 3d vectors
204 /// </summary>
205 /// <param name="a">A 3d vector</param>
206 /// <param name="b">A 3d vector</param>
207 /// <returns>The distance between the two vectors</returns>
208 public static double GetDistanceTo(Vector3 a, Vector3 b)
209 {
210 float dx = a.X - b.X;
211 float dy = a.Y - b.Y;
212 float dz = a.Z - b.Z;
213 return Math.Sqrt(dx * dx + dy * dy + dz * dz);
214 }
215  
216 /// <summary>
217 /// Returns true if the distance beween A and B is less than amount. Significantly faster than GetDistanceTo since it eliminates the Sqrt.
218 /// </summary>
219 /// <param name="a"></param>
220 /// <param name="b"></param>
221 /// <param name="amount"></param>
222 /// <returns></returns>
223 public static bool DistanceLessThan(Vector3 a, Vector3 b, double amount)
224 {
225 float dx = a.X - b.X;
226 float dy = a.Y - b.Y;
227 float dz = a.Z - b.Z;
228 return (dx*dx + dy*dy + dz*dz) < (amount*amount);
229 }
230  
231 /// <summary>
232 /// Get the magnitude of a 3d vector
233 /// </summary>
234 /// <param name="a">A 3d vector</param>
235 /// <returns>The magnitude of the vector</returns>
236 public static double GetMagnitude(Vector3 a)
237 {
238 return Math.Sqrt((a.X * a.X) + (a.Y * a.Y) + (a.Z * a.Z));
239 }
240  
241 /// <summary>
242 /// Get a normalized form of a 3d vector
243 /// </summary>
244 /// <param name="a">A 3d vector</param>
245 /// <returns>A new vector which is normalized form of the vector</returns>
246 /// <remarks>The vector paramater cannot be <0,0,0></remarks>
247 public static Vector3 GetNormalizedVector(Vector3 a)
248 {
249 if (IsZeroVector(a))
250 throw new ArgumentException("Vector paramater cannot be a zero vector.");
251  
252 float Mag = (float) GetMagnitude(a);
253 return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag);
254 }
255  
256 /// <summary>
257 /// Returns if a vector is a zero vector (has all zero components)
258 /// </summary>
259 /// <returns></returns>
260 public static bool IsZeroVector(Vector3 v)
261 {
262 if (v.X == 0 && v.Y == 0 && v.Z == 0)
263 {
264 return true;
265 }
266  
267 return false;
268 }
269  
270 # endregion
271  
272 public static Quaternion Axes2Rot(Vector3 fwd, Vector3 left, Vector3 up)
273 {
274 float s;
275 float tr = (float) (fwd.X + left.Y + up.Z + 1.0);
276  
277 if (tr >= 1.0)
278 {
279 s = (float) (0.5 / Math.Sqrt(tr));
280 return new Quaternion(
281 (left.Z - up.Y) * s,
282 (up.X - fwd.Z) * s,
283 (fwd.Y - left.X) * s,
284 (float) 0.25 / s);
285 }
286 else
287 {
288 float max = (left.Y > up.Z) ? left.Y : up.Z;
289  
290 if (max < fwd.X)
291 {
292 s = (float) (Math.Sqrt(fwd.X - (left.Y + up.Z) + 1.0));
293 float x = (float) (s * 0.5);
294 s = (float) (0.5 / s);
295 return new Quaternion(
296 x,
297 (fwd.Y + left.X) * s,
298 (up.X + fwd.Z) * s,
299 (left.Z - up.Y) * s);
300 }
301 else if (max == left.Y)
302 {
303 s = (float) (Math.Sqrt(left.Y - (up.Z + fwd.X) + 1.0));
304 float y = (float) (s * 0.5);
305 s = (float) (0.5 / s);
306 return new Quaternion(
307 (fwd.Y + left.X) * s,
308 y,
309 (left.Z + up.Y) * s,
310 (up.X - fwd.Z) * s);
311 }
312 else
313 {
314 s = (float) (Math.Sqrt(up.Z - (fwd.X + left.Y) + 1.0));
315 float z = (float) (s * 0.5);
316 s = (float) (0.5 / s);
317 return new Quaternion(
318 (up.X + fwd.Z) * s,
319 (left.Z + up.Y) * s,
320 z,
321 (fwd.Y - left.X) * s);
322 }
323 }
324 }
325  
326 public static Random RandomClass
327 {
328 get { return randomClass; }
329 }
330  
331 public static ulong UIntsToLong(uint X, uint Y)
332 {
333 return Utils.UIntsToLong(X, Y);
334 }
335  
336 public static T Clamp<T>(T x, T min, T max)
337 where T : IComparable<T>
338 {
339 return x.CompareTo(max) > 0 ? max :
340 x.CompareTo(min) < 0 ? min :
341 x;
342 }
343  
344 // Clamp the maximum magnitude of a vector
345 public static Vector3 ClampV(Vector3 x, float max)
346 {
347 float lenSq = x.LengthSquared();
348 if (lenSq > (max * max))
349 {
350 x = x / x.Length() * max;
351 }
352  
353 return x;
354 }
355  
356 // Inclusive, within range test (true if equal to the endpoints)
357 public static bool InRange<T>(T x, T min, T max)
358 where T : IComparable<T>
359 {
360 return x.CompareTo(max) <= 0 && x.CompareTo(min) >= 0;
361 }
362  
363 public static uint GetNextXferID()
364 {
365 uint id = 0;
366 lock (XferLock)
367 {
368 id = nextXferID;
369 nextXferID++;
370 }
371 return id;
372 }
373  
374 public static string GetFileName(string file)
375 {
376 // Return just the filename on UNIX platforms
377 // TODO: this should be customisable with a prefix, but that's something to do later.
378 if (Environment.OSVersion.Platform == PlatformID.Unix)
379 {
380 return file;
381 }
382  
383 // Return %APPDATA%/OpenSim/file for 2K/XP/NT/2K3/VISTA
384 // TODO: Switch this to System.Enviroment.SpecialFolders.ApplicationData
385 if (Environment.OSVersion.Platform == PlatformID.Win32NT)
386 {
387 if (!Directory.Exists("%APPDATA%\\OpenSim\\"))
388 {
389 Directory.CreateDirectory("%APPDATA%\\OpenSim");
390 }
391  
392 return "%APPDATA%\\OpenSim\\" + file;
393 }
394  
395 // Catch all - covers older windows versions
396 // (but those probably wont work anyway)
397 return file;
398 }
399  
400 /// <summary>
401 /// Debug utility function to convert OSD into formatted XML for debugging purposes.
402 /// </summary>
403 /// <param name="osd">
404 /// A <see cref="OSD"/>
405 /// </param>
406 /// <returns>
407 /// A <see cref="System.String"/>
408 /// </returns>
409 public static string GetFormattedXml(OSD osd)
410 {
411 return GetFormattedXml(OSDParser.SerializeLLSDXmlString(osd));
412 }
413  
414 /// <summary>
415 /// Debug utility function to convert unbroken strings of XML into something human readable for occasional debugging purposes.
416 /// </summary>
417 /// <remarks>
418 /// Please don't delete me even if I appear currently unused!
419 /// </remarks>
420 /// <param name="rawXml"></param>
421 /// <returns></returns>
422 public static string GetFormattedXml(string rawXml)
423 {
424 XmlDocument xd = new XmlDocument();
425 xd.LoadXml(rawXml);
426  
427 StringBuilder sb = new StringBuilder();
428 StringWriter sw = new StringWriter(sb);
429  
430 XmlTextWriter xtw = new XmlTextWriter(sw);
431 xtw.Formatting = Formatting.Indented;
432  
433 try
434 {
435 xd.WriteTo(xtw);
436 }
437 finally
438 {
439 xtw.Close();
440 }
441  
442 return sb.ToString();
443 }
444  
445 /// <summary>
446 /// Is the platform Windows?
447 /// </summary>
448 /// <returns>true if so, false otherwise</returns>
449 public static bool IsWindows()
450 {
451 PlatformID platformId = Environment.OSVersion.Platform;
452  
453 return (platformId == PlatformID.Win32NT
454 || platformId == PlatformID.Win32S
455 || platformId == PlatformID.Win32Windows
456 || platformId == PlatformID.WinCE);
457 }
458  
459 public static bool LoadArchSpecificWindowsDll(string libraryName)
460 {
461 // We do this so that OpenSimulator on Windows loads the correct native library depending on whether
462 // it's running as a 32-bit process or a 64-bit one. By invoking LoadLibary here, later DLLImports
463 // will find it already loaded later on.
464 //
465 // This isn't necessary for other platforms (e.g. Mac OSX and Linux) since the DLL used can be
466 // controlled in config files.
467 string nativeLibraryPath;
468  
469 if (Util.Is64BitProcess())
470 nativeLibraryPath = "lib64/" + libraryName;
471 else
472 nativeLibraryPath = "lib32/" + libraryName;
473  
474 m_log.DebugFormat("[UTIL]: Loading native Windows library at {0}", nativeLibraryPath);
475  
476 if (Util.LoadLibrary(nativeLibraryPath) == IntPtr.Zero)
477 {
478 m_log.ErrorFormat(
479 "[UTIL]: Couldn't find native Windows library at {0}", nativeLibraryPath);
480  
481 return false;
482 }
483 else
484 {
485 return true;
486 }
487 }
488  
489 public static bool IsEnvironmentSupported(ref string reason)
490 {
491 // Must have .NET 2.0 (Generics / libsl)
492 if (Environment.Version.Major < 2)
493 {
494 reason = ".NET 1.0/1.1 lacks components that is used by OpenSim";
495 return false;
496 }
497  
498 // Windows 95/98/ME are unsupported
499 if (Environment.OSVersion.Platform == PlatformID.Win32Windows &&
500 Environment.OSVersion.Platform != PlatformID.Win32NT)
501 {
502 reason = "Windows 95/98/ME will not run OpenSim";
503 return false;
504 }
505  
506 // Windows 2000 / Pre-SP2 XP
507 if (Environment.OSVersion.Version.Major == 5 &&
508 Environment.OSVersion.Version.Minor == 0)
509 {
510 reason = "Please update to Windows XP Service Pack 2 or Server2003";
511 return false;
512 }
513  
514 return true;
515 }
516  
517 public static int UnixTimeSinceEpoch()
518 {
519 return ToUnixTime(DateTime.UtcNow);
520 }
521  
522 public static int ToUnixTime(DateTime stamp)
523 {
524 TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
525 return (int)t.TotalSeconds;
526 }
527  
528 public static DateTime ToDateTime(ulong seconds)
529 {
530 return UnixEpoch.AddSeconds(seconds);
531 }
532  
533 public static DateTime ToDateTime(int seconds)
534 {
535 return UnixEpoch.AddSeconds(seconds);
536 }
537  
538 /// <summary>
539 /// Return an md5 hash of the given string
540 /// </summary>
541 /// <param name="data"></param>
542 /// <returns></returns>
543 public static string Md5Hash(string data)
544 {
545 byte[] dataMd5 = ComputeMD5Hash(data);
546 StringBuilder sb = new StringBuilder();
547 for (int i = 0; i < dataMd5.Length; i++)
548 sb.AppendFormat("{0:x2}", dataMd5[i]);
549 return sb.ToString();
550 }
551  
552 private static byte[] ComputeMD5Hash(string data)
553 {
554 MD5 md5 = MD5.Create();
555 return md5.ComputeHash(Encoding.Default.GetBytes(data));
556 }
557  
558 /// <summary>
559 /// Return an SHA1 hash
560 /// </summary>
561 /// <param name="data"></param>
562 /// <returns></returns>
563 public static string SHA1Hash(string data)
564 {
565 return SHA1Hash(Encoding.Default.GetBytes(data));
566 }
567  
568 /// <summary>
569 /// Return an SHA1 hash
570 /// </summary>
571 /// <param name="data"></param>
572 /// <returns></returns>
573 public static string SHA1Hash(byte[] data)
574 {
575 byte[] hash = ComputeSHA1Hash(data);
576 return BitConverter.ToString(hash).Replace("-", String.Empty);
577 }
578  
579 private static byte[] ComputeSHA1Hash(byte[] src)
580 {
581 SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();
582 return SHA1.ComputeHash(src);
583 }
584  
585 public static int fast_distance2d(int x, int y)
586 {
587 x = Math.Abs(x);
588 y = Math.Abs(y);
589  
590 int min = Math.Min(x, y);
591  
592 return (x + y - (min >> 1) - (min >> 2) + (min >> 4));
593 }
594  
595 /// <summary>
596 /// Determines whether a point is inside a bounding box.
597 /// </summary>
598 /// <param name='v'></param>
599 /// <param name='min'></param>
600 /// <param name='max'></param>
601 /// <returns></returns>
602 public static bool IsInsideBox(Vector3 v, Vector3 min, Vector3 max)
603 {
604 return v.X >= min.X & v.Y >= min.Y && v.Z >= min.Z
605 && v.X <= max.X && v.Y <= max.Y && v.Z <= max.Z;
606 }
607  
608 /// <summary>
609 /// Are the co-ordinates of the new region visible from the old region?
610 /// </summary>
611 /// <param name="oldx">Old region x-coord</param>
612 /// <param name="newx">New region x-coord</param>
613 /// <param name="oldy">Old region y-coord</param>
614 /// <param name="newy">New region y-coord</param>
615 /// <returns></returns>
616 public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy)
617 {
618 int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize);
619  
620 int startX = (int)oldx - dd;
621 int startY = (int)oldy - dd;
622  
623 int endX = (int)oldx + dd;
624 int endY = (int)oldy + dd;
625  
626 return (newx < startX || endX < newx || newy < startY || endY < newy);
627 }
628  
629 public static string FieldToString(byte[] bytes)
630 {
631 return FieldToString(bytes, String.Empty);
632 }
633  
634 /// <summary>
635 /// Convert a variable length field (byte array) to a string, with a
636 /// field name prepended to each line of the output
637 /// </summary>
638 /// <remarks>If the byte array has unprintable characters in it, a
639 /// hex dump will be put in the string instead</remarks>
640 /// <param name="bytes">The byte array to convert to a string</param>
641 /// <param name="fieldName">A field name to prepend to each line of output</param>
642 /// <returns>An ASCII string or a string containing a hex dump, minus
643 /// the null terminator</returns>
644 public static string FieldToString(byte[] bytes, string fieldName)
645 {
646 // Check for a common case
647 if (bytes.Length == 0) return String.Empty;
648  
649 StringBuilder output = new StringBuilder();
650 bool printable = true;
651  
652 for (int i = 0; i < bytes.Length; ++i)
653 {
654 // Check if there are any unprintable characters in the array
655 if ((bytes[i] < 0x20 || bytes[i] > 0x7E) && bytes[i] != 0x09
656 && bytes[i] != 0x0D && bytes[i] != 0x0A && bytes[i] != 0x00)
657 {
658 printable = false;
659 break;
660 }
661 }
662  
663 if (printable)
664 {
665 if (fieldName.Length > 0)
666 {
667 output.Append(fieldName);
668 output.Append(": ");
669 }
670  
671 output.Append(CleanString(Util.UTF8.GetString(bytes, 0, bytes.Length - 1)));
672 }
673 else
674 {
675 for (int i = 0; i < bytes.Length; i += 16)
676 {
677 if (i != 0)
678 output.Append(Environment.NewLine);
679 if (fieldName.Length > 0)
680 {
681 output.Append(fieldName);
682 output.Append(": ");
683 }
684  
685 for (int j = 0; j < 16; j++)
686 {
687 if ((i + j) < bytes.Length)
688 output.Append(String.Format("{0:X2} ", bytes[i + j]));
689 else
690 output.Append(" ");
691 }
692  
693 for (int j = 0; j < 16 && (i + j) < bytes.Length; j++)
694 {
695 if (bytes[i + j] >= 0x20 && bytes[i + j] < 0x7E)
696 output.Append((char) bytes[i + j]);
697 else
698 output.Append(".");
699 }
700 }
701 }
702  
703 return output.ToString();
704 }
705  
706 /// <summary>
707 /// Converts a URL to a IPAddress
708 /// </summary>
709 /// <param name="url">URL Standard Format</param>
710 /// <returns>A resolved IP Address</returns>
711 public static IPAddress GetHostFromURL(string url)
712 {
713 return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]);
714 }
715  
716 /// <summary>
717 /// Returns a IP address from a specified DNS, favouring IPv4 addresses.
718 /// </summary>
719 /// <param name="dnsAddress">DNS Hostname</param>
720 /// <returns>An IP address, or null</returns>
721 public static IPAddress GetHostFromDNS(string dnsAddress)
722 {
723 // Is it already a valid IP? No need to look it up.
724 IPAddress ipa;
725 if (IPAddress.TryParse(dnsAddress, out ipa))
726 return ipa;
727  
728 IPAddress[] hosts = null;
729  
730 // Not an IP, lookup required
731 try
732 {
733 hosts = Dns.GetHostEntry(dnsAddress).AddressList;
734 }
735 catch (Exception e)
736 {
737 m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e);
738  
739 // Still going to throw the exception on for now, since this was what was happening in the first place
740 throw e;
741 }
742  
743 foreach (IPAddress host in hosts)
744 {
745 if (host.AddressFamily == AddressFamily.InterNetwork)
746 {
747 return host;
748 }
749 }
750  
751 if (hosts.Length > 0)
752 return hosts[0];
753  
754 return null;
755 }
756  
757 public static Uri GetURI(string protocol, string hostname, int port, string path)
758 {
759 return new UriBuilder(protocol, hostname, port, path).Uri;
760 }
761  
762 /// <summary>
763 /// Gets a list of all local system IP addresses
764 /// </summary>
765 /// <returns></returns>
766 public static IPAddress[] GetLocalHosts()
767 {
768 return Dns.GetHostAddresses(Dns.GetHostName());
769 }
770  
771 public static IPAddress GetLocalHost()
772 {
773 IPAddress[] iplist = GetLocalHosts();
774  
775 if (iplist.Length == 0) // No accessible external interfaces
776 {
777 IPAddress[] loopback = Dns.GetHostAddresses("localhost");
778 IPAddress localhost = loopback[0];
779  
780 return localhost;
781 }
782  
783 foreach (IPAddress host in iplist)
784 {
785 if (!IPAddress.IsLoopback(host) && host.AddressFamily == AddressFamily.InterNetwork)
786 {
787 return host;
788 }
789 }
790  
791 if (iplist.Length > 0)
792 {
793 foreach (IPAddress host in iplist)
794 {
795 if (host.AddressFamily == AddressFamily.InterNetwork)
796 return host;
797 }
798 // Well all else failed...
799 return iplist[0];
800 }
801  
802 return null;
803 }
804  
805 /// <summary>
806 /// Removes all invalid path chars (OS dependent)
807 /// </summary>
808 /// <param name="path">path</param>
809 /// <returns>safe path</returns>
810 public static string safePath(string path)
811 {
812 return Regex.Replace(path, regexInvalidPathChars, String.Empty);
813 }
814  
815 /// <summary>
816 /// Removes all invalid filename chars (OS dependent)
817 /// </summary>
818 /// <param name="path">filename</param>
819 /// <returns>safe filename</returns>
820 public static string safeFileName(string filename)
821 {
822 return Regex.Replace(filename, regexInvalidFileChars, String.Empty);
823 ;
824 }
825  
826 //
827 // directory locations
828 //
829  
830 public static string homeDir()
831 {
832 string temp;
833 // string personal=(Environment.GetFolderPath(Environment.SpecialFolder.Personal));
834 // temp = Path.Combine(personal,".OpenSim");
835 temp = ".";
836 return temp;
837 }
838  
839 public static string assetsDir()
840 {
841 return Path.Combine(configDir(), "assets");
842 }
843  
844 public static string inventoryDir()
845 {
846 return Path.Combine(configDir(), "inventory");
847 }
848  
849 public static string configDir()
850 {
851 return ".";
852 }
853  
854 public static string dataDir()
855 {
856 return ".";
857 }
858  
859 public static string logFile()
860 {
861 foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
862 {
863 if (appender is FileAppender)
864 {
865 return ((FileAppender)appender).File;
866 }
867 }
868  
869 return "./OpenSim.log";
870 }
871  
872 public static string logDir()
873 {
874 return Path.GetDirectoryName(logFile());
875 }
876  
877 // From: http://coercedcode.blogspot.com/2008/03/c-generate-unique-filenames-within.html
878 public static string GetUniqueFilename(string FileName)
879 {
880 int count = 0;
881 string Name;
882  
883 if (File.Exists(FileName))
884 {
885 FileInfo f = new FileInfo(FileName);
886  
887 if (!String.IsNullOrEmpty(f.Extension))
888 {
889 Name = f.FullName.Substring(0, f.FullName.LastIndexOf('.'));
890 }
891 else
892 {
893 Name = f.FullName;
894 }
895  
896 while (File.Exists(FileName))
897 {
898 count++;
899 FileName = Name + count + f.Extension;
900 }
901 }
902 return FileName;
903 }
904  
905 #region Nini (config) related Methods
906 public static IConfigSource ConvertDataRowToXMLConfig(DataRow row, string fileName)
907 {
908 if (!File.Exists(fileName))
909 {
910 //create new file
911 }
912 XmlConfigSource config = new XmlConfigSource(fileName);
913 AddDataRowToConfig(config, row);
914 config.Save();
915  
916 return config;
917 }
918  
919 public static void AddDataRowToConfig(IConfigSource config, DataRow row)
920 {
921 config.Configs.Add((string) row[0]);
922 for (int i = 0; i < row.Table.Columns.Count; i++)
923 {
924 config.Configs[(string) row[0]].Set(row.Table.Columns[i].ColumnName, row[i]);
925 }
926 }
927  
928 public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section)
929 {
930 // First, check the Startup section, the default section
931 IConfig cnf = config.Configs["Startup"];
932 if (cnf == null)
933 return string.Empty;
934 string val = cnf.GetString(varname, string.Empty);
935  
936 // Then check for an overwrite of the default in the given section
937 if (!string.IsNullOrEmpty(section))
938 {
939 cnf = config.Configs[section];
940 if (cnf != null)
941 val = cnf.GetString(varname, val);
942 }
943  
944 return val;
945 }
946  
947 /// <summary>
948 /// Gets the value of a configuration variable by looking into
949 /// multiple sections in order. The latter sections overwrite
950 /// any values previously found.
951 /// </summary>
952 /// <typeparam name="T">Type of the variable</typeparam>
953 /// <param name="config">The configuration object</param>
954 /// <param name="varname">The configuration variable</param>
955 /// <param name="sections">Ordered sequence of sections to look at</param>
956 /// <returns></returns>
957 public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections)
958 {
959 return GetConfigVarFromSections<T>(config, varname, sections, default(T));
960 }
961  
962 /// <summary>
963 /// Gets the value of a configuration variable by looking into
964 /// multiple sections in order. The latter sections overwrite
965 /// any values previously found.
966 /// </summary>
967 /// <remarks>
968 /// If no value is found then the given default value is returned
969 /// </remarks>
970 /// <typeparam name="T">Type of the variable</typeparam>
971 /// <param name="config">The configuration object</param>
972 /// <param name="varname">The configuration variable</param>
973 /// <param name="sections">Ordered sequence of sections to look at</param>
974 /// <param name="val">Default value</param>
975 /// <returns></returns>
976 public static T GetConfigVarFromSections<T>(IConfigSource config, string varname, string[] sections, object val)
977 {
978 foreach (string section in sections)
979 {
980 IConfig cnf = config.Configs[section];
981 if (cnf == null)
982 continue;
983  
984 if (typeof(T) == typeof(String))
985 val = cnf.GetString(varname, (string)val);
986 else if (typeof(T) == typeof(Boolean))
987 val = cnf.GetBoolean(varname, (bool)val);
988 else if (typeof(T) == typeof(Int32))
989 val = cnf.GetInt(varname, (int)val);
990 else if (typeof(T) == typeof(float))
991 val = cnf.GetFloat(varname, (int)val);
992 else
993 m_log.ErrorFormat("[UTIL]: Unhandled type {0}", typeof(T));
994 }
995  
996 return (T)val;
997 }
998  
999 #endregion
1000  
1001 public static float Clip(float x, float min, float max)
1002 {
1003 return Math.Min(Math.Max(x, min), max);
1004 }
1005  
1006 public static int Clip(int x, int min, int max)
1007 {
1008 return Math.Min(Math.Max(x, min), max);
1009 }
1010  
1011 public static Vector3 Clip(Vector3 vec, float min, float max)
1012 {
1013 return new Vector3(Clip(vec.X, min, max), Clip(vec.Y, min, max),
1014 Clip(vec.Z, min, max));
1015 }
1016  
1017 /// <summary>
1018 /// Convert an UUID to a raw uuid string. Right now this is a string without hyphens.
1019 /// </summary>
1020 /// <param name="UUID"></param>
1021 /// <returns></returns>
1022 public static String ToRawUuidString(UUID UUID)
1023 {
1024 return UUID.Guid.ToString("n");
1025 }
1026  
1027 public static string CleanString(string input)
1028 {
1029 if (input.Length == 0)
1030 return input;
1031  
1032 int clip = input.Length;
1033  
1034 // Test for ++ string terminator
1035 int pos = input.IndexOf("\0");
1036 if (pos != -1 && pos < clip)
1037 clip = pos;
1038  
1039 // Test for CR
1040 pos = input.IndexOf("\r");
1041 if (pos != -1 && pos < clip)
1042 clip = pos;
1043  
1044 // Test for LF
1045 pos = input.IndexOf("\n");
1046 if (pos != -1 && pos < clip)
1047 clip = pos;
1048  
1049 // Truncate string before first end-of-line character found
1050 return input.Substring(0, clip);
1051 }
1052  
1053 /// <summary>
1054 /// returns the contents of /etc/issue on Unix Systems
1055 /// Use this for where it's absolutely necessary to implement platform specific stuff
1056 /// </summary>
1057 /// <returns></returns>
1058 public static string ReadEtcIssue()
1059 {
1060 try
1061 {
1062 StreamReader sr = new StreamReader("/etc/issue.net");
1063 string issue = sr.ReadToEnd();
1064 sr.Close();
1065 return issue;
1066 }
1067 catch (Exception)
1068 {
1069 return "";
1070 }
1071 }
1072  
1073 public static void SerializeToFile(string filename, Object obj)
1074 {
1075 IFormatter formatter = new BinaryFormatter();
1076 Stream stream = null;
1077  
1078 try
1079 {
1080 stream = new FileStream(
1081 filename, FileMode.Create,
1082 FileAccess.Write, FileShare.None);
1083  
1084 formatter.Serialize(stream, obj);
1085 }
1086 catch (Exception e)
1087 {
1088 m_log.Error(e.ToString());
1089 }
1090 finally
1091 {
1092 if (stream != null)
1093 {
1094 stream.Close();
1095 }
1096 }
1097 }
1098  
1099 public static Object DeserializeFromFile(string filename)
1100 {
1101 IFormatter formatter = new BinaryFormatter();
1102 Stream stream = null;
1103 Object ret = null;
1104  
1105 try
1106 {
1107 stream = new FileStream(
1108 filename, FileMode.Open,
1109 FileAccess.Read, FileShare.None);
1110  
1111 ret = formatter.Deserialize(stream);
1112 }
1113 catch (Exception e)
1114 {
1115 m_log.Error(e.ToString());
1116 }
1117 finally
1118 {
1119 if (stream != null)
1120 {
1121 stream.Close();
1122 }
1123 }
1124  
1125 return ret;
1126 }
1127  
1128 public static string Compress(string text)
1129 {
1130 byte[] buffer = Util.UTF8.GetBytes(text);
1131 MemoryStream memory = new MemoryStream();
1132 using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true))
1133 {
1134 compressor.Write(buffer, 0, buffer.Length);
1135 }
1136  
1137 memory.Position = 0;
1138  
1139 byte[] compressed = new byte[memory.Length];
1140 memory.Read(compressed, 0, compressed.Length);
1141  
1142 byte[] compressedBuffer = new byte[compressed.Length + 4];
1143 Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length);
1144 Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4);
1145 return Convert.ToBase64String(compressedBuffer);
1146 }
1147  
1148 public static string Decompress(string compressedText)
1149 {
1150 byte[] compressedBuffer = Convert.FromBase64String(compressedText);
1151 using (MemoryStream memory = new MemoryStream())
1152 {
1153 int msgLength = BitConverter.ToInt32(compressedBuffer, 0);
1154 memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4);
1155  
1156 byte[] buffer = new byte[msgLength];
1157  
1158 memory.Position = 0;
1159 using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress))
1160 {
1161 decompressor.Read(buffer, 0, buffer.Length);
1162 }
1163  
1164 return Util.UTF8.GetString(buffer);
1165 }
1166 }
1167  
1168 /// <summary>
1169 /// Copy data from one stream to another, leaving the read position of both streams at the beginning.
1170 /// </summary>
1171 /// <param name='inputStream'>
1172 /// Input stream. Must be seekable.
1173 /// </param>
1174 /// <exception cref='ArgumentException'>
1175 /// Thrown if the input stream is not seekable.
1176 /// </exception>
1177 public static Stream Copy(Stream inputStream)
1178 {
1179 if (!inputStream.CanSeek)
1180 throw new ArgumentException("Util.Copy(Stream inputStream) must receive an inputStream that can seek");
1181  
1182 const int readSize = 256;
1183 byte[] buffer = new byte[readSize];
1184 MemoryStream ms = new MemoryStream();
1185  
1186 int count = inputStream.Read(buffer, 0, readSize);
1187  
1188 while (count > 0)
1189 {
1190 ms.Write(buffer, 0, count);
1191 count = inputStream.Read(buffer, 0, readSize);
1192 }
1193  
1194 ms.Position = 0;
1195 inputStream.Position = 0;
1196  
1197 return ms;
1198 }
1199  
1200 public static XmlRpcResponse XmlRpcCommand(string url, string methodName, params object[] args)
1201 {
1202 return SendXmlRpcCommand(url, methodName, args);
1203 }
1204  
1205 public static XmlRpcResponse SendXmlRpcCommand(string url, string methodName, object[] args)
1206 {
1207 XmlRpcRequest client = new XmlRpcRequest(methodName, args);
1208 return client.Send(url, 6000);
1209 }
1210  
1211 /// <summary>
1212 /// Returns an error message that the user could not be found in the database
1213 /// </summary>
1214 /// <returns>XML string consisting of a error element containing individual error(s)</returns>
1215 public static XmlRpcResponse CreateUnknownUserErrorResponse()
1216 {
1217 XmlRpcResponse response = new XmlRpcResponse();
1218 Hashtable responseData = new Hashtable();
1219 responseData["error_type"] = "unknown_user";
1220 responseData["error_desc"] = "The user requested is not in the database";
1221  
1222 response.Value = responseData;
1223 return response;
1224 }
1225  
1226 /// <summary>
1227 /// Converts a byte array in big endian order into an ulong.
1228 /// </summary>
1229 /// <param name="bytes">
1230 /// The array of bytes
1231 /// </param>
1232 /// <returns>
1233 /// The extracted ulong
1234 /// </returns>
1235 public static ulong BytesToUInt64Big(byte[] bytes)
1236 {
1237 if (bytes.Length < 8) return 0;
1238 return ((ulong)bytes[0] << 56) | ((ulong)bytes[1] << 48) | ((ulong)bytes[2] << 40) | ((ulong)bytes[3] << 32) |
1239 ((ulong)bytes[4] << 24) | ((ulong)bytes[5] << 16) | ((ulong)bytes[6] << 8) | (ulong)bytes[7];
1240 }
1241  
1242 // used for RemoteParcelRequest (for "About Landmark")
1243 public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y)
1244 {
1245 byte[] bytes =
1246 {
1247 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1248 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1249 (byte)x, (byte)(x >> 8), 0, 0,
1250 (byte)y, (byte)(y >> 8), 0, 0 };
1251 return new UUID(bytes, 0);
1252 }
1253  
1254 public static UUID BuildFakeParcelID(ulong regionHandle, uint x, uint y, uint z)
1255 {
1256 byte[] bytes =
1257 {
1258 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1259 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1260 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
1261 (byte)y, (byte)(y >> 8), 0, 0 };
1262 return new UUID(bytes, 0);
1263 }
1264  
1265 public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y)
1266 {
1267 byte[] bytes = parcelID.GetBytes();
1268 regionHandle = Utils.BytesToUInt64(bytes);
1269 x = Utils.BytesToUInt(bytes, 8) & 0xffff;
1270 y = Utils.BytesToUInt(bytes, 12) & 0xffff;
1271 }
1272  
1273 public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z)
1274 {
1275 byte[] bytes = parcelID.GetBytes();
1276 regionHandle = Utils.BytesToUInt64(bytes);
1277 x = Utils.BytesToUInt(bytes, 8) & 0xffff;
1278 z = (Utils.BytesToUInt(bytes, 8) & 0xffff0000) >> 16;
1279 y = Utils.BytesToUInt(bytes, 12) & 0xffff;
1280 }
1281  
1282 public static void FakeParcelIDToGlobalPosition(UUID parcelID, out uint x, out uint y)
1283 {
1284 ulong regionHandle;
1285 uint rx, ry;
1286  
1287 ParseFakeParcelID(parcelID, out regionHandle, out x, out y);
1288 Utils.LongToUInts(regionHandle, out rx, out ry);
1289  
1290 x += rx;
1291 y += ry;
1292 }
1293  
1294 /// <summary>
1295 /// Get operating system information if available. Returns only the first 45 characters of information
1296 /// </summary>
1297 /// <returns>
1298 /// Operating system information. Returns an empty string if none was available.
1299 /// </returns>
1300 public static string GetOperatingSystemInformation()
1301 {
1302 string os = String.Empty;
1303  
1304 if (Environment.OSVersion.Platform != PlatformID.Unix)
1305 {
1306 os = Environment.OSVersion.ToString();
1307 }
1308 else
1309 {
1310 os = ReadEtcIssue();
1311 }
1312  
1313 if (os.Length > 45)
1314 {
1315 os = os.Substring(0, 45);
1316 }
1317  
1318 return os;
1319 }
1320  
1321 public static string GetRuntimeInformation()
1322 {
1323 string ru = String.Empty;
1324  
1325 if (Environment.OSVersion.Platform == PlatformID.Unix)
1326 ru = "Unix/Mono";
1327 else
1328 if (Environment.OSVersion.Platform == PlatformID.MacOSX)
1329 ru = "OSX/Mono";
1330 else
1331 {
1332 if (IsPlatformMono)
1333 ru = "Win/Mono";
1334 else
1335 ru = "Win/.NET";
1336 }
1337  
1338 return ru;
1339 }
1340  
1341 /// <summary>
1342 /// Is the given string a UUID?
1343 /// </summary>
1344 /// <param name="s"></param>
1345 /// <returns></returns>
1346 public static bool isUUID(string s)
1347 {
1348 return UUIDPattern.IsMatch(s);
1349 }
1350  
1351 public static string GetDisplayConnectionString(string connectionString)
1352 {
1353 int passPosition = 0;
1354 int passEndPosition = 0;
1355 string displayConnectionString = null;
1356  
1357 // hide the password in the connection string
1358 passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase);
1359 passPosition = connectionString.IndexOf("=", passPosition);
1360 if (passPosition < connectionString.Length)
1361 passPosition += 1;
1362 passEndPosition = connectionString.IndexOf(";", passPosition);
1363  
1364 displayConnectionString = connectionString.Substring(0, passPosition);
1365 displayConnectionString += "***";
1366 displayConnectionString += connectionString.Substring(passEndPosition, connectionString.Length - passEndPosition);
1367  
1368 return displayConnectionString;
1369 }
1370  
1371 public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass)
1372 {
1373 Type settingsType = settingsClass.GetType();
1374  
1375 FieldInfo[] fieldInfos = settingsType.GetFields();
1376 foreach (FieldInfo fieldInfo in fieldInfos)
1377 {
1378 if (!fieldInfo.IsStatic)
1379 {
1380 if (fieldInfo.FieldType == typeof(System.String))
1381 {
1382 fieldInfo.SetValue(settingsClass, config.Get(fieldInfo.Name, (string)fieldInfo.GetValue(settingsClass)));
1383 }
1384 else if (fieldInfo.FieldType == typeof(System.Boolean))
1385 {
1386 fieldInfo.SetValue(settingsClass, config.GetBoolean(fieldInfo.Name, (bool)fieldInfo.GetValue(settingsClass)));
1387 }
1388 else if (fieldInfo.FieldType == typeof(System.Int32))
1389 {
1390 fieldInfo.SetValue(settingsClass, config.GetInt(fieldInfo.Name, (int)fieldInfo.GetValue(settingsClass)));
1391 }
1392 else if (fieldInfo.FieldType == typeof(System.Single))
1393 {
1394 fieldInfo.SetValue(settingsClass, config.GetFloat(fieldInfo.Name, (float)fieldInfo.GetValue(settingsClass)));
1395 }
1396 else if (fieldInfo.FieldType == typeof(System.UInt32))
1397 {
1398 fieldInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(fieldInfo.Name, ((uint)fieldInfo.GetValue(settingsClass)).ToString())));
1399 }
1400 }
1401 }
1402  
1403 PropertyInfo[] propertyInfos = settingsType.GetProperties();
1404 foreach (PropertyInfo propInfo in propertyInfos)
1405 {
1406 if ((propInfo.CanRead) && (propInfo.CanWrite))
1407 {
1408 if (propInfo.PropertyType == typeof(System.String))
1409 {
1410 propInfo.SetValue(settingsClass, config.Get(propInfo.Name, (string)propInfo.GetValue(settingsClass, null)), null);
1411 }
1412 else if (propInfo.PropertyType == typeof(System.Boolean))
1413 {
1414 propInfo.SetValue(settingsClass, config.GetBoolean(propInfo.Name, (bool)propInfo.GetValue(settingsClass, null)), null);
1415 }
1416 else if (propInfo.PropertyType == typeof(System.Int32))
1417 {
1418 propInfo.SetValue(settingsClass, config.GetInt(propInfo.Name, (int)propInfo.GetValue(settingsClass, null)), null);
1419 }
1420 else if (propInfo.PropertyType == typeof(System.Single))
1421 {
1422 propInfo.SetValue(settingsClass, config.GetFloat(propInfo.Name, (float)propInfo.GetValue(settingsClass, null)), null);
1423 }
1424 if (propInfo.PropertyType == typeof(System.UInt32))
1425 {
1426 propInfo.SetValue(settingsClass, Convert.ToUInt32(config.Get(propInfo.Name, ((uint)propInfo.GetValue(settingsClass, null)).ToString())), null);
1427 }
1428 }
1429 }
1430  
1431 return settingsClass;
1432 }
1433  
1434 public static string Base64ToString(string str)
1435 {
1436 Decoder utf8Decode = Encoding.UTF8.GetDecoder();
1437  
1438 byte[] todecode_byte = Convert.FromBase64String(str);
1439 int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
1440 char[] decoded_char = new char[charCount];
1441 utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
1442 string result = new String(decoded_char);
1443 return result;
1444 }
1445  
1446 public static Guid GetHashGuid(string data, string salt)
1447 {
1448 byte[] hash = ComputeMD5Hash(data + salt);
1449  
1450 //string s = BitConverter.ToString(hash);
1451  
1452 Guid guid = new Guid(hash);
1453  
1454 return guid;
1455 }
1456  
1457 public static byte ConvertMaturityToAccessLevel(uint maturity)
1458 {
1459 byte retVal = 0;
1460 switch (maturity)
1461 {
1462 case 0: //PG
1463 retVal = 13;
1464 break;
1465 case 1: //Mature
1466 retVal = 21;
1467 break;
1468 case 2: // Adult
1469 retVal = 42;
1470 break;
1471 }
1472  
1473 return retVal;
1474  
1475 }
1476  
1477 public static uint ConvertAccessLevelToMaturity(byte maturity)
1478 {
1479 if (maturity <= 13)
1480 return 0;
1481 else if (maturity <= 21)
1482 return 1;
1483 else
1484 return 2;
1485 }
1486  
1487 /// <summary>
1488 /// Produces an OSDMap from its string representation on a stream
1489 /// </summary>
1490 /// <param name="data">The stream</param>
1491 /// <param name="length">The size of the data on the stream</param>
1492 /// <returns>The OSDMap or an exception</returns>
1493 public static OSDMap GetOSDMap(Stream stream, int length)
1494 {
1495 byte[] data = new byte[length];
1496 stream.Read(data, 0, length);
1497 string strdata = Util.UTF8.GetString(data);
1498 OSDMap args = null;
1499 OSD buffer;
1500 buffer = OSDParser.DeserializeJson(strdata);
1501 if (buffer.Type == OSDType.Map)
1502 {
1503 args = (OSDMap)buffer;
1504 return args;
1505 }
1506 return null;
1507 }
1508  
1509 public static OSDMap GetOSDMap(string data)
1510 {
1511 OSDMap args = null;
1512 try
1513 {
1514 OSD buffer;
1515 // We should pay attention to the content-type, but let's assume we know it's Json
1516 buffer = OSDParser.DeserializeJson(data);
1517 if (buffer.Type == OSDType.Map)
1518 {
1519 args = (OSDMap)buffer;
1520 return args;
1521 }
1522 else
1523 {
1524 // uh?
1525 m_log.Debug(("[UTILS]: Got OSD of unexpected type " + buffer.Type.ToString()));
1526 return null;
1527 }
1528 }
1529 catch (Exception ex)
1530 {
1531 m_log.Debug("[UTILS]: exception on GetOSDMap " + ex.Message);
1532 return null;
1533 }
1534 }
1535  
1536 public static string[] Glob(string path)
1537 {
1538 string vol=String.Empty;
1539  
1540 if (Path.VolumeSeparatorChar != Path.DirectorySeparatorChar)
1541 {
1542 string[] vcomps = path.Split(new char[] {Path.VolumeSeparatorChar}, 2, StringSplitOptions.RemoveEmptyEntries);
1543  
1544 if (vcomps.Length > 1)
1545 {
1546 path = vcomps[1];
1547 vol = vcomps[0];
1548 }
1549 }
1550  
1551 string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
1552  
1553 // Glob
1554  
1555 path = vol;
1556 if (vol != String.Empty)
1557 path += new String(new char[] {Path.VolumeSeparatorChar, Path.DirectorySeparatorChar});
1558 else
1559 path = new String(new char[] {Path.DirectorySeparatorChar});
1560  
1561 List<string> paths = new List<string>();
1562 List<string> found = new List<string>();
1563 paths.Add(path);
1564  
1565 int compIndex = -1;
1566 foreach (string c in comps)
1567 {
1568 compIndex++;
1569  
1570 List<string> addpaths = new List<string>();
1571 foreach (string p in paths)
1572 {
1573 string[] dirs = Directory.GetDirectories(p, c);
1574  
1575 if (dirs.Length != 0)
1576 {
1577 foreach (string dir in dirs)
1578 addpaths.Add(Path.Combine(path, dir));
1579 }
1580  
1581 // Only add files if that is the last path component
1582 if (compIndex == comps.Length - 1)
1583 {
1584 string[] files = Directory.GetFiles(p, c);
1585 foreach (string f in files)
1586 found.Add(f);
1587 }
1588 }
1589 paths = addpaths;
1590 }
1591  
1592 return found.ToArray();
1593 }
1594  
1595 public static string ServerURI(string uri)
1596 {
1597 if (uri == string.Empty)
1598 return string.Empty;
1599  
1600 // Get rid of eventual slashes at the end
1601 uri = uri.TrimEnd('/');
1602  
1603 IPAddress ipaddr1 = null;
1604 string port1 = "";
1605 try
1606 {
1607 ipaddr1 = Util.GetHostFromURL(uri);
1608 }
1609 catch { }
1610  
1611 try
1612 {
1613 port1 = uri.Split(new char[] { ':' })[2];
1614 }
1615 catch { }
1616  
1617 // We tried our best to convert the domain names to IP addresses
1618 return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
1619 }
1620  
1621 /// <summary>
1622 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
1623 /// </summary>
1624 /// <param name="str">
1625 /// If null or empty, then an bytes[0] is returned.
1626 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1627 /// </param>
1628 /// <param name="args">
1629 /// Arguments to substitute into the string via the {} mechanism.
1630 /// </param>
1631 /// <returns></returns>
1632 public static byte[] StringToBytes256(string str, params object[] args)
1633 {
1634 return StringToBytes256(string.Format(str, args));
1635 }
1636  
1637 /// <summary>
1638 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
1639 /// </summary>
1640 /// <param name="str">
1641 /// If null or empty, then an bytes[0] is returned.
1642 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1643 /// </param>
1644 /// <returns></returns>
1645 public static byte[] StringToBytes256(string str)
1646 {
1647 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
1648 if (str.Length > 254) str = str.Remove(254);
1649 if (!str.EndsWith("\0")) { str += "\0"; }
1650  
1651 // Because this is UTF-8 encoding and not ASCII, it's possible we
1652 // might have gotten an oversized array even after the string trim
1653 byte[] data = UTF8.GetBytes(str);
1654 if (data.Length > 256)
1655 {
1656 Array.Resize<byte>(ref data, 256);
1657 data[255] = 0;
1658 }
1659  
1660 return data;
1661 }
1662  
1663 /// <summary>
1664 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary.
1665 /// </summary>
1666 /// <param name="str">
1667 /// If null or empty, then an bytes[0] is returned.
1668 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1669 /// </param>
1670 /// <param name="args">
1671 /// Arguments to substitute into the string via the {} mechanism.
1672 /// </param>
1673 /// <returns></returns>
1674 public static byte[] StringToBytes1024(string str, params object[] args)
1675 {
1676 return StringToBytes1024(string.Format(str, args));
1677 }
1678  
1679 /// <summary>
1680 /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 1024 bytes if necessary.
1681 /// </summary>
1682 /// <param name="str">
1683 /// If null or empty, then an bytes[0] is returned.
1684 /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
1685 /// </param>
1686 /// <returns></returns>
1687 public static byte[] StringToBytes1024(string str)
1688 {
1689 if (String.IsNullOrEmpty(str)) { return Utils.EmptyBytes; }
1690 if (str.Length > 1023) str = str.Remove(1023);
1691 if (!str.EndsWith("\0")) { str += "\0"; }
1692  
1693 // Because this is UTF-8 encoding and not ASCII, it's possible we
1694 // might have gotten an oversized array even after the string trim
1695 byte[] data = UTF8.GetBytes(str);
1696 if (data.Length > 1024)
1697 {
1698 Array.Resize<byte>(ref data, 1024);
1699 data[1023] = 0;
1700 }
1701  
1702 return data;
1703 }
1704  
1705 /// <summary>
1706 /// Used to trigger an early library load on Windows systems.
1707 /// </summary>
1708 /// <remarks>
1709 /// Required to get 32-bit and 64-bit processes to automatically use the
1710 /// appropriate native library.
1711 /// </remarks>
1712 /// <param name="dllToLoad"></param>
1713 /// <returns></returns>
1714 [DllImport("kernel32.dll")]
1715 public static extern IntPtr LoadLibrary(string dllToLoad);
1716  
1717 /// <summary>
1718 /// Determine whether the current process is 64 bit
1719 /// </summary>
1720 /// <returns>true if so, false if not</returns>
1721 public static bool Is64BitProcess()
1722 {
1723 return IntPtr.Size == 8;
1724 }
1725  
1726 #region FireAndForget Threading Pattern
1727  
1728 /// <summary>
1729 /// Created to work around a limitation in Mono with nested delegates
1730 /// </summary>
1731 private sealed class FireAndForgetWrapper
1732 {
1733 private static volatile FireAndForgetWrapper instance;
1734 private static object syncRoot = new Object();
1735  
1736 public static FireAndForgetWrapper Instance {
1737 get {
1738  
1739 if (instance == null)
1740 {
1741 lock (syncRoot)
1742 {
1743 if (instance == null)
1744 {
1745 instance = new FireAndForgetWrapper();
1746 }
1747 }
1748 }
1749  
1750 return instance;
1751 }
1752 }
1753  
1754 public void FireAndForget(System.Threading.WaitCallback callback)
1755 {
1756 callback.BeginInvoke(null, EndFireAndForget, callback);
1757 }
1758  
1759 public void FireAndForget(System.Threading.WaitCallback callback, object obj)
1760 {
1761 callback.BeginInvoke(obj, EndFireAndForget, callback);
1762 }
1763  
1764 private static void EndFireAndForget(IAsyncResult ar)
1765 {
1766 System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
1767  
1768 try { callback.EndInvoke(ar); }
1769 catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
1770  
1771 ar.AsyncWaitHandle.Close();
1772 }
1773 }
1774  
1775 public static void FireAndForget(System.Threading.WaitCallback callback)
1776 {
1777 FireAndForget(callback, null);
1778 }
1779  
1780 public static void InitThreadPool(int minThreads, int maxThreads)
1781 {
1782 if (maxThreads < 2)
1783 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
1784 if (minThreads > maxThreads || minThreads < 2)
1785 throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads");
1786 if (m_ThreadPool != null)
1787 throw new InvalidOperationException("SmartThreadPool is already initialized");
1788  
1789 STPStartInfo startInfo = new STPStartInfo();
1790 startInfo.ThreadPoolName = "Util";
1791 startInfo.IdleTimeout = 2000;
1792 startInfo.MaxWorkerThreads = maxThreads;
1793 startInfo.MinWorkerThreads = minThreads;
1794  
1795 m_ThreadPool = new SmartThreadPool(startInfo);
1796 }
1797  
1798 public static int FireAndForgetCount()
1799 {
1800 const int MAX_SYSTEM_THREADS = 200;
1801  
1802 switch (FireAndForgetMethod)
1803 {
1804 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
1805 case FireAndForgetMethod.QueueUserWorkItem:
1806 case FireAndForgetMethod.BeginInvoke:
1807 int workerThreads, iocpThreads;
1808 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
1809 return workerThreads;
1810 case FireAndForgetMethod.SmartThreadPool:
1811 return m_ThreadPool.MaxThreads - m_ThreadPool.InUseThreads;
1812 case FireAndForgetMethod.Thread:
1813 return MAX_SYSTEM_THREADS - System.Diagnostics.Process.GetCurrentProcess().Threads.Count;
1814 default:
1815 throw new NotImplementedException();
1816 }
1817 }
1818  
1819 public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
1820 {
1821 WaitCallback realCallback;
1822  
1823 if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
1824 {
1825 // If we're running regression tests, then we want any exceptions to rise up to the test code.
1826 realCallback = o => { Culture.SetCurrentCulture(); callback(o); };
1827 }
1828 else
1829 {
1830 // When OpenSim interacts with a database or sends data over the wire, it must send this in en_US culture
1831 // so that we don't encounter problems where, for instance, data is saved with a culture that uses commas
1832 // for decimals places but is read by a culture that treats commas as number seperators.
1833 realCallback = o =>
1834 {
1835 Culture.SetCurrentCulture();
1836  
1837 try
1838 {
1839 callback(o);
1840 }
1841 catch (Exception e)
1842 {
1843 m_log.ErrorFormat(
1844 "[UTIL]: Continuing after async_call_method thread terminated with exception {0}{1}",
1845 e.Message, e.StackTrace);
1846 }
1847 };
1848 }
1849  
1850 switch (FireAndForgetMethod)
1851 {
1852 case FireAndForgetMethod.RegressionTest:
1853 case FireAndForgetMethod.None:
1854 realCallback.Invoke(obj);
1855 break;
1856 case FireAndForgetMethod.UnsafeQueueUserWorkItem:
1857 ThreadPool.UnsafeQueueUserWorkItem(realCallback, obj);
1858 break;
1859 case FireAndForgetMethod.QueueUserWorkItem:
1860 ThreadPool.QueueUserWorkItem(realCallback, obj);
1861 break;
1862 case FireAndForgetMethod.BeginInvoke:
1863 FireAndForgetWrapper wrapper = FireAndForgetWrapper.Instance;
1864 wrapper.FireAndForget(realCallback, obj);
1865 break;
1866 case FireAndForgetMethod.SmartThreadPool:
1867 if (m_ThreadPool == null)
1868 InitThreadPool(2, 15);
1869 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
1870 break;
1871 case FireAndForgetMethod.Thread:
1872 Thread thread = new Thread(delegate(object o) { realCallback(o); });
1873 thread.Start(obj);
1874 break;
1875 default:
1876 throw new NotImplementedException();
1877 }
1878 }
1879  
1880 /// <summary>
1881 /// Get information about the current state of the smart thread pool.
1882 /// </summary>
1883 /// <returns>
1884 /// null if this isn't the pool being used for non-scriptengine threads.
1885 /// </returns>
1886 public static STPInfo GetSmartThreadPoolInfo()
1887 {
1888 if (m_ThreadPool == null)
1889 return null;
1890  
1891 STPInfo stpi = new STPInfo();
1892 stpi.Name = m_ThreadPool.Name;
1893 stpi.STPStartInfo = m_ThreadPool.STPStartInfo;
1894 stpi.IsIdle = m_ThreadPool.IsIdle;
1895 stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown;
1896 stpi.MaxThreads = m_ThreadPool.MaxThreads;
1897 stpi.MinThreads = m_ThreadPool.MinThreads;
1898 stpi.InUseThreads = m_ThreadPool.InUseThreads;
1899 stpi.ActiveThreads = m_ThreadPool.ActiveThreads;
1900 stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks;
1901 stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency;
1902  
1903 return stpi;
1904 }
1905  
1906 #endregion FireAndForget Threading Pattern
1907  
1908 /// <summary>
1909 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive
1910 /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap
1911 /// for the callers.
1912 /// This trims it to a 12 day interval so don't let your frame time get too long.
1913 /// </summary>
1914 /// <returns></returns>
1915 public static Int32 EnvironmentTickCount()
1916 {
1917 return Environment.TickCount & EnvironmentTickCountMask;
1918 }
1919 const Int32 EnvironmentTickCountMask = 0x3fffffff;
1920  
1921 /// <summary>
1922 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive
1923 /// and negative every 24.9 days. Subtracts the passed value (previously fetched by
1924 /// 'EnvironmentTickCount()') and accounts for any wrapping.
1925 /// </summary>
1926 /// <param name="newValue"></param>
1927 /// <param name="prevValue"></param>
1928 /// <returns>subtraction of passed prevValue from current Environment.TickCount</returns>
1929 public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue)
1930 {
1931 Int32 diff = newValue - prevValue;
1932 return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
1933 }
1934  
1935 /// <summary>
1936 /// Environment.TickCount is an int but it counts all 32 bits so it goes positive
1937 /// and negative every 24.9 days. Subtracts the passed value (previously fetched by
1938 /// 'EnvironmentTickCount()') and accounts for any wrapping.
1939 /// </summary>
1940 /// <returns>subtraction of passed prevValue from current Environment.TickCount</returns>
1941 public static Int32 EnvironmentTickCountSubtract(Int32 prevValue)
1942 {
1943 return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue);
1944 }
1945  
1946 // Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount
1947 // Assumes both tcA and tcB came from previous calls to Util.EnvironmentTickCount().
1948 // A positive return value indicates A occured later than B
1949 public static Int32 EnvironmentTickCountCompare(Int32 tcA, Int32 tcB)
1950 {
1951 // A, B and TC are all between 0 and 0x3fffffff
1952 int tc = EnvironmentTickCount();
1953  
1954 if (tc - tcA >= 0)
1955 tcA += EnvironmentTickCountMask + 1;
1956  
1957 if (tc - tcB >= 0)
1958 tcB += EnvironmentTickCountMask + 1;
1959  
1960 return tcA - tcB;
1961 }
1962  
1963 /// <summary>
1964 /// Prints the call stack at any given point. Useful for debugging.
1965 /// </summary>
1966 public static void PrintCallStack()
1967 {
1968 PrintCallStack(m_log.DebugFormat);
1969 }
1970  
1971 public delegate void DebugPrinter(string msg, params Object[] parm);
1972 public static void PrintCallStack(DebugPrinter printer)
1973 {
1974 StackTrace stackTrace = new StackTrace(true); // get call stack
1975 StackFrame[] stackFrames = stackTrace.GetFrames(); // get method calls (frames)
1976  
1977 // write call stack method names
1978 foreach (StackFrame stackFrame in stackFrames)
1979 {
1980 MethodBase mb = stackFrame.GetMethod();
1981 printer("{0}.{1}:{2}", mb.DeclaringType, mb.Name, stackFrame.GetFileLineNumber()); // write method name
1982 }
1983 }
1984  
1985 /// <summary>
1986 /// Gets the client IP address
1987 /// </summary>
1988 /// <param name="xff"></param>
1989 /// <returns></returns>
1990 public static IPEndPoint GetClientIPFromXFF(string xff)
1991 {
1992 if (xff == string.Empty)
1993 return null;
1994  
1995 string[] parts = xff.Split(new char[] { ',' });
1996 if (parts.Length > 0)
1997 {
1998 try
1999 {
2000 return new IPEndPoint(IPAddress.Parse(parts[0]), 0);
2001 }
2002 catch (Exception e)
2003 {
2004 m_log.WarnFormat("[UTIL]: Exception parsing XFF header {0}: {1}", xff, e.Message);
2005 }
2006 }
2007  
2008 return null;
2009 }
2010  
2011 public static string GetCallerIP(Hashtable req)
2012 {
2013 if (req.ContainsKey("headers"))
2014 {
2015 try
2016 {
2017 Hashtable headers = (Hashtable)req["headers"];
2018 if (headers.ContainsKey("remote_addr") && headers["remote_addr"] != null)
2019 return headers["remote_addr"].ToString();
2020 }
2021 catch (Exception e)
2022 {
2023 m_log.WarnFormat("[UTIL]: exception in GetCallerIP: {0}", e.Message);
2024 }
2025 }
2026 return string.Empty;
2027 }
2028  
2029 #region Xml Serialization Utilities
2030 public static bool ReadBoolean(XmlTextReader reader)
2031 {
2032 reader.ReadStartElement();
2033 bool result = Boolean.Parse(reader.ReadContentAsString().ToLower());
2034 reader.ReadEndElement();
2035  
2036 return result;
2037 }
2038  
2039 public static UUID ReadUUID(XmlTextReader reader, string name)
2040 {
2041 UUID id;
2042 string idStr;
2043  
2044 reader.ReadStartElement(name);
2045  
2046 if (reader.Name == "Guid")
2047 idStr = reader.ReadElementString("Guid");
2048 else if (reader.Name == "UUID")
2049 idStr = reader.ReadElementString("UUID");
2050 else // no leading tag
2051 idStr = reader.ReadContentAsString();
2052 UUID.TryParse(idStr, out id);
2053 reader.ReadEndElement();
2054  
2055 return id;
2056 }
2057  
2058 public static Vector3 ReadVector(XmlTextReader reader, string name)
2059 {
2060 Vector3 vec;
2061  
2062 reader.ReadStartElement(name);
2063 vec.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // X or x
2064 vec.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Y or y
2065 vec.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty); // Z or z
2066 reader.ReadEndElement();
2067  
2068 return vec;
2069 }
2070  
2071 public static Quaternion ReadQuaternion(XmlTextReader reader, string name)
2072 {
2073 Quaternion quat = new Quaternion();
2074  
2075 reader.ReadStartElement(name);
2076 while (reader.NodeType != XmlNodeType.EndElement)
2077 {
2078 switch (reader.Name.ToLower())
2079 {
2080 case "x":
2081 quat.X = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2082 break;
2083 case "y":
2084 quat.Y = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2085 break;
2086 case "z":
2087 quat.Z = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2088 break;
2089 case "w":
2090 quat.W = reader.ReadElementContentAsFloat(reader.Name, String.Empty);
2091 break;
2092 }
2093 }
2094  
2095 reader.ReadEndElement();
2096  
2097 return quat;
2098 }
2099  
2100 public static T ReadEnum<T>(XmlTextReader reader, string name)
2101 {
2102 string value = reader.ReadElementContentAsString(name, String.Empty);
2103 // !!!!! to deal with flags without commas
2104 if (value.Contains(" ") && !value.Contains(","))
2105 value = value.Replace(" ", ", ");
2106  
2107 return (T)Enum.Parse(typeof(T), value); ;
2108 }
2109 #endregion
2110  
2111 #region Universal User Identifiers
2112 /// <summary>
2113 /// </summary>
2114 /// <param name="value">uuid[;endpoint[;first last[;secret]]]</param>
2115 /// <param name="uuid">the uuid part</param>
2116 /// <param name="url">the endpoint part (e.g. http://foo.com)</param>
2117 /// <param name="firstname">the first name part (e.g. Test)</param>
2118 /// <param name="lastname">the last name part (e.g User)</param>
2119 /// <param name="secret">the secret part</param>
2120 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret)
2121 {
2122 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty;
2123  
2124 string[] parts = value.Split(';');
2125 if (parts.Length >= 1)
2126 if (!UUID.TryParse(parts[0], out uuid))
2127 return false;
2128  
2129 if (parts.Length >= 2)
2130 url = parts[1];
2131  
2132 if (parts.Length >= 3)
2133 {
2134 string[] name = parts[2].Split();
2135 if (name.Length == 2)
2136 {
2137 firstname = name[0];
2138 lastname = name[1];
2139 }
2140 }
2141 if (parts.Length >= 4)
2142 secret = parts[3];
2143  
2144 return true;
2145 }
2146  
2147 /// <summary>
2148 /// Produces a universal (HG) system-facing identifier given the information
2149 /// </summary>
2150 /// <param name="acircuit"></param>
2151 /// <returns>uuid[;homeURI[;first last]]</returns>
2152 public static string ProduceUserUniversalIdentifier(AgentCircuitData acircuit)
2153 {
2154 if (acircuit.ServiceURLs.ContainsKey("HomeURI"))
2155 return UniversalIdentifier(acircuit.AgentID, acircuit.firstname, acircuit.lastname, acircuit.ServiceURLs["HomeURI"].ToString());
2156 else
2157 return acircuit.AgentID.ToString();
2158 }
2159  
2160 /// <summary>
2161 /// Produces a universal (HG) system-facing identifier given the information
2162 /// </summary>
2163 /// <param name="id">UUID of the user</param>
2164 /// <param name="firstName">first name (e.g Test)</param>
2165 /// <param name="lastName">last name (e.g. User)</param>
2166 /// <param name="homeURI">homeURI (e.g. http://foo.com)</param>
2167 /// <returns>a string of the form uuid[;homeURI[;first last]]</returns>
2168 public static string UniversalIdentifier(UUID id, String firstName, String lastName, String homeURI)
2169 {
2170 string agentsURI = homeURI;
2171 if (!agentsURI.EndsWith("/"))
2172 agentsURI += "/";
2173  
2174 // This is ugly, but there's no other way, given that the name is changed
2175 // in the agent circuit data for foreigners
2176 if (lastName.Contains("@"))
2177 {
2178 string[] parts = firstName.Split(new char[] { '.' });
2179 if (parts.Length == 2)
2180 return id.ToString() + ";" + agentsURI + ";" + parts[0] + " " + parts[1];
2181 }
2182 return id.ToString() + ";" + agentsURI + ";" + firstName + " " + lastName;
2183  
2184 }
2185  
2186 /// <summary>
2187 /// Produces a universal (HG) user-facing name given the information
2188 /// </summary>
2189 /// <param name="firstName"></param>
2190 /// <param name="lastName"></param>
2191 /// <param name="homeURI"></param>
2192 /// <returns>string of the form first.last @foo.com or first last</returns>
2193 public static string UniversalName(String firstName, String lastName, String homeURI)
2194 {
2195 Uri uri = null;
2196 try
2197 {
2198 uri = new Uri(homeURI);
2199 }
2200 catch (UriFormatException)
2201 {
2202 return firstName + " " + lastName;
2203 }
2204 return firstName + "." + lastName + " " + "@" + uri.Authority;
2205 }
2206 #endregion
2207  
2208 /// <summary>
2209 /// Escapes the special characters used in "LIKE".
2210 /// </summary>
2211 /// <remarks>
2212 /// For example: EscapeForLike("foo_bar%baz") = "foo\_bar\%baz"
2213 /// </remarks>
2214 public static string EscapeForLike(string str)
2215 {
2216 return str.Replace("_", "\\_").Replace("%", "\\%");
2217 }
2218 }
2219  
2220 public class DoubleQueue<T> where T:class
2221 {
2222 private Queue<T> m_lowQueue = new Queue<T>();
2223 private Queue<T> m_highQueue = new Queue<T>();
2224  
2225 private object m_syncRoot = new object();
2226 private Semaphore m_s = new Semaphore(0, 1);
2227  
2228 public DoubleQueue()
2229 {
2230 }
2231  
2232 public virtual int Count
2233 {
2234 get { return m_highQueue.Count + m_lowQueue.Count; }
2235 }
2236  
2237 public virtual void Enqueue(T data)
2238 {
2239 Enqueue(m_lowQueue, data);
2240 }
2241  
2242 public virtual void EnqueueLow(T data)
2243 {
2244 Enqueue(m_lowQueue, data);
2245 }
2246  
2247 public virtual void EnqueueHigh(T data)
2248 {
2249 Enqueue(m_highQueue, data);
2250 }
2251  
2252 private void Enqueue(Queue<T> q, T data)
2253 {
2254 lock (m_syncRoot)
2255 {
2256 q.Enqueue(data);
2257 m_s.WaitOne(0);
2258 m_s.Release();
2259 }
2260 }
2261  
2262 public virtual T Dequeue()
2263 {
2264 return Dequeue(Timeout.Infinite);
2265 }
2266  
2267 public virtual T Dequeue(int tmo)
2268 {
2269 return Dequeue(TimeSpan.FromMilliseconds(tmo));
2270 }
2271  
2272 public virtual T Dequeue(TimeSpan wait)
2273 {
2274 T res = null;
2275  
2276 if (!Dequeue(wait, ref res))
2277 return null;
2278  
2279 return res;
2280 }
2281  
2282 public bool Dequeue(int timeout, ref T res)
2283 {
2284 return Dequeue(TimeSpan.FromMilliseconds(timeout), ref res);
2285 }
2286  
2287 public bool Dequeue(TimeSpan wait, ref T res)
2288 {
2289 if (!m_s.WaitOne(wait))
2290 return false;
2291  
2292 lock (m_syncRoot)
2293 {
2294 if (m_highQueue.Count > 0)
2295 res = m_highQueue.Dequeue();
2296 else if (m_lowQueue.Count > 0)
2297 res = m_lowQueue.Dequeue();
2298  
2299 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
2300 return true;
2301  
2302 try
2303 {
2304 m_s.Release();
2305 }
2306 catch
2307 {
2308 }
2309  
2310 return true;
2311 }
2312 }
2313  
2314 public virtual void Clear()
2315 {
2316  
2317 lock (m_syncRoot)
2318 {
2319 // Make sure sem count is 0
2320 m_s.WaitOne(0);
2321  
2322 m_lowQueue.Clear();
2323 m_highQueue.Clear();
2324 }
2325 }
2326 }
2327 }