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