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