//\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
+// Permission is hereby granted, free of charge, to any person obtaining\r
+// a copy of this software and associated documentation files (the\r
+// "Software"), to deal in the Software without restriction, including\r
+// without limitation the rights to use, copy, modify, merge, publish,\r
+// distribute, sublicense, and/or sell copies of the Software, and to\r
+// permit persons to whom the Software is furnished to do so, subject to\r
+// the following conditions:\r
+// \r
+// The above copyright notice and this permission notice shall be\r
+// included in all copies or substantial portions of the Software.\r
+// \r
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\r
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\r
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\r
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\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
-
-//
-// 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.
-//
-\r
\r
-using System;\r
-using System.Net.Sockets;\r
-using System.Runtime.InteropServices;\r
+using System.Globalization;\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
+ struct IPv6AddressFormatter\r
+ {\r
+ ushort [] address;\r
+ long scopeId;\r
\r
- public static readonly IPv6Address Loopback = IPv6Address.Parse ("::1");\r
- public static readonly IPv6Address Unspecified = IPv6Address.Parse ("::");\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
- {\r
- this.scopeId = scopeId;\r
- } \r
- \r
- public static IPv6Address Parse (string ipString)\r
+ public IPv6AddressFormatter (ushort[] addr, long scopeId)\r
{\r
- if (ipString == null)\r
- throw new ArgumentNullException ("ipString");\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
- throw new FormatException ("Not a valid IPv6 address");\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
- try {\r
- prefixLen = Int32.Parse (prefix);\r
- } catch (Exception) {\r
- prefixLen = -1;\r
- }\r
- if (prefixLen < 0 || prefixLen > 128)\r
- throw new FormatException ("Not a valid prefix length");\r
- ipString = ipString.Substring (0, pos);\r
- } else {\r
- pos = ipString.LastIndexOf ('%');\r
- if (pos != -1) {\r
- string prefix = ipString.Substring (pos + 1);\r
- try {\r
- scopeId = Int32.Parse (prefix);\r
- } \r
- catch (Exception) {\r
- scopeId = 0;\r
- }\r
- ipString = ipString.Substring (0, pos);\r
- } \r
- }\r
- \r
- ushort [] addr = new ushort [8]; \r
- \r
- bool ipv4 = false;\r
- int pos2 = ipString.LastIndexOf (":");\r
- if (pos2 == -1)\r
- throw new FormatException ("Not a valid IPv6 address");\r
- if (pos2 < (ipString.Length - 1)) {\r
- string ipv4Str = ipString.Substring (pos2 + 1);\r
- if (ipv4Str.IndexOf ('.') != -1) {\r
- try {\r
- long a = IPAddress.Parse (ipv4Str).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 (ipString [pos2 - 1] == ':') \r
- ipString = ipString.Substring (0, pos2 + 1);\r
- else\r
- ipString = ipString.Substring (0, pos2);\r
- ipv4 = true;\r
- } catch (Exception) {\r
- throw new FormatException ("Not a valid IPv6 address"); \r
- }\r
- }\r
- } \r
- \r
- int origLen = ipString.Length;\r
- if (origLen < 2)\r
- throw new FormatException ("Not a valid IPv6 address"); \r
- ipString = ipString.Replace ("::", ":!:");\r
- int len = ipString.Length;\r
- if ((len - origLen) > 1) \r
- throw new FormatException ("Not a valid IPv6 address");\r
- \r
- if (ipString [1] == '!') \r
- ipString = ipString.Remove (0, 1);\r
- if (ipString [len - 2] == '!')\r
- ipString = ipString.Remove (len - 1, 1);\r
- if ((ipString.Length > 2) && \r
- ((ipString [0] == ':') || (ipString [ipString.Length - 1] == ':'))) \r
- throw new FormatException ("Not a valid IPv6 address");\r
- \r
- string [] pieces = ipString.Split (new char [] {':'});\r
- len = pieces.Length;\r
- if (len > (ipv4 ? 6 : 8)) \r
- throw new FormatException ("Not a valid IPv6 address");\r
- int piecedouble = -1;\r
- bool ipv6 = false;
- for (int i = 0; i < len; i++) {\r
- string piece = pieces [i];\r
- if (piece == "!")\r
- piecedouble = i;\r
- else {\r
- int plen = piece.Length;\r
- if (plen > 4)\r
- throw new FormatException ("Not a valid IPv6 address");\r
- int p = 0;\r
- for (int j = 0; j < plen; j++) \r
- try {\r
- p = (p << 4) + Uri.FromHex (piece [j]);\r
- } catch (ArgumentException) {\r
- throw new FormatException ("Not a valid IPv6 address");\r
- }\r
- addr [i] = (ushort) p;
- if (p != 0 || (i == 5 && p != 0xffff))
- ipv6 = true;
- }\r
- }\r
-\r
- //expand the :: token\r
- if (piecedouble != -1) {\r
- int totallen = (ipv4 ? 5 : 7);\r
- int i = totallen;\r
- for (i = totallen; i >= (totallen - (len - piecedouble - 1)); i--) {\r
- addr [i] = addr [(len - 1) + i - totallen];\r
- }\r
- for (; i >= piecedouble; i--) {\r
- addr [i] = 0;\r
- }\r
- } else if (len != (ipv4 ? 6 : 8)) \r
- throw new FormatException ("Not a valid IPv6 address");\r
-\r
- // check IPv4 validity
- if (ipv4 && !ipv6) {
- for (int i = 0; i < 5; i++) {
- if (addr [i] != 0)
- throw new FormatException ("Not a valid IPv6 address");
- }
-
- if (addr [5] != 0 && addr [5] != 0xffff)
- throw new FormatException ("Not a valid IPv6 address");
- }
-
- return new IPv6Address (addr, prefixLen, scopeId);
- }
-
- public ushort [] Address {\r
- get { return address; }\r
+ this.address = addr;\r
+ this.scopeId = scopeId;\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
+ static ushort SwapUShort (ushort number)\r
+ {\r
+ return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );\r
}\r
\r
- public ushort this [int index] {\r
- get { return address [index]; }\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
+ uint AsIPv4Int ()\r
+ {\r
+ return (uint)(SwapUShort (address [7]) << 16) + SwapUShort (address [6]);\r
+ } \r
\r
- public AddressFamily AddressFamily {\r
- get { return AddressFamily.InterNetworkV6; }\r
- }\r
-
- public static bool IsLoopback (IPv6Address addr)
- {
- if (addr.address [7] != 1)
- return false;
-
- int x = addr.address [6] >> 8;
- if (x != 0x7f && x != 0)
- return false;
-
- for (int i = 0; i < 4; i++) {
- if (addr.address [i] != 0)
- return false;
- }
-
- if (addr.address [5] != 0 && addr.address [5] != 0xffff)
- return false;
-
- return true;
- }
-
- private static ushort SwapUShort (ushort number)
- {
- return (ushort) ( ((number >> 8) & 0xFF) + ((number << 8) & 0xFF00) );
- }
-
- // Convert the address into a format expected by the IPAddress (long) ctor
- private int AsIPv4Int ()
- {
- return (SwapUShort (address [7]) << 16) + SwapUShort (address [6]);
- }
-
- public bool IsIPv4Compatible ()\r
+ bool IsIPv4Compatible ()\r
{\r
for (int i = 0; i < 6; i++) \r
if (address [i] != 0)\r
return false;\r
- return (AsIPv4Int () > 1);
+ /* MS .net only seems to format the last 4\r
+ * bytes as an IPv4 address if address[6] is\r
+ * non-zero\r
+ */\r
+ if (address[6] == 0)\r
+ return false;\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 false;\r
+ /* MS .net only seems to format the last 4\r
+ * bytes as an IPv4 address if address[6] is\r
+ * non-zero\r
+ */\r
+ if (address[6] == 0)\r
+ return false;\r
+ \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
if(IsIPv4Mapped())\r
s.Append("ffff:");\r
\r
- s.Append(new IPAddress( AsIPv4Int ()).ToString ());
+ s.Append(new IPAddress( AsIPv4Int ()).ToString ());\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
- }\r
- return s.ToString ();\r
- }\r
-
- public string ToString (bool fullLength)
- {
- if (!fullLength)
- return ToString ();
-
- StringBuilder sb = new StringBuilder ();
- for (int i=0; i < address.Length - 1; i++) {
- sb.AppendFormat ("{0:X4}:", address [i]);\r
- }
- sb.AppendFormat ("{0:X4}", address [address.Length - 1]);\r
- return sb.ToString ();
- }\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
+ s.AppendFormat("{0:x}", address [i]);\r
+ if (i < 7) s.Append (':');\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
+ if (scopeId != 0)\r
+ s.Append ('%').Append (scopeId);\r
+ return s.ToString ();\r
}\r
}\r
}\r