/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package java.net; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import libcore.base.EmptyArray; /** * This class is used to represent a network interface of the local device. An * interface is defined by its address and a platform dependent name. The class * provides methods to get all information about the available interfaces of the * system or to identify the local interface of a joined multicast group. */ public final class NetworkInterface extends Object { private static final int CHECK_CONNECT_NO_PORT = -1; static final int NO_INTERFACE_INDEX = 0; static final int UNSET_INTERFACE_INDEX = -1; private final String name; private final String displayName; private final List interfaceAddresses = new LinkedList(); private final List addresses = new LinkedList(); // The interface index is a positive integer which is non-negative. Where // value is zero then we do not have an index for the interface (which // occurs in systems which only support IPV4) private int interfaceIndex; private NetworkInterface parent = null; private final List children = new LinkedList(); private static NetworkInterface[] getNetworkInterfacesImpl() throws SocketException { Map networkInterfaces = new LinkedHashMap(); for (InterfaceAddress ia : getAllInterfaceAddressesImpl()) { if (ia != null) { // The array may contain harmless null elements. String name = ia.name; NetworkInterface ni = networkInterfaces.get(name); if (ni == null) { ni = new NetworkInterface(name, name, new InetAddress[] { ia.address }, ia.index); ni.interfaceAddresses.add(ia); networkInterfaces.put(name, ni); } else { ni.addresses.add(ia.address); ni.interfaceAddresses.add(ia); } } } return networkInterfaces.values().toArray(new NetworkInterface[networkInterfaces.size()]); } private static native InterfaceAddress[] getAllInterfaceAddressesImpl() throws SocketException; /** * This constructor is used by the native method in order to construct the * NetworkInterface objects in the array that it returns. * * @param name * internal name associated with the interface. * @param displayName * a user interpretable name for the interface. * @param addresses * the Internet addresses associated with the interface. * @param interfaceIndex * an index for the interface. Only set for platforms that * support IPV6. */ NetworkInterface(String name, String displayName, InetAddress[] addresses, int interfaceIndex) { this.name = name; this.displayName = displayName; this.interfaceIndex = interfaceIndex; if (addresses != null) { for (InetAddress address : addresses) { this.addresses.add(address); } } } /** * Returns the index for the network interface. Unless the system supports * IPV6 this will be 0. * * @return the index */ int getIndex() { return interfaceIndex; } /** * Returns the first address for the network interface. This is used in the * natives when we need one of the addresses for the interface and any one * will do * * @return the first address if one exists, otherwise null. */ InetAddress getFirstAddress() { if (addresses.size() >= 1) { return addresses.get(0); } return null; } /** * Gets the name associated with this network interface. * * @return the name of this {@code NetworkInterface} instance. */ public String getName() { return name; } /** * Gets a list of addresses bound to this network interface. * * @return the address list of the represented network interface. */ public Enumeration getInetAddresses() { return Collections.enumeration(addresses); } /** * Gets the human-readable name associated with this network interface. * * @return the display name of this network interface or the name if the * display name is not available. */ public String getDisplayName() { /* * we should return the display name unless it is blank in this case * return the name so that something is displayed. */ return displayName.isEmpty() ? name : displayName; } /** * Gets the specific network interface according to a given name. * * @param interfaceName * the name to identify the searched network interface. * @return the network interface with the specified name if one exists or * {@code null} otherwise. * @throws SocketException * if an error occurs while getting the network interface * information. * @throws NullPointerException * if the given interface's name is {@code null}. */ public static NetworkInterface getByName(String interfaceName) throws SocketException { if (interfaceName == null) { throw new NullPointerException(); } for (NetworkInterface networkInterface : getNetworkInterfacesList()) { if (networkInterface.name.equals(interfaceName)) { return networkInterface; } } return null; } /** * Gets the specific network interface according to the given address. * * @param address * the address to identify the searched network interface. * @return the network interface with the specified address if one exists or * {@code null} otherwise. * @throws SocketException * if an error occurs while getting the network interface * information. * @throws NullPointerException * if the given interface address is invalid. */ public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException { if (address == null) { throw new NullPointerException("address == null"); } for (NetworkInterface networkInterface : getNetworkInterfacesList()) { if (networkInterface.addresses.contains(address)) { return networkInterface; } } return null; } /** * Gets a list of all network interfaces available on the local system or * {@code null} if no interface is available. * * @return the list of {@code NetworkInterface} instances representing the * available interfaces. * @throws SocketException * if an error occurs while getting the network interface * information. */ public static Enumeration getNetworkInterfaces() throws SocketException { return Collections.enumeration(getNetworkInterfacesList()); } private static List getNetworkInterfacesList() throws SocketException { NetworkInterface[] interfaces = getNetworkInterfacesImpl(); for (NetworkInterface netif : interfaces) { // Ensure that current NetworkInterface is bound to at least // one InetAddress before processing for (InetAddress addr : netif.addresses) { if (addr.ipaddress.length == 16) { if (addr.isLinkLocalAddress() || addr.isSiteLocalAddress()) { ((Inet6Address) addr).scopedIf = netif; ((Inet6Address) addr).ifname = netif.name; ((Inet6Address) addr).scope_ifname_set = true; } } } } List result = new ArrayList(); boolean[] peeked = new boolean[interfaces.length]; for (int counter = 0; counter < interfaces.length; counter++) { // If this interface has been touched, continue. if (peeked[counter]) { continue; } int counter2 = counter; // Checks whether the following interfaces are children. for (; counter2 < interfaces.length; counter2++) { if (peeked[counter2]) { continue; } if (interfaces[counter2].name.startsWith(interfaces[counter].name + ":")) { // Tagged as peeked peeked[counter2] = true; interfaces[counter].children.add(interfaces[counter2]); interfaces[counter2].parent = interfaces[counter]; interfaces[counter].addresses.addAll(interfaces[counter2].addresses); } } // Tagged as peeked result.add(interfaces[counter]); peeked[counter] = true; } return result; } /** * Compares the specified object to this {@code NetworkInterface} and * returns whether they are equal or not. The object must be an instance of * {@code NetworkInterface} with the same name, {@code displayName} and list * of network interfaces to be equal. * * @param obj * the object to compare with this instance. * @return {@code true} if the specified object is equal to this {@code * NetworkInterface}, {@code false} otherwise. * @see #hashCode() */ @Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof NetworkInterface)) { return false; } NetworkInterface rhs = (NetworkInterface) obj; // TODO: should the order of the addresses matter (we use List.equals)? return interfaceIndex == rhs.interfaceIndex && name.equals(rhs.name) && displayName.equals(rhs.displayName) && addresses.equals(rhs.addresses); } /** * Returns the hash code for this {@code NetworkInterface}. Since the * name should be unique for each network interface the hash code is * generated using this name. */ @Override public int hashCode() { return name.hashCode(); } /** * Gets a string containing a concise, human-readable description of this * network interface. * * @return the textual representation for this network interface. */ @Override public String toString() { StringBuilder string = new StringBuilder(25); string.append("["); string.append(name); string.append("]["); string.append(displayName); string.append("]["); string.append(interfaceIndex); string.append("]"); /* * get the addresses through this call to make sure we only reveal those * that we should */ Enumeration theAddresses = getInetAddresses(); if (theAddresses != null) { while (theAddresses.hasMoreElements()) { InetAddress nextAddress = theAddresses.nextElement(); string.append("["); string.append(nextAddress.toString()); string.append("]"); } } return string.toString(); } /** * Returns a List of the InterfaceAddresses for this network interface. * @since 1.6 */ public List getInterfaceAddresses() { return Collections.unmodifiableList(interfaceAddresses); } /** * Returns an {@code Enumeration} of all the sub-interfaces of this network interface. * Sub-interfaces are also known as virtual interfaces. *

* For example, {@code eth0:1} would be a sub-interface of {@code eth0}. * * @return an Enumeration of all the sub-interfaces of this network interface * @since 1.6 */ public Enumeration getSubInterfaces() { return Collections.enumeration(children); } /** * Returns the parent NetworkInterface of this interface if this is a * sub-interface, or null if it's a physical (non virtual) interface. * * @return the NetworkInterface this interface is attached to. * @since 1.6 */ public NetworkInterface getParent() { return parent; } /** * Returns true if this network interface is up. * * @return true if the interface is up. * @throws SocketException if an I/O error occurs. * @since 1.6 */ public boolean isUp() throws SocketException { if (addresses.isEmpty()) { return false; } return isUpImpl(name); } private static native boolean isUpImpl(String n) throws SocketException; /** * Returns true if this network interface is a loopback interface. * * @return true if the interface is a loopback interface. * @throws SocketException if an I/O error occurs. * @since 1.6 */ public boolean isLoopback() throws SocketException { if (addresses.isEmpty()) { return false; } return isLoopbackImpl(name); } private static native boolean isLoopbackImpl(String n) throws SocketException; /** * Returns true if this network interface is a point-to-point interface. * (For example, a PPP connection using a modem.) * * @return true if the interface is point-to-point. * @throws SocketException if an I/O error occurs. * @since 1.6 */ public boolean isPointToPoint() throws SocketException { if (addresses.isEmpty()) { return false; } return isPointToPointImpl(name); } private static native boolean isPointToPointImpl(String n) throws SocketException; /** * Returns true if this network interface supports multicast. * * @throws SocketException if an I/O error occurs. * @since 1.6 */ public boolean supportsMulticast() throws SocketException { if (addresses.isEmpty()) { return false; } return supportsMulticastImpl(name); } private static native boolean supportsMulticastImpl(String n) throws SocketException; /** * Returns the hardware address of the interface, if it has one, and the * user has the necessary privileges to access the address. * * @return a byte array containing the address or null if the address * doesn't exist or is not accessible. * @throws SocketException if an I/O error occurs. * @since 1.6 */ public byte[] getHardwareAddress() throws SocketException { if (addresses.isEmpty()) { return EmptyArray.BYTE; } return getHardwareAddressImpl(name); } private static native byte[] getHardwareAddressImpl(String n) throws SocketException; /** * Returns the Maximum Transmission Unit (MTU) of this interface. * * @return the value of the MTU for the interface. * @throws SocketException if an I/O error occurs. * @since 1.6 */ public int getMTU() throws SocketException { if (addresses.isEmpty()) { return 0; } return getMTUImpl(name); } private static native int getMTUImpl(String n) throws SocketException; /** * Returns true if this interface is a virtual interface (also called * a sub-interface). Virtual interfaces are, on some systems, interfaces * created as a child of a physical interface and given different settings * (like address or MTU). Usually the name of the interface will the name of * the parent followed by a colon (:) and a number identifying the child, * since there can be several virtual interfaces attached to a single * physical interface. * * @return true if this interface is a virtual interface. * @since 1.6 */ public boolean isVirtual() { return parent != null; } }