2 // System.Net.IPv6Address.cs
\r
5 // Lawrence Pit (loz@cable.a2000.nl)
\r
7 // Note I: This class is not defined in the specs of .Net
\r
9 // Note II : The name of this class is perhaps unfortunate as it turns
\r
10 // out that in ms.net there's an internal class called
\r
11 // IPv6Address in namespace System.
\r
16 using System.Net.Sockets;
\r
17 using System.Runtime.InteropServices;
\r
20 namespace System.Net {
\r
23 /// Encapsulates an IPv6 Address.
\r
24 /// See RFC 2373 for more info on IPv6 addresses.
\r
27 internal class IPv6Address {
\r
28 private ushort [] address;
\r
29 private int prefixLength;
\r
31 public static readonly IPv6Address Loopback = IPv6Address.Parse ("::1");
\r
32 public static readonly IPv6Address Unspecified = IPv6Address.Parse ("::");
\r
35 /// Constructor from a 32-bit constant with its bytes
\r
36 /// in network order.
\r
38 public IPv6Address (ushort [] addr)
\r
41 throw new ArgumentNullException ("addr");
\r
42 if (addr.Length != 8)
\r
43 throw new ArgumentException ("addr");
\r
47 public IPv6Address (ushort [] addr, int prefixLength) : this (addr)
\r
49 if (prefixLength < 0 || prefixLength > 128)
\r
50 throw new ArgumentException ("prefixLength");
\r
51 this.prefixLength = prefixLength;
\r
54 public static IPv6Address Parse (string ipString)
\r
56 if (ipString == null)
\r
57 throw new ArgumentNullException ("ipString");
\r
59 if (ipString.Length > 2 &&
\r
60 ipString [0] == '[' &&
\r
61 ipString [ipString.Length - 1] == ']')
\r
62 ipString = ipString.Substring (1, ipString.Length - 2);
\r
64 if (ipString.Length < 2)
\r
65 throw new FormatException ("Not a valid IPv6 address");
\r
68 int pos = ipString.LastIndexOf ('/');
\r
70 string prefix = ipString.Substring (pos + 1);
\r
72 prefixLen = Int32.Parse (prefix);
\r
73 } catch (Exception) {
\r
76 if (prefixLen < 0 || prefixLen > 128)
\r
77 throw new FormatException ("Not a valid prefix length");;
\r
78 ipString = ipString.Substring (0, pos);
\r
81 ushort [] addr = new ushort [8];
\r
84 int pos2 = ipString.LastIndexOf (":");
\r
86 throw new FormatException ("Not a valid IPv6 address");
\r
87 if (pos2 < (ipString.Length - 1)) {
\r
88 string ipv4Str = ipString.Substring (pos2 + 1);
\r
89 if (ipv4Str.IndexOf ('.') != -1) {
\r
91 long a = IPAddress.Parse (ipv4Str).Address;
\r
92 addr [6] = (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff)));
\r
93 addr [7] = (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff)));
\r
94 if (ipString [pos2 - 1] == ':')
\r
95 ipString = ipString.Substring (0, pos2 + 1);
\r
97 ipString = ipString.Substring (0, pos2);
\r
99 } catch (Exception) {
\r
100 throw new FormatException ("Not a valid IPv6 address");
\r
105 int origLen = ipString.Length;
\r
107 throw new FormatException ("Not a valid IPv6 address");
\r
108 ipString = ipString.Replace ("::", ":!:");
\r
109 int len = ipString.Length;
\r
110 if ((len - origLen) > 1)
\r
111 throw new FormatException ("Not a valid IPv6 address");
\r
113 if (ipString [1] == '!')
\r
114 ipString = ipString.Remove (0, 1);
\r
115 if (ipString [len - 2] == '!')
\r
116 ipString = ipString.Remove (len - 1, 1);
\r
117 if ((ipString.Length > 2) &&
\r
118 ((ipString [0] == ':') || (ipString [ipString.Length - 1] == ':')))
\r
119 throw new FormatException ("Not a valid IPv6 address");
\r
121 string [] pieces = ipString.Split (new char [] {':'});
\r
122 len = pieces.Length;
\r
123 if (len > (ipv4 ? 6 : 8))
\r
124 throw new FormatException ("Not a valid IPv6 address");
\r
125 int piecedouble = -1;
\r
126 for (int i = 0; i < len; i++) {
\r
127 string piece = pieces [i];
\r
131 int plen = piece.Length;
\r
133 throw new FormatException ("Not a valid IPv6 address");
\r
135 for (int j = 0; j < plen; j++)
\r
137 p = (p << 4) + Uri.FromHex (piece [j]);
\r
138 } catch (ArgumentException) {
\r
139 throw new FormatException ("Not a valid IPv6 address");
\r
141 addr [i] = (ushort) p;
\r
145 //expand the :: token
\r
146 if (piecedouble != -1) {
\r
147 int totallen = (ipv4 ? 5 : 7);
\r
149 for (i = totallen; i >= (totallen - (len - piecedouble - 1)); i--) {
\r
150 addr [i] = addr [(len - 1) + i - totallen];
\r
152 for (; i >= piecedouble; i--) {
\r
155 } else if (len != (ipv4 ? 6 : 8))
\r
156 throw new FormatException ("Not a valid IPv6 address");
\r
158 // check IPv4 validity
\r
160 for (int i = 0; i < 5; i++)
\r
162 throw new FormatException ("Not a valid IPv6 address");
\r
163 if (addr [5] != 0 && addr [5] != 0xffff)
\r
164 throw new FormatException ("Not a valid IPv6 address");
\r
167 return new IPv6Address (addr, prefixLen);
\r
170 public ushort [] Address {
\r
171 get { return address; }
\r
174 public int PrefixLength {
\r
175 get { return this.prefixLength; }
\r
178 public ushort this [int index] {
\r
179 get { return address [index]; }
\r
182 public AddressFamily AddressFamily {
\r
183 get { return AddressFamily.InterNetworkV6; }
\r
187 /// Used to tell whether the given address is the loopback address.
\r
189 public static bool IsLoopback (IPv6Address addr)
\r
191 for (int i = 0; i < 4; i++)
\r
192 if (addr.address [i] != 0)
\r
194 if ((addr.address [5] != 0) && (addr.address [5] != 0xffff))
\r
196 if ((addr.address [6] >> 8) == 0x7f)
\r
198 return ((addr.address [5] == 0) &&
\r
199 (addr.address [6] == 0) &&
\r
200 (addr.address [7] == 1));
\r
203 public bool IsIPv4Compatible ()
\r
205 for (int i = 0; i < 6; i++)
\r
206 if (address [i] != 0)
\r
211 public bool IsIPv4Mapped ()
\r
213 for (int i = 0; i < 5; i++)
\r
214 if (address [i] != 0)
\r
216 return address [5] == 0xffff;
\r
220 /// Overrides System.Object.ToString to return
\r
221 /// this object rendered in a canonicalized notation
\r
223 public override string ToString ()
\r
225 StringBuilder s = new StringBuilder ();
\r
226 for (int i = 0; i < 7; i++)
\r
227 s.Append (String.Format ("{0:X4}", address [i])).Append (':');
\r
228 s.Append (String.Format ("{0:X4}", address [7]));
\r
229 return s.ToString ();
\r
233 /// Whether both objects are equal.
\r
235 public override bool Equals (object other)
\r
237 System.Net.IPv6Address ipv6 = other as System.Net.IPv6Address;
\r
238 if (ipv6 != null) {
\r
239 for (int i = 0; i < 8; i++)
\r
240 if (this.address [i] != ipv6.address [i])
\r
245 System.Net.IPAddress ipv4 = other as System.Net.IPAddress;
\r
246 if (ipv4 != null) {
\r
247 for (int i = 0; i < 5; i++)
\r
248 if (address [i] != 0)
\r
251 if (address [5] != 0 && address [5] != 0xffff)
\r
254 long a = ipv4.Address;
\r
255 if (address [6] != (ushort) (((int) (a & 0xff) << 8) + ((int) ((a >> 8) & 0xff))) ||
\r
256 address [7] != (ushort) (((int) ((a >> 16) & 0xff) << 8) + ((int) ((a >> 24) & 0xff))))
\r
265 public override int GetHashCode ()
\r
267 return Hash (((((int) address [0]) << 16) + address [1]),
\r
268 ((((int) address [2]) << 16) + address [3]),
\r
269 ((((int) address [4]) << 16) + address [5]),
\r
270 ((((int) address [6]) << 16) + address [7]));
\r
273 private static int Hash (int i, int j, int k, int l)
\r
275 return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25);
\r