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