From 41cc1e2f4a94c476d05cd9bda6ef1e183013b33c Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Mon, 4 Oct 2010 14:17:36 +0100 Subject: [PATCH] 6989190: SO_SNDBUF/SO_RCVBUF limits should only be checked when setsockopt fails (sol) Reviewed-by: chegar, michaelm --- jdk/src/solaris/native/java/net/net_util_md.c | 26 +++++++++---- .../Basic.java | 38 +++++++++++++++++++ .../AsynchronousSocketChannel/Basic.java | 16 +++++++- .../DatagramChannel/SocketOptionTests.java | 13 ++++++- .../SocketOptionTests.java | 4 ++ .../SocketChannel/SocketOptionTests.java | 9 +++++ 6 files changed, 94 insertions(+), 12 deletions(-) diff --git a/jdk/src/solaris/native/java/net/net_util_md.c b/jdk/src/solaris/native/java/net/net_util_md.c index 8a414e60141..43baab96ea8 100644 --- a/jdk/src/solaris/native/java/net/net_util_md.c +++ b/jdk/src/solaris/native/java/net/net_util_md.c @@ -363,17 +363,20 @@ void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, 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 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, } /* - * 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; } diff --git a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java index 54c0b0ea723..e526112ae26 100644 --- a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java @@ -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 class Basic { public static void main(String[] args) throws Exception { testBind(); testAccept(); + testSocketOptions(); } static void testBind() throws Exception { @@ -131,4 +134,39 @@ public class Basic { } } + + static void testSocketOptions() throws Exception { + System.out.println("-- socket options --"); + AsynchronousServerSocketChannel ch = AsynchronousServerSocketChannel.open(); + try { + // check supported options + Set> 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"); + } } diff --git a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java index df12b258ce1..e8f23f46866 100644 --- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java @@ -121,8 +121,20 @@ public class Basic { 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)) diff --git a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java index cbd6b1468a9..e09fd8c09aa 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -68,8 +68,17 @@ public class SocketOptionTests { 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); diff --git a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java index 8d30e3a1809..d5ad22687d1 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -56,6 +56,10 @@ public class SocketOptionTests { // 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); diff --git a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java index 89bbfcafc1a..9fe1abddef4 100644 --- a/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java @@ -70,6 +70,15 @@ public class SocketOptionTests { 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);