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