From 5e4d6cab00cb29cd088ab7b62ab13aff103b64cb Mon Sep 17 00:00:00 2001
From: onefang
Date: Sun, 19 May 2019 21:24:15 +1000
Subject: Dump OpenSim 0.9.0.1 into it's own branch.
---
OpenSim/Framework/Util.cs | 735 +++++++++++++++++++++++++++++++++++++---------
1 file changed, 604 insertions(+), 131 deletions(-)
(limited to 'OpenSim/Framework/Util.cs')
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
{
[Flags]
public enum PermissionMask : uint
- {
+ {
None = 0,
- Transfer = 1 << 13,
- Modify = 1 << 14,
- Copy = 1 << 15,
- Export = 1 << 16,
- Move = 1 << 19,
- Damage = 1 << 20,
+
+ // folded perms
+ FoldedTransfer = 1,
+ FoldedModify = 1 << 1,
+ FoldedCopy = 1 << 2,
+ FoldedExport = 1 << 3,
+
+ // DO NOT USE THIS FOR NEW WORK. IT IS DEPRECATED AND
+ // EXISTS ONLY TO REACT TO EXISTING OBJECTS HAVING IT.
+ // NEW CODE SHOULD NEVER SET THIS BIT!
+ // Use InventoryItemFlags.ObjectSlamPerm in the Flags field of
+ // this legacy slam bit. It comes from prior incomplete
+ // understanding of the code and the prohibition on
+ // reading viewer code that used to be in place.
+ Slam = (1 << 4),
+
+ FoldedMask = 0x0f,
+
+ FoldingShift = 13 , // number of bit shifts from normal perm to folded or back (same as Transfer shift below)
+ // when doing as a block
+
+ Transfer = 1 << 13, // 0x02000
+ Modify = 1 << 14, // 0x04000
+ Copy = 1 << 15, // 0x08000
+ Export = 1 << 16, // 0x10000
+ Move = 1 << 19, // 0x80000
+ Damage = 1 << 20, // 0x100000 does not seem to be in use
// All does not contain Export, which is special and must be
// explicitly given
- All = (1 << 13) | (1 << 14) | (1 << 15) | (1 << 19)
+ All = 0x8e000,
+ AllAndExport = 0x9e000,
+ AllEffective = 0x9e000,
+ UnfoldedMask = 0x1e000
}
///
@@ -103,7 +127,7 @@ namespace OpenSim.Framework
public STPStartInfo STPStartInfo { get; set; }
public WIGStartInfo WIGStartInfo { get; set; }
public bool IsIdle { get; set; }
- public bool IsShuttingDown { get; set; }
+ public bool IsShuttingDown { get; set; }
public int MaxThreads { get; set; }
public int MinThreads { get; set; }
public int InUseThreads { get; set; }
@@ -131,10 +155,16 @@ namespace OpenSim.Framework
public static readonly int MAX_THREADPOOL_LEVEL = 3;
+ public static double TimeStampClockPeriodMS;
+ public static double TimeStampClockPeriod;
+
static Util()
{
LogThreadPool = 0;
LogOverloads = true;
+ TimeStampClockPeriod = 1.0D/ (double)Stopwatch.Frequency;
+ TimeStampClockPeriodMS = 1e3 * TimeStampClockPeriod;
+ m_log.InfoFormat("[UTIL] TimeStamp clock with period of {0}ms", Math.Round(TimeStampClockPeriodMS,6,MidpointRounding.AwayFromZero));
}
private static uint nextXferID = 5000;
@@ -217,7 +247,7 @@ namespace OpenSim.Framework
public static Encoding UTF8NoBomEncoding = new UTF8Encoding(false);
///
- /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards)
+ /// Well known UUID for the blank texture used in the Linden SL viewer version 1.20 (and hopefully onwards)
///
public static UUID BLANK_TEXTURE_UUID = new UUID("5748decc-f629-461c-9a36-a35a221fe21f");
@@ -267,14 +297,12 @@ namespace OpenSim.Framework
///
/// A 3d vector
/// A new vector which is normalized form of the vector
- /// The vector paramater cannot be <0,0,0>
+
public static Vector3 GetNormalizedVector(Vector3 a)
{
- if (IsZeroVector(a))
- throw new ArgumentException("Vector paramater cannot be a zero vector.");
-
- float Mag = (float) GetMagnitude(a);
- return new Vector3(a.X / Mag, a.Y / Mag, a.Z / Mag);
+ Vector3 v = new Vector3(a.X, a.Y, a.Z);
+ v.Normalize();
+ return v;
}
///
@@ -357,47 +385,185 @@ namespace OpenSim.Framework
return Utils.UIntsToLong(X, Y);
}
- // Regions are identified with a 'handle' made up of its region coordinates packed into a ulong.
- // Several places rely on the ability to extract a region's location from its handle.
- // Note the location is in 'world coordinates' (see below).
- // Region handles are based on the lowest coordinate of the region so trim the passed x,y to be the regions 0,0.
+ // Regions are identified with a 'handle' made up of its world coordinates packed into a ulong.
+ // Region handles are based on the coordinate of the region corner with lower X and Y
+ // var regions need more work than this to get that right corner from a generic world position
+ // this corner must be on a grid point
public static ulong RegionWorldLocToHandle(uint X, uint Y)
{
- return Utils.UIntsToLong(X, Y);
+ ulong handle = X & 0xffffff00; // make sure it matchs grid coord points.
+ handle <<= 32; // to higher half
+ handle |= (Y & 0xffffff00);
+ return handle;
}
- public static ulong RegionLocToHandle(uint X, uint Y)
+ public static ulong RegionGridLocToHandle(uint X, uint Y)
{
- return Utils.UIntsToLong(Util.RegionToWorldLoc(X), Util.RegionToWorldLoc(Y));
+ ulong handle = X;
+ handle <<= 40; // shift to higher half and mult by 256)
+ handle |= (Y << 8); // mult by 256)
+ return handle;
}
public static void RegionHandleToWorldLoc(ulong handle, out uint X, out uint Y)
{
X = (uint)(handle >> 32);
- Y = (uint)(handle & (ulong)uint.MaxValue);
+ Y = (uint)(handle & 0xfffffffful);
}
public static void RegionHandleToRegionLoc(ulong handle, out uint X, out uint Y)
{
- uint worldX, worldY;
- RegionHandleToWorldLoc(handle, out worldX, out worldY);
- X = WorldToRegionLoc(worldX);
- Y = WorldToRegionLoc(worldY);
+ X = (uint)(handle >> 40) & 0x00ffffffu; // bring from higher half, divide by 256 and clean
+ Y = (uint)(handle >> 8) & 0x00ffffffu; // divide by 256 and clean
+ // if you trust the uint cast then the clean can be removed.
}
- // A region location can be 'world coordinates' (meters from zero) or 'region coordinates'
- // (number of regions from zero). This measurement of regions relies on the legacy 256 region size.
- // These routines exist to make what is being converted explicit so the next person knows what was meant.
- // Convert a region's 'world coordinate' to its 'region coordinate'.
+ // A region location can be 'world coordinates' (meters) or 'region grid coordinates'
+ // grid coordinates have a fixed step of 256m as defined by viewers
public static uint WorldToRegionLoc(uint worldCoord)
{
- return worldCoord / Constants.RegionSize;
+ return worldCoord >> 8;
}
- // Convert a region's 'region coordinate' to its 'world coordinate'.
+ // Convert a region's 'region grid coordinate' to its 'world coordinate'.
public static uint RegionToWorldLoc(uint regionCoord)
{
- return regionCoord * Constants.RegionSize;
+ return regionCoord << 8;
+ }
+
+
+ public static bool checkServiceURI(string uristr, out string serviceURI)
+ {
+ serviceURI = string.Empty;
+ try
+ {
+ Uri uri = new Uri(uristr);
+ serviceURI = uri.AbsoluteUri;
+ if(uri.Port == 80)
+ serviceURI = serviceURI.Trim(new char[] { '/', ' ' }) +":80/";
+ else if(uri.Port == 443)
+ serviceURI = serviceURI.Trim(new char[] { '/', ' ' }) +":443/";
+ return true;
+ }
+ catch
+ {
+ serviceURI = string.Empty;
+ }
+ return false;
+ }
+
+ public static bool buildHGRegionURI(string inputName, out string serverURI, out string regionName)
+ {
+ serverURI = string.Empty;
+ regionName = string.Empty;
+
+ inputName = inputName.Trim();
+
+ if (!inputName.StartsWith("http") && !inputName.StartsWith("https"))
+ {
+ // Formats: grid.example.com:8002:region name
+ // grid.example.com:region name
+ // grid.example.com:8002
+ // grid.example.com
+
+ string host;
+ uint port = 80;
+
+ string[] parts = inputName.Split(new char[] { ':' });
+ int indx;
+ if(parts.Length == 0)
+ return false;
+ if (parts.Length == 1)
+ {
+ indx = inputName.IndexOf('/');
+ if (indx < 0)
+ serverURI = "http://"+ inputName + "/";
+ else
+ {
+ serverURI = "http://"+ inputName.Substring(0,indx + 1);
+ if(indx + 2 < inputName.Length)
+ regionName = inputName.Substring(indx + 1);
+ }
+ }
+ else
+ {
+ host = parts[0];
+
+ if (parts.Length >= 2)
+ {
+ indx = parts[1].IndexOf('/');
+ if(indx < 0)
+ {
+ // If it's a number then assume it's a port. Otherwise, it's a region name.
+ if (!UInt32.TryParse(parts[1], out port))
+ {
+ port = 80;
+ regionName = parts[1];
+ }
+ }
+ else
+ {
+ string portstr = parts[1].Substring(0, indx);
+ if(indx + 2 < parts[1].Length)
+ regionName = parts[1].Substring(indx + 1);
+ if (!UInt32.TryParse(portstr, out port))
+ port = 80;
+ }
+ }
+ // always take the last one
+ if (parts.Length >= 3)
+ {
+ regionName = parts[2];
+ }
+
+ serverURI = "http://"+ host +":"+ port.ToString() + "/";
+ }
+ }
+ else
+ {
+ // Formats: http://grid.example.com region name
+ // http://grid.example.com "region name"
+ // http://grid.example.com
+
+ string[] parts = inputName.Split(new char[] { ' ' });
+
+ if (parts.Length == 0)
+ return false;
+
+ serverURI = parts[0];
+
+ int indx = serverURI.LastIndexOf('/');
+ if(indx > 10)
+ {
+ if(indx + 2 < inputName.Length)
+ regionName = inputName.Substring(indx + 1);
+ serverURI = inputName.Substring(0, indx + 1);
+ }
+ else if (parts.Length >= 2)
+ {
+ regionName = inputName.Substring(serverURI.Length);
+ }
+ }
+
+ // use better code for sanity check
+ Uri uri;
+ try
+ {
+ uri = new Uri(serverURI);
+ }
+ catch
+ {
+ return false;
+ }
+
+ if(!string.IsNullOrEmpty(regionName))
+ regionName = regionName.Trim(new char[] { '"', ' ' });
+ serverURI = uri.AbsoluteUri;
+ if(uri.Port == 80)
+ serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":80/";
+ else if(uri.Port == 443)
+ serverURI = serverURI.Trim(new char[] { '/', ' ' }) +":443/";
+ return true;
}
public static T Clamp(T x, T min, T max)
@@ -505,6 +671,7 @@ namespace OpenSim.Framework
public static string GetFormattedXml(string rawXml)
{
XmlDocument xd = new XmlDocument();
+ xd.XmlResolver=null;
xd.LoadXml(rawXml);
StringBuilder sb = new StringBuilder();
@@ -641,19 +808,25 @@ namespace OpenSim.Framework
///
///
///
+
public static string Md5Hash(string data)
{
- byte[] dataMd5 = ComputeMD5Hash(data);
+ return Md5Hash(data, Encoding.Default);
+ }
+
+ public static string Md5Hash(string data, Encoding encoding)
+ {
+ byte[] dataMd5 = ComputeMD5Hash(data, encoding);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < dataMd5.Length; i++)
sb.AppendFormat("{0:x2}", dataMd5[i]);
return sb.ToString();
}
- private static byte[] ComputeMD5Hash(string data)
+ private static byte[] ComputeMD5Hash(string data, Encoding encoding)
{
MD5 md5 = MD5.Create();
- return md5.ComputeHash(Encoding.Default.GetBytes(data));
+ return md5.ComputeHash(encoding.GetBytes(data));
}
///
@@ -661,6 +834,12 @@ namespace OpenSim.Framework
///
///
///
+
+ public static string SHA1Hash(string data, Encoding enc)
+ {
+ return SHA1Hash(enc.GetBytes(data));
+ }
+
public static string SHA1Hash(string data)
{
return SHA1Hash(Encoding.Default.GetBytes(data));
@@ -679,8 +858,10 @@ namespace OpenSim.Framework
private static byte[] ComputeSHA1Hash(byte[] src)
{
- SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider();
- return SHA1.ComputeHash(src);
+ byte[] ret;
+ using(SHA1CryptoServiceProvider SHA1 = new SHA1CryptoServiceProvider())
+ ret = SHA1.ComputeHash(src);
+ return ret;
}
public static int fast_distance2d(int x, int y)
@@ -713,18 +894,27 @@ namespace OpenSim.Framework
/// New region x-coord
/// Old region y-coord
/// New region y-coord
- ///
- public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy)
- {
- int dd = (int)((drawdist + Constants.RegionSize - 1) / Constants.RegionSize);
-
- int startX = (int)oldx - dd;
- int startY = (int)oldy - dd;
+ ///
+ public static bool IsOutsideView(float drawdist, uint oldx, uint newx, uint oldy, uint newy,
+ int oldsizex, int oldsizey, int newsizex, int newsizey)
+ {
+ // we still need to make sure we see new region 1stNeighbors
+ drawdist--;
+ oldx *= Constants.RegionSize;
+ newx *= Constants.RegionSize;
+ if (oldx + oldsizex + drawdist < newx)
+ return true;
+ if (newx + newsizex + drawdist < oldx)
+ return true;
- int endX = (int)oldx + dd;
- int endY = (int)oldy + dd;
+ oldy *= Constants.RegionSize;
+ newy *= Constants.RegionSize;
+ if (oldy + oldsizey + drawdist < newy)
+ return true;
+ if (newy + newsizey + drawdist < oldy)
+ return true;
- return (newx < startX || endX < newx || newy < startY || endY < newy);
+ return false;
}
public static string FieldToString(byte[] bytes)
@@ -804,6 +994,18 @@ namespace OpenSim.Framework
return output.ToString();
}
+ private static ExpiringCache dnscache = new ExpiringCache();
+
+ ///
+ /// Converts a URL to a IPAddress
+ ///
+ /// URL Standard Format
+ /// A resolved IP Address
+ public static IPAddress GetHostFromURL(string url)
+ {
+ return GetHostFromDNS(url.Split(new char[] {'/', ':'})[3]);
+ }
+
///
/// Returns a IP address from a specified DNS, favouring IPv4 addresses.
///
@@ -811,38 +1013,128 @@ namespace OpenSim.Framework
/// An IP address, or null
public static IPAddress GetHostFromDNS(string dnsAddress)
{
- // Is it already a valid IP? No need to look it up.
- IPAddress ipa;
- if (IPAddress.TryParse(dnsAddress, out ipa))
- return ipa;
+ if(String.IsNullOrWhiteSpace(dnsAddress))
+ return null;
- IPAddress[] hosts = null;
+ IPAddress ia = null;
+ if(dnscache.TryGetValue(dnsAddress, out ia) && ia != null)
+ {
+ dnscache.AddOrUpdate(dnsAddress, ia, 300);
+ return ia;
+ }
- // Not an IP, lookup required
+ ia = null;
+ // If it is already an IP, don't let GetHostEntry see it
+ if (IPAddress.TryParse(dnsAddress, out ia) && ia != null)
+ {
+ if (ia.Equals(IPAddress.Any) || ia.Equals(IPAddress.IPv6Any))
+ return null;
+ dnscache.AddOrUpdate(dnsAddress, ia, 300);
+ return ia;
+ }
+
+ IPHostEntry IPH;
try
{
- hosts = Dns.GetHostEntry(dnsAddress).AddressList;
+ IPH = Dns.GetHostEntry(dnsAddress);
}
- catch (Exception e)
+ catch // (SocketException e)
+ {
+ return null;
+ }
+
+ if(IPH == null || IPH.AddressList.Length == 0)
+ return null;
+
+ ia = null;
+ foreach (IPAddress Adr in IPH.AddressList)
{
- m_log.WarnFormat("[UTIL]: An error occurred while resolving host name {0}, {1}", dnsAddress, e);
+ if (ia == null)
+ ia = Adr;
- // Still going to throw the exception on for now, since this was what was happening in the first place
- throw e;
+ if (Adr.AddressFamily == AddressFamily.InterNetwork)
+ {
+ ia = Adr;
+ break;
+ }
}
+ if(ia != null)
+ dnscache.AddOrUpdate(dnsAddress, ia, 300);
+ return ia;
+ }
- foreach (IPAddress host in hosts)
+ public static IPEndPoint getEndPoint(IPAddress ia, int port)
+ {
+ if(ia == null)
+ return null;
+
+ IPEndPoint newEP = null;
+ try
+ {
+ newEP = new IPEndPoint(ia, port);
+ }
+ catch
+ {
+ newEP = null;
+ }
+ return newEP;
+ }
+
+ public static IPEndPoint getEndPoint(string hostname, int port)
+ {
+ if(String.IsNullOrWhiteSpace(hostname))
+ return null;
+
+ IPAddress ia = null;
+ if(dnscache.TryGetValue(hostname, out ia) && ia != null)
+ {
+ dnscache.AddOrUpdate(hostname, ia, 300);
+ return getEndPoint(ia, port);
+ }
+
+ ia = null;
+
+ // If it is already an IP, don't let GetHostEntry see it
+ if (IPAddress.TryParse(hostname, out ia) && ia != null)
+ {
+ if (ia.Equals(IPAddress.Any) || ia.Equals(IPAddress.IPv6Any))
+ return null;
+
+ dnscache.AddOrUpdate(hostname, ia, 300);
+ return getEndPoint(ia, port);
+ }
+
+
+ IPHostEntry IPH;
+ try
+ {
+ IPH = Dns.GetHostEntry(hostname);
+ }
+ catch // (SocketException e)
+ {
+ return null;
+ }
+
+ if(IPH == null || IPH.AddressList.Length == 0)
+ return null;
+
+ ia = null;
+ foreach (IPAddress Adr in IPH.AddressList)
{
- if (host.AddressFamily == AddressFamily.InterNetwork)
+ if (ia == null)
+ ia = Adr;
+
+ if (Adr.AddressFamily == AddressFamily.InterNetwork)
{
- return host;
+ ia = Adr;
+ break;
}
}
- if (hosts.Length > 0)
- return hosts[0];
+ if(ia != null)
+ dnscache.AddOrUpdate(hostname, ia, 300);
- return null;
+ return getEndPoint(ia,port);
}
public static Uri GetURI(string protocol, string hostname, int port, string path)
@@ -987,7 +1279,7 @@ namespace OpenSim.Framework
public static string configDir()
{
- return "../config";
+ return ".";
}
public static string dataDir()
@@ -999,13 +1291,26 @@ namespace OpenSim.Framework
{
foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
{
- if (appender is FileAppender)
+ if (appender is FileAppender && appender.Name == "LogFileAppender")
{
return ((FileAppender)appender).File;
}
}
- return "../logs/OpenSim.log";
+ return "./OpenSim.log";
+ }
+
+ public static string statsLogFile()
+ {
+ foreach (IAppender appender in LogManager.GetRepository().GetAppenders())
+ {
+ if (appender is FileAppender && appender.Name == "StatsLogFileAppender")
+ {
+ return ((FileAppender)appender).File;
+ }
+ }
+
+ return "./OpenSimStats.log";
}
public static string logDir()
@@ -1065,9 +1370,28 @@ namespace OpenSim.Framework
}
}
+ public static string GetConfigVarWithDefaultSection(IConfigSource config, string varname, string section)
+ {
+ // First, check the Startup section, the default section
+ IConfig cnf = config.Configs["Startup"];
+ if (cnf == null)
+ return string.Empty;
+ string val = cnf.GetString(varname, string.Empty);
+
+ // Then check for an overwrite of the default in the given section
+ if (!string.IsNullOrEmpty(section))
+ {
+ cnf = config.Configs[section];
+ if (cnf != null)
+ val = cnf.GetString(varname, val);
+ }
+
+ return val;
+ }
+
///
/// Gets the value of a configuration variable by looking into
- /// multiple sections in order. The latter sections overwrite
+ /// multiple sections in order. The latter sections overwrite
/// any values previously found.
///
/// Type of the variable
@@ -1082,7 +1406,7 @@ namespace OpenSim.Framework
///
/// Gets the value of a configuration variable by looking into
- /// multiple sections in order. The latter sections overwrite
+ /// multiple sections in order. The latter sections overwrite
/// any values previously found.
///
///
@@ -1138,7 +1462,7 @@ namespace OpenSim.Framework
ConfigSource.ExpandKeyValues();
}
}
-
+
public static T ReadSettingsFromIniFile(IConfig config, T settingsClass)
{
Type settingsType = settingsClass.GetType();
@@ -1249,7 +1573,7 @@ namespace OpenSim.Framework
if (File.Exists(configFile))
{
- // Merge
+ // Merge
config.Merge(new IniConfigSource(configFile));
config.ExpandKeyValues();
configFilePath = configFile;
@@ -1388,6 +1712,46 @@ namespace OpenSim.Framework
return ret;
}
+ public static string Compress(string text)
+ {
+ byte[] buffer = Util.UTF8.GetBytes(text);
+ MemoryStream memory = new MemoryStream();
+ using (GZipStream compressor = new GZipStream(memory, CompressionMode.Compress, true))
+ {
+ compressor.Write(buffer, 0, buffer.Length);
+ }
+
+ memory.Position = 0;
+
+ byte[] compressed = new byte[memory.Length];
+ memory.Read(compressed, 0, compressed.Length);
+
+ byte[] compressedBuffer = new byte[compressed.Length + 4];
+ Buffer.BlockCopy(compressed, 0, compressedBuffer, 4, compressed.Length);
+ Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, compressedBuffer, 0, 4);
+ return Convert.ToBase64String(compressedBuffer);
+ }
+
+ public static string Decompress(string compressedText)
+ {
+ byte[] compressedBuffer = Convert.FromBase64String(compressedText);
+ using (MemoryStream memory = new MemoryStream())
+ {
+ int msgLength = BitConverter.ToInt32(compressedBuffer, 0);
+ memory.Write(compressedBuffer, 4, compressedBuffer.Length - 4);
+
+ byte[] buffer = new byte[msgLength];
+
+ memory.Position = 0;
+ using (GZipStream decompressor = new GZipStream(memory, CompressionMode.Decompress))
+ {
+ decompressor.Read(buffer, 0, buffer.Length);
+ }
+
+ return Util.UTF8.GetString(buffer);
+ }
+ }
+
///
/// Copy data from one stream to another, leaving the read position of both streams at the beginning.
///
@@ -1405,7 +1769,7 @@ namespace OpenSim.Framework
const int readSize = 256;
byte[] buffer = new byte[readSize];
MemoryStream ms = new MemoryStream();
-
+
int count = inputStream.Read(buffer, 0, readSize);
while (count > 0)
@@ -1485,12 +1849,16 @@ namespace OpenSim.Framework
return new UUID(bytes, 0);
}
- public static void ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y)
+ public static bool ParseFakeParcelID(UUID parcelID, out ulong regionHandle, out uint x, out uint y)
{
byte[] bytes = parcelID.GetBytes();
regionHandle = Utils.BytesToUInt64(bytes);
x = Utils.BytesToUInt(bytes, 8) & 0xffff;
y = Utils.BytesToUInt(bytes, 12) & 0xffff;
+ // validation may fail, just reducing the odds of using a real UUID as encoded parcel
+ return ( bytes[0] == 0 && bytes[4] == 0 && // handler x,y multiples of 256
+ bytes[9] < 64 && bytes[13] < 64 && // positions < 16km
+ bytes[14] == 0 && bytes[15] == 0);
}
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
x += rx;
y += ry;
}
-
+
///
/// Get operating system information if available. Returns only the first 45 characters of information
///
@@ -1524,20 +1892,20 @@ namespace OpenSim.Framework
{
string os = String.Empty;
- if (Environment.OSVersion.Platform != PlatformID.Unix)
- {
- os = Environment.OSVersion.ToString();
- }
- else
- {
- os = ReadEtcIssue();
- }
-
- if (os.Length > 45)
- {
- os = os.Substring(0, 45);
- }
-
+// if (Environment.OSVersion.Platform != PlatformID.Unix)
+// {
+// os = Environment.OSVersion.ToString();
+// }
+// else
+// {
+// os = ReadEtcIssue();
+// }
+//
+// if (os.Length > 45)
+// {
+// os = os.Substring(0, 45);
+// }
+
return os;
}
@@ -1579,6 +1947,8 @@ namespace OpenSim.Framework
// hide the password in the connection string
passPosition = connectionString.IndexOf("password", StringComparison.OrdinalIgnoreCase);
+ if (passPosition == -1)
+ return connectionString;
passPosition = connectionString.IndexOf("=", passPosition);
if (passPosition < connectionString.Length)
passPosition += 1;
@@ -1645,7 +2015,7 @@ namespace OpenSim.Framework
public static Guid GetHashGuid(string data, string salt)
{
- byte[] hash = ComputeMD5Hash(data + salt);
+ byte[] hash = ComputeMD5Hash(data + salt, Encoding.Default);
//string s = BitConverter.ToString(hash);
@@ -1747,7 +2117,7 @@ namespace OpenSim.Framework
vol = vcomps[0];
}
}
-
+
string[] comps = path.Split(new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, StringSplitOptions.RemoveEmptyEntries);
// Glob
@@ -1792,6 +2162,32 @@ namespace OpenSim.Framework
return found.ToArray();
}
+ public static string ServerURI(string uri)
+ {
+ if (uri == string.Empty)
+ return string.Empty;
+
+ // Get rid of eventual slashes at the end
+ uri = uri.TrimEnd('/');
+
+ IPAddress ipaddr1 = null;
+ string port1 = "";
+ try
+ {
+ ipaddr1 = Util.GetHostFromURL(uri);
+ }
+ catch { }
+
+ try
+ {
+ port1 = uri.Split(new char[] { ':' })[2];
+ }
+ catch { }
+
+ // We tried our best to convert the domain names to IP addresses
+ return (ipaddr1 != null) ? "http://" + ipaddr1.ToString() + ":" + port1 : uri;
+ }
+
///
/// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to 256 bytes if necessary.
///
@@ -1823,14 +2219,14 @@ namespace OpenSim.Framework
if (!str.EndsWith("\0"))
str += "\0";
-
+
// Because this is UTF-8 encoding and not ASCII, it's possible we
// might have gotten an oversized array even after the string trim
byte[] data = UTF8.GetBytes(str);
- if (data.Length > 256)
+ if (data.Length > 255) //play safe
{
- int cut = 255;
+ int cut = 254;
if((data[cut] & 0x80 ) != 0 )
{
while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
@@ -1895,6 +2291,56 @@ namespace OpenSim.Framework
}
///
+ /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to MaxLength bytes if necessary.
+ ///
+ ///
+ /// If null or empty, then an bytes[0] is returned.
+ /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
+ ///
+ ///
+ /// Arguments to substitute into the string via the {} mechanism.
+ ///
+ ///
+ public static byte[] StringToBytes(string str, int MaxLength, params object[] args)
+ {
+ return StringToBytes1024(string.Format(str, args), MaxLength);
+ }
+
+ ///
+ /// Convert a string to a byte format suitable for transport in an LLUDP packet. The output is truncated to MaxLength bytes if necessary.
+ ///
+ ///
+ /// If null or empty, then an bytes[0] is returned.
+ /// Using "\0" will return a conversion of the null character to a byte. This is not the same as bytes[0]
+ ///
+ ///
+ public static byte[] StringToBytes(string str, int MaxLength)
+ {
+ if (String.IsNullOrEmpty(str))
+ return Utils.EmptyBytes;
+
+ if (!str.EndsWith("\0"))
+ str += "\0";
+
+ // Because this is UTF-8 encoding and not ASCII, it's possible we
+ // might have gotten an oversized array even after the string trim
+ byte[] data = UTF8.GetBytes(str);
+
+ if (data.Length > MaxLength)
+ {
+ int cut = MaxLength - 1 ;
+ if((data[cut] & 0x80 ) != 0 )
+ {
+ while(cut > 0 && (data[cut] & 0xc0) != 0xc0)
+ cut--;
+ }
+ Array.Resize(ref data, cut + 1);
+ data[cut] = 0;
+ }
+
+ return data;
+ }
+ ///
/// Pretty format the hashtable contents to a single line.
///
///
@@ -2004,7 +2450,7 @@ namespace OpenSim.Framework
STPStartInfo startInfo = new STPStartInfo();
startInfo.ThreadPoolName = "Util";
- startInfo.IdleTimeout = 2000;
+ startInfo.IdleTimeout = 20000;
startInfo.MaxWorkerThreads = maxThreads;
startInfo.MinWorkerThreads = minThreads;
@@ -2032,7 +2478,7 @@ namespace OpenSim.Framework
throw new NotImplementedException();
}
}
-
+
///
/// Additional information about threads in the main thread pool. Used to time how long the
/// thread has been running, and abort it if it has timed-out.
@@ -2043,14 +2489,15 @@ namespace OpenSim.Framework
public string StackTrace { get; set; }
private string context;
public bool LogThread { get; set; }
-
+
public IWorkItemResult WorkItem { get; set; }
public Thread Thread { get; set; }
public bool Running { get; set; }
public bool Aborted { get; set; }
private int started;
+ public bool DoTimeout;
- public ThreadInfo(long threadFuncNum, string context)
+ public ThreadInfo(long threadFuncNum, string context, bool dotimeout = true)
{
ThreadFuncNum = threadFuncNum;
this.context = context;
@@ -2058,6 +2505,7 @@ namespace OpenSim.Framework
Thread = null;
Running = false;
Aborted = false;
+ DoTimeout = dotimeout;
}
public void Started()
@@ -2128,7 +2576,7 @@ namespace OpenSim.Framework
foreach (KeyValuePair entry in activeThreads)
{
ThreadInfo t = entry.Value;
- if (t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT))
+ if (t.DoTimeout && t.Running && !t.Aborted && (t.Elapsed() >= THREAD_TIMEOUT))
{
m_log.WarnFormat("Timeout in threadfunc {0} ({1}) {2}", t.ThreadFuncNum, t.Thread.Name, t.GetStackTrace());
t.Abort();
@@ -2138,7 +2586,7 @@ namespace OpenSim.Framework
// It's possible that the thread won't abort. To make sure the thread pool isn't
// depleted, increase the pool size.
- m_ThreadPool.MaxThreads++;
+// m_ThreadPool.MaxThreads++;
}
}
}
@@ -2148,7 +2596,7 @@ namespace OpenSim.Framework
public static Dictionary GetFireAndForgetCallsMade()
{
return new Dictionary(m_fireAndForgetCallsMade);
- }
+ }
private static Dictionary m_fireAndForgetCallsMade = new Dictionary();
@@ -2168,11 +2616,11 @@ namespace OpenSim.Framework
{
FireAndForget(callback, obj, null);
}
-
- public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context)
+
+ public static void FireAndForget(System.Threading.WaitCallback callback, object obj, string context, bool dotimeout = true)
{
Interlocked.Increment(ref numTotalThreadFuncsCalled);
-
+/*
if (context != null)
{
if (!m_fireAndForgetCallsMade.ContainsKey(context))
@@ -2185,25 +2633,25 @@ namespace OpenSim.Framework
else
m_fireAndForgetCallsInProgress[context]++;
}
-
+*/
WaitCallback realCallback;
bool loggingEnabled = LogThreadPool > 0;
-
+
long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum);
- ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context);
+ ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context, dotimeout);
if (FireAndForgetMethod == FireAndForgetMethod.RegressionTest)
{
// If we're running regression tests, then we want any exceptions to rise up to the test code.
- realCallback =
- o =>
- {
- Culture.SetCurrentCulture();
- callback(o);
-
- if (context != null)
- m_fireAndForgetCallsInProgress[context]--;
+ realCallback =
+ o =>
+ {
+ Culture.SetCurrentCulture();
+ callback(o);
+
+// if (context != null)
+// m_fireAndForgetCallsInProgress[context]--;
};
}
else
@@ -2229,7 +2677,6 @@ namespace OpenSim.Framework
}
catch (ThreadAbortException e)
{
- m_log.Error(string.Format("Aborted threadfunc {0} ", threadFuncNum), e);
}
catch (Exception e)
{
@@ -2244,8 +2691,8 @@ namespace OpenSim.Framework
if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed()));
- if (context != null)
- m_fireAndForgetCallsInProgress[context]--;
+// if (context != null)
+// m_fireAndForgetCallsInProgress[context]--;
}
};
}
@@ -2253,6 +2700,7 @@ namespace OpenSim.Framework
long numQueued = Interlocked.Increment(ref numQueuedThreadFuncs);
try
{
+/*
long numRunning = numRunningThreadFuncs;
if (m_ThreadPool != null && LogOverloads)
@@ -2285,6 +2733,7 @@ namespace OpenSim.Framework
}
}
else
+*/
{
// Since we didn't log "Queue threadfunc", don't log "Run threadfunc" or "End threadfunc" either.
// Those log lines aren't useful when we don't know which function is running in the thread.
@@ -2342,7 +2791,7 @@ namespace OpenSim.Framework
if (stackTrace.Contains("BeginFireQueueEmpty"))
return false;
}
-
+
return true;
}
@@ -2355,7 +2804,7 @@ namespace OpenSim.Framework
{
string src = Environment.StackTrace;
string[] lines = src.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
-
+
StringBuilder dest = new StringBuilder(src.Length);
bool started = false;
@@ -2400,11 +2849,11 @@ namespace OpenSim.Framework
/// trace. And pausing another thread can cause a deadlock. This method attempts to
/// avoid deadlock by using a short timeout (200ms), after which it gives up and
/// returns 'null' instead of the stack trace.
- ///
+ ///
/// Take from: http://stackoverflow.com/a/14935378
- ///
+ ///
/// WARNING: this doesn't work in Mono. See https://bugzilla.novell.com/show_bug.cgi?id=571691
- ///
+ ///
///
/// The stack trace, or null if failed to get it
private static StackTrace GetStackTrace(Thread targetThread)
@@ -2500,12 +2949,22 @@ namespace OpenSim.Framework
return stpi;
}
+ public static void StopThreadPool()
+ {
+ if (m_ThreadPool == null)
+ return;
+ SmartThreadPool pool = m_ThreadPool;
+ m_ThreadPool = null;
+
+ try { pool.Shutdown(); } catch {}
+ }
+
#endregion FireAndForget Threading Pattern
///
/// Environment.TickCount is an int but it counts all 32 bits so it goes positive
/// and negative every 24.9 days. This trims down TickCount so it doesn't wrap
- /// for the callers.
+ /// for the callers.
/// This trims it to a 12 day interval so don't let your frame time get too long.
///
///
@@ -2513,6 +2972,7 @@ namespace OpenSim.Framework
{
return Environment.TickCount & EnvironmentTickCountMask;
}
+
const Int32 EnvironmentTickCountMask = 0x3fffffff;
///
@@ -2557,6 +3017,18 @@ namespace OpenSim.Framework
return tcA - tcB;
}
+ // returns a timestamp in ms as double
+ // using the time resolution avaiable to StopWatch
+ public static double GetTimeStamp()
+ {
+ return (double)Stopwatch.GetTimestamp() * TimeStampClockPeriod;
+ }
+
+ public static double GetTimeStampMS()
+ {
+ return (double)Stopwatch.GetTimestamp() * TimeStampClockPeriodMS;
+ }
+
///
/// Formats a duration (given in milliseconds).
///
@@ -2855,7 +3327,7 @@ namespace OpenSim.Framework
if (parts.Length == 2)
return CalcUniversalIdentifier(id, agentsURI, parts[0] + " " + parts[1]);
}
-
+
return CalcUniversalIdentifier(id, agentsURI, firstName + " " + lastName);
}
@@ -2940,6 +3412,7 @@ namespace OpenSim.Framework
}
+/* don't like this code
public class DoubleQueue where T:class
{
private Queue m_lowQueue = new Queue();
@@ -2954,10 +3427,10 @@ namespace OpenSim.Framework
public virtual int Count
{
- get
- {
+ get
+ {
lock (m_syncRoot)
- return m_highQueue.Count + m_lowQueue.Count;
+ return m_highQueue.Count + m_lowQueue.Count;
}
}
@@ -3051,7 +3524,7 @@ namespace OpenSim.Framework
}
}
}
-
+*/
public class BetterRandom
{
private const int BufferSize = 1024; // must be a multiple of 4
--
cgit v1.1