NetworkInterface.java revision b5fc5ecd3fe5315fc2756c0c25adc458cc8c8d91
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.Arrays; 21import java.util.Enumeration; 22import java.util.LinkedHashMap; 23import java.util.List; 24import java.util.Map; 25import java.util.Vector; 26 27import org.apache.harmony.luni.util.Msg; 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 41 static final int UNSET_INTERFACE_INDEX = -1; 42 43 private String name; 44 45 private String displayName; 46 47 InetAddress addresses[]; 48 49 // The interface index is a positive integer which is non-negative. Where 50 // value is zero then we do not have an index for the interface (which 51 // occurs in systems which only support IPV4) 52 private int interfaceIndex; 53 54 private int hashCode; 55 56 // BEGIN android-changed: we pay this extra complexity on the Java side 57 // in return for vastly simpler native code. 58 private static native InterfaceAddress[] getInterfaceAddresses() throws SocketException; 59 60 private static NetworkInterface[] getNetworkInterfacesImpl() throws SocketException { 61 Map<String, NetworkInterface> networkInterfaces = new LinkedHashMap<String, NetworkInterface>(); 62 for (InterfaceAddress ia : getInterfaceAddresses()) { 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 networkInterfaces.put(name, ni); 69 } else { 70 ni.addInterfaceAddress(ia.address); 71 } 72 } 73 } 74 return networkInterfaces.values().toArray(new NetworkInterface[networkInterfaces.size()]); 75 } 76 77 private void addInterfaceAddress(InetAddress address) { 78 InetAddress[] newAddresses = new InetAddress[addresses.length + 1]; 79 System.arraycopy(addresses, 0, newAddresses, 0, addresses.length); 80 newAddresses[addresses.length] = address; 81 addresses = newAddresses; 82 } 83 // END android-changed 84 85 /** 86 * This constructor is used by the native method in order to construct the 87 * NetworkInterface objects in the array that it returns. 88 * 89 * @param name 90 * internal name associated with the interface. 91 * @param displayName 92 * a user interpretable name for the interface. 93 * @param addresses 94 * the Internet addresses associated with the interface. 95 * @param interfaceIndex 96 * an index for the interface. Only set for platforms that 97 * support IPV6. 98 */ 99 NetworkInterface(String name, String displayName, InetAddress addresses[], 100 int interfaceIndex) { 101 this.name = name; 102 this.displayName = displayName; 103 this.addresses = addresses; 104 this.interfaceIndex = interfaceIndex; 105 } 106 107 /** 108 * Returns the index for the network interface. Unless the system supports 109 * IPV6 this will be 0. 110 * 111 * @return the index 112 */ 113 int getIndex() { 114 return interfaceIndex; 115 } 116 117 /** 118 * Returns the first address for the network interface. This is used in the 119 * natives when we need one of the addresses for the interface and any one 120 * will do 121 * 122 * @return the first address if one exists, otherwise null. 123 */ 124 InetAddress getFirstAddress() { 125 if ((addresses != null) && (addresses.length >= 1)) { 126 return addresses[0]; 127 } 128 return null; 129 } 130 131 /** 132 * Gets the name associated with this network interface. 133 * 134 * @return the name of this {@code NetworkInterface} instance. 135 */ 136 public String getName() { 137 return name; 138 } 139 140 /** 141 * Gets a list of addresses bound to this network interface. 142 * 143 * @return the address list of the represented network interface. 144 */ 145 public Enumeration<InetAddress> getInetAddresses() { 146 /* 147 * create new vector from which Enumeration to be returned can be 148 * generated set the initial capacity to be the number of addresses for 149 * the network interface which is the maximum required size 150 */ 151 152 /* 153 * return an empty enumeration if there are no addresses associated with 154 * the interface 155 */ 156 if (addresses == null) { 157 return new Vector<InetAddress>(0).elements(); 158 } 159 160 /* 161 * for those configuration that support the security manager we only 162 * return addresses for which checkConnect returns true 163 */ 164 Vector<InetAddress> accessibleAddresses = new Vector<InetAddress>( 165 addresses.length); 166 167 /* 168 * get the security manager. If one does not exist just return the full 169 * list 170 */ 171 SecurityManager security = System.getSecurityManager(); 172 if (security == null) { 173 return (new Vector<InetAddress>(Arrays.asList(addresses))) 174 .elements(); 175 } 176 177 /* 178 * ok security manager exists so check each address and return those 179 * that pass 180 */ 181 for (InetAddress element : addresses) { 182 if (security != null) { 183 try { 184 /* 185 * since we don't have a port in this case we pass in 186 * NO_PORT 187 */ 188 security.checkConnect(element.getHostName(), 189 CHECK_CONNECT_NO_PORT); 190 accessibleAddresses.add(element); 191 } catch (SecurityException e) { 192 } 193 } 194 } 195 196 Enumeration<InetAddress> theAccessibleElements = accessibleAddresses 197 .elements(); 198 if (theAccessibleElements.hasMoreElements()) { 199 return accessibleAddresses.elements(); 200 } 201 202 return new Vector<InetAddress>(0).elements(); 203 } 204 205 /** 206 * Gets the human-readable name associated with this network interface. 207 * 208 * @return the display name of this network interface or the name if the 209 * display name is not available. 210 */ 211 public String getDisplayName() { 212 /* 213 * we should return the display name unless it is blank in this case 214 * return the name so that something is displayed. 215 */ 216 if (!(displayName.equals(""))) { //$NON-NLS-1$ 217 return displayName; 218 } 219 return name; 220 } 221 222 /** 223 * Gets the specific network interface according to a given name. 224 * 225 * @param interfaceName 226 * the name to identify the searched network interface. 227 * @return the network interface with the specified name if one exists or 228 * {@code null} otherwise. 229 * @throws SocketException 230 * if an error occurs while getting the network interface 231 * information. 232 * @throws NullPointerException 233 * if the given interface's name is {@code null}. 234 */ 235 public static NetworkInterface getByName(String interfaceName) 236 throws SocketException { 237 238 if (interfaceName == null) { 239 throw new NullPointerException(Msg.getString("K0330")); //$NON-NLS-1$ 240 } 241 242 /* 243 * get the list of interfaces, and then loop through the list to look 244 * for one with a matching name 245 */ 246 Enumeration<NetworkInterface> interfaces = getNetworkInterfaces(); 247 if (interfaces != null) { 248 while (interfaces.hasMoreElements()) { 249 NetworkInterface netif = interfaces.nextElement(); 250 if (netif.getName().equals(interfaceName)) { 251 return netif; 252 } 253 } 254 } 255 return null; 256 } 257 258 /** 259 * Gets the specific network interface according to the given address. 260 * 261 * @param address 262 * the address to identify the searched network interface. 263 * @return the network interface with the specified address if one exists or 264 * {@code null} otherwise. 265 * @throws SocketException 266 * if an error occurs while getting the network interface 267 * information. 268 * @throws NullPointerException 269 * if the given interface address is invalid. 270 */ 271 public static NetworkInterface getByInetAddress(InetAddress address) 272 throws SocketException { 273 274 if (address == null) { 275 throw new NullPointerException(Msg.getString("K0331")); //$NON-NLS-1$ 276 } 277 278 /* 279 * get the list of interfaces, and then loop through the list. For each 280 * interface loop through the associated set of internet addresses and 281 * see if one matches. If so return that network interface 282 */ 283 Enumeration<NetworkInterface> interfaces = getNetworkInterfaces(); 284 if (interfaces != null) { 285 while (interfaces.hasMoreElements()) { 286 NetworkInterface netif = interfaces.nextElement(); 287 /* 288 * to be compatible use the raw addresses without any security 289 * filtering 290 */ 291 // Enumeration netifAddresses = netif.getInetAddresses(); 292 if ((netif.addresses != null) && (netif.addresses.length != 0)) { 293 Enumeration<InetAddress> netifAddresses = (new Vector<InetAddress>( 294 Arrays.asList(netif.addresses))).elements(); 295 if (netifAddresses != null) { 296 while (netifAddresses.hasMoreElements()) { 297 if (address.equals(netifAddresses.nextElement())) { 298 return netif; 299 } 300 } 301 } 302 } 303 } 304 } 305 return null; 306 } 307 308 /** 309 * Gets a list of all network interfaces available on the local system or 310 * {@code null} if no interface is available. 311 * 312 * @return the list of {@code NetworkInterface} instances representing the 313 * available interfaces. 314 * @throws SocketException 315 * if an error occurs while getting the network interface 316 * information. 317 */ 318 public static Enumeration<NetworkInterface> getNetworkInterfaces() 319 throws SocketException { 320 NetworkInterface[] interfaces = getNetworkInterfacesImpl(); 321 if (interfaces == null) { 322 return null; 323 } 324 325 for (NetworkInterface netif : interfaces) { 326 // Ensure that current NetworkInterface is bound to at least 327 // one InetAddress before processing 328 if (netif.addresses != null) { 329 for (InetAddress addr : netif.addresses) { 330 if (16 == addr.ipaddress.length) { 331 if (addr.isLinkLocalAddress() 332 || addr.isSiteLocalAddress()) { 333 ((Inet6Address) addr).scopedIf = netif; 334 ((Inet6Address) addr).ifname = netif.name; 335 ((Inet6Address) addr).scope_ifname_set = true; 336 } 337 } 338 } 339 } 340 } 341 342 return (new Vector<NetworkInterface>(Arrays.asList(interfaces))) 343 .elements(); 344 } 345 346 /** 347 * Compares the specified object to this {@code NetworkInterface} and 348 * returns whether they are equal or not. The object must be an instance of 349 * {@code NetworkInterface} with the same name, {@code displayName} and list 350 * of network interfaces to be equal. 351 * 352 * @param obj 353 * the object to compare with this instance. 354 * @return {@code true} if the specified object is equal to this {@code 355 * NetworkInterface}, {@code false} otherwise. 356 * @see #hashCode() 357 */ 358 @Override 359 public boolean equals(Object obj) { 360 // Return true if it is the exact same object. 361 if (obj == this) { 362 return true; 363 } 364 365 // Ensure it is the right type. 366 if (!(obj instanceof NetworkInterface)) { 367 return false; 368 } 369 370 /* 371 * Make sure that some simple checks pass. If the name is not the same 372 * then we are sure it is not the same one. We don't check the hashcode 373 * as it is generated from the name which we check 374 */ 375 NetworkInterface netif = (NetworkInterface) obj; 376 377 if (netif.getIndex() != interfaceIndex) { 378 return false; 379 } 380 381 if (!(name.equals("")) && (!netif.getName().equals(name))) { //$NON-NLS-1$ 382 return false; 383 } 384 385 if ((name.equals("")) && (!netif.getName().equals(displayName))) { //$NON-NLS-1$ 386 return false; 387 } 388 389 // Now check that the collection of internet addresses are equal. 390 Enumeration<InetAddress> netifAddresses = netif.getInetAddresses(); 391 Enumeration<InetAddress> localifAddresses = getInetAddresses(); 392 393 // Check for both null (same), or one null (not same). 394 if (netifAddresses == null) { 395 return localifAddresses == null; 396 } 397 if (localifAddresses == null) { 398 return false; 399 } 400 401 // Both are not null, check InetAddress elements. 402 while (netifAddresses.hasMoreElements() 403 && localifAddresses.hasMoreElements()) { 404 if (!(localifAddresses.nextElement()).equals( 405 netifAddresses.nextElement())) { 406 return false; 407 } 408 } 409 410 /* 411 * Now make sure that they had the same number of addresses, if not they 412 * are not the same interface. 413 */ 414 return !netifAddresses.hasMoreElements() 415 && !localifAddresses.hasMoreElements(); 416 } 417 418 /** 419 * Gets the hashcode for this {@code NetworkInterface} instance. Since the 420 * name should be unique for each network interface the hashcode is 421 * generated using this name. 422 * 423 * @return the hashcode value for this {@code NetworkInterface} instance. 424 */ 425 @Override 426 public int hashCode() { 427 if (hashCode == 0) { 428 hashCode = name.hashCode(); 429 } 430 return hashCode; 431 } 432 433 /** 434 * Gets a string containing a concise, human-readable description of this 435 * network interface. 436 * 437 * @return the textual representation for this network interface. 438 */ 439 @Override 440 public String toString() { 441 StringBuilder string = new StringBuilder(25); 442 string.append("["); //$NON-NLS-1$ 443 string.append(name); 444 string.append("]["); //$NON-NLS-1$ 445 string.append(displayName); 446 // BEGIN android-added: the RI shows this, and it's useful for IPv6 users. 447 string.append("]["); //$NON-NLS-1$ 448 string.append(interfaceIndex); 449 // END android-added 450 string.append("]"); //$NON-NLS-1$ 451 452 /* 453 * get the addresses through this call to make sure we only reveal those 454 * that we should 455 */ 456 Enumeration<InetAddress> theAddresses = getInetAddresses(); 457 if (theAddresses != null) { 458 while (theAddresses.hasMoreElements()) { 459 InetAddress nextAddress = theAddresses.nextElement(); 460 string.append("["); //$NON-NLS-1$ 461 string.append(nextAddress.toString()); 462 string.append("]"); //$NON-NLS-1$ 463 } 464 } 465 return string.toString(); 466 } 467} 468