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