6989190: SO_SNDBUF/SO_RCVBUF limits should only be checked when setsockopt fails (sol)
authoralanb
Mon, 04 Oct 2010 14:17:36 +0100
changeset 6696 7201f23dae0d
parent 6695 0e91810597f9
child 6697 39929804f9d4
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
jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java
jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java
jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java
jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java
jdk/test/java/nio/channels/SocketChannel/SocketOptionTests.java
--- 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);