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