7123896: Unexpected behavior due to Solaris using separate IPv4 and IPv6 port spaces
Reviewed-by: alanb
--- a/jdk/src/share/native/java/net/net_util.c Tue May 08 07:34:53 2012 -0700
+++ b/jdk/src/share/native/java/net/net_util.c Thu May 17 12:21:16 2012 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2012, 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
@@ -68,6 +68,8 @@
*/
IPv6_available = IPv6_supported() & (!preferIPv4Stack);
initLocalAddrTable ();
+ parseExclusiveBindProperty(env);
+
return JNI_VERSION_1_2;
}
--- a/jdk/src/share/native/java/net/net_util.h Tue May 08 07:34:53 2012 -0700
+++ b/jdk/src/share/native/java/net/net_util.h Thu May 17 12:21:16 2012 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -120,6 +120,7 @@
NET_SockaddrToInetAddress(JNIEnv *env, struct sockaddr *him, int *port);
void initLocalAddrTable ();
+void parseExclusiveBindProperty(JNIEnv *env);
void
NET_SetTrafficClass(struct sockaddr *him, int trafficClass);
--- a/jdk/src/solaris/native/java/net/net_util_md.c Tue May 08 07:34:53 2012 -0700
+++ b/jdk/src/solaris/native/java/net/net_util_md.c Thu May 17 12:21:16 2012 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2012, 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
@@ -76,7 +76,7 @@
getnameinfo_f getnameinfo_ptr = NULL;
/*
- * EXCLBIND socket options only on Solaris 8 & 9.
+ * EXCLBIND socket options only on Solaris
*/
#if defined(__solaris__) && !defined(TCP_EXCLBIND)
#define TCP_EXCLBIND 0x21
@@ -113,6 +113,7 @@
static int init_tcp_max_buf, init_udp_max_buf;
static int tcp_max_buf;
static int udp_max_buf;
+static int useExclBind = 0;
/*
* Get the specified parameter from the specified driver. The value
@@ -747,6 +748,26 @@
#endif
+void parseExclusiveBindProperty(JNIEnv *env) {
+#ifdef __solaris__
+ jstring s, flagSet;
+ jclass iCls;
+ jmethodID mid;
+
+ s = (*env)->NewStringUTF(env, "sun.net.useExclusiveBind");
+ CHECK_NULL(s);
+ iCls = (*env)->FindClass(env, "java/lang/System");
+ CHECK_NULL(iCls);
+ mid = (*env)->GetStaticMethodID(env, iCls, "getProperty",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+ CHECK_NULL(mid);
+ flagSet = (*env)->CallStaticObjectMethod(env, iCls, mid, s);
+ if (flagSet != NULL) {
+ useExclBind = 1;
+ }
+#endif
+}
+
/* In the case of an IPv4 Inetaddress this method will return an
* IPv4 mapped address where IPv6 is available and v4MappedAddress is TRUE.
* Otherwise it will return a sockaddr_in structure for an IPv4 InetAddress.
@@ -1450,8 +1471,8 @@
* Linux allows a socket to bind to 127.0.0.255 which must be
* caught.
*
- * On Solaris 8/9 with IPv6 enabled we must use an exclusive
- * bind to guaranteed a unique port number across the IPv4 and
+ * On Solaris with IPv6 enabled we must use an exclusive
+ * bind to guarantee a unique port number across the IPv4 and
* IPv6 port spaces.
*
*/
@@ -1481,10 +1502,10 @@
#if defined(__solaris__) && defined(AF_INET6)
/*
- * Solaris 8/9 have seperate IPv4 and IPv6 port spaces so we
+ * Solaris has separate IPv4 and IPv6 port spaces so we
* use an exclusive bind when SO_REUSEADDR is not used to
* give the illusion of a unified port space.
- * This also avoid problems with IPv6 sockets connecting
+ * This also avoids problems with IPv6 sockets connecting
* to IPv4 mapped addresses whereby the socket conversion
* results in a late bind that fails because the
* corresponding IPv4 port is in use.
@@ -1493,11 +1514,12 @@
int arg, len;
len = sizeof(arg);
- if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg,
- &len) == 0) {
- if (arg == 0) {
+ if (useExclBind || getsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (char *)&arg, &len) == 0) {
+ if (useExclBind || arg == 0) {
/*
- * SO_REUSEADDR is disabled so enable TCP_EXCLBIND or
+ * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
+ * property is true so enable TCP_EXCLBIND or
* UDP_EXCLBIND
*/
len = sizeof(arg);
--- a/jdk/src/windows/native/java/net/net_util_md.c Tue May 08 07:34:53 2012 -0700
+++ b/jdk/src/windows/native/java/net/net_util_md.c Thu May 17 12:21:16 2012 +0100
@@ -126,6 +126,7 @@
}
void initLocalAddrTable () {}
+void parseExclusiveBindProperty (JNIEnv *env) {}
/*
* Since winsock doesn't have the equivalent of strerror(errno)
--- a/jdk/test/java/net/Socket/setReuseAddress/Basic.java Tue May 08 07:34:53 2012 -0700
+++ b/jdk/test/java/net/Socket/setReuseAddress/Basic.java Thu May 17 12:21:16 2012 +0100
@@ -26,6 +26,8 @@
* @bug 4476378
* @summary Check the specific behaviour of the setReuseAddress(boolean)
* method.
+ * @run main Basic
+ * @run main/othervm -Dsun.net.useExclusiveBind Basic
*/
import java.net.*;
@@ -170,7 +172,12 @@
s2.bind( new InetSocketAddress(s1.getLocalPort()) );
passed();
} catch (BindException e) {
- failed();
+ if (System.getProperty("sun.net.useExclusiveBind") != null) {
+ // exclusive bind enabled - expected result
+ passed();
+ } else {
+ failed();
+ }
}
s2.close();
--- a/jdk/test/java/net/Socket/setReuseAddress/Restart.java Tue May 08 07:34:53 2012 -0700
+++ b/jdk/test/java/net/Socket/setReuseAddress/Restart.java Thu May 17 12:21:16 2012 +0100
@@ -26,6 +26,8 @@
* @bug 4476378
* @summary Check that SO_REUSEADDR allows a server to restart
* after a crash.
+ * @run main Restart
+ * @run main/othervm -Dsun.net.useExclusiveBind Restart
*/
import java.net.*;
@@ -57,6 +59,12 @@
// close the client socket
s1.close();
+ } catch (BindException be) {
+ if (System.getProperty("sun.net.useExclusiveBind") != null) {
+ // exclusive bind, expected exception
+ } else {
+ throw be;
+ }
} finally {
if (ss != null) ss.close();
if (s1 != null) s1.close();