6989190: SO_SNDBUF/SO_RCVBUF limits should only be checked when setsockopt fails (sol)
Reviewed-by: chegar, michaelm
--- a/jdk/src/solaris/native/java/net/net_util_md.c Sun Oct 03 19:39:25 2010 +0100
+++ b/jdk/src/solaris/native/java/net/net_util_md.c Mon Oct 04 14:17:36 2010 +0100
@@ -363,17 +363,20 @@
const char* hostname,
int gai_error)
{
+ int size;
+ char *buf;
const char *format = "%s: %s";
const char *error_string =
(gai_strerror_ptr == NULL) ? NULL : (*gai_strerror_ptr)(gai_error);
if (error_string == NULL)
error_string = "unknown error";
- int size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
- char *buf = (char *) malloc(size);
+ size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
+ buf = (char *) malloc(size);
if (buf) {
+ jstring s;
sprintf(buf, format, hostname, error_string);
- jstring s = JNU_NewStringPlatform(env, buf);
+ s = JNU_NewStringPlatform(env, buf);
if (s != NULL) {
jobject x = JNU_NewObjectByName(env,
"java/net/UnknownHostException",
@@ -1203,19 +1206,26 @@
}
/*
- * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris need to
- * ensure that value is <= max_buf as otherwise we get
- * an invalid argument.
+ * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
+ * the value when it exceeds the system limit.
*/
#ifdef __solaris__
if (level == SOL_SOCKET) {
if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
int sotype, arglen;
int *bufsize, maxbuf;
+ int ret;
+
+ /* Attempt with the original size */
+ ret = setsockopt(fd, level, opt, arg, len);
+ if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
+ return ret;
+
+ /* Exceeded system limit so clamp and retry */
if (!init_max_buf) {
- tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf", 64*1024);
- udp_max_buf = getParam("/dev/udp", "udp_max_buf", 64*1024);
+ tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf", 1024*1024);
+ udp_max_buf = getParam("/dev/udp", "udp_max_buf", 2048*1024);
init_max_buf = 1;
}
--- a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java Sun Oct 03 19:39:25 2010 +0100
+++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java Mon Oct 04 14:17:36 2010 +0100
@@ -29,7 +29,9 @@
import java.nio.channels.*;
import java.net.*;
+import static java.net.StandardSocketOption.*;
import java.io.IOException;
+import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference;
@@ -39,6 +41,7 @@
public static void main(String[] args) throws Exception {
testBind();
testAccept();
+ testSocketOptions();
}
static void testBind() throws Exception {
@@ -131,4 +134,39 @@
}
}
+
+ static void testSocketOptions() throws Exception {
+ System.out.println("-- socket options --");
+ AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel.open();
+ try {
+ // check supported options
+ Set<SocketOption<?>> options = ch.supportedOptions();
+ if (!options.contains(SO_REUSEADDR))
+ throw new RuntimeException("SO_REUSEADDR should be supported");
+ if (!options.contains(SO_RCVBUF))
+ throw new RuntimeException("SO_RCVBUF should be supported");
+
+ // allowed to change when not bound
+ ch.setOption(SO_RCVBUF, 256*1024); // can't check
+ int before = ch.getOption(SO_RCVBUF);
+ int after = ch.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
+ ch.setOption(SO_REUSEADDR, true);
+ checkOption(ch, SO_REUSEADDR, true);
+ ch.setOption(SO_REUSEADDR, false);
+ checkOption(ch, SO_REUSEADDR, false);
+ } finally {
+ ch.close();
+ }
+ }
+
+ static void checkOption(AsynchronousServerSocketChannel ch,
+ SocketOption name, Object expectedValue)
+ throws IOException
+ {
+ Object value = ch.getOption(name);
+ if (!value.equals(expectedValue))
+ throw new RuntimeException("value not as expected");
+ }
}
--- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java Sun Oct 03 19:39:25 2010 +0100
+++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java Mon Oct 04 14:17:36 2010 +0100
@@ -121,8 +121,20 @@
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()
.setOption(SO_RCVBUF, 128*1024)
.setOption(SO_SNDBUF, 128*1024)
- .setOption(SO_REUSEADDR, true)
- .bind(new InetSocketAddress(0));
+ .setOption(SO_REUSEADDR, true);
+
+ // check SO_SNDBUF/SO_RCVBUF limits
+ int before, after;
+ before = ch.getOption(SO_SNDBUF);
+ after = ch.setOption(SO_SNDBUF, Integer.MAX_VALUE).getOption(SO_SNDBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_SNDBUF to decrease");
+ before = ch.getOption(SO_RCVBUF);
+ after = ch.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
+
+ ch.bind(new InetSocketAddress(0));
// default values
if ((Boolean)ch.getOption(SO_KEEPALIVE))
--- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java Sun Oct 03 19:39:25 2010 +0100
+++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java Mon Oct 04 14:17:36 2010 +0100
@@ -68,8 +68,17 @@
checkOption(dc, SO_BROADCAST, true);
dc.setOption(SO_BROADCAST, false);
checkOption(dc, SO_BROADCAST, false);
- dc.setOption(SO_SNDBUF, 16*1024); // can't check
- dc.setOption(SO_RCVBUF, 16*1024); // can't check
+ dc.setOption(SO_SNDBUF, 128*1024); // can't check
+ dc.setOption(SO_RCVBUF, 128*1024); // can't check
+ int before, after;
+ before = dc.getOption(SO_SNDBUF);
+ after = dc.setOption(SO_SNDBUF, Integer.MAX_VALUE).getOption(SO_SNDBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_SNDBUF to decrease");
+ before = dc.getOption(SO_RCVBUF);
+ after = dc.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
dc.setOption(SO_REUSEADDR, true);
checkOption(dc, SO_REUSEADDR, true);
dc.setOption(SO_REUSEADDR, false);
--- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java Sun Oct 03 19:39:25 2010 +0100
+++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java Mon Oct 04 14:17:36 2010 +0100
@@ -56,6 +56,10 @@
// allowed to change when not bound
ssc.setOption(SO_RCVBUF, 256*1024); // can't check
+ int before = ssc.getOption(SO_RCVBUF);
+ int after = ssc.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
ssc.setOption(SO_REUSEADDR, true);
checkOption(ssc, SO_REUSEADDR, true);
ssc.setOption(SO_REUSEADDR, false);
--- a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java Sun Oct 03 19:39:25 2010 +0100
+++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java Mon Oct 04 14:17:36 2010 +0100
@@ -70,6 +70,15 @@
checkOption(sc, SO_KEEPALIVE, false);
sc.setOption(SO_SNDBUF, 128*1024); // can't check
sc.setOption(SO_RCVBUF, 256*1024); // can't check
+ int before, after;
+ before = sc.getOption(SO_SNDBUF);
+ after = sc.setOption(SO_SNDBUF, Integer.MAX_VALUE).getOption(SO_SNDBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_SNDBUF to decrease");
+ before = sc.getOption(SO_RCVBUF);
+ after = sc.setOption(SO_RCVBUF, Integer.MAX_VALUE).getOption(SO_RCVBUF);
+ if (after < before)
+ throw new RuntimeException("setOption caused SO_RCVBUF to decrease");
sc.setOption(SO_REUSEADDR, true);
checkOption(sc, SO_REUSEADDR, true);
sc.setOption(SO_REUSEADDR, false);