NetworkInterface.java revision fdb2704414a9ed92394ada0d1395e4db86889465
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.Arrays;
21import java.util.Enumeration;
22import java.util.Vector;
23
24import org.apache.harmony.luni.util.Msg;
25
26/**
27 * This class provides an methods that are used to get information about the
28 * network interfaces supported by the system
29 */
30public final class NetworkInterface extends Object {
31
32    private static final int CHECK_CONNECT_NO_PORT = -1;
33
34    static final int NO_INTERFACE_INDEX = 0;
35
36    static final int UNSET_INTERFACE_INDEX = -1;
37
38    private String name;
39
40    private String displayName;
41
42    InetAddress addresses[];
43
44    // The interface index is a positive integer which is non-negative. Where
45    // value is zero then we do not have an index for the interface (which
46    // occurs in systems which only support IPV4)
47    private int interfaceIndex;
48
49    private int hashCode;
50
51    /**
52     * This native returns the list of network interfaces supported by the
53     * system. An array is returned which is easier to generate and which can
54     * easily be converted into the required enumeration on the java side
55     *
56     * @return an array of zero or more NetworkInterface objects
57     *
58     * @throws SocketException
59     *             if an error occurs when getting network interface information
60     */
61    private static native NetworkInterface[] getNetworkInterfacesImpl()
62            throws SocketException;
63
64    /**
65     * This constructor is used by the native method in order to construct the
66     * NetworkInterface objects in the array that it returns
67     *
68     * @param name
69     *            internal name associated with the interface
70     * @param displayName
71     *            a user interpretable name for the interface
72     * @param addresses
73     *            the Internet addresses associated with the interface
74     * @param interfaceIndex
75     *            an index for the interface. Only set for platforms that
76     *            support IPV6
77     */
78    NetworkInterface(String name, String displayName, InetAddress addresses[],
79            int interfaceIndex) {
80        this.name = name;
81        this.displayName = displayName;
82        this.addresses = addresses;
83        this.interfaceIndex = interfaceIndex;
84    }
85
86    /**
87     * Returns the index for the network interface. Unless the system supports
88     * IPV6 this will be 0.
89     *
90     * @return the index
91     */
92    int getIndex() {
93        return interfaceIndex;
94    }
95
96    /**
97     * Returns the first address for the network interface. This is used in the
98     * natives when we need one of the addresses for the interface and any one
99     * will do
100     *
101     * @return the first address if one exists, otherwise null.
102     */
103    InetAddress getFirstAddress() {
104        if ((addresses != null) && (addresses.length >= 1)) {
105            return addresses[0];
106        }
107        return null;
108    }
109
110    /**
111     * Returns the name associated with the network interface
112     *
113     * @return name associated with the network interface
114     */
115    public String getName() {
116        return name;
117    }
118
119    /**
120     * Returns the list of internet addresses bound to the interface
121     *
122     * @return list of internet addresses bound to the interface
123     */
124    public Enumeration<InetAddress> getInetAddresses() {
125        /*
126         * create new vector from which Enumeration to be returned can be
127         * generated set the initial capacity to be the number of addresses for
128         * the network interface which is the maximum required size
129         */
130
131        /*
132         * return an empty enumeration if there are no addresses associated with
133         * the interface
134         */
135        if (addresses == null) {
136            return new Vector<InetAddress>(0).elements();
137        }
138
139        /*
140         * for those configuration that support the security manager we only
141         * return addresses for which checkConnect returns true
142         */
143        Vector<InetAddress> accessibleAddresses = new Vector<InetAddress>(
144                addresses.length);
145
146        /*
147         * get the security manager. If one does not exist just return the full
148         * list
149         */
150        SecurityManager security = System.getSecurityManager();
151        if (security == null) {
152            return (new Vector<InetAddress>(Arrays.asList(addresses)))
153                    .elements();
154        }
155
156        /*
157         * ok security manager exists so check each address and return those
158         * that pass
159         */
160        for (InetAddress element : addresses) {
161            if (security != null) {
162                try {
163                    /*
164                     * since we don't have a port in this case we pass in
165                     * NO_PORT
166                     */
167                    security.checkConnect(element.getHostName(),
168                            CHECK_CONNECT_NO_PORT);
169                    accessibleAddresses.add(element);
170                } catch (SecurityException e) {
171                }
172            }
173        }
174
175        Enumeration<InetAddress> theAccessibleElements = accessibleAddresses
176                .elements();
177        if (theAccessibleElements.hasMoreElements()) {
178            return accessibleAddresses.elements();
179        }
180
181        return new Vector<InetAddress>(0).elements();
182    }
183
184    /**
185     * Returns the user readable name associated with the network interface
186     *
187     * @return display name associated with the network interface or null if one
188     *         is not available
189     */
190    public String getDisplayName() {
191        /*
192         * we should return the display name unless it is blank in this case
193         * return the name so that something is displayed.
194         */
195        if (!(displayName.equals(""))) { //$NON-NLS-1$
196            return displayName;
197        }
198        return name;
199    }
200
201    /**
202     * Returns the network interface with the specified name, if one exists
203     *
204     * @return network interface for name specified if it exists, otherwise null
205     *
206     * @throws SocketException
207     *             if an error occurs when getting network interface information
208     * @throws NullPointerException
209     *             if the interface name passed in is null
210     */
211    public static NetworkInterface getByName(String interfaceName)
212            throws SocketException {
213
214        if (interfaceName == null) {
215            throw new NullPointerException(Msg.getString("K0330")); //$NON-NLS-1$
216        }
217
218        /*
219         * get the list of interfaces, and then loop through the list to look
220         * for one with a matching name
221         */
222        Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
223        if (interfaces != null) {
224            while (interfaces.hasMoreElements()) {
225                NetworkInterface netif = interfaces.nextElement();
226                if (netif.getName().equals(interfaceName)) {
227                    return netif;
228                }
229            }
230        }
231        return null;
232    }
233
234    /**
235     * Returns the network interface which has the specified internet address
236     * bound to it, if one exists.
237     *
238     * @param address
239     *            address of interest
240     * @return network interface for internet address specified if it exists,
241     *         otherwise null
242     *
243     * @throws SocketException
244     *             if an error occurs when getting network interface information
245     * @throws NullPointerException
246     *             if the address passed in is null
247     */
248    public static NetworkInterface getByInetAddress(InetAddress address)
249            throws SocketException {
250
251        if (address == null) {
252            throw new NullPointerException(Msg.getString("K0331")); //$NON-NLS-1$
253        }
254
255        /*
256         * get the list of interfaces, and then loop through the list. For each
257         * interface loop through the associated set of internet addresses and
258         * see if one matches. If so return that network interface
259         */
260        Enumeration<NetworkInterface> interfaces = getNetworkInterfaces();
261        if (interfaces != null) {
262            while (interfaces.hasMoreElements()) {
263                NetworkInterface netif = interfaces.nextElement();
264                /*
265                 * to be compatible use the raw addresses without any security
266                 * filtering
267                 */
268                // Enumeration netifAddresses = netif.getInetAddresses();
269                if ((netif.addresses != null) && (netif.addresses.length != 0)) {
270                    Enumeration<InetAddress> netifAddresses = (new Vector<InetAddress>(
271                            Arrays.asList(netif.addresses))).elements();
272                    if (netifAddresses != null) {
273                        while (netifAddresses.hasMoreElements()) {
274                            if (address.equals(netifAddresses.nextElement())) {
275                                return netif;
276                            }
277                        }
278                    }
279                }
280            }
281        }
282        return null;
283    }
284
285    /**
286     * Returns the list of network interfaces supported by the system or null if
287     * no interfaces are supported by the system
288     *
289     * @return Enumeration containing one NetworkInterface object for each
290     *         interface supported by the system
291     *
292     * @throws SocketException
293     *             if an error occurs when getting network interface information
294     */
295    public static Enumeration<NetworkInterface> getNetworkInterfaces()
296            throws SocketException {
297        NetworkInterface[] interfaces = getNetworkInterfacesImpl();
298        if (interfaces == null) {
299            return null;
300        }
301
302        for (NetworkInterface netif : interfaces) {
303            // Ensure that current NetworkInterface is bound to at least
304            // one InetAddress before processing
305            if (netif.addresses != null) {
306                for (InetAddress addr : netif.addresses) {
307                    if (16 == addr.ipaddress.length) {
308                        if (addr.isLinkLocalAddress()
309                                || addr.isSiteLocalAddress()) {
310                            ((Inet6Address) addr).scopedIf = netif;
311                            ((Inet6Address) addr).ifname = netif.name;
312                            ((Inet6Address) addr).scope_ifname_set = true;
313                        }
314                    }
315                }
316            }
317        }
318
319        return (new Vector<NetworkInterface>(Arrays.asList(interfaces)))
320                .elements();
321    }
322
323    /**
324     * Compares the specified object to this NetworkInterface and answer if they
325     * are equal. The object must be an instance of NetworkInterface with the
326     * same name, displayName and list of network interfaces to be the same
327     *
328     * @param obj
329     *            the object to compare
330     * @return true if the specified object is equal to this NetworkInterfcae,
331     *         false otherwise
332     *
333     * @see #hashCode
334     */
335    @Override
336    public boolean equals(Object obj) {
337        // just return true if it is the exact same object
338        if (obj == this) {
339            return true;
340        }
341
342        if (obj instanceof NetworkInterface) {
343            /*
344             * make sure that some simple checks pass. If the name is not the
345             * same then we are sure it is not the same one. We don't check the
346             * hashcode as it is generated from the name which we check
347             */
348            NetworkInterface netif = (NetworkInterface) obj;
349
350            if (netif.getIndex() != interfaceIndex) {
351                return false;
352            }
353
354            if (!(name.equals("")) && (!netif.getName().equals(name))) { //$NON-NLS-1$
355                return false;
356            }
357
358            if ((name.equals("")) && (!netif.getName().equals(displayName))) { //$NON-NLS-1$
359                return false;
360            }
361
362            // now check that the internet addresses are the same
363            Enumeration<InetAddress> netifAddresses = netif.getInetAddresses();
364            Enumeration<InetAddress> localifAddresses = getInetAddresses();
365            if ((netifAddresses == null) && (localifAddresses != null)) {
366                return false;
367            }
368
369            if ((netifAddresses == null) && (localifAddresses == null)) {
370                // neither have any addresses so they are the same
371                return true;
372            }
373
374            if (netifAddresses != null) {
375                while (netifAddresses.hasMoreElements()
376                        && localifAddresses.hasMoreElements()) {
377                    if (!(localifAddresses.nextElement()).equals(netifAddresses
378                            .nextElement())) {
379                        return false;
380                    }
381                }
382                /*
383                 * now make sure that they had the same number of internet
384                 * addresses, if not they are not the same interface
385                 */
386                if (netifAddresses.hasMoreElements()
387                        || localifAddresses.hasMoreElements()) {
388                    return false;
389                }
390            }
391            return true;
392        }
393        return false;
394    }
395
396    /**
397     * Returns a hash code for this NetworkInterface object. Since the name
398     * should be unique for each network interface the hash code is generated
399     * using this name
400     *
401     * @return the hashcode for hashtable indexing
402     */
403    @Override
404    public int hashCode() {
405        if (hashCode == 0) {
406            hashCode = name.hashCode();
407        }
408        return hashCode;
409    }
410
411    /**
412     * Returns a string containing a concise, human-readable description of the
413     * network interface
414     *
415     * @return a printable representation for the network interface
416     */
417    @Override
418    public String toString() {
419        StringBuilder string = new StringBuilder(25);
420        string.append("["); //$NON-NLS-1$
421        string.append(name);
422        string.append("]["); //$NON-NLS-1$
423        string.append(displayName);
424        string.append("]"); //$NON-NLS-1$
425
426        /*
427         * get the addresses through this call to make sure we only reveal those
428         * that we should
429         */
430        Enumeration<InetAddress> theAddresses = getInetAddresses();
431        if (theAddresses != null) {
432            while (theAddresses.hasMoreElements()) {
433                InetAddress nextAddress = theAddresses.nextElement();
434                string.append("["); //$NON-NLS-1$
435                string.append(nextAddress.toString());
436                string.append("]"); //$NON-NLS-1$
437            }
438        }
439        return string.toString();
440    }
441}
442