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