提交 efffd359 编写于 作者: A alanb

6989190: SO_SNDBUF/SO_RCVBUF limits should only be checked when setsockopt fails (sol)

Reviewed-by: chegar, michaelm
上级 b8b55293
...@@ -363,17 +363,20 @@ void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, ...@@ -363,17 +363,20 @@ void ThrowUnknownHostExceptionWithGaiError(JNIEnv *env,
const char* hostname, const char* hostname,
int gai_error) int gai_error)
{ {
int size;
char *buf;
const char *format = "%s: %s"; const char *format = "%s: %s";
const char *error_string = const char *error_string =
(gai_strerror_ptr == NULL) ? NULL : (*gai_strerror_ptr)(gai_error); (gai_strerror_ptr == NULL) ? NULL : (*gai_strerror_ptr)(gai_error);
if (error_string == NULL) if (error_string == NULL)
error_string = "unknown error"; error_string = "unknown error";
int size = strlen(format) + strlen(hostname) + strlen(error_string) + 2; size = strlen(format) + strlen(hostname) + strlen(error_string) + 2;
char *buf = (char *) malloc(size); buf = (char *) malloc(size);
if (buf) { if (buf) {
jstring s;
sprintf(buf, format, hostname, error_string); sprintf(buf, format, hostname, error_string);
jstring s = JNU_NewStringPlatform(env, buf); s = JNU_NewStringPlatform(env, buf);
if (s != NULL) { if (s != NULL) {
jobject x = JNU_NewObjectByName(env, jobject x = JNU_NewObjectByName(env,
"java/net/UnknownHostException", "java/net/UnknownHostException",
...@@ -1203,19 +1206,26 @@ NET_SetSockOpt(int fd, int level, int opt, const void *arg, ...@@ -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 * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
* ensure that value is <= max_buf as otherwise we get * the value when it exceeds the system limit.
* an invalid argument.
*/ */
#ifdef __solaris__ #ifdef __solaris__
if (level == SOL_SOCKET) { if (level == SOL_SOCKET) {
if (opt == SO_SNDBUF || opt == SO_RCVBUF) { if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
int sotype, arglen; int sotype, arglen;
int *bufsize, maxbuf; 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) { if (!init_max_buf) {
tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf", 64*1024); tcp_max_buf = getParam("/dev/tcp", "tcp_max_buf", 1024*1024);
udp_max_buf = getParam("/dev/udp", "udp_max_buf", 64*1024); udp_max_buf = getParam("/dev/udp", "udp_max_buf", 2048*1024);
init_max_buf = 1; init_max_buf = 1;
} }
......
...@@ -29,7 +29,9 @@ ...@@ -29,7 +29,9 @@
import java.nio.channels.*; import java.nio.channels.*;
import java.net.*; import java.net.*;
import static java.net.StandardSocketOption.*;
import java.io.IOException; import java.io.IOException;
import java.util.Set;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReference;
...@@ -39,6 +41,7 @@ public class Basic { ...@@ -39,6 +41,7 @@ public class Basic {
public static void main(String[] args) throws Exception { public static void main(String[] args) throws Exception {
testBind(); testBind();
testAccept(); testAccept();
testSocketOptions();
} }
static void testBind() throws Exception { static void testBind() throws Exception {
...@@ -131,4 +134,39 @@ public class Basic { ...@@ -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<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");
}
} }
...@@ -121,8 +121,20 @@ public class Basic { ...@@ -121,8 +121,20 @@ public class Basic {
AsynchronousSocketChannel ch = AsynchronousSocketChannel.open() AsynchronousSocketChannel ch = AsynchronousSocketChannel.open()
.setOption(SO_RCVBUF, 128*1024) .setOption(SO_RCVBUF, 128*1024)
.setOption(SO_SNDBUF, 128*1024) .setOption(SO_SNDBUF, 128*1024)
.setOption(SO_REUSEADDR, true) .setOption(SO_REUSEADDR, true);
.bind(new InetSocketAddress(0));
// 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 // default values
if ((Boolean)ch.getOption(SO_KEEPALIVE)) if ((Boolean)ch.getOption(SO_KEEPALIVE))
......
...@@ -68,8 +68,17 @@ public class SocketOptionTests { ...@@ -68,8 +68,17 @@ public class SocketOptionTests {
checkOption(dc, SO_BROADCAST, true); checkOption(dc, SO_BROADCAST, true);
dc.setOption(SO_BROADCAST, false); dc.setOption(SO_BROADCAST, false);
checkOption(dc, SO_BROADCAST, false); checkOption(dc, SO_BROADCAST, false);
dc.setOption(SO_SNDBUF, 16*1024); // can't check dc.setOption(SO_SNDBUF, 128*1024); // can't check
dc.setOption(SO_RCVBUF, 16*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); dc.setOption(SO_REUSEADDR, true);
checkOption(dc, SO_REUSEADDR, true); checkOption(dc, SO_REUSEADDR, true);
dc.setOption(SO_REUSEADDR, false); dc.setOption(SO_REUSEADDR, false);
......
...@@ -56,6 +56,10 @@ public class SocketOptionTests { ...@@ -56,6 +56,10 @@ public class SocketOptionTests {
// allowed to change when not bound // allowed to change when not bound
ssc.setOption(SO_RCVBUF, 256*1024); // can't check 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); ssc.setOption(SO_REUSEADDR, true);
checkOption(ssc, SO_REUSEADDR, true); checkOption(ssc, SO_REUSEADDR, true);
ssc.setOption(SO_REUSEADDR, false); ssc.setOption(SO_REUSEADDR, false);
......
...@@ -70,6 +70,15 @@ public class SocketOptionTests { ...@@ -70,6 +70,15 @@ public class SocketOptionTests {
checkOption(sc, SO_KEEPALIVE, false); checkOption(sc, SO_KEEPALIVE, false);
sc.setOption(SO_SNDBUF, 128*1024); // can't check sc.setOption(SO_SNDBUF, 128*1024); // can't check
sc.setOption(SO_RCVBUF, 256*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); sc.setOption(SO_REUSEADDR, true);
checkOption(sc, SO_REUSEADDR, true); checkOption(sc, SO_REUSEADDR, true);
sc.setOption(SO_REUSEADDR, false); sc.setOption(SO_REUSEADDR, false);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册