Respect -Djava.net.preferIPv4Stack when using epoll transport

Motivation:

On a system where ipv4 and ipv6 are supported a user may want to use -Djava.net.preferIPv4Stack=true to restrict it to use ipv4 only.
This is currently ignored with the epoll transport.

Modifications:

Respect java.net.preferIPv4Stack system property.

Result:

-Djava.net.preferIPv4Stack=true will have the effect the user is looking for.
This commit is contained in:
Norman Maurer 2015-03-06 13:05:43 +01:00
parent 88beae6838
commit 3df7b4dac7
2 changed files with 43 additions and 3 deletions

View File

@ -115,6 +115,11 @@ public final class NetUtil {
*/ */
private static final int IPV4_SEPARATORS = 3; private static final int IPV4_SEPARATORS = 3;
/**
* {@code true} if ipv4 should be used on a system that supports ipv4 and ipv6.
*/
private static final boolean IPV4_PREFERRED = Boolean.getBoolean("java.net.preferIPv4Stack");
/** /**
* The logger being used by this class * The logger being used by this class
*/ */
@ -260,6 +265,13 @@ public final class NetUtil {
SOMAXCONN = somaxconn; SOMAXCONN = somaxconn;
} }
/**
* Returns {@code true} if ipv4 should be prefered on a system that supports ipv4 and ipv6.
*/
public static boolean isIpV4StackPreferred() {
return IPV4_PREFERRED;
}
/** /**
* Creates an byte[] based on an ipAddressString. No error handling is * Creates an byte[] based on an ipAddressString. No error handling is
* performed here. * performed here.

View File

@ -84,6 +84,8 @@ jmethodID closedChannelExceptionMethodId = NULL;
jclass inetSocketAddressClass = NULL; jclass inetSocketAddressClass = NULL;
jclass datagramSocketAddressClass = NULL; jclass datagramSocketAddressClass = NULL;
jclass nativeDatagramPacketClass = NULL; jclass nativeDatagramPacketClass = NULL;
jclass netUtilClass = NULL;
jmethodID netUtilClassIpv4PreferredMethodId = NULL;
static int socketType; static int socketType;
static const char* ip4prefix = "::ffff:"; static const char* ip4prefix = "::ffff:";
@ -305,7 +307,13 @@ static int init_sockaddr(JNIEnv* env, jbyteArray address, jint scopeId, jint jpo
return 0; return 0;
} }
static int socket_type() { static int socket_type(JNIEnv* env) {
jboolean ipv4Preferred = (*env)->CallStaticBooleanMethod(env, netUtilClass, netUtilClassIpv4PreferredMethodId);
if (ipv4Preferred) {
// User asked to use ipv4 explicitly.
return AF_INET;
}
int fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0); int fd = socket(AF_INET6, SOCK_STREAM | SOCK_NONBLOCK, 0);
if (fd == -1) { if (fd == -1) {
if (errno == EAFNOSUPPORT) { if (errno == EAFNOSUPPORT) {
@ -343,6 +351,24 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) { if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_6) != JNI_OK) {
return JNI_ERR; return JNI_ERR;
} else { } else {
jclass localNetUtilClass = (*env)->FindClass(env, "io/netty/util/NetUtil" );
if (localNetUtilClass == NULL) {
// pending exception...
return JNI_ERR;
}
netUtilClass = (jclass) (*env)->NewGlobalRef(env, localNetUtilClass);
if (netUtilClass == NULL) {
// out-of-memory!
throwOutOfMemoryError(env);
return JNI_ERR;
}
netUtilClassIpv4PreferredMethodId = (*env)->GetStaticMethodID(env, netUtilClass, "isIpV4StackPreferred", "()Z" );
if (netUtilClassIpv4PreferredMethodId == NULL) {
// position method was not found.. something is wrong so bail out
throwRuntimeException(env, "failed to get method ID: NetUild.isIpV4StackPreferred()");
return JNI_ERR;
}
// cache classes that are used within other jni methods for performance reasons // cache classes that are used within other jni methods for performance reasons
jclass localClosedChannelExceptionClass = (*env)->FindClass(env, "java/nio/channels/ClosedChannelException"); jclass localClosedChannelExceptionClass = (*env)->FindClass(env, "java/nio/channels/ClosedChannelException");
if (localClosedChannelExceptionClass == NULL) { if (localClosedChannelExceptionClass == NULL) {
@ -509,7 +535,7 @@ jint JNI_OnLoad(JavaVM* vm, void* reserved) {
throwRuntimeException(env, "failed to get method ID: InetSocketAddress.<init>(String, int)"); throwRuntimeException(env, "failed to get method ID: InetSocketAddress.<init>(String, int)");
return JNI_ERR; return JNI_ERR;
} }
socketType = socket_type(); socketType = socket_type(env);
datagramSocketAddrMethodId = (*env)->GetMethodID(env, datagramSocketAddressClass, "<init>", "(Ljava/lang/String;II)V"); datagramSocketAddrMethodId = (*env)->GetMethodID(env, datagramSocketAddressClass, "<init>", "(Ljava/lang/String;II)V");
if (datagramSocketAddrMethodId == NULL) { if (datagramSocketAddrMethodId == NULL) {
@ -575,6 +601,9 @@ void JNI_OnUnload(JavaVM* vm, void* reserved) {
if (datagramSocketAddressClass != NULL) { if (datagramSocketAddressClass != NULL) {
(*env)->DeleteGlobalRef(env, datagramSocketAddressClass); (*env)->DeleteGlobalRef(env, datagramSocketAddressClass);
} }
if (netUtilClass != NULL) {
(*env)->DeleteGlobalRef(env, netUtilClass);
}
} }
} }
@ -952,7 +981,6 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_shutdown0(JNIEnv* env,
} }
static inline jint socket0(JNIEnv* env, jclass clazz, int type) { static inline jint socket0(JNIEnv* env, jclass clazz, int type) {
// TODO: Maybe also respect -Djava.net.preferIPv4Stack=true
int fd = socket(socketType, type | SOCK_NONBLOCK, 0); int fd = socket(socketType, type | SOCK_NONBLOCK, 0);
if (fd == -1) { if (fd == -1) {
return -errno; return -errno;