diff options
author | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2019-08-14 22:50:43 +0800 |
commit | 15740faf9fe9fe4be08965098bbf2947e096aeeb (patch) | |
tree | a730ec236656cc8cab5b13f088adfaed6bb218fb /Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs |
Diffstat (limited to 'Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs')
-rw-r--r-- | Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs | 503 |
1 files changed, 503 insertions, 0 deletions
diff --git a/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs new file mode 100644 index 0000000..61b254f --- /dev/null +++ b/Runtime/Managed/CrossDomainPolicyParser/Mono.Forks/IPAddress.cs @@ -0,0 +1,503 @@ +// +// System.Net.IPAddress.cs +// +// Author: +// Miguel de Icaza (miguel@ximian.com) +// Lawrence Pit (loz@cable.a2000.nl) +// +// (C) Ximian, Inc. http://www.ximian.com +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// + +using System; +using System.Globalization; +using MonoForks.System; +using MonoForks.System.Net; +using MonoForks.System.Net.Sockets; +using System.Runtime.InteropServices; + +namespace MonoForks.System.Net { + + /// <remarks> + /// Encapsulates an IP Address. + /// </remarks> + [Serializable] + public class IPAddress { + // Don't change the name of this field without also + // changing socket-io.c in the runtime + // The IP address is stored in little-endian order inside the int, + // meaning the lower order bytes contain the netid + private long m_Address; + private AddressFamily m_Family; + private ushort[] m_Numbers; /// ip6 Stored in network order (as ip4) + private long m_ScopeId; + + public static readonly IPAddress Any = new IPAddress(0); + public static readonly IPAddress Broadcast = IPAddress.Parse ("255.255.255.255"); + public static readonly IPAddress Loopback = IPAddress.Parse ("127.0.0.1"); + public static readonly IPAddress None = IPAddress.Parse ("255.255.255.255"); + public static readonly IPAddress IPv6Any = IPAddress.ParseIPV6 ("::"); + public static readonly IPAddress IPv6Loopback = IPAddress.ParseIPV6 ("::1"); + public static readonly IPAddress IPv6None = IPAddress.ParseIPV6 ("::"); + + private static short SwapShort (short number) + { + return (short) ( ((number >> 8) & 0xFF) | ((number << 8) & 0xFF00) ); + } + + private static int SwapInt (int number) + { + return (((number >> 24) & 0xFF) + | ((number >> 08) & 0xFF00) + | ((number << 08) & 0xFF0000) + | ((number << 24))); + } + + private static long SwapLong(long number) + { + return (((number >> 56) & 0xFF) + | ((number >> 40) & 0xFF00) + | ((number >> 24) & 0xFF0000) + | ((number >> 08) & 0xFF000000) + | ((number << 08) & 0xFF00000000) + | ((number << 24) & 0xFF0000000000) + | ((number << 40) & 0xFF000000000000) + | ((number << 56))); + } + + public static short HostToNetworkOrder(short host) { + if (!BitConverter.IsLittleEndian) + return(host); + + return SwapShort (host); + } + + public static int HostToNetworkOrder(int host) { + if (!BitConverter.IsLittleEndian) + return(host); + + return SwapInt (host); + } + + public static long HostToNetworkOrder(long host) { + if (!BitConverter.IsLittleEndian) + return(host); + + return SwapLong (host); + } + + public static short NetworkToHostOrder(short network) { + if (!BitConverter.IsLittleEndian) + return(network); + + return SwapShort (network); + } + + public static int NetworkToHostOrder(int network) { + if (!BitConverter.IsLittleEndian) + return(network); + + return SwapInt (network); + } + + public static long NetworkToHostOrder(long network) { + if (!BitConverter.IsLittleEndian) + return(network); + + return SwapLong (network); + } + + /// <summary> + /// Constructor from a 32-bit constant with the address bytes in + /// little-endian order (the lower order bytes contain the netid) + /// </summary> + public IPAddress (long addr) + { + m_Address = addr; + m_Family = AddressFamily.InterNetwork; + } + + public IPAddress (byte[] address) + { + if (address == null) + throw new ArgumentNullException ("address"); + + int len = address.Length; + +#if NET_2_0 + if (len != 16 && len != 4) + throw new ArgumentException ("An invalid IP address was specified.", + "address"); +#else + if (len != 16) + throw new ArgumentException ("address"); +#endif + + if (len == 16) { + m_Numbers = new ushort [8]; + Buffer.BlockCopy(address, 0, m_Numbers, 0, 16); + m_Family = AddressFamily.InterNetworkV6; + m_ScopeId = 0; + } else { + m_Address = ((uint) address [3] << 24) + (address [2] << 16) + + (address [1] << 8) + address [0]; + m_Family = AddressFamily.InterNetwork; + } + } + + public IPAddress(byte[] address, long scopeId) + { + if (address == null) + throw new ArgumentNullException ("address"); + + if (address.Length != 16) +#if NET_2_0 + throw new ArgumentException ("An invalid IP address was specified.", + "address"); +#else + throw new ArgumentException("address"); +#endif + + m_Numbers = new ushort [8]; + Buffer.BlockCopy(address, 0, m_Numbers, 0, 16); + m_Family = AddressFamily.InterNetworkV6; + m_ScopeId = scopeId; + } + + internal IPAddress(ushort[] address, long scopeId) + { + m_Numbers = address; + + for(int i=0; i<8; i++) + m_Numbers[i] = (ushort)HostToNetworkOrder((short)m_Numbers[i]); + + m_Family = AddressFamily.InterNetworkV6; + m_ScopeId = scopeId; + } + + public static IPAddress Parse (string ipString) + { + IPAddress ret; + if (TryParse (ipString, out ret)) + return ret; + throw new FormatException ("An invalid IP address was specified."); + } + +#if NET_2_0 + public +#else + internal +#endif + static bool TryParse (string ipString, out IPAddress address) + { + if (ipString == null) + throw new ArgumentNullException ("ipString"); + + if ((address = ParseIPV4 (ipString)) == null) + if ((address = ParseIPV6 (ipString)) == null) + return false; + return true; + } + + private static IPAddress ParseIPV4 (string ip) + { +#if ONLY_1_1 + if (ip.Length == 0 || ip == " ") + return new IPAddress (0); +#endif + + int pos = ip.IndexOf (' '); + if (pos != -1) { +#if NET_2_0 + string [] nets = ip.Substring (pos + 1).Split (new char [] {'.'}); + if (nets.Length > 0) { + string lastNet = nets [nets.Length - 1]; + if (lastNet.Length == 0) + return null; +#if NET_2_1 //workaround for smcs, as it generate code that can't access string.GetEnumerator () + foreach (char c in lastNet.ToCharArray ()) +#else + foreach (char c in lastNet) +#endif + if (!Uri.IsHexDigit (c)) + return null; + } +#endif + ip = ip.Substring (0, pos); + } + + if (ip.Length == 0 || ip [ip.Length - 1] == '.') + return null; + + string [] ips = ip.Split (new char [] {'.'}); + if (ips.Length > 4) + return null; + + // Make the number in network order + try { + long a = 0; + long val = 0; + for (int i = 0; i < ips.Length; i++) { + string subnet = ips [i]; + if ((3 <= subnet.Length && subnet.Length <= 4) && + (subnet [0] == '0') && (subnet [1] == 'x' || subnet [1] == 'X')) { + if (subnet.Length == 3) + val = (byte) Uri.FromHex (subnet [2]); + else + val = (byte) ((Uri.FromHex (subnet [2]) << 4) | Uri.FromHex (subnet [3])); + } else if (subnet.Length == 0) + return null; + else if (subnet [0] == '0') { + // octal + val = 0; + for (int j = 1; j < subnet.Length; j++) { + if ('0' <= subnet [j] && subnet [j] <= '7') + val = (val << 3) + subnet [j] - '0'; + else + return null; + } + } + else { +#if NET_2_0 + if (!Int64.TryParse (subnet, NumberStyles.None, null, out val)) + return null; +#else + val = long.Parse (subnet, NumberStyles.None); +#endif + } + + if (i == (ips.Length - 1)) + i = 3; + else if (val > 0xFF) + return null; // e.g. 256.0.0.1 + for (int j = 0; val > 0; j++, val /= 0x100) + a |= (val & 0xFF) << ((i - j) << 3); + } + + return (new IPAddress (a)); + } catch (Exception) { + return null; + } + } + + private static IPAddress ParseIPV6 (string ip) + { + IPv6Address newIPv6Address; + + if (IPv6Address.TryParse(ip, out newIPv6Address)) + return new IPAddress (newIPv6Address.Address, newIPv6Address.ScopeId); + return null; + } + + [Obsolete("This property is obsolete. Use GetAddressBytes.")] + public long Address + { + get { + if(m_Family != AddressFamily.InterNetwork) + throw new Exception("The attempted operation is not supported for the type of object referenced"); + + return m_Address; + } + set { + /* no need to do this test, ms.net accepts any value. + if (value < 0 || value > 0x00000000FFFFFFFF) + throw new ArgumentOutOfRangeException ( + "the address must be between 0 and 0xFFFFFFFF"); + */ + + if(m_Family != AddressFamily.InterNetwork) + throw new Exception("The attempted operation is not supported for the type of object referenced"); + + m_Address = value; + } + } + + internal long InternalIPv4Address { + get { return m_Address; } + } + +#if NET_2_0 + public bool IsIPv6LinkLocal { + get { + if (m_Family == AddressFamily.InterNetwork) + return false; + int v = NetworkToHostOrder ((short) m_Numbers [0]) & 0xFFF0; + return 0xFE80 <= v && v < 0xFEC0; + } + } + + public bool IsIPv6SiteLocal { + get { + if (m_Family == AddressFamily.InterNetwork) + return false; + int v = NetworkToHostOrder ((short) m_Numbers [0]) & 0xFFF0; + return 0xFEC0 <= v && v < 0xFF00; + } + } + + public bool IsIPv6Multicast { + get { + return m_Family != AddressFamily.InterNetwork && + ((ushort) NetworkToHostOrder ((short) m_Numbers [0]) & 0xFF00) == 0xFF00; + } + } +#endif + + public long ScopeId { + get { + if(m_Family != AddressFamily.InterNetworkV6) + throw new Exception("The attempted operation is not supported for the type of object referenced"); + + return m_ScopeId; + } + set { + if(m_Family != AddressFamily.InterNetworkV6) + throw new Exception("The attempted operation is not supported for the type of object referenced"); + + m_ScopeId = value; + } + } + + public byte [] GetAddressBytes () + { + if(m_Family == AddressFamily.InterNetworkV6) { + byte [] addressBytes = new byte [16]; + Buffer.BlockCopy (m_Numbers, 0, addressBytes, 0, 16); + return addressBytes; + } else { + return new byte [4] { (byte)(m_Address & 0xFF), + (byte)((m_Address >> 8) & 0xFF), + (byte)((m_Address >> 16) & 0xFF), + (byte)(m_Address >> 24) }; + } + } + + public AddressFamily AddressFamily + { + get { + return m_Family; + } + } + + + /// <summary> + /// Used to tell whether an address is a loopback. + /// All IP addresses of the form 127.X.Y.Z, where X, Y, and Z are in + /// the range 0-255, are loopback addresses. + /// </summary> + /// <param name="addr">Address to compare</param> + /// <returns></returns> + public static bool IsLoopback (IPAddress addr) + { + if(addr.m_Family == AddressFamily.InterNetwork) + return (addr.m_Address & 0xFF) == 127; + else { + for(int i=0; i<6; i++) { + if(addr.m_Numbers[i] != 0) + return false; + } + + return NetworkToHostOrder((short)addr.m_Numbers[7]) == 1; + } + } + + /// <summary> + /// Overrides System.Object.ToString to return + /// this object rendered in a quad-dotted notation + /// </summary> + public override string ToString () + { + if(m_Family == AddressFamily.InterNetwork) + return ToString (m_Address); + else + { + ushort[] numbers = m_Numbers.Clone() as ushort[]; + + for(int i=0; i<numbers.Length; i++) + numbers[i] = (ushort)NetworkToHostOrder((short)numbers[i]); + + IPv6Address v6 = new IPv6Address(numbers); + v6.ScopeId = ScopeId; + return v6.ToString(); + } + } + + /// <summary> + /// Returns this object rendered in a quad-dotted notation + /// </summary> + static string ToString (long addr) + { + // addr is in network order + return (addr & 0xff).ToString () + "." + + ((addr >> 8) & 0xff).ToString () + "." + + ((addr >> 16) & 0xff).ToString () + "." + + ((addr >> 24) & 0xff).ToString (); + } + + /// <returns> + /// Whether both objects are equal. + /// </returns> + public override bool Equals (object other) + { + if (other is System.Net.IPAddress){ + IPAddress otherAddr = other as IPAddress; + + if(AddressFamily != otherAddr.AddressFamily) + return false; + + if(AddressFamily == AddressFamily.InterNetwork) { + return m_Address == otherAddr.m_Address; + } else { + ushort[] vals = otherAddr.m_Numbers; + + for(int i=0; i<8; i++) + if(m_Numbers[i] != vals[i]) + return false; + + return true; + } + } + return false; + } + + public override int GetHashCode () + { + if(m_Family == AddressFamily.InterNetwork) + return (int)m_Address; + else + return Hash (((((int) m_Numbers[0]) << 16) + m_Numbers [1]), + ((((int) m_Numbers [2]) << 16) + m_Numbers [3]), + ((((int) m_Numbers [4]) << 16) + m_Numbers [5]), + ((((int) m_Numbers [6]) << 16) + m_Numbers [7])); + } + + private static int Hash (int i, int j, int k, int l) + { + return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25); + } + +#pragma warning disable 169 + // Added for serialization compatibility with MS.NET + private int m_HashCode; +#pragma warning restore + + } +} |