/////////////////////////////////////////////////////////////////////////////// // // Microsoft Research Singularity / Netstack // // Copyright (c) Microsoft Corporation. All rights reserved. // // File: IPv4.cs // using System; namespace System.Net.IP { /// /// IPv4 Address Structure. /// [ CLSCompliant(false) ] public struct IPv4 : IComparable { private uint addr; // Host order /// /// The number of bytes in an IPv4 address. /// public const int Length = 4; /// /// The number of bits in a IPv4 address. /// public const int BitCount = 32; /// /// Constructor. /// /// A 32-bit value representing an /// IPv4 address in host-order. public IPv4(uint hostOrderAddress) { addr = hostOrderAddress; } /// /// Copy-constructor /// /// Another IPv4 instance public IPv4(IPv4 other) { addr = other.addr; } #if HAVE_SYSTEM_NET_IPADDRESS /// /// Constructor /// /// An instance of the /// System.Net.IPAddress class. /// Thrown when /// argument is null. /// Thrown when /// AddressFamily of ipais other than /// InterNetwork public IPv4(IPAddress ipa) { if (ipa == null) { throw new ArgumentNullException(); } byte [] quad = ipa.GetAddressBytes(); if (quad.Length != Length) { throw new ArgumentException(); } addr =(uint)((quad[0] << 24) | (quad[1] << 16) | (quad[2] << 8) | quad[3]); } #endif // HAVE_SYSTEM_NET_IPADDRESS /// /// Provide a copy of the IPv4 address as an array of bytes. /// /// Array of bytes, ordered MSB to LSB. public byte[]! GetAddressBytes() { return new byte[Length] { (byte)(addr >> 24), (byte)(addr >> 16), (byte)(addr >> 8), (byte)(addr) }; } /// /// Create an IPv4 address representing a netmask. /// /// /// An IPv4 instance. /// Thrown if maskLength is /// outside of the range [0,32]. public static IPv4 NetMask(int maskLength) { if ((maskLength > BitCount) || (maskLength < 0)) { throw new ArgumentException("Mask length greater than possible."); } return IPv4.AllOnes << (BitCount - maskLength); } /// /// Create an IPv4 address from bytes in an array. The bytes /// are assumed to be in the order of MSB to LSB. /// /// Byte array to read address from. /// Offset in bytes of starting point. /// Thrown if the array /// is null. /// Thrown if there are less /// than 4 bytes from the offset to the end of the array. public static IPv4 ParseBytes(byte [] data, int offset) { if (data == null) { throw new ArgumentNullException(); } if (data.Length - offset < Length) { throw new ArgumentException("Byte array too short."); } return new IPv4((uint)((data[offset + 0] << 24) | (data[offset + 1] << 16) | (data[offset + 2] << 8) | (data[offset + 3])) ); } /// /// Create an IPv4 address from bytes in an array. /// /// Thrown if the array /// is null. /// Thrown if there are less /// than 4 bytes in the array. public static IPv4 ParseBytes(byte [] data) { return ParseBytes(data, 0); } private static bool ParseHexQuad(string! quad, out uint value) { const string hex = "00112233445566778899aAbBcCdDeEfF"; value = 0; if (quad.Length < 3 || quad.Length > 4) return false; if ((quad[0] != '0') || (quad[1] != 'x')) return false; int u = (quad.Length == 4) ? hex.IndexOf(quad[2]) : 0; int l = hex.IndexOf(quad[quad.Length - 1]); value = (uint)(((u << 3) & 0xf0) | (l >> 1)); return (u >= 0) && (l >= 0); } private static bool ParseOctalQuad(string! quad, out uint value) { value = 0; if (quad.Length < 2 || quad.Length > 4) return false; if (quad[0] != '0') return false; int result = 0; for (int i = 1; i < quad.Length; i++) { int tmp = quad[i] - '0'; if (tmp < 0 || tmp > 7) return false; result = result * 8 + tmp; } value = (uint)result; return result <= 255; } private static bool ParseDecimalQuad(string! quad, out uint value) { value = 0; if (quad.Length == 0 || quad.Length > 3) return false; int result = 0; for (int i = 0; i < quad.Length; i++) { int tmp = quad[i] - '0'; if (tmp < 0 || tmp > 9) return false; result = result * 10 + tmp; } value = (uint)result; return result <= 255; } private static bool ParseQuad(string! quad, out uint value) { if (ParseHexQuad(quad, out value) == true) return true; if (ParseOctalQuad(quad, out value) == true) return true; return ParseDecimalQuad(quad, out value); } /// /// Converts an IP address string into an IPv4 instance. /// /// Thrown if /// ipString is null. /// Thrown if /// ipString is invalid. public static IPv4 Parse(string ipString) { const string malformed = "Malformed address"; if (ipString == null) { throw new ArgumentNullException("ipString"); } string [] quads = ipString.Split('.'); if (quads.Length == 0 || quads.Length > 4) { throw new FormatException(malformed); } uint address = 0; uint tmp = 0; int i; for (i = 0; i < quads.Length - 1; i++) { if (ParseQuad((!)quads[i], out tmp) == false) { throw new FormatException(malformed); } address |= (tmp) << (24 - i * 8); } if (ParseQuad((!)quads[i], out tmp) == false) { throw new FormatException(malformed); } address |= tmp; return new IPv4(address); } /// /// Converts an IP address string into an IPv4 instance. /// /// Thrown if /// ipString is null. /// true on success, false on failure. public static bool Parse(string ipString, out IPv4 address) { try { address = Parse(ipString); } catch (FormatException) { address = IPv4.Zero; return false; } return true; } /// /// Writes network-order byte representation of IPv4 address /// into buffer at a specified offset. /// /// Thrown if buffer /// argument is null. /// Thrown if there is /// insufficient space between outputOffset and the end of /// buffer to write out the IP address. public int CopyOut(byte[] buffer, int outputOffset) { if (buffer == null) { throw new ArgumentNullException(); } if (buffer.Length - outputOffset < Length) { throw new ArgumentException("Byte array too short."); } buffer[outputOffset + 0] = (byte)(addr >> 24); buffer[outputOffset + 1] = (byte)(addr >> 16); buffer[outputOffset + 2] = (byte)(addr >> 8); buffer[outputOffset + 3] = (byte)(addr); return Length; } /// /// The less-than operator for two IPv4 addresses. /// /// /// /// True if the 32-bit number representing the lhs /// is less than rhs. public static bool operator < (IPv4 lhs, IPv4 rhs) { return lhs.addr < rhs.addr; } /// /// The less-than-or-equal-to operator for two IPv4 addresses. /// /// /// /// True if the 32-bit number representing the lhs /// is less than or equal to rhs. public static bool operator <= (IPv4 lhs, IPv4 rhs) { return lhs.addr <= rhs.addr; } /// /// The greater-than operator for two IPv4 addresses. /// /// /// /// True if the 32-bit number representing the lhs /// is greater than rhs. public static bool operator > (IPv4 lhs, IPv4 rhs) { return lhs.addr > rhs.addr; } /// /// The greater-than-or-equal-to operator for two IPv4 addresses. /// /// /// /// True if the 32-bit number representing the lhs /// is greater than or equal to rhs. public static bool operator >= (IPv4 lhs, IPv4 rhs) { return lhs.addr >= rhs.addr; } /// /// Equals operator. /// /// /// /// True if the addresses represented by lhs and /// rhs are the same. public static bool operator == (IPv4 lhs, IPv4 rhs) { return lhs.addr == rhs.addr; } /// /// Not-equals operator. /// /// /// /// True if the addresses represented by lhs and /// rhs are different. public static bool operator != (IPv4 lhs, IPv4 rhs) { return lhs.addr != rhs.addr; } /// /// Bit-wise AND operator. /// /// /// /// An IPv4 instance. public static IPv4 operator & (IPv4 lhs, IPv4 rhs) { return new IPv4(lhs.addr & rhs.addr); } /// /// Bit-wise OR operator. /// /// /// /// An IPv4 instance. public static IPv4 operator | (IPv4 lhs, IPv4 rhs) { return new IPv4(lhs.addr | rhs.addr); } /// /// Bit-wise XOR operator. /// /// /// /// An IPv4 instance. public static IPv4 operator ^ (IPv4 lhs, IPv4 rhs) { return new IPv4(lhs.addr ^ rhs.addr); } /// /// Bit-wise NOT operator. /// /// /// An IPv4 instance. public static IPv4 operator ~ (IPv4 ipv4) { return new IPv4(~ipv4.addr); } /// /// Increment IPv4 address. /// /// /// An IPv4 instance. public static IPv4 operator ++ (IPv4 ipv4) { return new IPv4(ipv4.addr + 1); } /// /// Decrement IPv4 address. /// /// /// An IPv4 instance. public static IPv4 operator -- (IPv4 ipv4) { return new IPv4(ipv4.addr - 1); } /// /// Right-shift operator. /// /// Address to be shifted. /// Number of bits to shift-by. /// An IPv4 address. public static IPv4 operator >> (IPv4 ipv4, int n) { if (n < BitCount) { return new IPv4(ipv4.addr >> n); } return IPv4.Zero; } /// /// Left-shift operator. /// /// Address to be shifted. /// Number of bits to shift-by. /// An IPv4 address. public static IPv4 operator << (IPv4 ipv4, int n) { if (n < BitCount) { return new IPv4(ipv4.addr << n); } return IPv4.Zero; } /// /// Get a single bit from an IPv4 address. /// /// Index of bit (ordered from msb-to-lsb) /// /// Returns true if bit is set, false if /// bit is unset or is out /// of range. /// public bool GetBit(int bitIndex) { if (bitIndex < 0 || bitIndex >= BitCount) { return false; } uint mask = 1u << (31 - bitIndex); return (addr & mask) == mask; } /// /// Get the mask length from an IPv4 address representing a netmask. /// /// public static int GetMaskLength(IPv4 netmask) { int i = 0; while (netmask.GetBit(i) == true) { i++; } return i; } #if HAVE_SYSTEM_NET_IPADDRESS /// /// Cast IPv4 instance into a System.Net.IPAddress /// /// /// An IPAddress instance. public static explicit operator IPAddress(IPv4 ipv4) { int netOrder = IPAddress.HostToNetworkOrder((int)ipv4.addr); return new IPAddress(((long)netOrder) & 0xffffffff); } #endif // HAVE_SYSTEM_NET_IPADDRESS /// /// Cast IPv4 instance into an unsigned integer. /// /// /// An unsigned integer. public static explicit operator uint(IPv4 ipAddress) { return ipAddress.addr; } /// /// Determines whether two Object instances are equal. /// /// Object to be compared to. /// True if o is an IPv4 address and numerically /// the same as instance. public override bool Equals(object other) { if (other is IPv4) { return addr == ((IPv4)other).addr; } return false; } /// /// Compute numeric hash of IPv4 instance. Value is /// suitable for use in hashing algorithms and data /// structures like a hash table. /// public override int GetHashCode() { return (int)addr; } /// /// Indicates whether instance represents a loopback address. /// /// True if instance represents a loopback /// address. public bool IsLoopback() { return (addr & 0xff000000) == 0x7f000000; } /// /// Indicates whether instance represents a multicast address. /// /// True if instance represents a multicast /// address. public bool IsMulticast() { return (addr & 0xf0000000) == 0xe0000000; } /// /// Returns a string representing IPv4 instance. /// public override string! ToString() { return String.Format("{0}.{1}.{2}.{3}", addr >> 24, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff); } public int CompareTo(object other) { if (other == null) return 1; if (other is IPv4) { IPv4 value = (IPv4) other; if (this < value) return -1; if (this > value) return + 1; return 0; } throw new ArgumentException ("Arg_MustBeIPv4"); } /// /// IPv4 address representing an unspecified host. /// public static readonly IPv4 Any = new IPv4(0U); /// /// IPv4 address with all bits set to zero. /// public static readonly IPv4 Zero = new IPv4(0U); /// /// IPv4 loopback address. /// public static readonly IPv4 Loopback = new IPv4(0x7f000001U); /// /// IPv4 broadcast address. /// public static readonly IPv4 Broadcast = new IPv4(~0U); /// /// IPv4 address with all bits set to one. /// public static readonly IPv4 AllOnes = new IPv4(~0U); } } // namespace System.Net.IP