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