NetworkInterface.java revision fd6bb3510c2f94d636f3572dcf5f7f4dcd1a2726
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        if (!(displayName.equals(""))) {
178            return displayName;
179        }
180        return name;
181    }
182
183    /**
184     * Gets the specific network interface according to a given name.
185     *
186     * @param interfaceName
187     *            the name to identify the searched network interface.
188     * @return the network interface with the specified name if one exists or
189     *         {@code null} otherwise.
190     * @throws SocketException
191     *             if an error occurs while getting the network interface
192     *             information.
193     * @throws NullPointerException
194     *             if the given interface's name is {@code null}.
195     */
196    public static NetworkInterface getByName(String interfaceName) throws SocketException {
197        if (interfaceName == null) {
198            throw new NullPointerException(Msg.getString("K0330"));
199        }
200        for (NetworkInterface networkInterface : getNetworkInterfacesList()) {
201            if (networkInterface.name.equals(interfaceName)) {
202                return networkInterface;
203            }
204        }
205        return null;
206    }
207
208    /**
209     * Gets the specific network interface according to the given address.
210     *
211     * @param address
212     *            the address to identify the searched network interface.
213     * @return the network interface with the specified address if one exists or
214     *         {@code null} otherwise.
215     * @throws SocketException
216     *             if an error occurs while getting the network interface
217     *             information.
218     * @throws NullPointerException
219     *             if the given interface address is invalid.
220     */
221    public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException {
222        if (address == null) {
223            throw new NullPointerException(Msg.getString("K0331"));
224        }
225        for (NetworkInterface networkInterface : getNetworkInterfacesList()) {
226            if (networkInterface.addresses.contains(address)) {
227                return networkInterface;
228            }
229        }
230        return null;
231    }
232
233    /**
234     * Gets a list of all network interfaces available on the local system or
235     * {@code null} if no interface is available.
236     *
237     * @return the list of {@code NetworkInterface} instances representing the
238     *         available interfaces.
239     * @throws SocketException
240     *             if an error occurs while getting the network interface
241     *             information.
242     */
243    public static Enumeration<NetworkInterface> getNetworkInterfaces() throws SocketException {
244        return Collections.enumeration(getNetworkInterfacesList());
245    }
246
247    private static List<NetworkInterface> getNetworkInterfacesList() throws SocketException {
248        NetworkInterface[] interfaces = getNetworkInterfacesImpl();
249
250        for (NetworkInterface netif : interfaces) {
251            // Ensure that current NetworkInterface is bound to at least
252            // one InetAddress before processing
253            for (InetAddress addr : netif.addresses) {
254                if (addr.ipaddress.length == 16) {
255                    if (addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) {
256                        ((Inet6Address) addr).scopedIf = netif;
257                        ((Inet6Address) addr).ifname = netif.name;
258                        ((Inet6Address) addr).scope_ifname_set = true;
259                    }
260                }
261            }
262        }
263
264        List<NetworkInterface> result = new ArrayList<NetworkInterface>();
265        boolean[] peeked = new boolean[interfaces.length];
266        for (int counter = 0; counter < interfaces.length; counter++) {
267            // If this interface has been touched, continue.
268            if (peeked[counter]) {
269                continue;
270            }
271            int counter2 = counter;
272            // Checks whether the following interfaces are children.
273            for (; counter2 < interfaces.length; counter2++) {
274                if (peeked[counter2]) {
275                    continue;
276                }
277                if (interfaces[counter2].name.startsWith(interfaces[counter].name + ":")) {
278                    // Tagged as peeked
279                    peeked[counter2] = true;
280                    interfaces[counter].children.add(interfaces[counter2]);
281                    interfaces[counter2].parent = interfaces[counter];
282                    interfaces[counter].addresses.addAll(interfaces[counter2].addresses);
283                }
284            }
285            // Tagged as peeked
286            result.add(interfaces[counter]);
287            peeked[counter] = true;
288        }
289        return result;
290    }
291
292    /**
293     * Compares the specified object to this {@code NetworkInterface} and
294     * returns whether they are equal or not. The object must be an instance of
295     * {@code NetworkInterface} with the same name, {@code displayName} and list
296     * of network interfaces to be equal.
297     *
298     * @param obj
299     *            the object to compare with this instance.
300     * @return {@code true} if the specified object is equal to this {@code
301     *         NetworkInterface}, {@code false} otherwise.
302     * @see #hashCode()
303     */
304    @Override
305    public boolean equals(Object obj) {
306        if (obj == this) {
307            return true;
308        }
309        if (!(obj instanceof NetworkInterface)) {
310            return false;
311        }
312        NetworkInterface rhs = (NetworkInterface) obj;
313        // TODO: should the order of the addresses matter (we use List.equals)?
314        return interfaceIndex == rhs.interfaceIndex &&
315                name.equals(rhs.name) && displayName.equals(rhs.displayName) &&
316                addresses.equals(rhs.addresses);
317    }
318
319    /**
320     * Returns the hash code for this {@code NetworkInterface}. Since the
321     * name should be unique for each network interface the hash code is
322     * generated using this name.
323     */
324    @Override
325    public int hashCode() {
326        return name.hashCode();
327    }
328
329    /**
330     * Gets a string containing a concise, human-readable description of this
331     * network interface.
332     *
333     * @return the textual representation for this network interface.
334     */
335    @Override
336    public String toString() {
337        StringBuilder string = new StringBuilder(25);
338        string.append("[");
339        string.append(name);
340        string.append("][");
341        string.append(displayName);
342        // BEGIN android-added: the RI shows this, and it's useful for IPv6 users.
343        string.append("][");
344        string.append(interfaceIndex);
345        // END android-added
346        string.append("]");
347
348        /*
349         * get the addresses through this call to make sure we only reveal those
350         * that we should
351         */
352        Enumeration<InetAddress> theAddresses = getInetAddresses();
353        if (theAddresses != null) {
354            while (theAddresses.hasMoreElements()) {
355                InetAddress nextAddress = theAddresses.nextElement();
356                string.append("[");
357                string.append(nextAddress.toString());
358                string.append("]");
359            }
360        }
361        return string.toString();
362    }
363
364    /**
365     * Returns a List the InterfaceAddresses for this network interface.
366     * <p>
367     * If there is a security manager, its checkConnect method is called with
368     * the InetAddress for each InterfaceAddress. Only InterfaceAddresses where
369     * the checkConnect doesn't throw a SecurityException will be returned.
370     *
371     * @return a List of the InterfaceAddresses for this network interface.
372     * @since 1.6
373     * @hide
374     */
375    public List<InterfaceAddress> getInterfaceAddresses() {
376        SecurityManager sm = System.getSecurityManager();
377        if (sm == null) {
378            return Collections.unmodifiableList(interfaceAddresses);
379        }
380        // TODO: Android should ditch SecurityManager and the associated pollution.
381        List<InterfaceAddress> result = new ArrayList<InterfaceAddress>(interfaceAddresses.size());
382        for (InterfaceAddress ia : interfaceAddresses) {
383            try {
384                sm.checkConnect(ia.getAddress().getHostName(), CHECK_CONNECT_NO_PORT);
385            } catch (SecurityException e) {
386                continue;
387            }
388            result.add(ia);
389        }
390        return result;
391    }
392
393    /**
394     * Returns an {@code Enumeration} of all the sub-interfaces of this network interface.
395     * Sub-interfaces are also known as virtual interfaces.
396     * <p>
397     * For example, {@code eth0:1} would be a sub-interface of {@code eth0}.
398     *
399     * @return an Enumeration of all the sub-interfaces of this network interface
400     * @since 1.6
401     * @hide
402     */
403    public Enumeration<NetworkInterface> getSubInterfaces() {
404        return Collections.enumeration(children);
405    }
406
407    /**
408     * Returns the parent NetworkInterface of this interface if this is a
409     * sub-interface, or null if it's a physical (non virtual) interface.
410     *
411     * @return the NetworkInterface this interface is attached to.
412     * @since 1.6
413     * @hide
414     */
415    public NetworkInterface getParent() {
416        return parent;
417    }
418
419    /**
420     * Returns true if this network interface is up.
421     *
422     * @return true if the interface is up.
423     * @throws SocketException if an I/O error occurs.
424     * @since 1.6
425     * @hide
426     */
427    public boolean isUp() throws SocketException {
428        if (addresses.isEmpty()) {
429            return false;
430        }
431        return isUpImpl(name);
432    }
433    private static native boolean isUpImpl(String n) throws SocketException;
434
435    /**
436     * Returns true if this network interface is a loopback interface.
437     *
438     * @return true if the interface is a loopback interface.
439     * @throws SocketException if an I/O error occurs.
440     * @since 1.6
441     * @hide
442     */
443    public boolean isLoopback() throws SocketException {
444        if (addresses.isEmpty()) {
445            return false;
446        }
447        return isLoopbackImpl(name);
448    }
449    private static native boolean isLoopbackImpl(String n) throws SocketException;
450
451    /**
452     * Returns true if this network interface is a point-to-point interface.
453     * (For example, a PPP connection using a modem.)
454     *
455     * @return true if the interface is point-to-point.
456     * @throws SocketException if an I/O error occurs.
457     * @since 1.6
458     * @hide
459     */
460    public boolean isPointToPoint() throws SocketException {
461        if (addresses.isEmpty()) {
462            return false;
463        }
464        return isPointToPointImpl(name);
465    }
466    private static native boolean isPointToPointImpl(String n) throws SocketException;
467
468    /**
469     * Returns true if this network interface supports multicast.
470     *
471     * @throws SocketException if an I/O error occurs.
472     * @since 1.6
473     * @hide
474     */
475    public boolean supportsMulticast() throws SocketException {
476        if (addresses.isEmpty()) {
477            return false;
478        }
479        return supportsMulticastImpl(name);
480    }
481    private static native boolean supportsMulticastImpl(String n) throws SocketException;
482
483    /**
484     * Returns the hardware address of the interface, if it has one, and the
485     * user has the necessary privileges to access the address.
486     *
487     * @return a byte array containing the address or null if the address
488     *         doesn't exist or is not accessible.
489     * @throws SocketException if an I/O error occurs.
490     * @since 1.6
491     * @hide
492     */
493    public byte[] getHardwareAddress() throws SocketException {
494        if (addresses.isEmpty()) {
495            return new byte[0];
496        }
497        return getHardwareAddressImpl(name);
498    }
499    private static native byte[] getHardwareAddressImpl(String n) throws SocketException;
500
501    /**
502     * Returns the Maximum Transmission Unit (MTU) of this interface.
503     *
504     * @return the value of the MTU for the interface.
505     * @throws SocketException if an I/O error occurs.
506     * @since 1.6
507     * @hide
508     */
509    public int getMTU() throws SocketException {
510        if (addresses.isEmpty()) {
511            return 0;
512        }
513        return getMTUImpl(name);
514    }
515    private static native int getMTUImpl(String n) throws SocketException;
516
517    /**
518     * Returns true if this interface is a virtual interface (also called
519     * a sub-interface). Virtual interfaces are, on some systems, interfaces
520     * created as a child of a physical interface and given different settings
521     * (like address or MTU). Usually the name of the interface will the name of
522     * the parent followed by a colon (:) and a number identifying the child,
523     * since there can be several virtual interfaces attached to a single
524     * physical interface.
525     *
526     * @return true if this interface is a virtual interface.
527     * @since 1.6
528     * @hide
529     */
530    public boolean isVirtual() {
531        return parent != null;
532    }
533}
534