//\r
-// System.Net.IPv6Address.cs\r
+// System.Net.IPv6AddressFormatter.cs\r
//\r
// Author:\r
// Lawrence Pit (loz@cable.a2000.nl)\r
-//\r
-// Note I: This class is not defined in the specs of .Net\r
-//\r
-// Note II : The name of this class is perhaps unfortunate as it turns\r
-// out that in ms.net there's an internal class called\r
-// IPv6Address in namespace System.\r
-//\r
-\r
//\r
// Permission is hereby granted, free of charge, to any person obtaining\r
// a copy of this software and associated documentation files (the\r
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
//\r
\r
-\r
-using System;\r
using System.Globalization;\r
-using System.Net.Sockets;\r
-using System.Runtime.InteropServices;\r
using System.Text;\r
\r
namespace System.Net {\r
\r
- /// <remarks>\r
- /// Encapsulates an IPv6 Address.\r
- /// See RFC 2373 for more info on IPv6 addresses.\r
- /// </remarks>\r
- [Serializable]\r
- internal class IPv6Address {\r
- private ushort [] address;\r
- private int prefixLength;\r
- private long scopeId = 0;\r
-\r
- public static readonly IPv6Address Loopback = IPv6Address.Parse ("::1");\r
- public static readonly IPv6Address Unspecified = IPv6Address.Parse ("::");\r
+ struct IPv6AddressFormatter\r
+ {\r
+ ushort [] address;\r
+ long scopeId;\r
\r
- public IPv6Address (ushort [] addr)\r
- {\r
- if (addr == null)\r
- throw new ArgumentNullException ("addr"); \r
- if (addr.Length != 8) \r
- throw new ArgumentException ("addr");\r
- address = addr; \r
- }\r
- \r
- public IPv6Address (ushort [] addr, int prefixLength) : this (addr)\r
- {\r
- if (prefixLength < 0 || prefixLength > 128)\r
- throw new ArgumentException ("prefixLength");\r
- this.prefixLength = prefixLength;\r
- }\r
- \r
- public IPv6Address (ushort [] addr, int prefixLength, int scopeId) : this (addr, prefixLength)\r
+ public IPv6AddressFormatter (ushort[] addr, long scopeId)\r
{\r
+ this.address = addr;\r
this.scopeId = scopeId;\r
}\r
\r
- public static IPv6Address Parse (string ipString)\r
- {\r
- if (ipString == null)\r
- throw new ArgumentNullException ("ipString");\r
-\r
- IPv6Address result;\r
- if (TryParse (ipString, out result))\r
- return result;\r
- throw new FormatException ("Not a valid IPv6 address");\r
- }\r
-\r
- static int Fill (ushort [] addr, string ipString)\r
- {\r
- int p = 0;\r
- int pdigits = 0;\r
- int slot = 0;\r
-\r
- if (ipString.Length == 0)\r
- return 0;\r
- \r
- // Catch double uses of ::\r
- if (ipString.IndexOf ("::", StringComparison.Ordinal) != -1)\r
- return -1;\r
-\r
- for (int i = 0; i < ipString.Length; i++){\r
- char c = ipString [i];\r
- int n;\r
-\r
- if (c == ':'){\r
- // Leading : is not allowed.\r
- if (i == 0)\r
- return -1;\r
- \r
- // Trailing : is not allowed.\r
- if (i == ipString.Length-1)\r
- return -1;\r
- \r
- if (slot == 8)\r
- return -1;\r
- \r
- addr [slot++] = (ushort) p;\r
- p = 0;\r
- pdigits = 0;\r
- continue;\r
- }\r
- pdigits++;\r
- if (pdigits > 4)\r
- return -1;\r
- if ('0' <= c && c <= '9')\r
- n = (int) (c - '0');\r
- else if ('a' <= c && c <= 'f')\r
- n = (int) (c - 'a' + 10);\r
- else if ('A' <= c && c <= 'F')\r
- n = (int) (c - 'A' + 10);\r
- else \r
- return -1;\r
- p = (p << 4) + n;\r
- if (p > UInt16.MaxValue)\r
- return -1;\r
- }\r
-\r
- if (slot == 8)\r
- return -1;\r
- \r
- addr [slot++] = (ushort) p;\r
-\r
- return slot;\r
- }\r
-\r
- static bool TryParse (string prefix, out int res)\r
- {\r
- return Int32.TryParse (prefix, NumberStyles.Integer, CultureInfo.InvariantCulture, out res);\r
- }\r
- \r
- public static bool TryParse (string ipString, out IPv6Address result)\r
- {\r
- result = null;\r
- if (ipString == null)\r
- return false;\r
-\r
- if (ipString.Length > 2 && \r
- ipString [0] == '[' && \r
- ipString [ipString.Length - 1] == ']')\r
- ipString = ipString.Substring (1, ipString.Length - 2);\r
-\r
- if (ipString.Length < 2)\r
- return false;\r
-\r
- int prefixLen = 0;\r
- int scopeId = 0;\r
- int pos = ipString.LastIndexOf ('/');\r
- if (pos != -1) {\r
- string prefix = ipString.Substring (pos + 1);\r
- if (!TryParse (prefix , out prefixLen))\r
- prefixLen = -1;\r
- if (prefixLen < 0 || prefixLen > 128)\r
- return false;\r
- ipString = ipString.Substring (0, pos);\r
- } else {\r
- pos = ipString.LastIndexOf ('%');\r
- if (pos != -1) {\r
- string prefix = ipString.Substring (pos + 1);\r
- if (!TryParse (prefix, out scopeId))\r
- scopeId = 0;\r
- ipString = ipString.Substring (0, pos);\r
- } \r
- }\r
-\r
- //\r
- // At this point the prefix/suffixes have been removed\r
- // and we only have to deal with the ipv4 or ipv6 addressed\r
- //\r
- ushort [] addr = new ushort [8];\r
-\r
- //\r
- // Is there an ipv4 address at the end?\r
- //\r
- int pos2 = ipString.LastIndexOf (':');\r
- if (pos2 == -1)\r
- return false;\r
-\r
- int slots = 0;\r
- if (pos2 < (ipString.Length - 1)) {\r
- string ipv4Str = ipString.Substring (pos2 + 1);\r
- if (ipv4Str.IndexOf ('.') != -1) {\r
- IPAddress ip;\r
- \r
- if (!IPAddress.TryParse (ipv4Str, out ip))\r
- return false;\r
- \r
- long a = ip.InternalIPv4Address;\r
- addr [6] = (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff)));\r
- addr [7] = (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff)));\r
- if (pos2 > 0 && ipString [pos2 - 1] == ':') \r
- ipString = ipString.Substring (0, pos2 + 1);\r
- else\r
- ipString = ipString.Substring (0, pos2);\r
- slots = 2;\r
- }\r
- } \r
-\r
- //\r
- // Only an ipv6 block remains, either:\r
- // "hexnumbers::hexnumbers", "hexnumbers::" or "hexnumbers"\r
- //\r
- int c = ipString.IndexOf ("::", StringComparison.Ordinal);\r
- if (c != -1){\r
- int right_slots = Fill (addr, ipString.Substring (c+2));\r
- if (right_slots == -1){\r
- return false;\r
- }\r
-\r
- if (right_slots + slots > 8){\r
- return false;\r
- }\r
-\r
- int d = 8-slots-right_slots;\r
- for (int i = right_slots; i > 0; i--){\r
- addr [i+d-1] = addr [i-1];\r
- addr [i-1] = 0;\r
- }\r
- \r
- int left_slots = Fill (addr, ipString.Substring (0, c));\r
- if (left_slots == -1)\r
- return false;\r
-\r
- if (left_slots + right_slots + slots > 7)\r
- return false;\r
- } else {\r
- if (Fill (addr, ipString) != 8-slots)\r
- return false;\r
- }\r
-\r
- result = new IPv6Address (addr, prefixLen, scopeId);\r
- return true;\r
- }\r
-\r
- public ushort [] Address {\r
- get { return address; }\r
- }\r
-\r
- public int PrefixLength {\r
- get { return this.prefixLength; }\r
- }\r
- \r
- public long ScopeId {\r
- get {\r
- return scopeId;\r
- }\r
- set {\r
- scopeId = value;\r
- }\r
- }\r
-\r
- public ushort this [int index] {\r
- get { return address [index]; }\r
- } \r
-\r
- public AddressFamily AddressFamily {\r
- get { return AddressFamily.InterNetworkV6; }\r
- }\r
-\r
- public static bool IsLoopback (IPv6Address addr)\r
- {\r
- if (addr.address [7] != 1)\r
- return false;\r
-\r
- int x = addr.address [6] >> 8;\r
- if (x != 0x7f && x != 0)\r
- return false;\r
-\r
- for (int i = 0; i < 4; i++) {\r
- if (addr.address [i] != 0)\r
- return false;\r
- }\r
-\r
- if (addr.address [5] != 0 && addr.address [5] != 0xffff)\r
- return false;\r
-\r
- return true;\r
- }\r
-\r
- private static ushort SwapUShort (ushort number)\r
+ static ushort SwapUShort (ushort number)\r
{\r
return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );\r
}\r
\r
// Convert the address into a format expected by the IPAddress (long) ctor\r
// This needs to be unsigned to satisfy the '> 1' test in IsIPv4Compatible()\r
- private uint AsIPv4Int ()\r
+ uint AsIPv4Int ()\r
{\r
return (uint)(SwapUShort (address [7]) << 16) + SwapUShort (address [6]);\r
} \r
\r
- public bool IsIPv4Compatible ()\r
+ bool IsIPv4Compatible ()\r
{\r
for (int i = 0; i < 6; i++) \r
if (address [i] != 0)\r
return (AsIPv4Int () > 1);\r
}\r
\r
- public bool IsIPv4Mapped ()\r
+ bool IsIPv4Mapped ()\r
{\r
for (int i = 0; i < 5; i++) \r
if (address [i] != 0)\r
return address [5] == 0xffff;\r
}\r
\r
- /// <summary>\r
- /// Overrides System.Object.ToString to return\r
- /// this object rendered in a canonicalized notation\r
- /// </summary>\r
public override string ToString ()\r
{\r
StringBuilder s = new StringBuilder ();\r
\r
return s.ToString ();\r
}\r
- else\r
- {\r
- int bestChStart = -1; // Best chain start\r
- int bestChLen = 0; // Best chain length\r
- int currChLen = 0; // Current chain length\r
+ \r
+ int bestChStart = -1; // Best chain start\r
+ int bestChLen = 0; // Best chain length\r
+ int currChLen = 0; // Current chain length\r
\r
- // Looks for the longest zero chain\r
- for (int i=0; i<8; i++)\r
+ // Looks for the longest zero chain\r
+ for (int i=0; i<8; i++)\r
+ {\r
+ if (address[i] != 0)\r
{\r
- if (address[i] != 0)\r
+ if ((currChLen > bestChLen) \r
+ && (currChLen > 1))\r
{\r
- if ((currChLen > bestChLen) \r
- && (currChLen > 1))\r
- {\r
- bestChLen = currChLen;\r
- bestChStart = i - currChLen;\r
- }\r
- currChLen = 0;\r
+ bestChLen = currChLen;\r
+ bestChStart = i - currChLen;\r
}\r
- else\r
- currChLen++;\r
- }\r
- if ((currChLen > bestChLen) \r
- && (currChLen > 1))\r
- {\r
- bestChLen = currChLen;\r
- bestChStart = 8 - currChLen;\r
+ currChLen = 0;\r
}\r
+ else\r
+ currChLen++;\r
+ }\r
+ if ((currChLen > bestChLen) \r
+ && (currChLen > 1))\r
+ {\r
+ bestChLen = currChLen;\r
+ bestChStart = 8 - currChLen;\r
+ }\r
\r
- // makes the string\r
- if (bestChStart == 0)\r
- s.Append(":");\r
- for (int i=0; i<8; i++)\r
+ // makes the string\r
+ if (bestChStart == 0)\r
+ s.Append(":");\r
+ for (int i=0; i<8; i++)\r
+ {\r
+ if (i == bestChStart)\r
{\r
- if (i == bestChStart)\r
- {\r
- s.Append (":");\r
- i += (bestChLen - 1);\r
- continue;\r
- }\r
- s.AppendFormat("{0:x}", address [i]);\r
- if (i < 7) s.Append (':');\r
+ s.Append (":");\r
+ i += (bestChLen - 1);\r
+ continue;\r
}\r
+ s.AppendFormat("{0:x}", address [i]);\r
+ if (i < 7) s.Append (':');\r
}\r
+ \r
if (scopeId != 0)\r
s.Append ('%').Append (scopeId);\r
return s.ToString ();\r
}\r
-\r
- public string ToString (bool fullLength)\r
- {\r
- if (!fullLength)\r
- return ToString ();\r
-\r
- StringBuilder sb = new StringBuilder ();\r
- for (int i=0; i < address.Length - 1; i++) {\r
- sb.AppendFormat ("{0:X4}:", address [i]);\r
- }\r
- sb.AppendFormat ("{0:X4}", address [address.Length - 1]);\r
- return sb.ToString ();\r
- }\r
-\r
- /// <returns>\r
- /// Whether both objects are equal.\r
- /// </returns>\r
- public override bool Equals (object other)\r
- {\r
- System.Net.IPv6Address ipv6 = other as System.Net.IPv6Address;\r
- if (ipv6 != null) {\r
- for (int i = 0; i < 8; i++) \r
- if (this.address [i] != ipv6.address [i])\r
- return false;\r
- return true;\r
- }\r
- \r
- System.Net.IPAddress ipv4 = other as System.Net.IPAddress;\r
- if (ipv4 != null) {\r
- for (int i = 0; i < 5; i++) \r
- if (address [i] != 0)\r
- return false;\r
-\r
- if (address [5] != 0 && address [5] != 0xffff)\r
- return false;\r
-\r
- long a = ipv4.InternalIPv4Address;\r
- if (address [6] != (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff))) ||\r
- address [7] != (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff))))\r
- return false;\r
-\r
- return true;\r
- }\r
- \r
- return false;\r
- }\r
-\r
- public override int GetHashCode ()\r
- {\r
- return Hash (((((int) address [0]) << 16) + address [1]), \r
- ((((int) address [2]) << 16) + address [3]),\r
- ((((int) address [4]) << 16) + address [5]),\r
- ((((int) address [6]) << 16) + address [7]));\r
- }\r
- \r
- private static int Hash (int i, int j, int k, int l) \r
- {\r
- return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25);\r
- }\r
}\r
}\r