001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.net;
019:
020: import java.util.Arrays;
021: import java.util.Enumeration;
022: import java.util.Vector;
023:
024: import org.apache.harmony.luni.util.Msg;
025:
026: /**
027: * This class provides an methods that are used to get information about the
028: * network interfaces supported by the system
029: */
030: public final class NetworkInterface extends Object {
031:
032: private static final int CHECK_CONNECT_NO_PORT = -1;
033:
034: static final int NO_INTERFACE_INDEX = 0;
035:
036: static final int UNSET_INTERFACE_INDEX = -1;
037:
038: private String name;
039:
040: private String displayName;
041:
042: InetAddress addresses[];
043:
044: // The interface index is a positive integer which is non-negative. Where
045: // value is zero then we do not have an index for the interface (which
046: // occurs in systems which only support IPV4)
047: private int interfaceIndex;
048:
049: private int hashCode;
050:
051: /**
052: * This native answers the list of network interfaces supported by the
053: * system. An array is returned which is easier to generate and which can
054: * easily be converted into the required enumeration on the java side
055: *
056: * @return an array of zero or more NetworkInterface objects
057: *
058: * @throws SocketException
059: * if an error occurs when getting network interface information
060: */
061: private static native NetworkInterface[] getNetworkInterfacesImpl()
062: throws SocketException;
063:
064: /**
065: * This constructor is used by the native method in order to construct the
066: * NetworkInterface objects in the array that it returns
067: *
068: * @param name
069: * internal name associated with the interface
070: * @param displayName
071: * a user interpretable name for the interface
072: * @param addresses
073: * the Internet addresses associated with the interface
074: * @param interfaceIndex
075: * an index for the interface. Only set for platforms that
076: * support IPV6
077: */
078: NetworkInterface(String name, String displayName,
079: InetAddress addresses[], int interfaceIndex) {
080: this .name = name;
081: this .displayName = displayName;
082: this .addresses = addresses;
083: this .interfaceIndex = interfaceIndex;
084: }
085:
086: /**
087: * Answers the index for the network interface. Unless the system supports
088: * IPV6 this will be 0.
089: *
090: * @return the index
091: */
092: int getIndex() {
093: return interfaceIndex;
094: }
095:
096: /**
097: * Answers the first address for the network interface. This is used in the
098: * natives when we need one of the addresses for the interface and any one
099: * 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: * Answers 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: * Answers 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: * Answers 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: * Answers 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: * Answers 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)
270: && (netif.addresses.length != 0)) {
271: Enumeration<InetAddress> netifAddresses = (new Vector<InetAddress>(
272: Arrays.asList(netif.addresses))).elements();
273: if (netifAddresses != null) {
274: while (netifAddresses.hasMoreElements()) {
275: if (address.equals(netifAddresses
276: .nextElement())) {
277: return netif;
278: }
279: }
280: }
281: }
282: }
283: }
284: return null;
285: }
286:
287: /**
288: * Answers the list of network interfaces supported by the system or null if
289: * no interfaces are supported by the system
290: *
291: * @return Enumeration containing one NetworkInterface object for each
292: * interface supported by the system
293: *
294: * @throws SocketException
295: * if an error occurs when getting network interface information
296: */
297: public static Enumeration<NetworkInterface> getNetworkInterfaces()
298: throws SocketException {
299: NetworkInterface[] interfaces = getNetworkInterfacesImpl();
300: if (interfaces == null) {
301: return null;
302: }
303:
304: for (NetworkInterface netif : interfaces) {
305: // Ensure that current NetworkInterface is bound to at least
306: // one InetAddress before processing
307: if (netif.addresses != null) {
308: for (InetAddress addr : netif.addresses) {
309: if (16 == addr.ipaddress.length) {
310: if (addr.isLinkLocalAddress()
311: || addr.isSiteLocalAddress()) {
312: ((Inet6Address) addr).scopedIf = netif;
313: ((Inet6Address) addr).ifname = netif.name;
314: ((Inet6Address) addr).scope_ifname_set = true;
315: }
316: }
317: }
318: }
319: }
320:
321: return (new Vector<NetworkInterface>(Arrays.asList(interfaces)))
322: .elements();
323: }
324:
325: /**
326: * Compares the specified object to this NetworkInterface and answer if they
327: * are equal. The object must be an instance of NetworkInterface with the
328: * same name, displayName and list of network interfaces to be the same
329: *
330: * @param obj
331: * the object to compare
332: * @return true if the specified object is equal to this NetworkInterfcae,
333: * false otherwise
334: *
335: * @see #hashCode
336: */
337: @Override
338: public boolean equals(Object obj) {
339: // just return true if it is the exact same object
340: if (obj == this ) {
341: return true;
342: }
343:
344: if (obj instanceof NetworkInterface) {
345: /*
346: * make sure that some simple checks pass. If the name is not the
347: * same then we are sure it is not the same one. We don't check the
348: * hashcode as it is generated from the name which we check
349: */
350: NetworkInterface netif = (NetworkInterface) obj;
351:
352: if (netif.getIndex() != interfaceIndex) {
353: return false;
354: }
355:
356: if (!(name.equals("")) && (!netif.getName().equals(name))) { //$NON-NLS-1$
357: return false;
358: }
359:
360: if ((name.equals("")) && (!netif.getName().equals(displayName))) { //$NON-NLS-1$
361: return false;
362: }
363:
364: // now check that the internet addresses are the same
365: Enumeration<InetAddress> netifAddresses = netif
366: .getInetAddresses();
367: Enumeration<InetAddress> localifAddresses = getInetAddresses();
368: if ((netifAddresses == null) && (localifAddresses != null)) {
369: return false;
370: }
371:
372: if ((netifAddresses == null) && (localifAddresses == null)) {
373: // neither have any addresses so they are the same
374: return true;
375: }
376:
377: if (netifAddresses != null) {
378: while (netifAddresses.hasMoreElements()
379: && localifAddresses.hasMoreElements()) {
380: if (!(localifAddresses.nextElement())
381: .equals(netifAddresses.nextElement())) {
382: return false;
383: }
384: }
385: /*
386: * now make sure that they had the same number of internet
387: * addresses, if not they are not the same interface
388: */
389: if (netifAddresses.hasMoreElements()
390: || localifAddresses.hasMoreElements()) {
391: return false;
392: }
393: }
394: return true;
395: }
396: return false;
397: }
398:
399: /**
400: * Answers a hash code for this NetworkInterface object. Since the name
401: * should be unique for each network interface the hash code is generated
402: * using this name
403: *
404: * @return the hashcode for hashtable indexing
405: */
406: @Override
407: public int hashCode() {
408: if (hashCode == 0) {
409: hashCode = name.hashCode();
410: }
411: return hashCode;
412: }
413:
414: /**
415: * Answers a string containing a concise, human-readable description of the
416: * network interface
417: *
418: * @return a printable representation for the network interface
419: */
420: @Override
421: public String toString() {
422: StringBuilder string = new StringBuilder(25);
423: string.append("["); //$NON-NLS-1$
424: string.append(name);
425: string.append("]["); //$NON-NLS-1$
426: string.append(displayName);
427: string.append("]"); //$NON-NLS-1$
428:
429: /*
430: * get the addresses through this call to make sure we only reveal those
431: * that we should
432: */
433: Enumeration<InetAddress> theAddresses = getInetAddresses();
434: if (theAddresses != null) {
435: while (theAddresses.hasMoreElements()) {
436: InetAddress nextAddress = theAddresses.nextElement();
437: string.append("["); //$NON-NLS-1$
438: string.append(nextAddress.toString());
439: string.append("]"); //$NON-NLS-1$
440: }
441: }
442: return string.toString();
443: }
444: }
|