--- old/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c 2015-11-18 17:26:33.110896516 -0800 +++ new/src/java.base/unix/native/libnet/ExtendedOptionsImpl.c 2015-11-18 17:26:33.010896515 -0800 @@ -54,6 +54,7 @@ /* OS specific code is implemented in these three functions */ static jboolean flowSupported0() ; +static jboolean reuseportSupported0() ; /* * Class: sun_net_ExtendedOptionsImpl @@ -142,6 +143,25 @@ } /* + * Returns a java.lang.Boolean based on 'b' + */ +static jobject createBoolean(JNIEnv *env, int b) { + static jclass b_class; + static jmethodID b_ctrID; + + if (b_class == NULL) { + jclass c = (*env)->FindClass(env, "java/lang/Boolean"); + CHECK_NULL_RETURN(c, NULL); + b_ctrID = (*env)->GetMethodID(env, c, "", "(Z)V"); + CHECK_NULL_RETURN(b_ctrID, NULL); + b_class = (*env)->NewGlobalRef(env, c); + CHECK_NULL_RETURN(b_class, NULL); + } + + return( (*env)->NewObject(env, b_class, b_ctrID, (jboolean)(b!=0)) ); +} + +/* * Retrieve the int file-descriptor from a public socket type object. * Gets impl, then the FileDescriptor from the impl, and then the fd * from that. @@ -337,8 +357,131 @@ #endif /* __solaris__ */ + +#ifdef __linux__ +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: setReusePortOption + * Signature: (Ljava/io/FileDescriptor;Ljava/lang/Object;)V + */ +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setReusePortOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jboolean on) +{ + int fd = getFD(env, fileDesc); + int optval; + + if (fd < 0) { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); + return; + } else { + int rv; + optval = (on ? 1 : 0); + rv = setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)); + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", + "set option SO_REUSEPORT failed"); + } + return; + } + } +} +/* + * Class: sun_net_ExtendedOptionsImpl + * Method: getReusePortOption + * Signature: (Ljava/io/FileDescriptor;)Ljava/lang/Object; + */ +JNIEXPORT jobject JNICALL Java_sun_net_ExtendedOptionsImpl_getReusePortOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc) +{ + int fd = getFD(env, fileDesc); + + if (fd < 0) { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", "socket closed"); + return JNI_FALSE; + } else { + int on; + socklen_t sz = sizeof(on); + + int rv = getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &on, &sz); + if (rv < 0) { + if (errno == ENOPROTOOPT) { + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + } else { + NET_ERROR(env, JNU_JAVANETPKG "SocketException", + "set option SO_REUSEPORT failed"); + } + } + printf("getReusePortOption returns %d\n", on); + return createBoolean(env, on); + } +} + +static jboolean reuseportsupported; +static jboolean reuseportsupported_set = JNI_FALSE; + +static jboolean reuseportSupported0() +{ + /* Do a simple dummy call, and try to figure out from that */ + int one = 1; + int rv, s; + if (reuseportsupported_set) { + return reuseportsupported; + } + s = socket(PF_INET, SOCK_STREAM, 0); + if (s < 0) { + reuseportsupported = JNI_FALSE; + reuseportsupported_set = JNI_TRUE; + return JNI_FALSE; + } + rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one)); + if (rv != 0 && errno == ENOPROTOOPT) { + rv = JNI_FALSE; + } else { + rv = JNI_TRUE; + } + close(s); + reuseportsupported = rv; + reuseportsupported_set = JNI_TRUE; + return reuseportsupported; +} + +#else /* __linux__ */ + +/* Non Linux. Functionality is not supported. So, throw UnsupportedOpExc */ + +JNIEXPORT void JNICALL Java_sun_net_ExtendedOptionsImpl_setReusePortOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc, jboolean on) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); +} + +JNIEXPORT jobject JNICALL Java_sun_net_ExtendedOptionsImpl_getReusePortOption + (JNIEnv *env, jclass UNUSED, jobject fileDesc) +{ + JNU_ThrowByName(env, "java/lang/UnsupportedOperationException", + "unsupported socket option"); + return JNI_FALSE; +} + +static jboolean reuseportSupported0() { + return JNI_FALSE; +} +#endif /* __linux__ */ + JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_flowSupported (JNIEnv *env, jclass UNUSED) { return flowSupported0(); } + +JNIEXPORT jboolean JNICALL Java_sun_net_ExtendedOptionsImpl_reuseportSupported + (JNIEnv *env, jclass UNUSED) +{ + return reuseportSupported0(); +}