diff options
author | Elliott Hughes <enh@google.com> | 2010-03-08 17:38:17 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-03-08 17:38:17 -0800 |
commit | bf5d76daa288a111dcaa33b084a099948c52d200 (patch) | |
tree | cad9392668ddf9165124b74dfc92bc2af3864715 /luni | |
parent | a48356a4fc2cacdf8d466680bc456ae69215e027 (diff) | |
parent | d2af45a6fd008ceb958ac74e5a50e582b8419e9c (diff) | |
download | libcore-bf5d76daa288a111dcaa33b084a099948c52d200.zip libcore-bf5d76daa288a111dcaa33b084a099948c52d200.tar.gz libcore-bf5d76daa288a111dcaa33b084a099948c52d200.tar.bz2 |
Merge "Implement the Java 6 NetworkInterface/InterfaceAddress functionality." into dalvik-dev
Diffstat (limited to 'luni')
-rw-r--r-- | luni/src/main/java/java/net/InetAddress.java | 80 | ||||
-rw-r--r-- | luni/src/main/java/java/net/InterfaceAddress.java | 127 | ||||
-rw-r--r-- | luni/src/main/java/java/net/NetworkInterface.java | 450 | ||||
-rw-r--r-- | luni/src/main/native/ifaddrs-android.h | 49 | ||||
-rw-r--r-- | luni/src/main/native/java_net_NetworkInterface.cpp | 104 | ||||
-rw-r--r-- | luni/src/test/java/tests/api/java/net/NetworkInterfaceTest.java | 1030 |
6 files changed, 1018 insertions, 822 deletions
diff --git a/luni/src/main/java/java/net/InetAddress.java b/luni/src/main/java/java/net/InetAddress.java index ad96ed6..4827e70 100644 --- a/luni/src/main/java/java/net/InetAddress.java +++ b/luni/src/main/java/java/net/InetAddress.java @@ -27,8 +27,10 @@ import java.io.Serializable; import java.security.AccessController; import java.util.Arrays; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; +import java.util.List; import java.util.StringTokenizer; import org.apache.harmony.luni.net.NetUtil; @@ -114,40 +116,12 @@ public class InetAddress implements Serializable { super(); } - // BEGIN android-removed - /** - * Constructs an {@code InetAddress}, representing the {@code address} and - * {@code hostName}. - * - * @param address - * the network address. - */ - // InetAddress(byte[] address) { - // super(); - // this.ipaddress = address; - // } - // END android-removed - - // BEGIN android-removed - /** - * Constructs an {@code InetAddress}, representing the {@code address} and - * {@code hostName}. - * - * @param address - * the network address. - * - */ - // InetAddress(byte[] address, String hostName) { - // super(); - // this.ipaddress = address; - // this.hostName = hostName; - // } + // BEGIN android-removed: use Inet4Address/Inet6Address instead, as appropriate. + // InetAddress(byte[] address) { ... } // END android-removed - // BEGIN android-removed - // CacheElement cacheElement() { - // return new CacheElement(); - // } + // BEGIN android-removed: use Inet4Address/Inet6Address instead, as appropriate. + // InetAddress(byte[] address, String hostName) { ... } // END android-removed /** @@ -744,7 +718,7 @@ public class InetAddress implements Serializable { * ICMP <i>(ICMP ECHO REQUEST)</i>. When first step fails, a TCP connection * on port 7 (Echo) of the remote host is established. * - * @param netif + * @param networkInterface * the network interface on which to connection should be * established. * @param ttl @@ -759,36 +733,16 @@ public class InetAddress implements Serializable { * @throws IllegalArgumentException * if ttl or timeout is less than zero. */ - public boolean isReachable(NetworkInterface netif, final int ttl, + public boolean isReachable(NetworkInterface networkInterface, final int ttl, final int timeout) throws IOException { - if (0 > ttl || 0 > timeout) { + if (ttl < 0 || timeout < 0) { throw new IllegalArgumentException(Msg.getString("K0051")); //$NON-NLS-1$ } - boolean reachable = false; - if (null == netif) { - // network interface is null, binds to no address - // BEGIN android-changed - // reachable = NETIMPL.isReachableByICMP(this, null, ttl, timeout); - // if (!reachable) { - reachable = isReachableByTCP(this, null, timeout); - // } - // END android-changed + if (networkInterface == null) { + return isReachableByTCP(this, null, timeout); } else { - // Not Bind to any address - if (null == netif.addresses) { - return false; - } - // binds to all address on this NetworkInterface, tries ICMP ping - // first - // BEGIN android-changed - // reachable = isReachableByICMPUseMultiThread(netif, ttl, timeout); - // if (!reachable) { - // tries TCP echo if ICMP ping fails - reachable = isReachableByMultiThread(netif, ttl, timeout); - // } - // END adnroid-changed + return isReachableByMultiThread(networkInterface, ttl, timeout); } - return reachable; } /* @@ -800,16 +754,14 @@ public class InetAddress implements Serializable { final int ttl, final int timeout) // END android-changed throws IOException { - if (null == netif.addresses) { + List<InetAddress> addresses = Collections.list(netif.getInetAddresses()); + if (addresses.isEmpty()) { return false; } - Enumeration<InetAddress> addresses = netif.getInetAddresses(); reached = false; - addrCount = netif.addresses.length; + addrCount = addresses.size(); boolean needWait = false; - while (addresses.hasMoreElements()) { - final InetAddress addr = addresses.nextElement(); - + for (final InetAddress addr : addresses) { // loopback interface can only reach to local addresses if (addr.isLoopbackAddress()) { Enumeration<NetworkInterface> NetworkInterfaces = NetworkInterface diff --git a/luni/src/main/java/java/net/InterfaceAddress.java b/luni/src/main/java/java/net/InterfaceAddress.java index 7bc3936..2fa99f7 100644 --- a/luni/src/main/java/java/net/InterfaceAddress.java +++ b/luni/src/main/java/java/net/InterfaceAddress.java @@ -20,22 +20,131 @@ package java.net; * Identifies one of a network interface's addresses. * These are passed back from the JNI behind NetworkInterface.getNetworkInterfaces. * Multiple addresses for the same interface are collected together on the Java side. + * + * @hide + * @since 1.6 */ -class InterfaceAddress { - // An IPv4 or IPv6 address. - final InetAddress address; - - // The kernel's interface index for the network interface this address - // is currently assigned to. Values start at 1, because 0 means "unknown" - // or "any", depending on context. +public class InterfaceAddress { + /** + * The kernel's interface index for the network interface this address + * is currently assigned to. Values start at 1, because 0 means "unknown" + * or "any", depending on context. + */ final int index; - // The network interface's name. "lo" or "eth0", for example. + /** + * The network interface's name. "lo" or "eth0", for example. + */ final String name; - InterfaceAddress(int index, String name, InetAddress address) { + /** + * An IPv4 or IPv6 address. + */ + final InetAddress address; + + /** + * The IPv4 broadcast address, or null for IPv6. + */ + private final InetAddress broadcastAddress; + + private final short prefixLength; + + InterfaceAddress(int index, String name, InetAddress address, InetAddress mask) { + assert ((address instanceof Inet4Address) == (mask instanceof Inet4Address)); this.index = index; this.name = name; this.address = address; + this.broadcastAddress = makeBroadcastAddress(address, mask); + this.prefixLength = countPrefixLength(mask); + } + + private static InetAddress makeBroadcastAddress(InetAddress address, InetAddress mask) { + if (!(address instanceof Inet4Address)) { + return null; + } + byte[] broadcast = new byte[4]; + byte[] maskBytes = mask.ipaddress; + byte[] addrBytes = address.ipaddress; + if (maskBytes[0] != 0) { + for (int i = 0; i < broadcast.length; ++i) { + broadcast[i] = (byte) (addrBytes[i] | ~maskBytes[i]); + } + } + return new Inet4Address(broadcast); + } + + private static short countPrefixLength(InetAddress mask) { + short count = 0; + for (byte b : mask.ipaddress) { + for (int i = 0; i < 8; ++i) { + if ((b & (1 << i)) != 0) { + ++count; + } + } + } + return count; + } + + /** + * Tests whether this object is equal to another one. Returns true if + * the address, broadcast address and prefix length are all equal. + * + * @param obj the object to be compared. + * @return true if 'obj' is equal to this InterfaceAddress, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj == this){ + return true; + } + if (!(obj instanceof InterfaceAddress)) { + return false; + } + InterfaceAddress rhs = (InterfaceAddress) obj; + return ((address == null) ? rhs.address == null : address.equals(rhs.address)) && + (rhs.prefixLength == prefixLength) && + ((broadcastAddress == null) ? rhs.broadcastAddress == null : broadcastAddress.equals(rhs.broadcastAddress)); + } + + @Override + public int hashCode() { + int hashCode = address == null ? 0 : -address.hashCode(); + hashCode += broadcastAddress == null ? 0 : broadcastAddress.hashCode(); + hashCode += prefixLength; + return hashCode; + } + + /** + * Returns a string representation for this interface address. + * The string is of the form: InetAddress / prefix length [ broadcast address ]. + * + * @return a string representation of this interface address. + */ + @Override + public String toString() { + return address + "/" + prefixLength + " [" + broadcastAddress + "]"; + } + + /** + * Returns the InetAddress for this address. + */ + public InetAddress getAddress() { + return address; + } + + /** + * Returns the subnet-directed broadcast address if this is an IPv4 interface, null otherwise. + */ + public InetAddress getBroadcast() { + return broadcastAddress; + } + + /** + * Returns the network prefix length in bits. + * (In IPv4 parlance, this is known as the subnet mask, + * but this method applies to IPv6 addresses too.) + */ + public short getNetworkPrefixLength() { + return prefixLength; } } diff --git a/luni/src/main/java/java/net/NetworkInterface.java b/luni/src/main/java/java/net/NetworkInterface.java index 93a30cb..b3e242e 100644 --- a/luni/src/main/java/java/net/NetworkInterface.java +++ b/luni/src/main/java/java/net/NetworkInterface.java @@ -17,9 +17,12 @@ package java.net; +import java.util.ArrayList; import java.util.Arrays; +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 java.util.Vector; @@ -37,49 +40,45 @@ 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 String name; - - private String displayName; + private final String name; + private final String displayName; + private final List<InterfaceAddress> interfaceAddresses = new LinkedList<InterfaceAddress>(); - InetAddress addresses[]; + private final List<InetAddress> addresses = new LinkedList<InetAddress>(); // 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 int hashCode; + private NetworkInterface parent = null; + + private final List<NetworkInterface> children = new LinkedList<NetworkInterface>(); // BEGIN android-changed: we pay this extra complexity on the Java side // in return for vastly simpler native code. - private static native InterfaceAddress[] getInterfaceAddresses() throws SocketException; + private static native InterfaceAddress[] getAllInterfaceAddressesImpl() throws SocketException; private static NetworkInterface[] getNetworkInterfacesImpl() throws SocketException { Map<String, NetworkInterface> networkInterfaces = new LinkedHashMap<String, NetworkInterface>(); - for (InterfaceAddress ia : getInterfaceAddresses()) { + 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.addInterfaceAddress(ia.address); + ni.addresses.add(ia.address); + ni.interfaceAddresses.add(ia); } } } return networkInterfaces.values().toArray(new NetworkInterface[networkInterfaces.size()]); } - - private void addInterfaceAddress(InetAddress address) { - InetAddress[] newAddresses = new InetAddress[addresses.length + 1]; - System.arraycopy(addresses, 0, newAddresses, 0, addresses.length); - newAddresses[addresses.length] = address; - addresses = newAddresses; - } // END android-changed /** @@ -96,12 +95,16 @@ public final class NetworkInterface extends Object { * an index for the interface. Only set for platforms that * support IPV6. */ - NetworkInterface(String name, String displayName, InetAddress addresses[], + NetworkInterface(String name, String displayName, InetAddress[] addresses, int interfaceIndex) { this.name = name; this.displayName = displayName; - this.addresses = addresses; this.interfaceIndex = interfaceIndex; + if (addresses != null) { + for (InetAddress address : addresses) { + this.addresses.add(address); + } + } } /** @@ -122,8 +125,8 @@ public final class NetworkInterface extends Object { * @return the first address if one exists, otherwise null. */ InetAddress getFirstAddress() { - if ((addresses != null) && (addresses.length >= 1)) { - return addresses[0]; + if (addresses.size() >= 1) { + return addresses.get(0); } return null; } @@ -143,63 +146,21 @@ public final class NetworkInterface extends Object { * @return the address list of the represented network interface. */ public Enumeration<InetAddress> getInetAddresses() { - /* - * create new vector from which Enumeration to be returned can be - * generated set the initial capacity to be the number of addresses for - * the network interface which is the maximum required size - */ - - /* - * return an empty enumeration if there are no addresses associated with - * the interface - */ - if (addresses == null) { - return new Vector<InetAddress>(0).elements(); - } - - /* - * for those configuration that support the security manager we only - * return addresses for which checkConnect returns true - */ - Vector<InetAddress> accessibleAddresses = new Vector<InetAddress>( - addresses.length); - - /* - * get the security manager. If one does not exist just return the full - * list - */ - SecurityManager security = System.getSecurityManager(); - if (security == null) { - return (new Vector<InetAddress>(Arrays.asList(addresses))) - .elements(); + SecurityManager sm = System.getSecurityManager(); + if (sm == null || addresses.isEmpty()) { + return Collections.enumeration(addresses); } - - /* - * ok security manager exists so check each address and return those - * that pass - */ - for (InetAddress element : addresses) { - if (security != null) { - try { - /* - * since we don't have a port in this case we pass in - * NO_PORT - */ - security.checkConnect(element.getHostName(), - CHECK_CONNECT_NO_PORT); - accessibleAddresses.add(element); - } catch (SecurityException e) { - } + // TODO: Android should ditch SecurityManager and the associated pollution. + List<InetAddress> result = new ArrayList<InetAddress>(addresses.size()); + for (InetAddress address : addresses) { + try { + sm.checkConnect(address.getHostName(), CHECK_CONNECT_NO_PORT); + } catch (SecurityException e) { + continue; } + result.add(address); } - - Enumeration<InetAddress> theAccessibleElements = accessibleAddresses - .elements(); - if (theAccessibleElements.hasMoreElements()) { - return accessibleAddresses.elements(); - } - - return new Vector<InetAddress>(0).elements(); + return Collections.enumeration(result); } /** @@ -232,24 +193,13 @@ public final class NetworkInterface extends Object { * @throws NullPointerException * if the given interface's name is {@code null}. */ - public static NetworkInterface getByName(String interfaceName) - throws SocketException { - + public static NetworkInterface getByName(String interfaceName) throws SocketException { if (interfaceName == null) { throw new NullPointerException(Msg.getString("K0330")); //$NON-NLS-1$ } - - /* - * get the list of interfaces, and then loop through the list to look - * for one with a matching name - */ - Enumeration<NetworkInterface> interfaces = getNetworkInterfaces(); - if (interfaces != null) { - while (interfaces.hasMoreElements()) { - NetworkInterface netif = interfaces.nextElement(); - if (netif.getName().equals(interfaceName)) { - return netif; - } + for (NetworkInterface networkInterface : getNetworkInterfacesList()) { + if (networkInterface.name.equals(interfaceName)) { + return networkInterface; } } return null; @@ -268,38 +218,13 @@ public final class NetworkInterface extends Object { * @throws NullPointerException * if the given interface address is invalid. */ - public static NetworkInterface getByInetAddress(InetAddress address) - throws SocketException { - + public static NetworkInterface getByInetAddress(InetAddress address) throws SocketException { if (address == null) { throw new NullPointerException(Msg.getString("K0331")); //$NON-NLS-1$ } - - /* - * get the list of interfaces, and then loop through the list. For each - * interface loop through the associated set of internet addresses and - * see if one matches. If so return that network interface - */ - Enumeration<NetworkInterface> interfaces = getNetworkInterfaces(); - if (interfaces != null) { - while (interfaces.hasMoreElements()) { - NetworkInterface netif = interfaces.nextElement(); - /* - * to be compatible use the raw addresses without any security - * filtering - */ - // Enumeration netifAddresses = netif.getInetAddresses(); - if ((netif.addresses != null) && (netif.addresses.length != 0)) { - Enumeration<InetAddress> netifAddresses = (new Vector<InetAddress>( - Arrays.asList(netif.addresses))).elements(); - if (netifAddresses != null) { - while (netifAddresses.hasMoreElements()) { - if (address.equals(netifAddresses.nextElement())) { - return netif; - } - } - } - } + for (NetworkInterface networkInterface : getNetworkInterfacesList()) { + if (networkInterface.addresses.contains(address)) { + return networkInterface; } } return null; @@ -315,32 +240,53 @@ public final class NetworkInterface extends Object { * if an error occurs while getting the network interface * information. */ - public static Enumeration<NetworkInterface> getNetworkInterfaces() - throws SocketException { + public static Enumeration<NetworkInterface> getNetworkInterfaces() throws SocketException { + return Collections.enumeration(getNetworkInterfacesList()); + } + + private static List<NetworkInterface> getNetworkInterfacesList() throws SocketException { NetworkInterface[] interfaces = getNetworkInterfacesImpl(); - if (interfaces == null) { - return null; - } for (NetworkInterface netif : interfaces) { // Ensure that current NetworkInterface is bound to at least // one InetAddress before processing - if (netif.addresses != null) { - for (InetAddress addr : netif.addresses) { - if (16 == addr.ipaddress.length) { - if (addr.isLinkLocalAddress() - || addr.isSiteLocalAddress()) { - ((Inet6Address) addr).scopedIf = netif; - ((Inet6Address) addr).ifname = netif.name; - ((Inet6Address) addr).scope_ifname_set = true; - } + 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; } } } } - return (new Vector<NetworkInterface>(Arrays.asList(interfaces))) - .elements(); + List<NetworkInterface> result = new ArrayList<NetworkInterface>(); + 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; } /** @@ -357,77 +303,27 @@ public final class NetworkInterface extends Object { */ @Override public boolean equals(Object obj) { - // Return true if it is the exact same object. if (obj == this) { return true; } - - // Ensure it is the right type. if (!(obj instanceof NetworkInterface)) { return false; } - - /* - * Make sure that some simple checks pass. If the name is not the same - * then we are sure it is not the same one. We don't check the hashcode - * as it is generated from the name which we check - */ - NetworkInterface netif = (NetworkInterface) obj; - - if (netif.getIndex() != interfaceIndex) { - return false; - } - - if (!(name.equals("")) && (!netif.getName().equals(name))) { //$NON-NLS-1$ - return false; - } - - if ((name.equals("")) && (!netif.getName().equals(displayName))) { //$NON-NLS-1$ - return false; - } - - // Now check that the collection of internet addresses are equal. - Enumeration<InetAddress> netifAddresses = netif.getInetAddresses(); - Enumeration<InetAddress> localifAddresses = getInetAddresses(); - - // Check for both null (same), or one null (not same). - if (netifAddresses == null) { - return localifAddresses == null; - } - if (localifAddresses == null) { - return false; - } - - // Both are not null, check InetAddress elements. - while (netifAddresses.hasMoreElements() - && localifAddresses.hasMoreElements()) { - if (!(localifAddresses.nextElement()).equals( - netifAddresses.nextElement())) { - return false; - } - } - - /* - * Now make sure that they had the same number of addresses, if not they - * are not the same interface. - */ - return !netifAddresses.hasMoreElements() - && !localifAddresses.hasMoreElements(); + 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); } /** - * Gets the hashcode for this {@code NetworkInterface} instance. Since the - * name should be unique for each network interface the hashcode is + * 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. - * - * @return the hashcode value for this {@code NetworkInterface} instance. */ @Override public int hashCode() { - if (hashCode == 0) { - hashCode = name.hashCode(); - } - return hashCode; + return name.hashCode(); } /** @@ -464,4 +360,174 @@ public final class NetworkInterface extends Object { } return string.toString(); } + + /** + * Returns a List the InterfaceAddresses for this network interface. + * <p> + * If there is a security manager, its checkConnect method is called with + * the InetAddress for each InterfaceAddress. Only InterfaceAddresses where + * the checkConnect doesn't throw a SecurityException will be returned. + * + * @return a List of the InterfaceAddresses for this network interface. + * @since 1.6 + * @hide + */ + public List<InterfaceAddress> getInterfaceAddresses() { + SecurityManager sm = System.getSecurityManager(); + if (sm == null) { + return Collections.unmodifiableList(interfaceAddresses); + } + // TODO: Android should ditch SecurityManager and the associated pollution. + List<InterfaceAddress> result = new ArrayList<InterfaceAddress>(interfaceAddresses.size()); + for (InterfaceAddress ia : interfaceAddresses) { + try { + sm.checkConnect(ia.getAddress().getHostName(), CHECK_CONNECT_NO_PORT); + } catch (SecurityException e) { + continue; + } + result.add(ia); + } + return result; + } + + /** + * Returns an {@code Enumeration} of all the sub-interfaces of this network interface. + * Sub-interfaces are also known as virtual interfaces. + * <p> + * 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 + * @hide + */ + public Enumeration<NetworkInterface> 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 + * @hide + */ + 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 + * @hide + */ + public boolean isUp() throws SocketException { + if (addresses.isEmpty()) { + return false; + } + return isUpImpl(name, interfaceIndex); + } + private static native boolean isUpImpl(String n, int index) 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 + * @hide + */ + public boolean isLoopback() throws SocketException { + if (addresses.isEmpty()) { + return false; + } + return isLoopbackImpl(name, interfaceIndex); + } + private static native boolean isLoopbackImpl(String n, int index) 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 + * @hide + */ + public boolean isPointToPoint() throws SocketException { + if (addresses.isEmpty()) { + return false; + } + return isPointToPointImpl(name, interfaceIndex); + } + private static native boolean isPointToPointImpl(String n, int index) throws SocketException; + + /** + * Returns true if this network interface supports multicast. + * + * @throws SocketException if an I/O error occurs. + * @since 1.6 + * @hide + */ + public boolean supportsMulticast() throws SocketException { + if (addresses.isEmpty()) { + return false; + } + return supportsMulticastImpl(name, interfaceIndex); + } + private static native boolean supportsMulticastImpl(String n, int index) 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 + * @hide + */ + public byte[] getHardwareAddress() throws SocketException { + if (addresses.isEmpty()) { + return new byte[0]; + } + return getHardwareAddressImpl(name, interfaceIndex); + } + private static native byte[] getHardwareAddressImpl(String n, int index) 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 + * @hide + */ + public int getMTU() throws SocketException { + if (addresses.isEmpty()) { + return 0; + } + return getMTUImpl(name, interfaceIndex); + } + private static native int getMTUImpl(String n, int index) 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 + * @hide + */ + public boolean isVirtual() { + return parent != null; + } } diff --git a/luni/src/main/native/ifaddrs-android.h b/luni/src/main/native/ifaddrs-android.h index 0c3d203..de87b02 100644 --- a/luni/src/main/native/ifaddrs-android.h +++ b/luni/src/main/native/ifaddrs-android.h @@ -17,8 +17,13 @@ #ifndef IFADDRS_ANDROID_H_included #define IFADDRS_ANDROID_H_included +#include <arpa/inet.h> #include <cstring> +#include <errno.h> +#include <net/if.h> +#include <netinet/in.h> #include <new> +#include <sys/ioctl.h> #include <sys/types.h> #include <sys/socket.h> #include <stdio.h> @@ -43,11 +48,14 @@ struct ifaddrs { // Interface flags. unsigned int ifa_flags; - // Interface address. + // Interface network address. sockaddr* ifa_addr; + // Interface netmask. + sockaddr* ifa_netmask; + ifaddrs(ifaddrs* next) - : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL) + : ifa_next(next), ifa_name(NULL), ifa_flags(0), ifa_addr(NULL), ifa_netmask(NULL) { } @@ -55,6 +63,7 @@ struct ifaddrs { delete ifa_next; delete[] ifa_name; delete ifa_addr; + delete ifa_netmask; } // Sadly, we can't keep the interface index for portability with BSD. @@ -91,16 +100,41 @@ struct ifaddrs { // stitch the two bits together into the sockaddr that's part of // our portable interface. void setAddress(int family, void* data, size_t byteCount) { + // Set the address proper... + sockaddr_storage* ss = new sockaddr_storage; + memset(ss, 0, sizeof(*ss)); + ifa_addr = reinterpret_cast<sockaddr*>(ss); + ss->ss_family = family; + uint8_t* dst = sockaddrBytes(family, ss); + memcpy(dst, data, byteCount); + } + + // Netlink gives us the prefix length as a bit count. We need to turn + // that into a BSD-compatible netmask represented by a sockaddr*. + void setNetmask(int family, size_t prefixLength) { + // ...and work out the netmask from the prefix length. sockaddr_storage* ss = new sockaddr_storage; + memset(ss, 0, sizeof(*ss)); + ifa_netmask = reinterpret_cast<sockaddr*>(ss); ss->ss_family = family; + uint8_t* dst = sockaddrBytes(family, ss); + memset(dst, 0xff, prefixLength / 8); + if ((prefixLength % 8) != 0) { + dst[prefixLength/8] = (0xff << (8 - (prefixLength % 8))); + } + } + + // Returns a pointer to the first byte in the address data (which is + // stored in network byte order). + uint8_t* sockaddrBytes(int family, sockaddr_storage* ss) { if (family == AF_INET) { - void* dst = &reinterpret_cast<sockaddr_in*>(ss)->sin_addr; - memcpy(dst, data, byteCount); + sockaddr_in* ss4 = reinterpret_cast<sockaddr_in*>(ss); + return reinterpret_cast<uint8_t*>(&ss4->sin_addr); } else if (family == AF_INET6) { - void* dst = &reinterpret_cast<sockaddr_in6*>(ss)->sin6_addr; - memcpy(dst, data, byteCount); + sockaddr_in6* ss6 = reinterpret_cast<sockaddr_in6*>(ss); + return reinterpret_cast<uint8_t*>(&ss6->sin6_addr); } - ifa_addr = reinterpret_cast<sockaddr*>(ss); + return NULL; } }; @@ -167,6 +201,7 @@ inline int getifaddrs(ifaddrs** result) { return -1; } (*result)->setAddress(family, RTA_DATA(rta), RTA_PAYLOAD(rta)); + (*result)->setNetmask(family, address->ifa_prefixlen); } } rta = RTA_NEXT(rta, ifaPayloadLength); diff --git a/luni/src/main/native/java_net_NetworkInterface.cpp b/luni/src/main/native/java_net_NetworkInterface.cpp index 1a72710..bf2c89d 100644 --- a/luni/src/main/native/java_net_NetworkInterface.cpp +++ b/luni/src/main/native/java_net_NetworkInterface.cpp @@ -64,27 +64,34 @@ static void jniThrowSocketException(JNIEnv* env) { jniStrError(errno, buf, sizeof(buf))); } -static jobject makeInterfaceAddress(JNIEnv* env, jint interfaceIndex, const char* name, sockaddr_storage* ss) { +static jobject makeInterfaceAddress(JNIEnv* env, jint interfaceIndex, ifaddrs* ifa) { jclass clazz = env->FindClass("java/net/InterfaceAddress"); if (clazz == NULL) { return NULL; } - jmethodID constructor = env->GetMethodID(clazz, "<init>", "(ILjava/lang/String;Ljava/net/InetAddress;)V"); + jmethodID constructor = env->GetMethodID(clazz, "<init>", + "(ILjava/lang/String;Ljava/net/InetAddress;Ljava/net/InetAddress;)V"); if (constructor == NULL) { return NULL; } - jobject javaName = env->NewStringUTF(name); + jobject javaName = env->NewStringUTF(ifa->ifa_name); if (javaName == NULL) { return NULL; } - jobject javaAddress = socketAddressToInetAddress(env, ss); + sockaddr_storage* addr = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr); + jobject javaAddress = socketAddressToInetAddress(env, addr); if (javaAddress == NULL) { return NULL; } - return env->NewObject(clazz, constructor, interfaceIndex, javaName, javaAddress); + sockaddr_storage* mask = reinterpret_cast<sockaddr_storage*>(ifa->ifa_netmask); + jobject javaMask = socketAddressToInetAddress(env, mask); + if (javaMask == NULL) { + return NULL; + } + return env->NewObject(clazz, constructor, interfaceIndex, javaName, javaAddress, javaMask); } -static jobjectArray getInterfaceAddresses(JNIEnv* env, jclass) { +static jobjectArray getAllInterfaceAddressesImpl(JNIEnv* env, jclass) { // Get the list of interface addresses. ScopedInterfaceAddresses addresses; if (!addresses.init()) { @@ -128,8 +135,7 @@ static jobjectArray getInterfaceAddresses(JNIEnv* env, jclass) { continue; } // Make a new InterfaceAddress, and insert it into the array. - sockaddr_storage* ss = reinterpret_cast<sockaddr_storage*>(ifa->ifa_addr); - jobject element = makeInterfaceAddress(env, interfaceIndex, ifa->ifa_name, ss); + jobject element = makeInterfaceAddress(env, interfaceIndex, ifa); if (element == NULL) { return NULL; } @@ -142,9 +148,89 @@ static jobjectArray getInterfaceAddresses(JNIEnv* env, jclass) { return result; } +static bool doIoctl(JNIEnv* env, jstring name, int request, ifreq& ifr) { + // Copy the name into the ifreq structure, if there's room... + jsize nameLength = env->GetStringLength(name); + if (nameLength >= IFNAMSIZ) { + errno = ENAMETOOLONG; + jniThrowSocketException(env); + return false; + } + memset(&ifr, 0, sizeof(ifr)); + env->GetStringUTFRegion(name, 0, nameLength, ifr.ifr_name); + + // ...and do the ioctl. + ScopedFd fd(socket(AF_INET, SOCK_DGRAM, 0)); + if (fd.get() == -1) { + jniThrowSocketException(env); + return false; + } + int rc = ioctl(fd.get(), request, &ifr); + if (rc == -1) { + jniThrowSocketException(env); + return false; + } + return true; +} + +static jboolean hasFlag(JNIEnv* env, jstring name, int flag) { + ifreq ifr; + doIoctl(env, name, SIOCGIFFLAGS, ifr); // May throw. + return (ifr.ifr_flags & flag) != 0; +} + +static jbyteArray getHardwareAddressImpl(JNIEnv* env, jclass, jstring name, jint index) { + ifreq ifr; + if (!doIoctl(env, name, SIOCGIFHWADDR, ifr)) { + return NULL; + } + jbyte bytes[IFHWADDRLEN]; + bool isEmpty = true; + for (int i = 0; i < IFHWADDRLEN; ++i) { + bytes[i] = ifr.ifr_hwaddr.sa_data[i]; + if (bytes[i] != 0) { + isEmpty = false; + } + } + if (isEmpty) { + return NULL; + } + jbyteArray result = env->NewByteArray(IFHWADDRLEN); + env->SetByteArrayRegion(result, 0, IFHWADDRLEN, bytes); + return result; +} + +static jint getMTUImpl(JNIEnv* env, jclass, jstring name, jint index) { + ifreq ifr; + doIoctl(env, name, SIOCGIFMTU, ifr); // May throw. + return ifr.ifr_mtu; +} + +static jboolean isLoopbackImpl(JNIEnv* env, jclass, jstring name, jint index) { + return hasFlag(env, name, IFF_LOOPBACK); +} + +static jboolean isPointToPointImpl(JNIEnv* env, jclass, jstring name, jint index) { + return hasFlag(env, name, IFF_POINTOPOINT); // Unix API typo! +} + +static jboolean isUpImpl(JNIEnv* env, jclass, jstring name, jint index) { + return hasFlag(env, name, IFF_UP); +} + +static jboolean supportsMulticastImpl(JNIEnv* env, jclass, jstring name, jint index) { + return hasFlag(env, name, IFF_MULTICAST); +} + static JNINativeMethod gMethods[] = { /* name, signature, funcPtr */ - { "getInterfaceAddresses", "()[Ljava/net/InterfaceAddress;", (void*) getInterfaceAddresses }, + { "getAllInterfaceAddressesImpl", "()[Ljava/net/InterfaceAddress;", (void*) getAllInterfaceAddressesImpl }, + { "getHardwareAddressImpl", "(Ljava/lang/String;I)[B", (void*) getHardwareAddressImpl }, + { "getMTUImpl", "(Ljava/lang/String;I)I", (void*) getMTUImpl }, + { "isLoopbackImpl", "(Ljava/lang/String;I)Z", (void*) isLoopbackImpl }, + { "isPointToPointImpl", "(Ljava/lang/String;I)Z", (void*) isPointToPointImpl }, + { "isUpImpl", "(Ljava/lang/String;I)Z", (void*) isUpImpl }, + { "supportsMulticastImpl", "(Ljava/lang/String;I)Z", (void*) supportsMulticastImpl }, }; int register_java_net_NetworkInterface(JNIEnv* env) { return jniRegisterNativeMethods(env, "java/net/NetworkInterface", diff --git a/luni/src/test/java/tests/api/java/net/NetworkInterfaceTest.java b/luni/src/test/java/tests/api/java/net/NetworkInterfaceTest.java index 0272af1..26960c4 100644 --- a/luni/src/test/java/tests/api/java/net/NetworkInterfaceTest.java +++ b/luni/src/test/java/tests/api/java/net/NetworkInterfaceTest.java @@ -17,597 +17,545 @@ package tests.api.java.net; -import dalvik.annotation.TestTargetClass; -import dalvik.annotation.TestTargets; -import dalvik.annotation.TestLevel; -import dalvik.annotation.TestTargetNew; - import java.net.InetAddress; +import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; -import java.security.Permission; import java.util.ArrayList; import java.util.Enumeration; +import java.util.List; -@TestTargetClass(NetworkInterface.class) public class NetworkInterfaceTest extends junit.framework.TestCase { - // private member variables used for tests - boolean atLeastOneInterface = false; - - boolean atLeastTwoInterfaces = false; - - private NetworkInterface networkInterface1 = null; - - private NetworkInterface sameAsNetworkInterface1 = null; - - private NetworkInterface networkInterface2 = null; - - /** - * @tests java.net.NetworkInterface#getName() - */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "getName", - args = {} - ) - public void test_getName() { - if (atLeastOneInterface) { - assertNotNull("validate that non null name is returned", - networkInterface1.getName()); - assertFalse("validate that non-zero length name is generated", - networkInterface1.getName().equals("")); - } - if (atLeastTwoInterfaces) { - assertFalse( - "Validate strings are different for different interfaces", - networkInterface1.getName().equals( - networkInterface2.getName())); - } - } - - /** - * @tests java.net.NetworkInterface#getInetAddresses() - */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "getInetAddresses", - args = {} - ) - public void test_getInetAddresses() { - - // security manager that allows us to check that we only return the - // addresses that we should - class mySecurityManager extends SecurityManager { - - ArrayList disallowedNames = null; - - public mySecurityManager(ArrayList addresses) { - disallowedNames = new ArrayList(); - for (int i = 0; i < addresses.size(); i++) { - disallowedNames.add(((InetAddress) addresses.get(i)) - .getHostName()); - disallowedNames.add(((InetAddress) addresses.get(i)) - .getHostAddress()); - } - } - - public void checkConnect(String host, int port) { - - if (host == null) { - throw new NullPointerException("host was null)"); - } - - for (int i = 0; i < disallowedNames.size(); i++) { - if (((String) disallowedNames.get(i)).equals(host)) { - throw new SecurityException("not allowed"); - } - } - } - - public void checkPermission(Permission perm) { - // allow everything + // private member variables used for tests + Enumeration<NetworkInterface> theInterfaces = null; + + boolean atLeastOneInterface = false; + + boolean atLeastTwoInterfaces = false; + + private NetworkInterface networkInterface1 = null; + + private NetworkInterface sameAsNetworkInterface1 = null; + + private NetworkInterface networkInterface2 = null; + + /** + * @tests java.net.NetworkInterface#getName() + */ + public void test_getName() { + if (atLeastOneInterface) { + assertNotNull("validate that non null name is returned", + networkInterface1.getName()); + assertFalse("validate that non-zero length name is generated", + networkInterface1.getName().equals("")); + } + if (atLeastTwoInterfaces) { + assertFalse( + "Validate strings are different for different interfaces", + networkInterface1.getName().equals( + networkInterface2.getName())); + } + } + + /** + * @tests java.net.NetworkInterface#getInetAddresses() + */ + public void test_getInetAddresses() throws Exception { + + // security manager that allows us to check that we only return the + // addresses that we should + class mySecurityManager extends SecurityManager { + + ArrayList disallowedNames = null; + + public mySecurityManager(ArrayList addresses) { + disallowedNames = new ArrayList(); + for (int i = 0; i < addresses.size(); i++) { + disallowedNames.add(((InetAddress) addresses.get(i)) + .getHostName()); + disallowedNames.add(((InetAddress) addresses.get(i)) + .getHostAddress()); + } + } + + public void checkConnect(String host, int port) { + + if (host == null) { + throw new NullPointerException("host was null)"); + } + + for (int i = 0; i < disallowedNames.size(); i++) { + if (((String) disallowedNames.get(i)).equals(host)) { + throw new SecurityException("not allowed"); + } + } + } + + } + + if (atLeastOneInterface) { + Enumeration theAddresses = networkInterface1.getInetAddresses(); + while (theAddresses.hasMoreElements()) { + InetAddress theAddress = (InetAddress) theAddresses + .nextElement(); + assertNotNull("validate that address is not null", theAddress); } } - if (atLeastOneInterface) { - Enumeration theAddresses = networkInterface1.getInetAddresses(); - if (theAddresses != null) { - while (theAddresses.hasMoreElements()) { - InetAddress theAddress = (InetAddress) theAddresses - .nextElement(); - assertTrue("validate that address is not null", - null != theAddress); + if (atLeastTwoInterfaces) { + Enumeration theAddresses = networkInterface2.getInetAddresses(); + while (theAddresses.hasMoreElements()) { + InetAddress theAddress = (InetAddress) theAddresses + .nextElement(); + assertNotNull("validate that address is not null", theAddress); + } + } + + // create the list of ok and not ok addresses to return + if (atLeastOneInterface) { + ArrayList okAddresses = new ArrayList(); + Enumeration addresses = networkInterface1.getInetAddresses(); + int index = 0; + ArrayList notOkAddresses = new ArrayList(); + while (addresses.hasMoreElements()) { + InetAddress theAddress = (InetAddress) addresses.nextElement(); + if (index != 0) { + okAddresses.add(theAddress); + } else { + notOkAddresses.add(theAddress); } + index++; } - } - if (atLeastTwoInterfaces) { - Enumeration theAddresses = networkInterface2.getInetAddresses(); - if (theAddresses != null) { - while (theAddresses.hasMoreElements()) { - InetAddress theAddress = (InetAddress) theAddresses + // do the same for network interface 2 if it exists + if (atLeastTwoInterfaces) { + addresses = networkInterface2.getInetAddresses(); + index = 0; + while (addresses.hasMoreElements()) { + InetAddress theAddress = (InetAddress) addresses + .nextElement(); + if (index != 0) { + okAddresses.add(theAddress); + } else { + notOkAddresses.add(theAddress); + } + index++; + } + } + + // set the security manager that will make the first address not + // visible + System.setSecurityManager(new mySecurityManager(notOkAddresses)); + + // validate not ok addresses are not returned + for (int i = 0; i < notOkAddresses.size(); i++) { + Enumeration reducedAddresses = networkInterface1 + .getInetAddresses(); + while (reducedAddresses.hasMoreElements()) { + InetAddress nextAddress = (InetAddress) reducedAddresses .nextElement(); - assertTrue("validate that address is not null", - null != theAddress); + assertTrue( + "validate that address without permission is not returned", + !nextAddress.equals(notOkAddresses.get(i))); } - } - } - - // create the list of ok and not ok addresses to return - if (atLeastOneInterface) { - ArrayList okAddresses = new ArrayList(); - Enumeration addresses = networkInterface1.getInetAddresses(); - int index = 0; - ArrayList notOkAddresses = new ArrayList(); - if (addresses != null) { - while (addresses.hasMoreElements()) { - InetAddress theAddress = (InetAddress) addresses + if (atLeastTwoInterfaces) { + reducedAddresses = networkInterface2.getInetAddresses(); + while (reducedAddresses.hasMoreElements()) { + InetAddress nextAddress = (InetAddress) reducedAddresses + .nextElement(); + assertTrue( + "validate that address without permission is not returned", + !nextAddress.equals(notOkAddresses.get(i))); + } + } + } + + // validate that ok addresses are returned + for (int i = 0; i < okAddresses.size(); i++) { + boolean addressReturned = false; + Enumeration reducedAddresses = networkInterface1 + .getInetAddresses(); + while (reducedAddresses.hasMoreElements()) { + InetAddress nextAddress = (InetAddress) reducedAddresses .nextElement(); - if (index != 0) { - okAddresses.add(theAddress); - } else { - notOkAddresses.add(theAddress); + if (nextAddress.equals(okAddresses.get(i))) { + addressReturned = true; } - index++; } + if (atLeastTwoInterfaces) { + reducedAddresses = networkInterface2.getInetAddresses(); + while (reducedAddresses.hasMoreElements()) { + InetAddress nextAddress = (InetAddress) reducedAddresses + .nextElement(); + if (nextAddress.equals(okAddresses.get(i))) { + addressReturned = true; + } + } + } + assertTrue("validate that address with permission is returned", + addressReturned); + } + + // validate that we can get the interface by specifying the address. + // This is to be compatible + for (int i = 0; i < notOkAddresses.size(); i++) { + assertNotNull( + "validate we cannot get the NetworkInterface with an address for which we have no privs", + NetworkInterface + .getByInetAddress((InetAddress) notOkAddresses + .get(i))); } - // do the same for network interface 2 it it exists - if (atLeastTwoInterfaces) { - addresses = networkInterface2.getInetAddresses(); - index = 0; - if (addresses != null) { - while (addresses.hasMoreElements()) { - InetAddress theAddress = (InetAddress) addresses - .nextElement(); - if (index != 0) { - okAddresses.add(theAddress); - } else { - notOkAddresses.add(theAddress); - } - index++; - } - } + // validate that we can get the network interface for the good + // addresses + for (int i = 0; i < okAddresses.size(); i++) { + assertNotNull( + "validate we cannot get the NetworkInterface with an address fro which we have no privs", + NetworkInterface + .getByInetAddress((InetAddress) okAddresses + .get(i))); } - // set the security manager that will make the first address not - // visible - System.setSecurityManager(new mySecurityManager(notOkAddresses)); - - // validate not ok addresses are not returned - for (int i = 0; i < notOkAddresses.size(); i++) { - Enumeration reducedAddresses = networkInterface1 - .getInetAddresses(); - if (reducedAddresses != null) { - while (reducedAddresses.hasMoreElements()) { - InetAddress nextAddress = (InetAddress) reducedAddresses - .nextElement(); - assertTrue( - "validate that address without permission is not returned", - !nextAddress.equals(notOkAddresses.get(i))); - } - } - if (atLeastTwoInterfaces) { - reducedAddresses = networkInterface2.getInetAddresses(); - if (reducedAddresses != null) { - while (reducedAddresses.hasMoreElements()) { - InetAddress nextAddress = (InetAddress) reducedAddresses - .nextElement(); - assertTrue( - "validate that address without permission is not returned", - !nextAddress.equals(notOkAddresses.get(i))); - } - } - } + System.setSecurityManager(null); + } + } + + /** + * @tests java.net.NetworkInterface#getDisplayName() + */ + public void test_getDisplayName() { + if (atLeastOneInterface) { + assertNotNull("validate that non null display name is returned", + networkInterface1.getDisplayName()); + assertFalse( + "validate that non-zero length display name is generated", + networkInterface1.getDisplayName().equals("")); + } + if (atLeastTwoInterfaces) { + assertFalse( + "Validate strings are different for different interfaces", + networkInterface1.getDisplayName().equals( + networkInterface2.getDisplayName())); + } + } + + /** + * @tests java.net.NetworkInterface#getByName(java.lang.String) + */ + public void test_getByNameLjava_lang_String() throws Exception { + try { + assertNull("validate null handled ok", + NetworkInterface.getByName(null)); + fail("getByName did not throw NullPointerException for null argument"); + } catch (NullPointerException e) { + } + + assertNull("validate handled ok if we ask for name not associated with any interface", + NetworkInterface.getByName("8not a name4")); + + // for each address in an interface validate that we get the right + // interface for that name + if (atLeastOneInterface) { + String theName = networkInterface1.getName(); + if (theName != null) { + assertEquals( + "validate that Interface can be obtained with its name", + networkInterface1, NetworkInterface.getByName(theName)); } - - // validate that ok addresses are returned - for (int i = 0; i < okAddresses.size(); i++) { - boolean addressReturned = false; - Enumeration reducedAddresses = networkInterface1 - .getInetAddresses(); - if (reducedAddresses != null) { - while (reducedAddresses.hasMoreElements()) { - InetAddress nextAddress = (InetAddress) reducedAddresses - .nextElement(); - if (nextAddress.equals(okAddresses.get(i))) { - addressReturned = true; - } - } - } - if (atLeastTwoInterfaces) { - reducedAddresses = networkInterface2.getInetAddresses(); - if (reducedAddresses != null) { - while (reducedAddresses.hasMoreElements()) { - InetAddress nextAddress = (InetAddress) reducedAddresses - .nextElement(); - if (nextAddress.equals(okAddresses.get(i))) { - addressReturned = true; - } - } - } - } - assertTrue("validate that address with permission is returned", - addressReturned); + } + + // validate that we get the right interface with the second interface as + // well (ie we just don't always get the first interface + if (atLeastTwoInterfaces) { + String theName = networkInterface2.getName(); + if (theName != null) { + assertEquals( + "validate that Interface can be obtained with its name", + networkInterface2, NetworkInterface.getByName(theName)); } - - // validate that we can get the interface by specifying the address. - // This is to be compatible - for (int i = 0; i < notOkAddresses.size(); i++) { - try { - assertNotNull( - "validate we cannot get the NetworkInterface with an address for which we have no privs", - NetworkInterface - .getByInetAddress((InetAddress) notOkAddresses - .get(i))); - } catch (Exception e) { - fail("get NetworkInterface for address with no perm - exception"); - } + } + } + + /** + * @tests java.net.NetworkInterface#getByInetAddress(java.net.InetAddress) + */ + public void test_getByInetAddressLjava_net_InetAddress() throws Exception { + + byte addressBytes[] = new byte[4]; + addressBytes[0] = 0; + addressBytes[1] = 0; + addressBytes[2] = 0; + addressBytes[3] = 0; + + try { + assertNull("validate null handled ok", + NetworkInterface.getByInetAddress(null)); + fail("should not get here if getByInetAddress throws " + + "NullPointerException if null passed in"); + } catch (NullPointerException e) { + } + + assertNull("validate handled ok if we ask for address not associated with any interface", + NetworkInterface.getByInetAddress(InetAddress + .getByAddress(addressBytes))); + + // for each address in an interface validate that we get the right + // interface for that address + if (atLeastOneInterface) { + Enumeration addresses = networkInterface1.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress theAddress = (InetAddress) addresses.nextElement(); + assertEquals( + "validate that Interface can be obtained with any one of its addresses", + networkInterface1, NetworkInterface + .getByInetAddress(theAddress)); } - - // validate that we can get the network interface for the good - // addresses - try { - for (int i = 0; i < okAddresses.size(); i++) { - assertNotNull( - "validate we cannot get the NetworkInterface with an address fro which we have no privs", - NetworkInterface - .getByInetAddress((InetAddress) okAddresses - .get(i))); - } - } catch (Exception e) { - fail("get NetworkInterface for address with perm - exception"); + } + + // validate that we get the right interface with the second interface as + // well (ie we just don't always get the first interface + if (atLeastTwoInterfaces) { + Enumeration addresses = networkInterface2.getInetAddresses(); + while (addresses.hasMoreElements()) { + InetAddress theAddress = (InetAddress) addresses.nextElement(); + assertEquals( + "validate that Interface can be obtained with any one of its addresses", + networkInterface2, NetworkInterface + .getByInetAddress(theAddress)); } - - System.setSecurityManager(null); + } + } + + /** + * @tests java.net.NetworkInterface#getNetworkInterfaces() + */ + public void test_getNetworkInterfaces() throws Exception { + + // really this is tested by all of the other calls but just make sure we + // can call it and get a list of interfaces if they exist + Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces(); + } + + /** + * @tests java.net.NetworkInterface#equals(java.lang.Object) + */ + public void test_equalsLjava_lang_Object() { + // Test for method boolean + // java.net.SocketPermission.equals(java.lang.Object) + if (atLeastOneInterface) { + assertEquals("If objects are the same true is returned", + sameAsNetworkInterface1, networkInterface1); + assertNotNull("Validate Null handled ok", networkInterface1); } - } - - /** - * @tests java.net.NetworkInterface#getDisplayName() - */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "getDisplayName", - args = {} - ) - public void test_getDisplayName() { - if (atLeastOneInterface) { - assertNotNull("validate that non null display name is returned", - networkInterface1.getDisplayName()); - assertFalse( - "validate that non-zero lengtj display name is generated", - networkInterface1.getDisplayName().equals("")); - } - if (atLeastTwoInterfaces) { - assertFalse( - "Validate strings are different for different interfaces", - networkInterface1.getDisplayName().equals( - networkInterface2.getDisplayName())); + if (atLeastTwoInterfaces) { + assertFalse("If objects are different false is returned", + networkInterface1.equals(networkInterface2)); + } + } + + /** + * @tests java.net.NetworkInterface#hashCode() + */ + public void test_hashCode() { + + if (atLeastOneInterface) { + assertTrue( + "validate that hash codes are the same for two calls on the same object", + networkInterface1.hashCode() == networkInterface1 + .hashCode()); + assertTrue( + "validate that hash codes are the same for two objects for which equals is true", + networkInterface1.hashCode() == sameAsNetworkInterface1 + .hashCode()); + } + } + + /** + * @tests java.net.NetworkInterface#toString() + */ + public void test_toString() { + if (atLeastOneInterface) { + assertNotNull("validate that non null string is generated", + networkInterface1.toString()); + assertFalse("validate that non-zero length string is generated", + networkInterface1.toString().equals("")); + } + if (atLeastTwoInterfaces) { + assertFalse( + "Validate strings are different for different interfaces", + networkInterface1.toString().equals( + networkInterface2.toString())); + } + } + + private class MockSecurityManager extends SecurityManager { + @Override + public void checkConnect(String host, int port) { + throw new SecurityException(); } } /** - * @tests java.net.NetworkInterface#getByName(java.lang.String) + * + * @tests java.net.NetworkInterface#getInterfaceAddresses() + * + * @since 1.6 */ - @TestTargetNew( - level = TestLevel.SUFFICIENT, - notes = "SocketException checking missed.", - method = "getByName", - args = {java.lang.String.class} - ) - public void test_getByNameLjava_lang_String() { - try { - assertNull("validate null handled ok", - NetworkInterface.getByName(null)); - fail("getByName did not throw NullPointerException for null argument"); - } catch (NullPointerException e) { - } catch (Exception e) { - fail("getByName, null inetAddress - raised exception : " - + e.getMessage()); - } - - try { - assertNull("validate handled ok if we ask for name not associated with any interface", - NetworkInterface.getByName("8not a name4")); - } catch (Exception e) { - fail("getByName, unknown inetAddress - raised exception : " - + e.getMessage()); - } - - // for each address in an interface validate that we get the right - // interface for that name - if (atLeastOneInterface) { - String theName = networkInterface1.getName(); - if (theName != null) { - try { - assertTrue( - "validate that Interface can be obtained with its name", - NetworkInterface.getByName(theName).equals( - networkInterface1)); - } catch (Exception e) { - fail("validate to get network interface using name - socket exception"); - } - } - try { - NetworkInterface.getByName(null); - fail("NullPointerException was not thrown."); - } catch(NullPointerException npe) { - //expected - } catch (SocketException e) { - fail("SocketException was thrown."); + public void test_getInterfaceAddresses() throws SocketException { + if (theInterfaces != null) { + SecurityManager oldSM = System.getSecurityManager(); + System.setSecurityManager(new MockSecurityManager()); + + while (theInterfaces.hasMoreElements()) { + NetworkInterface netif = theInterfaces.nextElement(); + assertEquals(netif.getName() + + " getInterfaceAddresses should contain no element", 0, + netif.getInterfaceAddresses().size()); } - } - - // validate that we get the right interface with the second interface as - // well (ie we just don't always get the first interface - if (atLeastTwoInterfaces) { - String theName = networkInterface2.getName(); - if (theName != null) { - try { - assertTrue( - "validate that Interface can be obtained with its name", - NetworkInterface.getByName(theName).equals( - networkInterface2)); - } catch (Exception e) { - fail("validate to get network interface using name - socket exception"); + System.setSecurityManager(oldSM); + + theInterfaces = NetworkInterface.getNetworkInterfaces(); + while (theInterfaces.hasMoreElements()) { + NetworkInterface netif = theInterfaces.nextElement(); + List<InterfaceAddress> interfaceAddrs = netif.getInterfaceAddresses(); + assertTrue(interfaceAddrs instanceof ArrayList); + for (InterfaceAddress addr : interfaceAddrs) { + assertNotNull(addr); } + + List<InterfaceAddress> interfaceAddrs2 = netif.getInterfaceAddresses(); + // RI fails on this since it cannot tolerate null broadcast address. + assertEquals(interfaceAddrs, interfaceAddrs2); } } - } - + } + /** - * @tests java.net.NetworkInterface#getByInetAddress(java.net.InetAddress) + * @tests java.net.NetworkInterface#isLoopback() + * + * @since 1.6 */ - @TestTargetNew( - level = TestLevel.SUFFICIENT, - notes = "SocketException checking missed.", - method = "getByInetAddress", - args = {java.net.InetAddress.class} - ) - public void test_getByInetAddressLjava_net_InetAddress() { - - byte addressBytes[] = new byte[4]; - addressBytes[0] = 0; - addressBytes[1] = 0; - addressBytes[2] = 0; - addressBytes[3] = 0; - - try { - assertNull("validate null handled ok", - NetworkInterface.getByInetAddress(null)); - fail("should not get here if getByInetAddress throws " - + "NullPointerException if null passed in"); - } catch (NullPointerException e) { - } catch (Exception e) { - fail("getByInetAddress, null inetAddress should have raised NPE" - + " but instead threw a : " + e.getMessage()); - } - - try { - assertNull("validate handled ok if we ask for address not associated with any interface", - NetworkInterface.getByInetAddress(InetAddress - .getByAddress(addressBytes))); - } catch (Exception e) { - fail("getByInetAddress, unknown inetAddress threw exception : " + e); - } - - // for each address in an interface validate that we get the right - // interface for that address - if (atLeastOneInterface) { - Enumeration addresses = networkInterface1.getInetAddresses(); - if (addresses != null) { - while (addresses.hasMoreElements()) { - InetAddress theAddress = (InetAddress) addresses - .nextElement(); - try { - assertTrue( - "validate that Interface can be obtained with any one of its addresses", - NetworkInterface.getByInetAddress(theAddress) - .equals(networkInterface1)); - } catch (Exception e) { - fail("validate to get address using inetAddress " + - "threw exception : " + e); + public void test_isLoopback() throws SocketException { + if (theInterfaces != null) { + while (theInterfaces.hasMoreElements()) { + NetworkInterface netif = theInterfaces.nextElement(); + boolean loopback = false; + Enumeration<InetAddress> addrs = netif.getInetAddresses(); + while(addrs != null && addrs.hasMoreElements()){ + if(addrs.nextElement().isLoopbackAddress()){ + loopback = true; + break; } } + assertEquals(loopback, netif.isLoopback()); } - - try { - NetworkInterface.getByInetAddress(null); - fail("NullPointerException should be thrown."); - } catch(NullPointerException npe) { - //expected - } catch (SocketException e) { - fail("SocketException was thrown."); - } - } - - // validate that we get the right interface with the second interface as - // well (ie we just don't always get the first interface - if (atLeastTwoInterfaces) { - Enumeration addresses = networkInterface2.getInetAddresses(); - if (addresses != null) { - while (addresses.hasMoreElements()) { - InetAddress theAddress = (InetAddress) addresses - .nextElement(); - try { - assertTrue( - "validate that Interface can be obtained with any one of its addresses", - NetworkInterface.getByInetAddress(theAddress) - .equals(networkInterface2)); - } catch (Exception e) { - fail("validate to get address using inetAddress " - + "threw exception : " + e); - } - } - } - } - } - - /** - * @tests java.net.NetworkInterface#getNetworkInterfaces() - */ - @TestTargetNew( - level = TestLevel.SUFFICIENT, - notes = "SocketException checking missed.", - method = "getNetworkInterfaces", - args = {} - ) - public void test_getNetworkInterfaces() { - - // really this is tested by all of the other calls but just make sure we - // can call it and get a list of interfaces if they exist - try { - Enumeration theInterfaces = NetworkInterface.getNetworkInterfaces(); - } catch (Exception e) { - fail("get Network Interfaces - raised exception : " - + e.getMessage()); - } - } - - /** - * @tests java.net.NetworkInterface#equals(java.lang.Object) - */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "equals", - args = {java.lang.Object.class} - ) - public void test_equalsLjava_lang_Object() { - // Test for method boolean - // java.net.SocketPermission.equals(java.lang.Object) - if (atLeastOneInterface) { - assertTrue("If objects are the same true is returned", - networkInterface1.equals(sameAsNetworkInterface1)); - assertFalse("Validate Null handled ok", networkInterface1 - .equals(null)); - } - if (atLeastTwoInterfaces) { - assertFalse("If objects are different false is returned", - networkInterface1.equals(networkInterface2)); } } - + /** - * @tests java.net.NetworkInterface#hashCode() + * @tests java.net.NetworkInterface#getHardwareAddress() + * + * @since 1.6 */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "hashCode", - args = {} - ) - public void test_hashCode() { - - if (atLeastOneInterface) { - assertTrue( - "validate that hash codes are the same for two calls on the same object", - networkInterface1.hashCode() == networkInterface1 - .hashCode()); - assertTrue( - "validate that hash codes are the same for two objects for which equals is true", - networkInterface1.hashCode() == sameAsNetworkInterface1 - .hashCode()); + public void test_getHardwareAddress() throws SocketException { + if (theInterfaces != null) { + while (theInterfaces.hasMoreElements()) { + NetworkInterface netif = theInterfaces.nextElement(); + byte[] hwAddr = netif.getHardwareAddress(); + if (netif.isLoopback()) { + assertTrue(hwAddr == null || hwAddr.length == 0); + } else { + assertTrue(hwAddr.length >= 0); + } + } } } - + /** - * @tests java.net.NetworkInterface#toString() + * + * @tests java.net.NetworkInterface#getHardwareAddress() + * + * @since 1.6 */ - @TestTargetNew( - level = TestLevel.COMPLETE, - notes = "", - method = "toString", - args = {} - ) - public void test_toString() { - if (atLeastOneInterface) { - assertNotNull("validate that non null string is generated", - networkInterface1.toString()); - assertFalse("validate that non-zero length string is generated", - networkInterface1.toString().equals("")); + public void test_getMTU() throws SocketException { + if (theInterfaces != null) { + while (theInterfaces.hasMoreElements()) { + NetworkInterface netif = theInterfaces.nextElement(); + assertTrue(netif.getName() + "has non-positive MTU", netif.getMTU() >= 0); + } } - if (atLeastTwoInterfaces) { - assertFalse( - "Validate strings are different for different interfaces", - networkInterface1.toString().equals( - networkInterface2.toString())); - } - } - - protected void setUp() { - - Enumeration theInterfaces = null; - try { - theInterfaces = NetworkInterface.getNetworkInterfaces(); - } catch (Exception e) { - fail("Exception occurred getting network interfaces : " + e); - } - - // Set up NetworkInterface instance members. Note that because the call - // to NetworkInterface.getNetworkInterfaces() returns *all* of the - // interfaces on the test machine it is possible that one or more of - // them will not currently be bound to an InetAddress. e.g. a laptop - // running connected by a wire to the local network may also have a - // wireless interface that is not active and so has no InetAddress - // bound to it. For these tests only work with NetworkInterface objects - // that are bound to an InetAddress. - if ((theInterfaces != null) && (theInterfaces.hasMoreElements())) { - while ((theInterfaces.hasMoreElements()) - && (atLeastOneInterface == false)) { - NetworkInterface theInterface = (NetworkInterface) theInterfaces - .nextElement(); - if (theInterface.getInetAddresses() != null) { - // Ensure that the current NetworkInterface has at least - // one InetAddress bound to it. - Enumeration addrs = theInterface.getInetAddresses(); - if ((addrs != null) && (addrs.hasMoreElements())) { - atLeastOneInterface = true; - networkInterface1 = theInterface; - }// end if - } - } - - while ((theInterfaces.hasMoreElements()) - && (atLeastTwoInterfaces == false)) { - NetworkInterface theInterface = (NetworkInterface) theInterfaces - .nextElement(); - if (theInterface.getInetAddresses() != null) { - // Ensure that the current NetworkInterface has at least - // one InetAddress bound to it. - Enumeration addrs = theInterface.getInetAddresses(); - if ((addrs != null) && (addrs.hasMoreElements())) { - atLeastTwoInterfaces = true; - networkInterface2 = theInterface; - }// end if - } - } - - // Only set sameAsNetworkInterface1 if we succeeded in finding - // at least one good NetworkInterface - if (atLeastOneInterface) { - Enumeration addresses = networkInterface1.getInetAddresses(); - if (addresses != null) { - try { - if (addresses.hasMoreElements()) { - sameAsNetworkInterface1 = NetworkInterface - .getByInetAddress((InetAddress) addresses - .nextElement()); - } - } catch (SocketException e) { - fail("SocketException occurred : " + e); - } - } - }// end if atLeastOneInterface - } - } - - protected void tearDown() { - System.setSecurityManager(null); } + + protected void setUp() throws SocketException { + + Enumeration theInterfaces = null; + try { + theInterfaces = NetworkInterface.getNetworkInterfaces(); + } catch (Exception e) { + fail("Exception occurred getting network interfaces : " + e); + } + + // Set up NetworkInterface instance members. Note that because the call + // to NetworkInterface.getNetworkInterfaces() returns *all* of the + // interfaces on the test machine it is possible that one or more of + // them will not currently be bound to an InetAddress. e.g. a laptop + // running connected by a wire to the local network may also have a + // wireless interface that is not active and so has no InetAddress + // bound to it. For these tests only work with NetworkInterface objects + // that are bound to an InetAddress. + if ((theInterfaces != null) && (theInterfaces.hasMoreElements())) { + while ((theInterfaces.hasMoreElements()) + && (atLeastOneInterface == false)) { + NetworkInterface theInterface = (NetworkInterface) theInterfaces + .nextElement(); + if (theInterface.getInetAddresses().hasMoreElements()) { + // Ensure that the current NetworkInterface has at least + // one InetAddress bound to it. + Enumeration addrs = theInterface.getInetAddresses(); + if ((addrs != null) && (addrs.hasMoreElements())) { + atLeastOneInterface = true; + networkInterface1 = theInterface; + }// end if + } + } + + while ((theInterfaces.hasMoreElements()) + && (atLeastTwoInterfaces == false)) { + NetworkInterface theInterface = (NetworkInterface) theInterfaces + .nextElement(); + if (theInterface.getInetAddresses().hasMoreElements()) { + // Ensure that the current NetworkInterface has at least + // one InetAddress bound to it. + Enumeration addrs = theInterface.getInetAddresses(); + if ((addrs != null) && (addrs.hasMoreElements())) { + atLeastTwoInterfaces = true; + networkInterface2 = theInterface; + }// end if + } + } + + // Only set sameAsNetworkInterface1 if we succeeded in finding + // at least one good NetworkInterface + if (atLeastOneInterface) { + Enumeration addresses = networkInterface1.getInetAddresses(); + if (addresses.hasMoreElements()) { + try { + if (addresses.hasMoreElements()) { + sameAsNetworkInterface1 = NetworkInterface + .getByInetAddress((InetAddress) addresses + .nextElement()); + } + } catch (SocketException e) { + fail("SocketException occurred : " + e); + } + } + }// end if atLeastOneInterface + } + theInterfaces = NetworkInterface.getNetworkInterfaces(); + } + + protected void tearDown() { + System.setSecurityManager(null); + } } |