diff options
Diffstat (limited to 'OpenSim/Framework/Util.cs')
-rw-r--r-- | OpenSim/Framework/Util.cs | 735 |
1 files changed, 604 insertions, 131 deletions
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index b5c3e75..7093010 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs | |||
@@ -59,17 +59,41 @@ namespace OpenSim.Framework | |||
59 | { | 59 | { |
60 | [Flags] | 60 | [Flags] |
61 | public enum PermissionMask : uint | 61 | public enum PermissionMask : uint |
62 | { | 62 | { |
63 | None = 0, | 63 | None = 0, |
64 | Transfer = 1 << 13, | 64 | |
65 | Modify = 1 << 14, | 65 | // folded perms |
66 | Copy = 1 << 15, | 66 | FoldedTransfer = 1, |
67 | Export = 1 << 16, | 67 | FoldedModify = 1 << 1, |
68 | Move = 1 << 19, | 68 | FoldedCopy = 1 << 2, |
69 | Damage = 1 << 20, | 69 | FoldedExport = 1 << 3, |
70 | |||
71 | // DO NOT USE THIS FOR NEW WORK. IT IS DEPRECATED AND | ||
72 | // EXISTS ONLY TO REACT TO EXISTING OBJECTS HAVING IT. | ||
73 | // NEW CODE SHOULD NEVER SET THIS BIT! | ||
74 | // Use InventoryItemFlags.ObjectSlamPerm in the Flags field of | ||
75 | // this legacy slam bit. It comes from prior incomplete | ||
76 | // understanding of the code and the prohibition on | ||
77 | // reading viewer code that used to be in place. | ||
78 | Slam = (1 << 4), | ||
79 | |||
80 | FoldedMask = 0x0f, | ||
81 | |||
82 | FoldingShift = 13 , // number of bit shifts from normal perm to folded or back (same as Transfer shift below) | ||
83 | // when doing as a block | ||
84 | |||
85 | Transfer = 1 << 13, // 0x02000 | ||
86 | Modify = 1 << 14, // 0x04000 | ||
87 | Copy = 1 << 15, // 0x08000 | ||
88 | Export = 1 << 16, // 0x10000 | ||
89 | Move = 1 << 19, // 0x80000 | ||
90 | Damage = 1 << 20, // 0x100000 does not seem to be in use | ||
70 | // All does not contain Export, which is special and must be | 91 | // All does not contain Export, which is special and must be |
71 | // explicitly given | 92 | // explicitly given |
72 | All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19) | 93 | All = 0x8e000, |
94 | AllAndExport = 0x9e000, | ||
95 | AllEffective = 0x9e000, | ||
96 | UnfoldedMask = 0x1e000 | ||
73 | } | 97 | } |
74 | 98 | ||
75 | /// <summary> | 99 | /// <summary> |
@@ -103,7 +127,7 @@ namespace OpenSim.Framework | |||
103 | public STPStartInfo STPStartInfo { get; set; } | 127 | public STPStartInfo STPStartInfo { get; set; } |
104 | public WIGStartInfo WIGStartInfo { get; set; } | 128 | public WIGStartInfo WIGStartInfo { get; set; } |
105 | public bool IsIdle { get; set; } | 129 | public bool IsIdle { get; set; } |
106 | public bool IsShuttingDown { get; set; } | 130 | public bool IsShuttingDown { get; set; } |
107 | public int MaxThreads { get; set; } | 131 | public int MaxThreads { get; set; } |
108 | public int MinThreads { get; set; } | 132 | public int MinThreads { get; set; } |
109 | public int InUseThreads { get; set; } | 133 | public int InUseThreads { get; set; } |
@@ -131,10 +155,16 @@ namespace OpenSim.Framework | |||
131 | 155 | ||
132 | public static readonly int MAX_THREADPOOL_LEVEL = 3; | 156 | public static readonly int MAX_THREADPOOL_LEVEL = 3; |
133 | 157 | ||
158 | public static double TimeStampClockPeriodMS; | ||
159 | public static double TimeStampClockPeriod; | ||
160 | |||
134 | static Util() | 161 | static Util() |
135 | { | 162 | { |
136 | LogThreadPool = 0; | 163 | LogThreadPool = 0; |
137 | LogOverloads = true; | 164 | LogOverloads = true; |
165 | TimeStampClockPeriod = 1.0D/ (double)Stopwatch.Frequency; | ||
166 | TimeStampClockPeriodMS = 1e3 * TimeStampClockPeriod; | ||
167 | m_log.InfoFormat("[UTIL] TimeStamp clock with period of {0}ms", Math.Round(TimeStampClockPeriodMS,6,MidpointRounding.AwayFromZero)); | ||
138 | } | 168 | } |
139 | 169 | ||
140 | private static uint nextXferID = 5000; | 170 | private static uint nextXferID = 5000; |
@@ -217,7 +247,7 @@ namespace OpenSim.Framework | |||
217 | public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false); | 247 | public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false); |
218 | 248 | ||
219 | /// <value> | 249 | /// <value> |
220 | /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) | 250 | /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards) |
221 | /// </value> | 251 | /// </value> |
222 | public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); | 252 | public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f"); |
223 | 253 | ||
@@ -267,14 +297,12 @@ namespace OpenSim.Framework | |||
267 | /// </summary> | 297 | /// </summary> |
268 | /// <param name="a">A 3d vector</param> | 298 | /// <param name="a">A 3d vector</param> |
269 | /// <returns>A new vector which is normalized form of the vector</returns> | 299 | /// <returns>A new vector which is normalized form of the vector</returns> |
270 | /// <remarks>The vector paramater cannot be <0,0,0></remarks> | 300 | |
271 | public static Vector3 GetNormalizedVector(Vector3 a) | 301 | public static Vector3 GetNormalizedVector(Vector3 a) |
272 | { | 302 | { |
273 | if (IsZeroVector(a)) | 303 | Vector3 v = new Vector3(a.X, a.Y, a.Z); |
274 | throw new ArgumentException("Vector paramater cannot be a zero vector."); | 304 | v.Normalize(); |
275 | 305 | return v; | |
276 | float Mag = (float) GetMagnitude(a); | ||
277 | return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag); | ||
278 | } | 306 | } |
279 | 307 | ||
280 | /// <summary> | 308 | /// <summary> |
@@ -357,47 +385,185 @@ namespace OpenSim.Framework | |||
357 | return Utils.UIntsToLong(X, Y); | 385 | return Utils.UIntsToLong(X, Y); |
358 | } | 386 | } |
359 | 387 | ||
360 | // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong. | 388 | // Regions are identified with a 'handle' made up of its world coordinates packed into a ulong. |
361 | // Several places rely on the ability to extract a region's location from its handle. | 389 | // Region handles are based on the coordinate of the region corner with lower X and Y |
362 | // Note the location is in 'world coordinates' (see below). | 390 | // var regions need more work than this to get that right corner from a generic world position |
363 | // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0. | 391 | // this corner must be on a grid point |
364 | public static ulong RegionWorldLocToHandle(uint X, uint Y) | 392 | public static ulong RegionWorldLocToHandle(uint X, uint Y) |
365 | { | 393 | { |
366 | return Utils.UIntsToLong(X, Y); | 394 | ulong handle = X & 0xffffff00; // make sure it matchs grid coord points. |
395 | handle <<= 32; // to higher half | ||
396 | handle |= (Y & 0xffffff00); | ||
397 | return handle; | ||
367 | } | 398 | } |
368 | 399 | ||
369 | public static ulong RegionLocToHandle(uint X, uint Y) | 400 | public static ulong RegionGridLocToHandle(uint X, uint Y) |
370 | { | 401 | { |
371 | return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y)); | 402 | ulong handle = X; |
403 | handle <<= 40; // shift to higher half and mult by 256) | ||
404 | handle |= (Y << 8); // mult by 256) | ||
405 | return handle; | ||
372 | } | 406 | } |
373 | 407 | ||
374 | public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) | 408 | public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y) |
375 | { | 409 | { |
376 | X = (uint)(handle >> 32); | 410 | X = (uint)(handle >> 32); |
377 | Y = (uint)(handle & (ulong)uint.MaxValue); | 411 | Y = (uint)(handle & 0xfffffffful); |
378 | } | 412 | } |
379 | 413 | ||
380 | public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) | 414 | public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y) |
381 | { | 415 | { |
382 | uint worldX, worldY; | 416 | X = (uint)(handle >> 40) & 0x00ffffffu; // bring from higher half, divide by 256 and clean |
383 | RegionHandleToWorldLoc(handle, out worldX, out worldY); | 417 | Y = (uint)(handle >> 8) & 0x00ffffffu; // divide by 256 and clean |
384 | X = WorldToRegionLoc(worldX); | 418 | // if you trust the uint cast then the clean can be removed. |
385 | Y = WorldToRegionLoc(worldY); | ||
386 | } | 419 | } |
387 | 420 | ||
388 | // A region location can be 'world coordinates' (meters from zero) or 'region coordinates' | 421 | // A region location can be 'world coordinates' (meters) or 'region grid coordinates' |
389 | // (number of regions from zero). This measurement of regions relies on the legacy 256 region size. | 422 | // grid coordinates have a fixed step of 256m as defined by viewers |
390 | // These routines exist to make what is being converted explicit so the next person knows what was meant. | ||
391 | // Convert a region's 'world coordinate' to its 'region coordinate'. | ||
392 | public static uint WorldToRegionLoc(uint worldCoord) | 423 | public static uint WorldToRegionLoc(uint worldCoord) |
393 | { | 424 | { |
394 | return worldCoord / Constants.RegionSize; | 425 | return worldCoord >> 8; |
395 | } | 426 | } |
396 | 427 | ||
397 | // Convert a region's 'region coordinate' to its 'world coordinate'. | 428 | // Convert a region's 'region grid coordinate' to its 'world coordinate'. |
398 | public static uint RegionToWorldLoc(uint regionCoord) | 429 | public static uint RegionToWorldLoc(uint regionCoord) |
399 | { | 430 | { |
400 | return regionCoord * Constants.RegionSize; | 431 | return regionCoord << 8; |
432 | } | ||
433 | |||
434 | |||
435 | public static bool checkServiceURI(string uristr, out string serviceURI) | ||
436 | { | ||
437 | serviceURI = string.Empty; | ||
438 | try | ||
439 | { | ||
440 | Uri uri = new Uri(uristr); | ||
441 | serviceURI = uri.AbsoluteUri; | ||
442 | if(uri.Port == 80) | ||
443 | serviceURI = serviceURI.Trim(new char[] { '/', ' ' }) +":80/"; | ||
444 | else if(uri.Port == 443) | ||
445 | serviceURI = serviceURI.Trim(new char[] { '/', ' ' }) +":443/"; | ||
446 | return true; | ||
447 | } | ||
448 | catch | ||
449 | { | ||
450 | serviceURI = string.Empty; | ||
451 | } | ||
452 | return false; | ||
453 | } | ||
454 | |||
455 | public static bool buildHGRegionURI(string inputName, out string serverURI, out string regionName) | ||
456 | { | ||
457 | serverURI = string.Empty; | ||
458 | regionName = string.Empty; | ||
459 | |||
460 | inputName = inputName.Trim(); | ||
461 | |||
462 | if (!inputName.StartsWith("http") && !inputName.StartsWith("https")) | ||
463 | { | ||
464 | // Formats: grid.example.com:8002:region name | ||
465 | // grid.example.com:region name | ||
466 | // grid.example.com:8002 | ||
467 | // grid.example.com | ||
468 | |||
469 | string host; | ||
470 | uint port = 80; | ||
471 | |||
472 | string[] parts = inputName.Split(new char[] { ':' }); | ||
473 | int indx; | ||
474 | if(parts.Length == 0) | ||
475 | return false; | ||
476 | if (parts.Length == 1) | ||
477 | { | ||
478 | indx = inputName.IndexOf('/'); | ||
479 | if (indx < 0) | ||
480 | serverURI = "http://"+ inputName + "/"; | ||
481 | else | ||
482 | { | ||
483 | serverURI = "http://"+ inputName.Substring(0,indx + 1); | ||
484 | if(indx + 2 < inputName.Length) | ||
485 | regionName = inputName.Substring(indx + 1); | ||
486 | } | ||
487 | } | ||
488 | else | ||
489 | { | ||
490 | host = parts[0]; | ||
491 | |||
492 | if (parts.Length >= 2) | ||
493 | { | ||
494 | indx = parts[1].IndexOf('/'); | ||
495 | if(indx < 0) | ||
496 | { | ||
497 | // If it's a number then assume it's a port. Otherwise, it's a region name. | ||
498 | if (!UInt32.TryParse(parts[1], out port)) | ||
499 | { | ||
500 | port = 80; | ||
501 | regionName = parts[1]; | ||
502 | } | ||
503 | } | ||
504 | else | ||
505 | { | ||
506 | string portstr = parts[1].Substring(0, indx); | ||
507 | if(indx + 2 < parts[1].Length) | ||
508 | regionName = parts[1].Substring(indx + 1); | ||
509 | if (!UInt32.TryParse(portstr, out port)) | ||
510 | port = 80; | ||
511 | } | ||
512 | } | ||
513 | // always take the last one | ||
514 | if (parts.Length >= 3) | ||
515 | { | ||
516 | regionName = parts[2]; | ||
517 | } | ||
518 | |||
519 | serverURI = "http://"+ host +":"+ port.ToString() + "/"; | ||
520 | } | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | // Formats: http://grid.example.com region name | ||
525 | // http://grid.example.com "region name" | ||
526 | // http://grid.example.com | ||
527 | |||
528 | string[] parts = inputName.Split(new char[] { ' ' }); | ||
529 | |||
530 | if (parts.Length == 0) | ||
531 | return false; | ||
532 | |||
533 | serverURI = parts[0]; | ||
534 | |||
535 | int indx = serverURI.LastIndexOf('/'); | ||
536 | if(indx > 10) | ||
537 | { | ||
538 | if(indx + 2 < inputName.Length) | ||
539 | regionName = inputName.Substring(indx + 1); | ||
540 | serverURI = inputName.Substring(0, indx + 1); | ||
541 | } | ||
542 | else if (parts.Length >= 2) | ||
543 | { | ||
544 | regionName = inputName.Substring(serverURI.Length); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | // use better code for sanity check | ||
549 | Uri uri; | ||
550 | try | ||
551 | { | ||
552 | uri = new Uri(serverURI); | ||
553 | } | ||
554 | catch | ||
555 | { | ||
556 | return false; | ||
557 | } | ||
558 | |||
559 | if(!string.IsNullOrEmpty(regionName)) | ||
560 | regionName = regionName.Trim(new char[] { '"', ' ' }); | ||
561 | serverURI = uri.AbsoluteUri; | ||
562 | if(uri.Port == 80) | ||
563 | serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":80/"; | ||
564 | else if(uri.Port == 443) | ||
565 | serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":443/"; | ||
566 | return true; | ||
401 | } | 567 | } |
402 | 568 | ||
403 | public static T Clamp<T>(T x, T min, T max) | 569 | public static T Clamp<T>(T x, T min, T max) |
@@ -505,6 +671,7 @@ namespace OpenSim.Framework | |||
505 | public static string GetFormattedXml(string rawXml) | 671 | public static string GetFormattedXml(string rawXml) |
506 | { | 672 | { |
507 | XmlDocument xd = new XmlDocument(); | 673 | XmlDocument xd = new XmlDocument(); |
674 | xd.XmlResolver=null; | ||
508 | xd.LoadXml(rawXml); | 675 | xd.LoadXml(rawXml); |
509 | 676 | ||
510 | StringBuilder sb = new StringBuilder(); | 677 | StringBuilder sb = new StringBuilder(); |
@@ -641,19 +808,25 @@ namespace OpenSim.Framework | |||
641 | /// </summary> | 808 | /// </summary> |
642 | /// <param name="data"></param> | 809 | /// <param name="data"></param> |
643 | /// <returns></returns> | 810 | /// <returns></returns> |
811 | |||
644 | public static string Md5Hash(string data) | 812 | public static string Md5Hash(string data) |
645 | { | 813 | { |
646 | byte[] dataMd5 = ComputeMD5Hash(data); | 814 | return Md5Hash(data, Encoding.Default); |
815 | } | ||
816 | |||
817 | public static string Md5Hash(string data, Encoding encoding) | ||
818 | { | ||
819 | byte[] dataMd5 = ComputeMD5Hash(data, encoding); | ||
647 | StringBuilder sb = new StringBuilder(); | 820 | StringBuilder sb = new StringBuilder(); |
648 | for (int i = 0; i < dataMd5.Length; i++) | 821 | for (int i = 0; i < dataMd5.Length; i++) |
649 | sb.AppendFormat("{0:x2}", dataMd5[i]); | 822 | sb.AppendFormat("{0:x2}", dataMd5[i]); |
650 | return sb.ToString(); | 823 | return sb.ToString(); |
651 | } | 824 | } |
652 | 825 | ||
653 | private static byte[] ComputeMD5Hash(string data) | 826 | private static byte[] ComputeMD5Hash(string data, Encoding encoding) |
654 | { | 827 | { |
655 | MD5 md5 = MD5.Create(); | 828 | MD5 md5 = MD5.Create(); |
656 | return md5.ComputeHash(Encoding.Default.GetBytes(data)); | 829 | return md5.ComputeHash(encoding.GetBytes(data)); |
657 | } | 830 | } |
658 | 831 | ||
659 | /// <summary> | 832 | /// <summary> |
@@ -661,6 +834,12 @@ namespace OpenSim.Framework | |||
661 | /// </summary> | 834 | /// </summary> |
662 | /// <param name="data"></param> | 835 | /// <param name="data"></param> |
663 | /// <returns></returns> | 836 | /// <returns></returns> |
837 | |||
838 | public static string SHA1Hash(string data, Encoding enc) | ||
839 | { | ||
840 | return SHA1Hash(enc.GetBytes(data)); | ||
841 | } | ||
842 | |||
664 | public static string SHA1Hash(string data) | 843 | public static string SHA1Hash(string data) |
665 | { | 844 | { |
666 | return SHA1Hash(Encoding.Default.GetBytes(data)); | 845 | return SHA1Hash(Encoding.Default.GetBytes(data)); |
@@ -679,8 +858,10 @@ namespace OpenSim.Framework | |||
679 | 858 | ||
680 | private static byte[] ComputeSHA1Hash(byte[] src) | 859 | private static byte[] ComputeSHA1Hash(byte[] src) |
681 | { | 860 | { |
682 | SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider(); | 861 | byte[] ret; |
683 | return SHA1.ComputeHash(src); | 862 | using(SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider()) |
863 | ret = SHA1.ComputeHash(src); | ||
864 | return ret; | ||
684 | } | 865 | } |
685 | 866 | ||
686 | public static int fast_distance2d(int x, int y) | 867 | public static int fast_distance2d(int x, int y) |
@@ -713,18 +894,27 @@ namespace OpenSim.Framework | |||
713 | /// <param name="newx">New region x-coord</param> | 894 | /// <param name="newx">New region x-coord</param> |
714 | /// <param name="oldy">Old region y-coord</param> | 895 | /// <param name="oldy">Old region y-coord</param> |
715 | /// <param name="newy">New region y-coord</param> | 896 | /// <param name="newy">New region y-coord</param> |
716 | /// <returns></returns> | 897 | /// <returns></returns> |
717 | public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy) | 898 | public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy, |
718 | { | 899 | int oldsizex, int oldsizey, int newsizex, int newsizey) |
719 | int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize); | 900 | { |
720 | 901 | // we still need to make sure we see new region 1stNeighbors | |
721 | int startX = (int)oldx - dd; | 902 | drawdist--; |
722 | int startY = (int)oldy - dd; | 903 | oldx *= Constants.RegionSize; |
904 | newx *= Constants.RegionSize; | ||
905 | if (oldx + oldsizex + drawdist < newx) | ||
906 | return true; | ||
907 | if (newx + newsizex + drawdist < oldx) | ||
908 | return true; | ||
723 | 909 | ||
724 | int endX = (int)oldx + dd; | 910 | oldy *= Constants.RegionSize; |
725 | int endY = (int)oldy + dd; | 911 | newy *= Constants.RegionSize; |
912 | if (oldy + oldsizey + drawdist < newy) | ||
913 | return true; | ||
914 | if (newy + newsizey + drawdist < oldy) | ||
915 | return true; | ||
726 | 916 | ||
727 | return (newx < startX || endX < newx || newy < startY || endY < newy); | 917 | return false; |
728 | } | 918 | } |
729 | 919 | ||
730 | public static string FieldToString(byte[] bytes) | 920 | public static string FieldToString(byte[] bytes) |
@@ -804,6 +994,18 @@ namespace OpenSim.Framework | |||
804 | return output.ToString(); | 994 | return output.ToString(); |
805 | } | 995 | } |
806 | 996 | ||
997 | private static ExpiringCache<string,IPAddress> dnscache = new ExpiringCache<string, IPAddress>(); | ||
998 | |||
999 | /// <summary> | ||
1000 | /// Converts a URL to a IPAddress | ||
1001 | /// </summary> | ||
1002 | /// <param name="url">URL Standard Format</param> | ||
1003 | /// <returns>A resolved IP Address</returns> | ||
1004 | public static IPAddress GetHostFromURL(string url) | ||
1005 | { | ||
1006 | return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]); | ||
1007 | } | ||
1008 | |||
807 | /// <summary> | 1009 | /// <summary> |
808 | /// Returns a IP address from a specified DNS, favouring IPv4 addresses. | 1010 | /// Returns a IP address from a specified DNS, favouring IPv4 addresses. |
809 | /// </summary> | 1011 | /// </summary> |
@@ -811,38 +1013,128 @@ namespace OpenSim.Framework | |||
811 | /// <returns>An IP address, or null</returns> | 1013 | /// <returns>An IP address, or null</returns> |
812 | public static IPAddress GetHostFromDNS(string dnsAddress) | 1014 | public static IPAddress GetHostFromDNS(string dnsAddress) |
813 | { | 1015 | { |
814 | // Is it already a valid IP? No need to look it up. | 1016 | if(String.IsNullOrWhiteSpace(dnsAddress)) |
815 | IPAddress ipa; | 1017 | return null; |
816 | if (IPAddress.TryParse(dnsAddress, out ipa)) | ||
817 | return ipa; | ||
818 | 1018 | ||
819 | IPAddress[] hosts = null; | 1019 | IPAddress ia = null; |
1020 | if(dnscache.TryGetValue(dnsAddress, out ia) && ia != null) | ||
1021 | { | ||
1022 | dnscache.AddOrUpdate(dnsAddress, ia, 300); | ||
1023 | return ia; | ||
1024 | } | ||
820 | 1025 | ||
821 | // Not an IP, lookup required | 1026 | ia = null; |
1027 | // If it is already an IP, don't let GetHostEntry see it | ||
1028 | if (IPAddress.TryParse(dnsAddress, out ia) && ia != null) | ||
1029 | { | ||
1030 | if (ia.Equals(IPAddress.Any) || ia.Equals(IPAddress.IPv6Any)) | ||
1031 | return null; | ||
1032 | dnscache.AddOrUpdate(dnsAddress, ia, 300); | ||
1033 | return ia; | ||
1034 | } | ||
1035 | |||
1036 | IPHostEntry IPH; | ||
822 | try | 1037 | try |
823 | { | 1038 | { |
824 | hosts = Dns.GetHostEntry(dnsAddress).AddressList; | 1039 | IPH = Dns.GetHostEntry(dnsAddress); |
825 | } | 1040 | } |
826 | catch (Exception e) | 1041 | catch // (SocketException e) |
1042 | { | ||
1043 | return null; | ||
1044 | } | ||
1045 | |||
1046 | if(IPH == null || IPH.AddressList.Length == 0) | ||
1047 | return null; | ||
1048 | |||
1049 | ia = null; | ||
1050 | foreach (IPAddress Adr in IPH.AddressList) | ||
827 | { | 1051 | { |
828 | m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e); | 1052 | if (ia == null) |
1053 | ia = Adr; | ||
829 | 1054 | ||
830 | // Still going to throw the exception on for now, since this was what was happening in the first place | 1055 | if (Adr.AddressFamily == AddressFamily.InterNetwork) |
831 | throw e; | 1056 | { |
1057 | ia = Adr; | ||
1058 | break; | ||
1059 | } | ||
832 | } | 1060 | } |
1061 | if(ia != null) | ||
1062 | dnscache.AddOrUpdate(dnsAddress, ia, 300); | ||
1063 | return ia; | ||
1064 | } | ||
833 | 1065 | ||
834 | foreach (IPAddress host in hosts) | 1066 | public static IPEndPoint getEndPoint(IPAddress ia, int port) |
1067 | { | ||
1068 | if(ia == null) | ||
1069 | return null; | ||
1070 | |||
1071 | IPEndPoint newEP = null; | ||
1072 | try | ||
1073 | { | ||
1074 | newEP = new IPEndPoint(ia, port); | ||
1075 | } | ||
1076 | catch | ||
1077 | { | ||
1078 | newEP = null; | ||
1079 | } | ||
1080 | return newEP; | ||
1081 | } | ||
1082 | |||
1083 | public static IPEndPoint getEndPoint(string hostname, int port) | ||
1084 | { | ||
1085 | if(String.IsNullOrWhiteSpace(hostname)) | ||
1086 | return null; | ||
1087 | |||
1088 | IPAddress ia = null; | ||
1089 | if(dnscache.TryGetValue(hostname, out ia) && ia != null) | ||
1090 | { | ||
1091 | dnscache.AddOrUpdate(hostname, ia, 300); | ||
1092 | return getEndPoint(ia, port); | ||
1093 | } | ||
1094 | |||
1095 | ia = null; | ||
1096 | |||
1097 | // If it is already an IP, don't let GetHostEntry see it | ||
1098 | if (IPAddress.TryParse(hostname, out ia) && ia != null) | ||
1099 | { | ||
1100 | if (ia.Equals(IPAddress.Any) || ia.Equals(IPAddress.IPv6Any)) | ||
1101 | return null; | ||
1102 | |||
1103 | dnscache.AddOrUpdate(hostname, ia, 300); | ||
1104 | return getEndPoint(ia, port); | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | IPHostEntry IPH; | ||
1109 | try | ||
1110 | { | ||
1111 | IPH = Dns.GetHostEntry(hostname); | ||
1112 | } | ||
1113 | catch // (SocketException e) | ||
1114 | { | ||
1115 | return null; | ||
1116 | } | ||
1117 | |||
1118 | if(IPH == null || IPH.AddressList.Length == 0) | ||
1119 | return null; | ||
1120 | |||
1121 | ia = null; | ||
1122 | foreach (IPAddress Adr in IPH.AddressList) | ||
835 | { | 1123 | { |
836 | if (host.AddressFamily == AddressFamily.InterNetwork) | 1124 | if (ia == null) |
1125 | ia = Adr; | ||
1126 | |||
1127 | if (Adr.AddressFamily == AddressFamily.InterNetwork) | ||
837 | { | 1128 | { |
838 | return host; | 1129 | ia = Adr; |
1130 | break; | ||
839 | } | 1131 | } |
840 | } | 1132 | } |
841 | 1133 | ||
842 | if (hosts.Length > 0) | 1134 | if(ia != null) |
843 | return hosts[0]; | 1135 | dnscache.AddOrUpdate(hostname, ia, 300); |
844 | 1136 | ||
845 | return null; | 1137 | return getEndPoint(ia,port); |
846 | } | 1138 | } |
847 | 1139 | ||
848 | public static Uri GetURI(string protocol, string hostname, int port, string path) | 1140 | public static Uri GetURI(string protocol, string hostname, int port, string path) |
@@ -987,7 +1279,7 @@ namespace OpenSim.Framework | |||
987 | 1279 | ||
988 | public static string configDir() | 1280 | public static string configDir() |
989 | { | 1281 | { |
990 | return "../config"; | 1282 | return "."; |
991 | } | 1283 | } |
992 | 1284 | ||
993 | public static string dataDir() | 1285 | public static string dataDir() |
@@ -999,13 +1291,26 @@ namespace OpenSim.Framework | |||
999 | { | 1291 | { |
1000 | foreach (IAppender appender in LogManager.GetRepository().GetAppenders()) | 1292 | foreach (IAppender appender in LogManager.GetRepository().GetAppenders()) |
1001 | { | 1293 | { |
1002 | if (appender is FileAppender) | 1294 | if (appender is FileAppender && appender.Name == "LogFileAppender") |
1003 | { | 1295 | { |
1004 | return ((FileAppender)appender).File; | 1296 | return ((FileAppender)appender).File; |
1005 | } | 1297 | } |
1006 | } | 1298 | } |
1007 | 1299 | ||
1008 | return "../logs/OpenSim.log"; | 1300 | return "./OpenSim.log"; |
1301 | } | ||
1302 | |||
1303 | public static string statsLogFile() | ||
1304 | { | ||
1305 | foreach (IAppender appender in LogManager.GetRepository().GetAppenders()) | ||
1306 | { | ||
1307 | if (appender is FileAppender && appender.Name == "StatsLogFileAppender") | ||
1308 | { | ||
1309 | return ((FileAppender)appender).File; | ||
1310 | } | ||
1311 | } | ||
1312 | |||
1313 | return "./OpenSimStats.log"; | ||
1009 | } | 1314 | } |
1010 | 1315 | ||
1011 | public static string logDir() | 1316 | public static string logDir() |
@@ -1065,9 +1370,28 @@ namespace OpenSim.Framework | |||
1065 | } | 1370 | } |
1066 | } | 1371 | } |
1067 | 1372 | ||
1373 | public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section) | ||
1374 | { | ||
1375 | // First, check the Startup section, the default section | ||
1376 | IConfig cnf = config.Configs["Startup"]; | ||
1377 | if (cnf == null) | ||
1378 | return string.Empty; | ||
1379 | string val = cnf.GetString(varname, string.Empty); | ||
1380 | |||
1381 | // Then check for an overwrite of the default in the given section | ||
1382 | if (!string.IsNullOrEmpty(section)) | ||
1383 | { | ||
1384 | cnf = config.Configs[section]; | ||
1385 | if (cnf != null) | ||
1386 | val = cnf.GetString(varname, val); | ||
1387 | } | ||
1388 | |||
1389 | return val; | ||
1390 | } | ||
1391 | |||
1068 | /// <summary> | 1392 | /// <summary> |
1069 | /// Gets the value of a configuration variable by looking into | 1393 | /// Gets the value of a configuration variable by looking into |
1070 | /// multiple sections in order. The latter sections overwrite | 1394 | /// multiple sections in order. The latter sections overwrite |
1071 | /// any values previously found. | 1395 | /// any values previously found. |
1072 | /// </summary> | 1396 | /// </summary> |
1073 | /// <typeparam name="T">Type of the variable</typeparam> | 1397 | /// <typeparam name="T">Type of the variable</typeparam> |
@@ -1082,7 +1406,7 @@ namespace OpenSim.Framework | |||
1082 | 1406 | ||
1083 | /// <summary> | 1407 | /// <summary> |
1084 | /// Gets the value of a configuration variable by looking into | 1408 | /// Gets the value of a configuration variable by looking into |
1085 | /// multiple sections in order. The latter sections overwrite | 1409 | /// multiple sections in order. The latter sections overwrite |
1086 | /// any values previously found. | 1410 | /// any values previously found. |
1087 | /// </summary> | 1411 | /// </summary> |
1088 | /// <remarks> | 1412 | /// <remarks> |
@@ -1138,7 +1462,7 @@ namespace OpenSim.Framework | |||
1138 | ConfigSource.ExpandKeyValues(); | 1462 | ConfigSource.ExpandKeyValues(); |
1139 | } | 1463 | } |
1140 | } | 1464 | } |
1141 | 1465 | ||
1142 | public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass) | 1466 | public static T ReadSettingsFromIniFile<T>(IConfig config, T settingsClass) |
1143 | { | 1467 | { |
1144 | Type settingsType = settingsClass.GetType(); | 1468 | Type settingsType = settingsClass.GetType(); |
@@ -1249,7 +1573,7 @@ namespace OpenSim.Framework | |||
1249 | 1573 | ||
1250 | if (File.Exists(configFile)) | 1574 | if (File.Exists(configFile)) |
1251 | { | 1575 | { |
1252 | // Merge | 1576 | // Merge |
1253 | config.Merge(new IniConfigSource(configFile)); | 1577 | config.Merge(new IniConfigSource(configFile)); |
1254 | config.ExpandKeyValues(); | 1578 | config.ExpandKeyValues(); |
1255 | configFilePath = configFile; | 1579 | configFilePath = configFile; |
@@ -1388,6 +1712,46 @@ namespace OpenSim.Framework | |||
1388 | return ret; | 1712 | return ret; |
1389 | } | 1713 | } |
1390 | 1714 | ||
1715 | public static string Compress(string text) | ||
1716 | { | ||
1717 | byte[] buffer = Util.UTF8.GetBytes(text); | ||
1718 | MemoryStream memory = new MemoryStream(); | ||
1719 | using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true)) | ||
1720 | { | ||
1721 | compressor.Write(buffer, 0, buffer.Length); | ||
1722 | } | ||
1723 | |||
1724 | memory.Position = 0; | ||
1725 | |||
1726 | byte[] compressed = new byte[memory.Length]; | ||
1727 | memory.Read(compressed, 0, compressed.Length); | ||
1728 | |||
1729 | byte[] compressedBuffer = new byte[compressed.Length + 4]; | ||
1730 | Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length); | ||
1731 | Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4); | ||
1732 | return Convert.ToBase64String(compressedBuffer); | ||
1733 | } | ||
1734 | |||
1735 | public static string Decompress(string compressedText) | ||
1736 | { | ||
1737 | byte[] compressedBuffer = Convert.FromBase64String(compressedText); | ||
1738 | using (MemoryStream memory = new MemoryStream()) | ||
1739 | { | ||
1740 | int msgLength = BitConverter.ToInt32(compressedBuffer, 0); | ||
1741 | memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4); | ||
1742 | |||
1743 | byte[] buffer = new byte[msgLength]; | ||
1744 | |||
1745 | memory.Position = 0; | ||
1746 | using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress)) | ||
1747 | { | ||
1748 | decompressor.Read(buffer, 0, buffer.Length); | ||
1749 | } | ||
1750 | |||
1751 | return Util.UTF8.GetString(buffer); | ||
1752 | } | ||
1753 | } | ||
1754 | |||
1391 | /// <summary> | 1755 | /// <summary> |
1392 | /// Copy data from one stream to another, leaving the read position of both streams at the beginning. | 1756 | /// Copy data from one stream to another, leaving the read position of both streams at the beginning. |
1393 | /// </summary> | 1757 | /// </summary> |
@@ -1405,7 +1769,7 @@ namespace OpenSim.Framework | |||
1405 | const int readSize = 256; | 1769 | const int readSize = 256; |
1406 | byte[] buffer = new byte[readSize]; | 1770 | byte[] buffer = new byte[readSize]; |
1407 | MemoryStream ms = new MemoryStream(); | 1771 | MemoryStream ms = new MemoryStream(); |
1408 | 1772 | ||
1409 | int count = inputStream.Read(buffer, 0, readSize); | 1773 | int count = inputStream.Read(buffer, 0, readSize); |
1410 | 1774 | ||
1411 | while (count > 0) | 1775 | while (count > 0) |
@@ -1485,12 +1849,16 @@ namespace OpenSim.Framework | |||
1485 | return new UUID(bytes, 0); | 1849 | return new UUID(bytes, 0); |
1486 | } | 1850 | } |
1487 | 1851 | ||
1488 | public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) | 1852 | public static bool ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y) |
1489 | { | 1853 | { |
1490 | byte[] bytes = parcelID.GetBytes(); | 1854 | byte[] bytes = parcelID.GetBytes(); |
1491 | regionHandle = Utils.BytesToUInt64(bytes); | 1855 | regionHandle = Utils.BytesToUInt64(bytes); |
1492 | x = Utils.BytesToUInt(bytes, 8) & 0xffff; | 1856 | x = Utils.BytesToUInt(bytes, 8) & 0xffff; |
1493 | y = Utils.BytesToUInt(bytes, 12) & 0xffff; | 1857 | y = Utils.BytesToUInt(bytes, 12) & 0xffff; |
1858 | // validation may fail, just reducing the odds of using a real UUID as encoded parcel | ||
1859 | return ( bytes[0] == 0 && bytes[4] == 0 && // handler x,y multiples of 256 | ||
1860 | bytes[9] < 64 && bytes[13] < 64 && // positions < 16km | ||
1861 | bytes[14] == 0 && bytes[15] == 0); | ||
1494 | } | 1862 | } |
1495 | 1863 | ||
1496 | public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) | 1864 | public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y, out uint z) |
@@ -1513,7 +1881,7 @@ namespace OpenSim.Framework | |||
1513 | x += rx; | 1881 | x += rx; |
1514 | y += ry; | 1882 | y += ry; |
1515 | } | 1883 | } |
1516 | 1884 | ||
1517 | /// <summary> | 1885 | /// <summary> |
1518 | /// Get operating system information if available. Returns only the first 45 characters of information | 1886 | /// Get operating system information if available. Returns only the first 45 characters of information |
1519 | /// </summary> | 1887 | /// </summary> |
@@ -1524,20 +1892,20 @@ namespace OpenSim.Framework | |||
1524 | { | 1892 | { |
1525 | string os = String.Empty; | 1893 | string os = String.Empty; |
1526 | 1894 | ||
1527 | if (Environment.OSVersion.Platform != PlatformID.Unix) | 1895 | // if (Environment.OSVersion.Platform != PlatformID.Unix) |
1528 | { | 1896 | // { |
1529 | os = Environment.OSVersion.ToString(); | 1897 | // os = Environment.OSVersion.ToString(); |
1530 | } | 1898 | // } |
1531 | else | 1899 | // else |
1532 | { | 1900 | // { |
1533 | os = ReadEtcIssue(); | 1901 | // os = ReadEtcIssue(); |
1534 | } | 1902 | // } |
1535 | 1903 | // | |
1536 | if (os.Length > 45) | 1904 | // if (os.Length > 45) |
1537 | { | 1905 | // { |
1538 | os = os.Substring(0, 45); | 1906 | // os = os.Substring(0, 45); |
1539 | } | 1907 | // } |
1540 | 1908 | ||
1541 | return os; | 1909 | return os; |
1542 | } | 1910 | } |
1543 | 1911 | ||
@@ -1579,6 +1947,8 @@ namespace OpenSim.Framework | |||
1579 | 1947 | ||
1580 | // hide the password in the connection string | 1948 | // hide the password in the connection string |
1581 | passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); | 1949 | passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase); |
1950 | if (passPosition == -1) | ||
1951 | return connectionString; | ||
1582 | passPosition = connectionString.IndexOf("=", passPosition); | 1952 | passPosition = connectionString.IndexOf("=", passPosition); |
1583 | if (passPosition < connectionString.Length) | 1953 | if (passPosition < connectionString.Length) |
1584 | passPosition += 1; | 1954 | passPosition += 1; |
@@ -1645,7 +2015,7 @@ namespace OpenSim.Framework | |||
1645 | 2015 | ||
1646 | public static Guid GetHashGuid(string data, string salt) | 2016 | public static Guid GetHashGuid(string data, string salt) |
1647 | { | 2017 | { |
1648 | byte[] hash = ComputeMD5Hash(data + salt); | 2018 | byte[] hash = ComputeMD5Hash(data + salt, Encoding.Default); |
1649 | 2019 | ||
1650 | //string s = BitConverter.ToString(hash); | 2020 | //string s = BitConverter.ToString(hash); |
1651 | 2021 | ||
@@ -1747,7 +2117,7 @@ namespace OpenSim.Framework | |||
1747 | vol = vcomps[0]; | 2117 | vol = vcomps[0]; |
1748 | } | 2118 | } |
1749 | } | 2119 | } |
1750 | 2120 | ||
1751 | string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); | 2121 | string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries); |
1752 | 2122 | ||
1753 | // Glob | 2123 | // Glob |
@@ -1792,6 +2162,32 @@ namespace OpenSim.Framework | |||
1792 | return found.ToArray(); | 2162 | return found.ToArray(); |
1793 | } | 2163 | } |
1794 | 2164 | ||
2165 | public static string ServerURI(string uri) | ||
2166 | { | ||
2167 | if (uri == string.Empty) | ||
2168 | return string.Empty; | ||
2169 | |||
2170 | // Get rid of eventual slashes at the end | ||
2171 | uri = uri.TrimEnd('/'); | ||
2172 | |||
2173 | IPAddress ipaddr1 = null; | ||
2174 | string port1 = ""; | ||
2175 | try | ||
2176 | { | ||
2177 | ipaddr1 = Util.GetHostFromURL(uri); | ||
2178 | } | ||
2179 | catch { } | ||
2180 | |||
2181 | try | ||
2182 | { | ||
2183 | port1 = uri.Split(new char[] { ':' })[2]; | ||
2184 | } | ||
2185 | catch { } | ||
2186 | |||
2187 | // We tried our best to convert the domain names to IP addresses | ||
2188 | return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri; | ||
2189 | } | ||
2190 | |||
1795 | /// <summary> | 2191 | /// <summary> |
1796 | /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. | 2192 | /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary. |
1797 | /// </summary> | 2193 | /// </summary> |
@@ -1823,14 +2219,14 @@ namespace OpenSim.Framework | |||
1823 | 2219 | ||
1824 | if (!str.EndsWith("\0")) | 2220 | if (!str.EndsWith("\0")) |
1825 | str += "\0"; | 2221 | str += "\0"; |
1826 | 2222 | ||
1827 | // Because this is UTF-8 encoding and not ASCII, it's possible we | 2223 | // Because this is UTF-8 encoding and not ASCII, it's possible we |
1828 | // might have gotten an oversized array even after the string trim | 2224 | // might have gotten an oversized array even after the string trim |
1829 | byte[] data = UTF8.GetBytes(str); | 2225 | byte[] data = UTF8.GetBytes(str); |
1830 | 2226 | ||
1831 | if (data.Length > 256) | 2227 | if (data.Length > 255) //play safe |
1832 | { | 2228 | { |
1833 | int cut = 255; | 2229 | int cut = 254; |
1834 | if((data[cut] & 0x80 ) != 0 ) | 2230 | if((data[cut] & 0x80 ) != 0 ) |
1835 | { | 2231 | { |
1836 | while(cut > 0 && (data[cut] & 0xc0) != 0xc0) | 2232 | while(cut > 0 && (data[cut] & 0xc0) != 0xc0) |
@@ -1895,6 +2291,56 @@ namespace OpenSim.Framework | |||
1895 | } | 2291 | } |
1896 | 2292 | ||
1897 | /// <summary> | 2293 | /// <summary> |
2294 | /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to MaxLength bytes if necessary. | ||
2295 | /// </summary> | ||
2296 | /// <param name="str"> | ||
2297 | /// If null or empty, then an bytes[0] is returned. | ||
2298 | /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] | ||
2299 | /// </param> | ||
2300 | /// <param name="args"> | ||
2301 | /// Arguments to substitute into the string via the {} mechanism. | ||
2302 | /// </param> | ||
2303 | /// <returns></returns> | ||
2304 | public static byte[] StringToBytes(string str, int MaxLength, params object[] args) | ||
2305 | { | ||
2306 | return StringToBytes1024(string.Format(str, args), MaxLength); | ||
2307 | } | ||
2308 | |||
2309 | /// <summary> | ||
2310 | /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to MaxLength bytes if necessary. | ||
2311 | /// </summary> | ||
2312 | /// <param name="str"> | ||
2313 | /// If null or empty, then an bytes[0] is returned. | ||
2314 | /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0] | ||
2315 | /// </param> | ||
2316 | /// <returns></returns> | ||
2317 | public static byte[] StringToBytes(string str, int MaxLength) | ||
2318 | { | ||
2319 | if (String.IsNullOrEmpty(str)) | ||
2320 | return Utils.EmptyBytes; | ||
2321 | |||
2322 | if (!str.EndsWith("\0")) | ||
2323 | str += "\0"; | ||
2324 | |||
2325 | // Because this is UTF-8 encoding and not ASCII, it's possible we | ||
2326 | // might have gotten an oversized array even after the string trim | ||
2327 | byte[] data = UTF8.GetBytes(str); | ||
2328 | |||
2329 | if (data.Length > MaxLength) | ||
2330 | { | ||
2331 | int cut = MaxLength - 1 ; | ||
2332 | if((data[cut] & 0x80 ) != 0 ) | ||
2333 | { | ||
2334 | while(cut > 0 && (data[cut] & 0xc0) != 0xc0) | ||
2335 | cut--; | ||
2336 | } | ||
2337 | Array.Resize<byte>(ref data, cut + 1); | ||
2338 | data[cut] = 0; | ||
2339 | } | ||
2340 | |||
2341 | return data; | ||
2342 | } | ||
2343 | /// <summary> | ||
1898 | /// Pretty format the hashtable contents to a single line. | 2344 | /// Pretty format the hashtable contents to a single line. |
1899 | /// </summary> | 2345 | /// </summary> |
1900 | /// <remarks> | 2346 | /// <remarks> |
@@ -2004,7 +2450,7 @@ namespace OpenSim.Framework | |||
2004 | 2450 | ||
2005 | STPStartInfo startInfo = new STPStartInfo(); | 2451 | STPStartInfo startInfo = new STPStartInfo(); |
2006 | startInfo.ThreadPoolName = "Util"; | 2452 | startInfo.ThreadPoolName = "Util"; |
2007 | startInfo.IdleTimeout = 2000; | 2453 | startInfo.IdleTimeout = 20000; |
2008 | startInfo.MaxWorkerThreads = maxThreads; | 2454 | startInfo.MaxWorkerThreads = maxThreads; |
2009 | startInfo.MinWorkerThreads = minThreads; | 2455 | startInfo.MinWorkerThreads = minThreads; |
2010 | 2456 | ||
@@ -2032,7 +2478,7 @@ namespace OpenSim.Framework | |||
2032 | throw new NotImplementedException(); | 2478 | throw new NotImplementedException(); |
2033 | } | 2479 | } |
2034 | } | 2480 | } |
2035 | 2481 | ||
2036 | /// <summary> | 2482 | /// <summary> |
2037 | /// Additional information about threads in the main thread pool. Used to time how long the | 2483 | /// Additional information about threads in the main thread pool. Used to time how long the |
2038 | /// thread has been running, and abort it if it has timed-out. | 2484 | /// thread has been running, and abort it if it has timed-out. |
@@ -2043,14 +2489,15 @@ namespace OpenSim.Framework | |||
2043 | public string StackTrace { get; set; } | 2489 | public string StackTrace { get; set; } |
2044 | private string context; | 2490 | private string context; |
2045 | public bool LogThread { get; set; } | 2491 | public bool LogThread { get; set; } |
2046 | 2492 | ||
2047 | public IWorkItemResult WorkItem { get; set; } | 2493 | public IWorkItemResult WorkItem { get; set; } |
2048 | public Thread Thread { get; set; } | 2494 | public Thread Thread { get; set; } |
2049 | public bool Running { get; set; } | 2495 | public bool Running { get; set; } |
2050 | public bool Aborted { get; set; } | 2496 | public bool Aborted { get; set; } |
2051 | private int started; | 2497 | private int started; |
2498 | public bool DoTimeout; | ||
2052 | 2499 | ||
2053 | public ThreadInfo(long threadFuncNum, string context) | 2500 | public ThreadInfo(long threadFuncNum, string context, bool dotimeout = true) |
2054 | { | 2501 | { |
2055 | ThreadFuncNum = threadFuncNum; | 2502 | ThreadFuncNum = threadFuncNum; |
2056 | this.context = context; | 2503 | this.context = context; |
@@ -2058,6 +2505,7 @@ namespace OpenSim.Framework | |||
2058 | Thread = null; | 2505 | Thread = null; |
2059 | Running = false; | 2506 | Running = false; |
2060 | Aborted = false; | 2507 | Aborted = false; |
2508 | DoTimeout = dotimeout; | ||
2061 | } | 2509 | } |
2062 | 2510 | ||
2063 | public void Started() | 2511 | public void Started() |
@@ -2128,7 +2576,7 @@ namespace OpenSim.Framework | |||
2128 | foreach (KeyValuePair<long, ThreadInfo> entry in activeThreads) | 2576 | foreach (KeyValuePair<long, ThreadInfo> entry in activeThreads) |
2129 | { | 2577 | { |
2130 | ThreadInfo t = entry.Value; | 2578 | ThreadInfo t = entry.Value; |
2131 | if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT)) | 2579 | if (t.DoTimeout && t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT)) |
2132 | { | 2580 | { |
2133 | m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace()); | 2581 | m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace()); |
2134 | t.Abort(); | 2582 | t.Abort(); |
@@ -2138,7 +2586,7 @@ namespace OpenSim.Framework | |||
2138 | 2586 | ||
2139 | // It's possible that the thread won't abort. To make sure the thread pool isn't | 2587 | // It's possible that the thread won't abort. To make sure the thread pool isn't |
2140 | // depleted, increase the pool size. | 2588 | // depleted, increase the pool size. |
2141 | m_ThreadPool.MaxThreads++; | 2589 | // m_ThreadPool.MaxThreads++; |
2142 | } | 2590 | } |
2143 | } | 2591 | } |
2144 | } | 2592 | } |
@@ -2148,7 +2596,7 @@ namespace OpenSim.Framework | |||
2148 | public static Dictionary<string, int> GetFireAndForgetCallsMade() | 2596 | public static Dictionary<string, int> GetFireAndForgetCallsMade() |
2149 | { | 2597 | { |
2150 | return new Dictionary<string, int>(m_fireAndForgetCallsMade); | 2598 | return new Dictionary<string, int>(m_fireAndForgetCallsMade); |
2151 | } | 2599 | } |
2152 | 2600 | ||
2153 | private static Dictionary<string, int> m_fireAndForgetCallsMade = new Dictionary<string, int>(); | 2601 | private static Dictionary<string, int> m_fireAndForgetCallsMade = new Dictionary<string, int>(); |
2154 | 2602 | ||
@@ -2168,11 +2616,11 @@ namespace OpenSim.Framework | |||
2168 | { | 2616 | { |
2169 | FireAndForget(callback, obj, null); | 2617 | FireAndForget(callback, obj, null); |
2170 | } | 2618 | } |
2171 | 2619 | ||
2172 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context) | 2620 | public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context, bool dotimeout = true) |
2173 | { | 2621 | { |
2174 | Interlocked.Increment(ref numTotalThreadFuncsCalled); | 2622 | Interlocked.Increment(ref numTotalThreadFuncsCalled); |
2175 | 2623 | /* | |
2176 | if (context != null) | 2624 | if (context != null) |
2177 | { | 2625 | { |
2178 | if (!m_fireAndForgetCallsMade.ContainsKey(context)) | 2626 | if (!m_fireAndForgetCallsMade.ContainsKey(context)) |
@@ -2185,25 +2633,25 @@ namespace OpenSim.Framework | |||
2185 | else | 2633 | else |
2186 | m_fireAndForgetCallsInProgress[context]++; | 2634 | m_fireAndForgetCallsInProgress[context]++; |
2187 | } | 2635 | } |
2188 | 2636 | */ | |
2189 | WaitCallback realCallback; | 2637 | WaitCallback realCallback; |
2190 | 2638 | ||
2191 | bool loggingEnabled = LogThreadPool > 0; | 2639 | bool loggingEnabled = LogThreadPool > 0; |
2192 | 2640 | ||
2193 | long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); | 2641 | long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum); |
2194 | ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context); | 2642 | ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context, dotimeout); |
2195 | 2643 | ||
2196 | if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) | 2644 | if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest) |
2197 | { | 2645 | { |
2198 | // If we're running regression tests, then we want any exceptions to rise up to the test code. | 2646 | // If we're running regression tests, then we want any exceptions to rise up to the test code. |
2199 | realCallback = | 2647 | realCallback = |
2200 | o => | 2648 | o => |
2201 | { | 2649 | { |
2202 | Culture.SetCurrentCulture(); | 2650 | Culture.SetCurrentCulture(); |
2203 | callback(o); | 2651 | callback(o); |
2204 | 2652 | ||
2205 | if (context != null) | 2653 | // if (context != null) |
2206 | m_fireAndForgetCallsInProgress[context]--; | 2654 | // m_fireAndForgetCallsInProgress[context]--; |
2207 | }; | 2655 | }; |
2208 | } | 2656 | } |
2209 | else | 2657 | else |
@@ -2229,7 +2677,6 @@ namespace OpenSim.Framework | |||
2229 | } | 2677 | } |
2230 | catch (ThreadAbortException e) | 2678 | catch (ThreadAbortException e) |
2231 | { | 2679 | { |
2232 | m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e); | ||
2233 | } | 2680 | } |
2234 | catch (Exception e) | 2681 | catch (Exception e) |
2235 | { | 2682 | { |
@@ -2244,8 +2691,8 @@ namespace OpenSim.Framework | |||
2244 | if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) | 2691 | if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread) |
2245 | m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); | 2692 | m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed())); |
2246 | 2693 | ||
2247 | if (context != null) | 2694 | // if (context != null) |
2248 | m_fireAndForgetCallsInProgress[context]--; | 2695 | // m_fireAndForgetCallsInProgress[context]--; |
2249 | } | 2696 | } |
2250 | }; | 2697 | }; |
2251 | } | 2698 | } |
@@ -2253,6 +2700,7 @@ namespace OpenSim.Framework | |||
2253 | long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs); | 2700 | long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs); |
2254 | try | 2701 | try |
2255 | { | 2702 | { |
2703 | /* | ||
2256 | long numRunning = numRunningThreadFuncs; | 2704 | long numRunning = numRunningThreadFuncs; |
2257 | 2705 | ||
2258 | if (m_ThreadPool != null && LogOverloads) | 2706 | if (m_ThreadPool != null && LogOverloads) |
@@ -2285,6 +2733,7 @@ namespace OpenSim.Framework | |||
2285 | } | 2733 | } |
2286 | } | 2734 | } |
2287 | else | 2735 | else |
2736 | */ | ||
2288 | { | 2737 | { |
2289 | // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either. | 2738 | // Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either. |
2290 | // Those log lines aren't useful when we don't know which function is running in the thread. | 2739 | // Those log lines aren't useful when we don't know which function is running in the thread. |
@@ -2342,7 +2791,7 @@ namespace OpenSim.Framework | |||
2342 | if (stackTrace.Contains("BeginFireQueueEmpty")) | 2791 | if (stackTrace.Contains("BeginFireQueueEmpty")) |
2343 | return false; | 2792 | return false; |
2344 | } | 2793 | } |
2345 | 2794 | ||
2346 | return true; | 2795 | return true; |
2347 | } | 2796 | } |
2348 | 2797 | ||
@@ -2355,7 +2804,7 @@ namespace OpenSim.Framework | |||
2355 | { | 2804 | { |
2356 | string src = Environment.StackTrace; | 2805 | string src = Environment.StackTrace; |
2357 | string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); | 2806 | string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None); |
2358 | 2807 | ||
2359 | StringBuilder dest = new StringBuilder(src.Length); | 2808 | StringBuilder dest = new StringBuilder(src.Length); |
2360 | 2809 | ||
2361 | bool started = false; | 2810 | bool started = false; |
@@ -2400,11 +2849,11 @@ namespace OpenSim.Framework | |||
2400 | /// trace. And pausing another thread can cause a deadlock. This method attempts to | 2849 | /// trace. And pausing another thread can cause a deadlock. This method attempts to |
2401 | /// avoid deadlock by using a short timeout (200ms), after which it gives up and | 2850 | /// avoid deadlock by using a short timeout (200ms), after which it gives up and |
2402 | /// returns 'null' instead of the stack trace. | 2851 | /// returns 'null' instead of the stack trace. |
2403 | /// | 2852 | /// |
2404 | /// Take from: http://stackoverflow.com/a/14935378 | 2853 | /// Take from: http://stackoverflow.com/a/14935378 |
2405 | /// | 2854 | /// |
2406 | /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691 | 2855 | /// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691 |
2407 | /// | 2856 | /// |
2408 | /// </remarks> | 2857 | /// </remarks> |
2409 | /// <returns>The stack trace, or null if failed to get it</returns> | 2858 | /// <returns>The stack trace, or null if failed to get it</returns> |
2410 | private static StackTrace GetStackTrace(Thread targetThread) | 2859 | private static StackTrace GetStackTrace(Thread targetThread) |
@@ -2500,12 +2949,22 @@ namespace OpenSim.Framework | |||
2500 | return stpi; | 2949 | return stpi; |
2501 | } | 2950 | } |
2502 | 2951 | ||
2952 | public static void StopThreadPool() | ||
2953 | { | ||
2954 | if (m_ThreadPool == null) | ||
2955 | return; | ||
2956 | SmartThreadPool pool = m_ThreadPool; | ||
2957 | m_ThreadPool = null; | ||
2958 | |||
2959 | try { pool.Shutdown(); } catch {} | ||
2960 | } | ||
2961 | |||
2503 | #endregion FireAndForget Threading Pattern | 2962 | #endregion FireAndForget Threading Pattern |
2504 | 2963 | ||
2505 | /// <summary> | 2964 | /// <summary> |
2506 | /// Environment.TickCount is an int but it counts all 32 bits so it goes positive | 2965 | /// Environment.TickCount is an int but it counts all 32 bits so it goes positive |
2507 | /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap | 2966 | /// and negative every 24.9 days. This trims down TickCount so it doesn't wrap |
2508 | /// for the callers. | 2967 | /// for the callers. |
2509 | /// This trims it to a 12 day interval so don't let your frame time get too long. | 2968 | /// This trims it to a 12 day interval so don't let your frame time get too long. |
2510 | /// </summary> | 2969 | /// </summary> |
2511 | /// <returns></returns> | 2970 | /// <returns></returns> |
@@ -2513,6 +2972,7 @@ namespace OpenSim.Framework | |||
2513 | { | 2972 | { |
2514 | return Environment.TickCount & EnvironmentTickCountMask; | 2973 | return Environment.TickCount & EnvironmentTickCountMask; |
2515 | } | 2974 | } |
2975 | |||
2516 | const Int32 EnvironmentTickCountMask = 0x3fffffff; | 2976 | const Int32 EnvironmentTickCountMask = 0x3fffffff; |
2517 | 2977 | ||
2518 | /// <summary> | 2978 | /// <summary> |
@@ -2557,6 +3017,18 @@ namespace OpenSim.Framework | |||
2557 | return tcA - tcB; | 3017 | return tcA - tcB; |
2558 | } | 3018 | } |
2559 | 3019 | ||
3020 | // returns a timestamp in ms as double | ||
3021 | // using the time resolution avaiable to StopWatch | ||
3022 | public static double GetTimeStamp() | ||
3023 | { | ||
3024 | return (double)Stopwatch.GetTimestamp() * TimeStampClockPeriod; | ||
3025 | } | ||
3026 | |||
3027 | public static double GetTimeStampMS() | ||
3028 | { | ||
3029 | return (double)Stopwatch.GetTimestamp() * TimeStampClockPeriodMS; | ||
3030 | } | ||
3031 | |||
2560 | /// <summary> | 3032 | /// <summary> |
2561 | /// Formats a duration (given in milliseconds). | 3033 | /// Formats a duration (given in milliseconds). |
2562 | /// </summary> | 3034 | /// </summary> |
@@ -2855,7 +3327,7 @@ namespace OpenSim.Framework | |||
2855 | if (parts.Length == 2) | 3327 | if (parts.Length == 2) |
2856 | return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]); | 3328 | return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]); |
2857 | } | 3329 | } |
2858 | 3330 | ||
2859 | return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName); | 3331 | return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName); |
2860 | } | 3332 | } |
2861 | 3333 | ||
@@ -2940,6 +3412,7 @@ namespace OpenSim.Framework | |||
2940 | 3412 | ||
2941 | } | 3413 | } |
2942 | 3414 | ||
3415 | /* don't like this code | ||
2943 | public class DoubleQueue<T> where T:class | 3416 | public class DoubleQueue<T> where T:class |
2944 | { | 3417 | { |
2945 | private Queue<T> m_lowQueue = new Queue<T>(); | 3418 | private Queue<T> m_lowQueue = new Queue<T>(); |
@@ -2954,10 +3427,10 @@ namespace OpenSim.Framework | |||
2954 | 3427 | ||
2955 | public virtual int Count | 3428 | public virtual int Count |
2956 | { | 3429 | { |
2957 | get | 3430 | get |
2958 | { | 3431 | { |
2959 | lock (m_syncRoot) | 3432 | lock (m_syncRoot) |
2960 | return m_highQueue.Count + m_lowQueue.Count; | 3433 | return m_highQueue.Count + m_lowQueue.Count; |
2961 | } | 3434 | } |
2962 | } | 3435 | } |
2963 | 3436 | ||
@@ -3051,7 +3524,7 @@ namespace OpenSim.Framework | |||
3051 | } | 3524 | } |
3052 | } | 3525 | } |
3053 | } | 3526 | } |
3054 | 3527 | */ | |
3055 | public class BetterRandom | 3528 | public class BetterRandom |
3056 | { | 3529 | { |
3057 | private const int BufferSize = 1024; // must be a multiple of 4 | 3530 | private const int BufferSize = 1024; // must be a multiple of 4 |