Inet6Address.java revision f5597e626ecf7949d249dea08c1a2964d890ec11
1/* 2 * Licensed to the Apache Software Foundation (ASF) under one or more 3 * contributor license agreements. See the NOTICE file distributed with 4 * this work for additional information regarding copyright ownership. 5 * The ASF licenses this file to You under the Apache License, Version 2.0 6 * (the "License"); you may not use this file except in compliance with 7 * the License. You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package java.net; 19 20import java.io.IOException; 21import java.io.ObjectInputStream; 22import java.io.ObjectOutputStream; 23import java.io.ObjectStreamField; 24import java.util.Enumeration; 25 26import org.apache.harmony.luni.util.Inet6Util; 27import org.apache.harmony.luni.util.Msg; 28 29/** 30 * This class represents a 128 bit long IPv6 address. 31 */ 32public final class Inet6Address extends InetAddress { 33 34 private static final long serialVersionUID = 6880410070516793377L; 35 36 static final byte[] any_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37 0, 0 }; 38 39 static final byte[] localhost_bytes = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 40 0, 0, 0, 1 }; 41 42 static final InetAddress ANY = new Inet6Address(any_bytes); 43 44 static final InetAddress LOOPBACK = new Inet6Address(localhost_bytes, 45 "localhost"); //$NON-NLS-1$ 46 47 int scope_id; 48 49 boolean scope_id_set; 50 51 boolean scope_ifname_set; 52 53 String ifname; 54 55 /* 56 * scoped interface. 57 */ 58 transient NetworkInterface scopedIf; 59 60 Inet6Address(byte address[]) { 61 ipaddress = address; 62 scope_id = 0; 63 } 64 65 Inet6Address(byte address[], String name) { 66 hostName = name; 67 ipaddress = address; 68 scope_id = 0; 69 } 70 71 /** 72 * Constructs an {@code InetAddress} representing the {@code address} and 73 * {@code name} and {@code scope_id}. 74 * 75 * @param address 76 * the network address. 77 * @param name 78 * the name associated with the address. 79 * @param scope_id 80 * the scope id for link- or site-local addresses. 81 */ 82 Inet6Address(byte address[], String name, int scope_id) { 83 hostName = name; 84 ipaddress = address; 85 this.scope_id = scope_id; 86 if (scope_id != 0) { 87 scope_id_set = true; 88 } 89 } 90 91 /** 92 * Constructs an IPv6 address according to the given {@code host}, {@code 93 * addr} and {@code scope_id}. 94 * 95 * @param host 96 * the host name associated with the address. 97 * @param addr 98 * the network address. 99 * @param scope_id 100 * the scope id for link- or site-local addresses. 101 * @return the Inet6Address instance representing the IP address. 102 * @throws UnknownHostException 103 * if the address is null or has an invalid length. 104 */ 105 public static Inet6Address getByAddress(String host, byte[] addr, 106 int scope_id) throws UnknownHostException { 107 if (null == addr || 16 != addr.length) { 108 // KA020=Illegal IPv6 address 109 throw new UnknownHostException(Msg.getString("KA020")); //$NON-NLS-1$ 110 } 111 if (scope_id < 0) { 112 scope_id = 0; 113 } 114 return new Inet6Address(addr, host, scope_id); 115 } 116 117 /** 118 * Gets an IPv6 address instance according to the given {@code host}, 119 * {@code addr} and {@code nif}. {@code scope_id} is set according to the 120 * given {@code nif} and the {@code addr} type (for example site-local or 121 * link-local). 122 * 123 * @param host 124 * the hostname associated with the address. 125 * @param addr 126 * the network address. 127 * @param nif 128 * the network interface that this address is associated with. 129 * @return the Inet6Address instance representing the IP address. 130 * @throws UnknownHostException 131 * if the address is {@code null} or has an invalid length or 132 * the interface doesn't have a numeric scope id for the given 133 * address type. 134 */ 135 public static Inet6Address getByAddress(String host, byte[] addr, 136 NetworkInterface nif) throws UnknownHostException { 137 138 Inet6Address address = Inet6Address.getByAddress(host, addr, 0); 139 140 // if nif is null, nothing needs to be set. 141 if (null == nif) { 142 return address; 143 } 144 145 // find the first address which matches the type addr, 146 // then set the scope_id, ifname and scopedIf. 147 Enumeration<InetAddress> addressList = nif.getInetAddresses(); 148 while (addressList.hasMoreElements()) { 149 InetAddress ia = addressList.nextElement(); 150 if (ia.getAddress().length == 16) { 151 Inet6Address v6ia = (Inet6Address) ia; 152 boolean isSameType = v6ia.compareLocalType(address); 153 if (isSameType) { 154 address.scope_id_set = true; 155 address.scope_id = v6ia.scope_id; 156 address.scope_ifname_set = true; 157 address.ifname = nif.getName(); 158 address.scopedIf = nif; 159 break; 160 } 161 } 162 } 163 // if no address matches the type of addr, throws an 164 // UnknownHostException. 165 if (!address.scope_id_set) { 166 // KA021=Scope id is not found for the given address 167 throw new UnknownHostException(Msg.getString("KA021")); //$NON-NLS-1$ 168 } 169 return address; 170 } 171 172 /** 173 * Returns {@code true} if one of following cases applies: 174 * <p> 175 * <ol> 176 * <li>both addresses are site local</li> 177 * <li>both addresses are link local</li> 178 * <li>{@code ia} is neither site local nor link local</li> 179 * </ol> 180 */ 181 private boolean compareLocalType(Inet6Address ia) { 182 if (ia.isSiteLocalAddress() && isSiteLocalAddress()) { 183 return true; 184 } 185 if (ia.isLinkLocalAddress() && isLinkLocalAddress()) { 186 return true; 187 } 188 if (!ia.isSiteLocalAddress() && !ia.isLinkLocalAddress()) { 189 return true; 190 } 191 return false; 192 } 193 194 /** 195 * Constructs an {@code InetAddress} representing the {@code address} and 196 * {@code scope_id}. 197 * 198 * @param address 199 * the network address. 200 * @param scope_id 201 * the scope id for link- or site-local addresses. 202 */ 203 Inet6Address(byte address[], int scope_id) { 204 ipaddress = address; 205 this.scope_id = scope_id; 206 if (scope_id != 0) { 207 scope_id_set = true; 208 } 209 } 210 211 /** 212 * Returns whether this address is an IP multicast address or not. Valid 213 * IPv6 multicast addresses are binary prefixed with 11111111 or FF (hex). 214 * 215 * @return {@code true} if this address is in the multicast group, {@code 216 * false} otherwise. 217 */ 218 @Override 219 public boolean isMulticastAddress() { 220 // Multicast addresses are prefixed with 11111111 (255) 221 return ipaddress[0] == -1; 222 } 223 224 /** 225 * Returns whether this address is a unspecified wildcard address "::" or 226 * not. 227 * 228 * @return {@code true} if this instance represents a wildcard address, 229 * {@code false} otherwise. 230 */ 231 @Override 232 public boolean isAnyLocalAddress() { 233 for (int i = 0; i < ipaddress.length; i++) { 234 if (ipaddress[i] != 0) { 235 return false; 236 } 237 } 238 return true; 239 } 240 241 /** 242 * Returns whether this address is the loopback address or not. The only 243 * valid IPv6 loopback address is "::1". 244 * 245 * @return {@code true} if this instance represents the loopback address, 246 * {@code false} otherwise. 247 */ 248 @Override 249 public boolean isLoopbackAddress() { 250 251 // The last word must be 1 252 if (ipaddress[15] != 1) { 253 return false; 254 } 255 256 // All other words must be 0 257 for (int i = 0; i < 15; i++) { 258 if (ipaddress[i] != 0) { 259 return false; 260 } 261 } 262 263 return true; 264 } 265 266 /** 267 * Returns whether this address is a link-local address or not. A valid IPv6 268 * link-local address is prefixed with 1111111010. 269 * 270 * @return {@code true} if this instance represents a link-local address, 271 * {@code false} otherwise. 272 */ 273 @Override 274 public boolean isLinkLocalAddress() { 275 276 // the first 10 bits need to be 1111111010 (1018) 277 return (ipaddress[0] == -2) && ((ipaddress[1] & 255) >>> 6) == 2; 278 } 279 280 /** 281 * Returns whether this address is a site-local address or not. A valid IPv6 282 * site-local address is prefixed with 1111111011. 283 * 284 * @return {@code true} if this instance represents a site-local address, 285 * {@code false} otherwise. 286 */ 287 @Override 288 public boolean isSiteLocalAddress() { 289 290 // the first 10 bits need to be 1111111011 (1019) 291 return (ipaddress[0] == -2) && ((ipaddress[1] & 255) >>> 6) == 3; 292 } 293 294 /** 295 * Returns whether this address is a global multicast address or not. A 296 * valid IPv6 global multicast address is 11111111xxxx1110 or FF0E hex. 297 * 298 * @return {@code true} if this instance represents a global multicast 299 * address, {@code false} otherwise. 300 */ 301 @Override 302 public boolean isMCGlobal() { 303 // the first byte should be 0xFF and the lower 4 bits 304 // of the second byte should be 0xE 305 return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 14; 306 } 307 308 /** 309 * Returns whether this address is a node-local multicast address or not. A 310 * valid IPv6 node-local multicast address is prefixed with 311 * 11111111xxxx0001. 312 * 313 * @return {@code true} if this instance represents a node-local multicast 314 * address, {@code false} otherwise. 315 */ 316 @Override 317 public boolean isMCNodeLocal() { 318 // the first byte should be 0xFF and the lower 4 bits 319 // of the second byte should be 0x1 320 return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 1; 321 } 322 323 /** 324 * Returns whether this address is a link-local multicast address or not. A 325 * valid IPv6 link-local multicast address is prefixed with 326 * 11111111xxxx0010. 327 * 328 * @return {@code true} if this instance represents a link-local multicast 329 * address, {@code false} otherwise. 330 */ 331 @Override 332 public boolean isMCLinkLocal() { 333 // the first byte should be 0xFF and the lower 4 bits 334 // of the second byte should be 0x2 335 return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 2; 336 } 337 338 /** 339 * Returns whether this address is a site-local multicast address or not. A 340 * valid IPv6 site-local multicast address is prefixed with 341 * 11111111xxxx0101. 342 * 343 * @return {@code true} if this instance represents a site-local multicast 344 * address, {@code false} otherwise. 345 */ 346 @Override 347 public boolean isMCSiteLocal() { 348 // the first byte should be 0xFF and the lower 4 bits 349 // of the second byte should be 0x5 350 return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 5; 351 } 352 353 /** 354 * Returns whether this address is a organization-local multicast address or 355 * not. A valid IPv6 org-local multicast address is prefixed with 356 * 11111111xxxx1000. 357 * 358 * @return {@code true} if this instance represents a org-local multicast 359 * address, {@code false} otherwise. 360 */ 361 @Override 362 public boolean isMCOrgLocal() { 363 // the first byte should be 0xFF and the lower 4 bits 364 // of the second byte should be 0x8 365 return (ipaddress[0] == -1) && (ipaddress[1] & 15) == 8; 366 } 367 368 /** 369 * Gets the textual representation of this IP address. 370 * 371 * @return the as a dotted string formatted IP address. 372 */ 373 @Override 374 public String getHostAddress() { 375 return Inet6Util.createIPAddrStringFromByteArray(ipaddress); 376 } 377 378 /** 379 * Gets the scope id as a number if this address is linked to an interface. 380 * Otherwise returns {@code 0}. 381 * 382 * @return the scope_id of this address or 0 when not linked with an 383 * interface. 384 */ 385 public int getScopeId() { 386 if (scope_id_set) { 387 return scope_id; 388 } 389 return 0; 390 } 391 392 /** 393 * Gets the network interface if this address is instanced with a scoped 394 * network interface. Otherwise returns {@code null}. 395 * 396 * @return the scoped network interface of this address. 397 */ 398 public NetworkInterface getScopedInterface() { 399 if (scope_ifname_set) { 400 return scopedIf; 401 } 402 return null; 403 } 404 405 /** 406 * Gets the hashcode of the represented IP address. 407 * 408 * @return the appropriate hashcode value. 409 */ 410 @Override 411 public int hashCode() { 412 /* Returns the low order int as the hash code */ 413 return bytesToInt(ipaddress, 12); 414 } 415 416 /** 417 * Compares this instance with the IP address in the object {@code obj} and 418 * returns {@code true} if they are of the same type and represent the same 419 * IP address, {@code false} otherwise. The scope id does not seem to be 420 * part of the comparison. 421 * 422 * @param obj 423 * the object to be tested for equality. 424 * @return {@code true} if the addresses are equal, {@code false} otherwise. 425 */ 426 @Override 427 public boolean equals(Object obj) { 428 return super.equals(obj); 429 } 430 431 /** 432 * Returns whether this address is IPv4 compatible or not. An IPv4 433 * compatible address is prefixed with 96 bits of 0's. The last 32-bits are 434 * varied corresponding with the 32-bit IPv4 address space. 435 * 436 * @return {@code true} if this instance represents an IPv4 compatible 437 * address, {@code false} otherwise. 438 */ 439 public boolean isIPv4CompatibleAddress() { 440 for (int i = 0; i < 12; i++) { 441 if (ipaddress[i] != 0) { 442 return false; 443 } 444 } 445 return true; 446 } 447 448 private static final ObjectStreamField[] serialPersistentFields = { 449 new ObjectStreamField("ipaddress", new byte[0].getClass()), //$NON-NLS-1$ 450 new ObjectStreamField("scope_id", Integer.TYPE), //$NON-NLS-1$ 451 new ObjectStreamField("scope_id_set", Boolean.TYPE), //$NON-NLS-1$ 452 new ObjectStreamField("scope_ifname_set", Boolean.TYPE), //$NON-NLS-1$ 453 new ObjectStreamField("ifname", String.class), }; //$NON-NLS-1$ 454 455 private void writeObject(ObjectOutputStream stream) throws IOException { 456 ObjectOutputStream.PutField fields = stream.putFields(); 457 if (ipaddress == null) { 458 fields.put("ipaddress", null); //$NON-NLS-1$ 459 } else { 460 fields.put("ipaddress", ipaddress); //$NON-NLS-1$ 461 } 462 463 fields.put("scope_id", scope_id); //$NON-NLS-1$ 464 fields.put("scope_id_set", scope_id_set); //$NON-NLS-1$ 465 fields.put("scope_ifname_set", scope_ifname_set); //$NON-NLS-1$ 466 fields.put("ifname", ifname); //$NON-NLS-1$ 467 stream.writeFields(); 468 } 469 470 private void readObject(ObjectInputStream stream) throws IOException, 471 ClassNotFoundException { 472 ObjectInputStream.GetField fields = stream.readFields(); 473 ipaddress = (byte[]) fields.get("ipaddress", null); //$NON-NLS-1$ 474 scope_id = fields.get("scope_id", 0); //$NON-NLS-1$ 475 scope_id_set = fields.get("scope_id_set", false); //$NON-NLS-1$ 476 ifname = (String) fields.get("ifname", null); //$NON-NLS-1$ 477 scope_ifname_set = fields.get("scope_ifname_set", false); //$NON-NLS-1$ 478 if (scope_ifname_set && null != ifname) { 479 scopedIf = NetworkInterface.getByName(ifname); 480 } 481 } 482 483 /** 484 * Returns a string containing a concise, human-readable description of this 485 * IP address. 486 * 487 * @return the description, as host/address. 488 */ 489 @Override 490 public String toString() { 491 if (ifname != null) { 492 return super.toString() + "%" + ifname; //$NON-NLS-1$ 493 } 494 if (scope_id != 0) { 495 return super.toString() + "%" + scope_id; //$NON-NLS-1$ 496 } 497 return super.toString(); 498 } 499} 500