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