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