Skip to content

Commit

Permalink
8225239: Refactor NetworkInterface lookups
Browse files Browse the repository at this point in the history
Reviewed-by: michaelm, dfuchs, chegar
  • Loading branch information
cl4es committed Jul 5, 2019
1 parent eb28184 commit 7f1f9a5
Show file tree
Hide file tree
Showing 8 changed files with 415 additions and 142 deletions.
35 changes: 20 additions & 15 deletions src/java.base/share/classes/java/net/Inet6AddressImpl.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand All @@ -25,6 +25,8 @@
package java.net;

import java.io.IOException;

import static java.net.InetAddress.IPv6;
import static java.net.InetAddress.PREFER_IPV6_VALUE;
import static java.net.InetAddress.PREFER_SYSTEM_VALUE;

Expand Down Expand Up @@ -70,7 +72,7 @@ public boolean isReachable(InetAddress addr, int timeout,
* stack system).
*/
java.util.Enumeration<InetAddress> it = netif.getInetAddresses();
InetAddress inetaddr = null;
InetAddress inetaddr;
while (it.hasMoreElements()) {
inetaddr = it.nextElement();
if (inetaddr.getClass().isInstance(addr)) {
Expand Down Expand Up @@ -110,20 +112,23 @@ public synchronized InetAddress loopbackAddress() {
boolean preferIPv6Address =
InetAddress.preferIPv6Address == PREFER_IPV6_VALUE ||
InetAddress.preferIPv6Address == PREFER_SYSTEM_VALUE;
InetAddress loopback4 = (new Inet4AddressImpl()).loopbackAddress();
InetAddress loopback6 = new Inet6Address("localhost",
new byte[] {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
// Order the candidate addresses by preference.
InetAddress[] addresses = preferIPv6Address
? new InetAddress[] {loopback6, loopback4}
: new InetAddress[] {loopback4, loopback6};
// In case of failure, default to the preferred address.
loopbackAddress = addresses[0];
// Pick the first candidate address that actually exists.
for (InetAddress address : addresses) {

for (int i = 0; i < 2; i++) {
InetAddress address;
// Order the candidate addresses by preference.
if (i == (preferIPv6Address ? 0 : 1)) {
address = new Inet6Address("localhost",
new byte[]{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01});
} else {
address = new Inet4Address("localhost", new byte[]{ 0x7f,0x00,0x00,0x01 });
}
if (i == 0) {
// In case of failure, default to the preferred address.
loopbackAddress = address;
}
try {
if (NetworkInterface.getByInetAddress(address) == null) {
if (!NetworkInterface.isBoundInetAddress(address)) {
continue;
}
} catch (SocketException e) {
Expand Down
5 changes: 2 additions & 3 deletions src/java.base/share/classes/java/net/InetAddress.java
Expand Up @@ -290,7 +290,7 @@ InetAddressHolder holder() {
}

/* Used to store the name service provider */
private static transient NameService nameService = null;
private static transient NameService nameService;

/**
* Used to store the best available hostname.
Expand All @@ -305,8 +305,7 @@ InetAddressHolder holder() {
* Load net library into runtime, and perform initializations.
*/
static {
String str = java.security.AccessController.doPrivileged(
new GetPropertyAction("java.net.preferIPv6Addresses"));
String str = GetPropertyAction.privilegedGetProperty("java.net.preferIPv6Addresses");
if (str == null) {
preferIPv6Address = PREFER_IPV4_VALUE;
} else if (str.equalsIgnoreCase("true")) {
Expand Down
37 changes: 28 additions & 9 deletions src/java.base/share/classes/java/net/NetworkInterface.java
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -321,17 +321,16 @@ public static NetworkInterface getByInetAddress(InetAddress addr) throws SocketE
if (addr == null) {
throw new NullPointerException();
}
if (addr instanceof Inet4Address) {
Inet4Address inet4Address = (Inet4Address) addr;
if (inet4Address.holder.family != InetAddress.IPv4) {

if (addr.holder.family == InetAddress.IPv4) {
if (!(addr instanceof Inet4Address)) {
throw new IllegalArgumentException("invalid family type: "
+ inet4Address.holder.family);
+ addr.holder.family);
}
} else if (addr instanceof Inet6Address) {
Inet6Address inet6Address = (Inet6Address) addr;
if (inet6Address.holder.family != InetAddress.IPv6) {
} else if (addr.holder.family == InetAddress.IPv6) {
if (!(addr instanceof Inet6Address)) {
throw new IllegalArgumentException("invalid family type: "
+ inet6Address.holder.family);
+ addr.holder.family);
}
} else {
throw new IllegalArgumentException("invalid address type: " + addr);
Expand Down Expand Up @@ -394,6 +393,23 @@ public static Stream<NetworkInterface> networkInterfaces()
}
}

/**
* Checks if the given address is bound to any of the interfaces on this
* machine.
*
* @param addr
* The {@code InetAddress} to search with.
* @return true iff the addr parameter is currently bound to one of
* the interfaces on this machine.
*
* @throws SocketException
* If an I/O error occurs.
*/
/* package-private */ static boolean isBoundInetAddress(InetAddress addr)
throws SocketException {
return boundInetAddress0(addr);
}

private static <T> Enumeration<T> enumerationFromArray(T[] a) {
return new Enumeration<>() {
int i = 0;
Expand Down Expand Up @@ -431,6 +447,9 @@ private static native NetworkInterface getByName0(String name)
private static native NetworkInterface getByIndex0(int index)
throws SocketException;

private static native boolean boundInetAddress0(InetAddress addr)
throws SocketException;

private static native NetworkInterface getByInetAddress0(InetAddress addr)
throws SocketException;

Expand Down
142 changes: 102 additions & 40 deletions src/java.base/unix/native/libnet/NetworkInterface.c
Expand Up @@ -320,33 +320,9 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByIndex0
return obj;
}

/*
* Class: java_net_NetworkInterface
* Method: getByInetAddress0
* Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
*/
JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
(JNIEnv *env, jclass cls, jobject iaObj)
{
netif *ifs, *curr;
jobject obj = NULL;
jboolean match = JNI_FALSE;
int family = getInetAddress_family(env, iaObj);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);

if (family == java_net_InetAddress_IPv4) {
family = AF_INET;
} else if (family == java_net_InetAddress_IPv6) {
family = AF_INET6;
} else {
return NULL; // Invalid family
}
ifs = enumInterfaces(env);
if (ifs == NULL) {
return NULL;
}

curr = ifs;
// Return the interface in ifs that iaObj is bound to, if any - otherwise NULL
static netif* find_bound_interface(JNIEnv *env, netif* ifs, jobject iaObj, int family) {
netif* curr = ifs;
while (curr != NULL) {
netaddr *addrP = curr->addr;

Expand All @@ -359,11 +335,10 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
((struct sockaddr_in *)addrP->addr)->sin_addr.s_addr);
int address2 = getInetAddress_addr(env, iaObj);
if ((*env)->ExceptionCheck(env)) {
goto cleanup;
return NULL;
}
if (address1 == address2) {
match = JNI_TRUE;
break;
return curr;
}
} else if (family == AF_INET6) {
jbyte *bytes = (jbyte *)&(
Expand All @@ -383,30 +358,117 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
i++;
}
if (i >= 16) {
match = JNI_TRUE;
break;
return curr;
}
}
}

if (match) {
break;
}
addrP = addrP->next;
}
curr = curr->next;
}

if (match) {
break;
return NULL;
}

/*
* Class: java_net_NetworkInterface
* Method: boundInetAddress0
* Signature: (Ljava/net/InetAddress;)boundInetAddress;
*/
JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_boundInetAddress0
(JNIEnv *env, jclass cls, jobject iaObj)
{
netif *ifs = NULL;
jboolean bound = JNI_FALSE;
int sock;

int family = getInetAddress_family(env, iaObj);
JNU_CHECK_EXCEPTION_RETURN(env, JNI_FALSE);

if (family == java_net_InetAddress_IPv4) {
family = AF_INET;
} else if (family == java_net_InetAddress_IPv6) {
family = AF_INET6;
} else {
return JNI_FALSE; // Invalid family
}

if (family == AF_INET) {
sock = openSocket(env, AF_INET);
if (sock < 0 && (*env)->ExceptionOccurred(env)) {
return JNI_FALSE;
}
curr = curr->next;

// enumerate IPv4 addresses
if (sock >= 0) {
ifs = enumIPv4Interfaces(env, sock, ifs);
close(sock);

if ((*env)->ExceptionOccurred(env)) {
goto cleanup;
}
}
if (find_bound_interface(env, ifs, iaObj, family) != NULL)
bound = JNI_TRUE;
} else if (ipv6_available()) {
// If IPv6 is available then enumerate IPv6 addresses.
// User can disable ipv6 explicitly by -Djava.net.preferIPv4Stack=true,
// so we have to call ipv6_available()
sock = openSocket(env, AF_INET6);
if (sock < 0) {
return JNI_FALSE;
}

ifs = enumIPv6Interfaces(env, sock, ifs);
close(sock);

if ((*env)->ExceptionOccurred(env)) {
goto cleanup;
}

if (find_bound_interface(env, ifs, iaObj, family) != NULL)
bound = JNI_TRUE;
}

cleanup:
freeif(ifs);

return bound;
}

/*
* Class: java_net_NetworkInterface
* Method: getByInetAddress0
* Signature: (Ljava/net/InetAddress;)Ljava/net/NetworkInterface;
*/
JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByInetAddress0
(JNIEnv *env, jclass cls, jobject iaObj)
{
netif *ifs, *curr;
jobject obj = NULL;
int family = getInetAddress_family(env, iaObj);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);

if (family == java_net_InetAddress_IPv4) {
family = AF_INET;
} else if (family == java_net_InetAddress_IPv6) {
family = AF_INET6;
} else {
return NULL; // Invalid family
}
ifs = enumInterfaces(env);
if (ifs == NULL) {
return NULL;
}

curr = find_bound_interface(env, ifs, iaObj, family);

// if found create a NetworkInterface
if (match) {
if (curr != NULL) {
obj = createNetworkInterface(env, curr);
}

cleanup:
// release the interface list
freeif(ifs);

Expand Down

0 comments on commit 7f1f9a5

Please sign in to comment.