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