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