NetworkInterface.java revision ad41624e761bcf1af9c8008eb45187fc13983717
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 return Collections.enumeration(addresses); 143 } 144 145 /** 146 * Gets the human-readable name associated with this network interface. 147 * 148 * @return the display name of this network interface or the name if the 149 * display name is not available. 150 */ 151 public String getDisplayName() { 152 /* 153 * we should return the display name unless it is blank in this case 154 * return the name so that something is displayed. 155 */ 156 return displayName.isEmpty() ? name : displayName; 157 } 158 159 /** 160 * Gets the specific network interface according to a given name. 161 * 162 * @param interfaceName 163 * the name to identify the searched network interface. 164 * @return the network interface with the specified name if one exists or 165 * {@code null} otherwise. 166 * @throws SocketException 167 * if an error occurs while getting the network interface 168 * information. 169 * @throws NullPointerException 170 * if the given interface's name is {@code null}. 171 */ 172 public static NetworkInterface getByName(String interfaceName) throws SocketException { 173 if (interfaceName == null) { 174 throw new NullPointerException(); 175 } 176 for (NetworkInterface networkInterface : getNetworkInterfacesList()) { 177 if (networkInterface.name.equals(interfaceName)) { 178 return networkInterface; 179 } 180 } 181 return null; 182 } 183 184 /** 185 * Gets the specific network interface according to the given address. 186 * 187 * @param address 188 * the address to identify the searched network interface. 189 * @return the network interface with the specified address if one exists or 190 * {@code null} otherwise. 191 * @throws SocketException 192 * if an error occurs while getting the network interface 193 * information. 194 * @throws NullPointerException 195 * if the given interface address is invalid. 196 */ 197 public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException { 198 if (address == null) { 199 throw new NullPointerException("address == null"); 200 } 201 for (NetworkInterface networkInterface : getNetworkInterfacesList()) { 202 if (networkInterface.addresses.contains(address)) { 203 return networkInterface; 204 } 205 } 206 return null; 207 } 208 209 /** 210 * Gets a list of all network interfaces available on the local system or 211 * {@code null} if no interface is available. 212 * 213 * @return the list of {@code NetworkInterface} instances representing the 214 * available interfaces. 215 * @throws SocketException 216 * if an error occurs while getting the network interface 217 * information. 218 */ 219 public static Enumeration<NetworkInterface> getNetworkInterfaces() throws SocketException { 220 return Collections.enumeration(getNetworkInterfacesList()); 221 } 222 223 private static List<NetworkInterface> getNetworkInterfacesList() throws SocketException { 224 NetworkInterface[] interfaces = getNetworkInterfacesImpl(); 225 226 for (NetworkInterface netif : interfaces) { 227 // Ensure that current NetworkInterface is bound to at least 228 // one InetAddress before processing 229 for (InetAddress addr : netif.addresses) { 230 if (addr.ipaddress.length == 16) { 231 if (addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) { 232 ((Inet6Address) addr).scopedIf = netif; 233 ((Inet6Address) addr).ifname = netif.name; 234 ((Inet6Address) addr).scope_ifname_set = true; 235 } 236 } 237 } 238 } 239 240 List<NetworkInterface> result = new ArrayList<NetworkInterface>(); 241 boolean[] peeked = new boolean[interfaces.length]; 242 for (int counter = 0; counter < interfaces.length; counter++) { 243 // If this interface has been touched, continue. 244 if (peeked[counter]) { 245 continue; 246 } 247 int counter2 = counter; 248 // Checks whether the following interfaces are children. 249 for (; counter2 < interfaces.length; counter2++) { 250 if (peeked[counter2]) { 251 continue; 252 } 253 if (interfaces[counter2].name.startsWith(interfaces[counter].name + ":")) { 254 // Tagged as peeked 255 peeked[counter2] = true; 256 interfaces[counter].children.add(interfaces[counter2]); 257 interfaces[counter2].parent = interfaces[counter]; 258 interfaces[counter].addresses.addAll(interfaces[counter2].addresses); 259 } 260 } 261 // Tagged as peeked 262 result.add(interfaces[counter]); 263 peeked[counter] = true; 264 } 265 return result; 266 } 267 268 /** 269 * Compares the specified object to this {@code NetworkInterface} and 270 * returns whether they are equal or not. The object must be an instance of 271 * {@code NetworkInterface} with the same name, {@code displayName} and list 272 * of network interfaces to be equal. 273 * 274 * @param obj 275 * the object to compare with this instance. 276 * @return {@code true} if the specified object is equal to this {@code 277 * NetworkInterface}, {@code false} otherwise. 278 * @see #hashCode() 279 */ 280 @Override 281 public boolean equals(Object obj) { 282 if (obj == this) { 283 return true; 284 } 285 if (!(obj instanceof NetworkInterface)) { 286 return false; 287 } 288 NetworkInterface rhs = (NetworkInterface) obj; 289 // TODO: should the order of the addresses matter (we use List.equals)? 290 return interfaceIndex == rhs.interfaceIndex && 291 name.equals(rhs.name) && displayName.equals(rhs.displayName) && 292 addresses.equals(rhs.addresses); 293 } 294 295 /** 296 * Returns the hash code for this {@code NetworkInterface}. Since the 297 * name should be unique for each network interface the hash code is 298 * generated using this name. 299 */ 300 @Override 301 public int hashCode() { 302 return name.hashCode(); 303 } 304 305 /** 306 * Gets a string containing a concise, human-readable description of this 307 * network interface. 308 * 309 * @return the textual representation for this network interface. 310 */ 311 @Override 312 public String toString() { 313 StringBuilder string = new StringBuilder(25); 314 string.append("["); 315 string.append(name); 316 string.append("]["); 317 string.append(displayName); 318 string.append("]["); 319 string.append(interfaceIndex); 320 string.append("]"); 321 322 /* 323 * get the addresses through this call to make sure we only reveal those 324 * that we should 325 */ 326 Enumeration<InetAddress> theAddresses = getInetAddresses(); 327 if (theAddresses != null) { 328 while (theAddresses.hasMoreElements()) { 329 InetAddress nextAddress = theAddresses.nextElement(); 330 string.append("["); 331 string.append(nextAddress.toString()); 332 string.append("]"); 333 } 334 } 335 return string.toString(); 336 } 337 338 /** 339 * Returns a List of the InterfaceAddresses for this network interface. 340 * @since 1.6 341 */ 342 public List<InterfaceAddress> getInterfaceAddresses() { 343 return Collections.unmodifiableList(interfaceAddresses); 344 } 345 346 /** 347 * Returns an {@code Enumeration} of all the sub-interfaces of this network interface. 348 * Sub-interfaces are also known as virtual interfaces. 349 * <p> 350 * For example, {@code eth0:1} would be a sub-interface of {@code eth0}. 351 * 352 * @return an Enumeration of all the sub-interfaces of this network interface 353 * @since 1.6 354 */ 355 public Enumeration<NetworkInterface> getSubInterfaces() { 356 return Collections.enumeration(children); 357 } 358 359 /** 360 * Returns the parent NetworkInterface of this interface if this is a 361 * sub-interface, or null if it's a physical (non virtual) interface. 362 * 363 * @return the NetworkInterface this interface is attached to. 364 * @since 1.6 365 */ 366 public NetworkInterface getParent() { 367 return parent; 368 } 369 370 /** 371 * Returns true if this network interface is up. 372 * 373 * @return true if the interface is up. 374 * @throws SocketException if an I/O error occurs. 375 * @since 1.6 376 */ 377 public boolean isUp() throws SocketException { 378 if (addresses.isEmpty()) { 379 return false; 380 } 381 return isUpImpl(name); 382 } 383 private static native boolean isUpImpl(String n) throws SocketException; 384 385 /** 386 * Returns true if this network interface is a loopback interface. 387 * 388 * @return true if the interface is a loopback interface. 389 * @throws SocketException if an I/O error occurs. 390 * @since 1.6 391 */ 392 public boolean isLoopback() throws SocketException { 393 if (addresses.isEmpty()) { 394 return false; 395 } 396 return isLoopbackImpl(name); 397 } 398 private static native boolean isLoopbackImpl(String n) throws SocketException; 399 400 /** 401 * Returns true if this network interface is a point-to-point interface. 402 * (For example, a PPP connection using a modem.) 403 * 404 * @return true if the interface is point-to-point. 405 * @throws SocketException if an I/O error occurs. 406 * @since 1.6 407 */ 408 public boolean isPointToPoint() throws SocketException { 409 if (addresses.isEmpty()) { 410 return false; 411 } 412 return isPointToPointImpl(name); 413 } 414 private static native boolean isPointToPointImpl(String n) throws SocketException; 415 416 /** 417 * Returns true if this network interface supports multicast. 418 * 419 * @throws SocketException if an I/O error occurs. 420 * @since 1.6 421 */ 422 public boolean supportsMulticast() throws SocketException { 423 if (addresses.isEmpty()) { 424 return false; 425 } 426 return supportsMulticastImpl(name); 427 } 428 private static native boolean supportsMulticastImpl(String n) throws SocketException; 429 430 /** 431 * Returns the hardware address of the interface, if it has one, and the 432 * user has the necessary privileges to access the address. 433 * 434 * @return a byte array containing the address or null if the address 435 * doesn't exist or is not accessible. 436 * @throws SocketException if an I/O error occurs. 437 * @since 1.6 438 */ 439 public byte[] getHardwareAddress() throws SocketException { 440 if (addresses.isEmpty()) { 441 return EmptyArray.BYTE; 442 } 443 return getHardwareAddressImpl(name); 444 } 445 private static native byte[] getHardwareAddressImpl(String n) throws SocketException; 446 447 /** 448 * Returns the Maximum Transmission Unit (MTU) of this interface. 449 * 450 * @return the value of the MTU for the interface. 451 * @throws SocketException if an I/O error occurs. 452 * @since 1.6 453 */ 454 public int getMTU() throws SocketException { 455 if (addresses.isEmpty()) { 456 return 0; 457 } 458 return getMTUImpl(name); 459 } 460 private static native int getMTUImpl(String n) throws SocketException; 461 462 /** 463 * Returns true if this interface is a virtual interface (also called 464 * a sub-interface). Virtual interfaces are, on some systems, interfaces 465 * created as a child of a physical interface and given different settings 466 * (like address or MTU). Usually the name of the interface will the name of 467 * the parent followed by a colon (:) and a number identifying the child, 468 * since there can be several virtual interfaces attached to a single 469 * physical interface. 470 * 471 * @return true if this interface is a virtual interface. 472 * @since 1.6 473 */ 474 public boolean isVirtual() { 475 return parent != null; 476 } 477} 478