• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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