NetworkInterface.java revision fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726
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.util.ArrayList; 21import java.util.Arrays; 22import java.util.Collections; 23import java.util.Enumeration; 24import java.util.LinkedHashMap; 25import java.util.LinkedList; 26import java.util.List; 27import java.util.Map; 28import java.util.Vector; 29 30import org.apache.harmony.luni.util.Msg; 31 32/** 33 * This class is used to represent a network interface of the local device. An 34 * interface is defined by its address and a platform dependent name. The class 35 * provides methods to get all information about the available interfaces of the 36 * system or to identify the local interface of a joined multicast group. 37 */ 38public final class NetworkInterface extends Object { 39 40 private static final int CHECK_CONNECT_NO_PORT = -1; 41 42 static final int NO_INTERFACE_INDEX = 0; 43 static final int UNSET_INTERFACE_INDEX = -1; 44 45 private final String name; 46 private final String displayName; 47 private final List<InterfaceAddress> interfaceAddresses = new LinkedList<InterfaceAddress>(); 48 49 private final List<InetAddress> addresses = new LinkedList<InetAddress>(); 50 51 // The interface index is a positive integer which is non-negative. Where 52 // value is zero then we do not have an index for the interface (which 53 // occurs in systems which only support IPV4) 54 private int interfaceIndex; 55 56 private NetworkInterface parent = null; 57 58 private final List<NetworkInterface> children = new LinkedList<NetworkInterface>(); 59 60 // BEGIN android-changed: we pay this extra complexity on the Java side 61 // in return for vastly simpler native code. 62 private static native InterfaceAddress[] getAllInterfaceAddressesImpl() throws SocketException; 63 64 private static NetworkInterface[] getNetworkInterfacesImpl() throws SocketException { 65 Map<String, NetworkInterface> networkInterfaces = new LinkedHashMap<String, NetworkInterface>(); 66 for (InterfaceAddress ia : getAllInterfaceAddressesImpl()) { 67 if (ia != null) { // The array may contain harmless null elements. 68 String name = ia.name; 69 NetworkInterface ni = networkInterfaces.get(name); 70 if (ni == null) { 71 ni = new NetworkInterface(name, name, new InetAddress[] { ia.address }, ia.index); 72 ni.interfaceAddresses.add(ia); 73 networkInterfaces.put(name, ni); 74 } else { 75 ni.addresses.add(ia.address); 76 ni.interfaceAddresses.add(ia); 77 } 78 } 79 } 80 return networkInterfaces.values().toArray(new NetworkInterface[networkInterfaces.size()]); 81 } 82 // END android-changed 83 84 /** 85 * This constructor is used by the native method in order to construct the 86 * NetworkInterface objects in the array that it returns. 87 * 88 * @param name 89 * internal name associated with the interface. 90 * @param displayName 91 * a user interpretable name for the interface. 92 * @param addresses 93 * the Internet addresses associated with the interface. 94 * @param interfaceIndex 95 * an index for the interface. Only set for platforms that 96 * support IPV6. 97 */ 98 NetworkInterface(String name, String displayName, InetAddress[] addresses, 99 int interfaceIndex) { 100 this.name = name; 101 this.displayName = displayName; 102 this.interfaceIndex = interfaceIndex; 103 if (addresses != null) { 104 for (InetAddress address : addresses) { 105 this.addresses.add(address); 106 } 107 } 108 } 109 110 /** 111 * Returns the index for the network interface. Unless the system supports 112 * IPV6 this will be 0. 113 * 114 * @return the index 115 */ 116 int getIndex() { 117 return interfaceIndex; 118 } 119 120 /** 121 * Returns the first address for the network interface. This is used in the 122 * natives when we need one of the addresses for the interface and any one 123 * will do 124 * 125 * @return the first address if one exists, otherwise null. 126 */ 127 InetAddress getFirstAddress() { 128 if (addresses.size() >= 1) { 129 return addresses.get(0); 130 } 131 return null; 132 } 133 134 /** 135 * Gets the name associated with this network interface. 136 * 137 * @return the name of this {@code NetworkInterface} instance. 138 */ 139 public String getName() { 140 return name; 141 } 142 143 /** 144 * Gets a list of addresses bound to this network interface. 145 * 146 * @return the address list of the represented network interface. 147 */ 148 public Enumeration<InetAddress> getInetAddresses() { 149 SecurityManager sm = System.getSecurityManager(); 150 if (sm == null || addresses.isEmpty()) { 151 return Collections.enumeration(addresses); 152 } 153 // TODO: Android should ditch SecurityManager and the associated pollution. 154 List<InetAddress> result = new ArrayList<InetAddress>(addresses.size()); 155 for (InetAddress address : addresses) { 156 try { 157 sm.checkConnect(address.getHostName(), CHECK_CONNECT_NO_PORT); 158 } catch (SecurityException e) { 159 continue; 160 } 161 result.add(address); 162 } 163 return Collections.enumeration(result); 164 } 165 166 /** 167 * Gets the human-readable name associated with this network interface. 168 * 169 * @return the display name of this network interface or the name if the 170 * display name is not available. 171 */ 172 public String getDisplayName() { 173 /* 174 * we should return the display name unless it is blank in this case 175 * return the name so that something is displayed. 176 */ 177 if (!(displayName.equals(""))) { 178 return displayName; 179 } 180 return name; 181 } 182 183 /** 184 * Gets the specific network interface according to a given name. 185 * 186 * @param interfaceName 187 * the name to identify the searched network interface. 188 * @return the network interface with the specified name if one exists or 189 * {@code null} otherwise. 190 * @throws SocketException 191 * if an error occurs while getting the network interface 192 * information. 193 * @throws NullPointerException 194 * if the given interface's name is {@code null}. 195 */ 196 public static NetworkInterface getByName(String interfaceName) throws SocketException { 197 if (interfaceName == null) { 198 throw new NullPointerException(Msg.getString("K0330")); 199 } 200 for (NetworkInterface networkInterface : getNetworkInterfacesList()) { 201 if (networkInterface.name.equals(interfaceName)) { 202 return networkInterface; 203 } 204 } 205 return null; 206 } 207 208 /** 209 * Gets the specific network interface according to the given address. 210 * 211 * @param address 212 * the address to identify the searched network interface. 213 * @return the network interface with the specified address if one exists or 214 * {@code null} otherwise. 215 * @throws SocketException 216 * if an error occurs while getting the network interface 217 * information. 218 * @throws NullPointerException 219 * if the given interface address is invalid. 220 */ 221 public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException { 222 if (address == null) { 223 throw new NullPointerException(Msg.getString("K0331")); 224 } 225 for (NetworkInterface networkInterface : getNetworkInterfacesList()) { 226 if (networkInterface.addresses.contains(address)) { 227 return networkInterface; 228 } 229 } 230 return null; 231 } 232 233 /** 234 * Gets a list of all network interfaces available on the local system or 235 * {@code null} if no interface is available. 236 * 237 * @return the list of {@code NetworkInterface} instances representing the 238 * available interfaces. 239 * @throws SocketException 240 * if an error occurs while getting the network interface 241 * information. 242 */ 243 public static Enumeration<NetworkInterface> getNetworkInterfaces() throws SocketException { 244 return Collections.enumeration(getNetworkInterfacesList()); 245 } 246 247 private static List<NetworkInterface> getNetworkInterfacesList() throws SocketException { 248 NetworkInterface[] interfaces = getNetworkInterfacesImpl(); 249 250 for (NetworkInterface netif : interfaces) { 251 // Ensure that current NetworkInterface is bound to at least 252 // one InetAddress before processing 253 for (InetAddress addr : netif.addresses) { 254 if (addr.ipaddress.length == 16) { 255 if (addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) { 256 ((Inet6Address) addr).scopedIf = netif; 257 ((Inet6Address) addr).ifname = netif.name; 258 ((Inet6Address) addr).scope_ifname_set = true; 259 } 260 } 261 } 262 } 263 264 List<NetworkInterface> result = new ArrayList<NetworkInterface>(); 265 boolean[] peeked = new boolean[interfaces.length]; 266 for (int counter = 0; counter < interfaces.length; counter++) { 267 // If this interface has been touched, continue. 268 if (peeked[counter]) { 269 continue; 270 } 271 int counter2 = counter; 272 // Checks whether the following interfaces are children. 273 for (; counter2 < interfaces.length; counter2++) { 274 if (peeked[counter2]) { 275 continue; 276 } 277 if (interfaces[counter2].name.startsWith(interfaces[counter].name + ":")) { 278 // Tagged as peeked 279 peeked[counter2] = true; 280 interfaces[counter].children.add(interfaces[counter2]); 281 interfaces[counter2].parent = interfaces[counter]; 282 interfaces[counter].addresses.addAll(interfaces[counter2].addresses); 283 } 284 } 285 // Tagged as peeked 286 result.add(interfaces[counter]); 287 peeked[counter] = true; 288 } 289 return result; 290 } 291 292 /** 293 * Compares the specified object to this {@code NetworkInterface} and 294 * returns whether they are equal or not. The object must be an instance of 295 * {@code NetworkInterface} with the same name, {@code displayName} and list 296 * of network interfaces to be equal. 297 * 298 * @param obj 299 * the object to compare with this instance. 300 * @return {@code true} if the specified object is equal to this {@code 301 * NetworkInterface}, {@code false} otherwise. 302 * @see #hashCode() 303 */ 304 @Override 305 public boolean equals(Object obj) { 306 if (obj == this) { 307 return true; 308 } 309 if (!(obj instanceof NetworkInterface)) { 310 return false; 311 } 312 NetworkInterface rhs = (NetworkInterface) obj; 313 // TODO: should the order of the addresses matter (we use List.equals)? 314 return interfaceIndex == rhs.interfaceIndex && 315 name.equals(rhs.name) && displayName.equals(rhs.displayName) && 316 addresses.equals(rhs.addresses); 317 } 318 319 /** 320 * Returns the hash code for this {@code NetworkInterface}. Since the 321 * name should be unique for each network interface the hash code is 322 * generated using this name. 323 */ 324 @Override 325 public int hashCode() { 326 return name.hashCode(); 327 } 328 329 /** 330 * Gets a string containing a concise, human-readable description of this 331 * network interface. 332 * 333 * @return the textual representation for this network interface. 334 */ 335 @Override 336 public String toString() { 337 StringBuilder string = new StringBuilder(25); 338 string.append("["); 339 string.append(name); 340 string.append("]["); 341 string.append(displayName); 342 // BEGIN android-added: the RI shows this, and it's useful for IPv6 users. 343 string.append("]["); 344 string.append(interfaceIndex); 345 // END android-added 346 string.append("]"); 347 348 /* 349 * get the addresses through this call to make sure we only reveal those 350 * that we should 351 */ 352 Enumeration<InetAddress> theAddresses = getInetAddresses(); 353 if (theAddresses != null) { 354 while (theAddresses.hasMoreElements()) { 355 InetAddress nextAddress = theAddresses.nextElement(); 356 string.append("["); 357 string.append(nextAddress.toString()); 358 string.append("]"); 359 } 360 } 361 return string.toString(); 362 } 363 364 /** 365 * Returns a List the InterfaceAddresses for this network interface. 366 * <p> 367 * If there is a security manager, its checkConnect method is called with 368 * the InetAddress for each InterfaceAddress. Only InterfaceAddresses where 369 * the checkConnect doesn't throw a SecurityException will be returned. 370 * 371 * @return a List of the InterfaceAddresses for this network interface. 372 * @since 1.6 373 * @hide 374 */ 375 public List<InterfaceAddress> getInterfaceAddresses() { 376 SecurityManager sm = System.getSecurityManager(); 377 if (sm == null) { 378 return Collections.unmodifiableList(interfaceAddresses); 379 } 380 // TODO: Android should ditch SecurityManager and the associated pollution. 381 List<InterfaceAddress> result = new ArrayList<InterfaceAddress>(interfaceAddresses.size()); 382 for (InterfaceAddress ia : interfaceAddresses) { 383 try { 384 sm.checkConnect(ia.getAddress().getHostName(), CHECK_CONNECT_NO_PORT); 385 } catch (SecurityException e) { 386 continue; 387 } 388 result.add(ia); 389 } 390 return result; 391 } 392 393 /** 394 * Returns an {@code Enumeration} of all the sub-interfaces of this network interface. 395 * Sub-interfaces are also known as virtual interfaces. 396 * <p> 397 * For example, {@code eth0:1} would be a sub-interface of {@code eth0}. 398 * 399 * @return an Enumeration of all the sub-interfaces of this network interface 400 * @since 1.6 401 * @hide 402 */ 403 public Enumeration<NetworkInterface> getSubInterfaces() { 404 return Collections.enumeration(children); 405 } 406 407 /** 408 * Returns the parent NetworkInterface of this interface if this is a 409 * sub-interface, or null if it's a physical (non virtual) interface. 410 * 411 * @return the NetworkInterface this interface is attached to. 412 * @since 1.6 413 * @hide 414 */ 415 public NetworkInterface getParent() { 416 return parent; 417 } 418 419 /** 420 * Returns true if this network interface is up. 421 * 422 * @return true if the interface is up. 423 * @throws SocketException if an I/O error occurs. 424 * @since 1.6 425 * @hide 426 */ 427 public boolean isUp() throws SocketException { 428 if (addresses.isEmpty()) { 429 return false; 430 } 431 return isUpImpl(name); 432 } 433 private static native boolean isUpImpl(String n) throws SocketException; 434 435 /** 436 * Returns true if this network interface is a loopback interface. 437 * 438 * @return true if the interface is a loopback interface. 439 * @throws SocketException if an I/O error occurs. 440 * @since 1.6 441 * @hide 442 */ 443 public boolean isLoopback() throws SocketException { 444 if (addresses.isEmpty()) { 445 return false; 446 } 447 return isLoopbackImpl(name); 448 } 449 private static native boolean isLoopbackImpl(String n) throws SocketException; 450 451 /** 452 * Returns true if this network interface is a point-to-point interface. 453 * (For example, a PPP connection using a modem.) 454 * 455 * @return true if the interface is point-to-point. 456 * @throws SocketException if an I/O error occurs. 457 * @since 1.6 458 * @hide 459 */ 460 public boolean isPointToPoint() throws SocketException { 461 if (addresses.isEmpty()) { 462 return false; 463 } 464 return isPointToPointImpl(name); 465 } 466 private static native boolean isPointToPointImpl(String n) throws SocketException; 467 468 /** 469 * Returns true if this network interface supports multicast. 470 * 471 * @throws SocketException if an I/O error occurs. 472 * @since 1.6 473 * @hide 474 */ 475 public boolean supportsMulticast() throws SocketException { 476 if (addresses.isEmpty()) { 477 return false; 478 } 479 return supportsMulticastImpl(name); 480 } 481 private static native boolean supportsMulticastImpl(String n) throws SocketException; 482 483 /** 484 * Returns the hardware address of the interface, if it has one, and the 485 * user has the necessary privileges to access the address. 486 * 487 * @return a byte array containing the address or null if the address 488 * doesn't exist or is not accessible. 489 * @throws SocketException if an I/O error occurs. 490 * @since 1.6 491 * @hide 492 */ 493 public byte[] getHardwareAddress() throws SocketException { 494 if (addresses.isEmpty()) { 495 return new byte[0]; 496 } 497 return getHardwareAddressImpl(name); 498 } 499 private static native byte[] getHardwareAddressImpl(String n) throws SocketException; 500 501 /** 502 * Returns the Maximum Transmission Unit (MTU) of this interface. 503 * 504 * @return the value of the MTU for the interface. 505 * @throws SocketException if an I/O error occurs. 506 * @since 1.6 507 * @hide 508 */ 509 public int getMTU() throws SocketException { 510 if (addresses.isEmpty()) { 511 return 0; 512 } 513 return getMTUImpl(name); 514 } 515 private static native int getMTUImpl(String n) throws SocketException; 516 517 /** 518 * Returns true if this interface is a virtual interface (also called 519 * a sub-interface). Virtual interfaces are, on some systems, interfaces 520 * created as a child of a physical interface and given different settings 521 * (like address or MTU). Usually the name of the interface will the name of 522 * the parent followed by a colon (:) and a number identifying the child, 523 * since there can be several virtual interfaces attached to a single 524 * physical interface. 525 * 526 * @return true if this interface is a virtual interface. 527 * @since 1.6 528 * @hide 529 */ 530 public boolean isVirtual() { 531 return parent != null; 532 } 533} 534