--- a/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java Wed May 29 08:21:33 2019 -0400
+++ b/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java Wed May 29 13:58:05 2019 +0100
@@ -35,12 +35,14 @@
import java.security.PrivilegedExceptionAction;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Objects;
import java.util.Set;
import sun.net.ConnectionResetException;
import sun.net.NetHooks;
import sun.net.PlatformSocketImpl;
import sun.net.ResourceManager;
+import sun.net.ext.ExtendedSocketOptions;
import sun.net.util.SocketExceptions;
/**
@@ -84,6 +86,9 @@
*/
protected boolean stream;
+ /* whether this is a server or not */
+ final boolean isServer;
+
/**
* Load net library into runtime.
*/
@@ -112,27 +117,7 @@
}
AbstractPlainSocketImpl(boolean isServer) {
- super(isServer);
- }
-
- /**
- * Returns a set of SocketOptions supported by this impl and by this impl's
- * socket (Socket or ServerSocket)
- *
- * @return a Set of SocketOptions
- */
- @Override
- protected Set<SocketOption<?>> supportedOptions() {
- Set<SocketOption<?>> options;
- if (isReusePortAvailable()) {
- options = new HashSet<>();
- options.addAll(super.supportedOptions());
- options.add(StandardSocketOptions.SO_REUSEPORT);
- options = Collections.unmodifiableSet(options);
- } else {
- options = super.supportedOptions();
- }
- return options;
+ this.isServer = isServer;
}
/**
@@ -394,6 +379,121 @@
}
}
+ static final ExtendedSocketOptions extendedOptions =
+ ExtendedSocketOptions.getInstance();
+
+ private static final Set<SocketOption<?>> clientSocketOptions = clientSocketOptions();
+ private static final Set<SocketOption<?>> serverSocketOptions = serverSocketOptions();
+
+ private static Set<SocketOption<?>> clientSocketOptions() {
+ HashSet<SocketOption<?>> options = new HashSet<>();
+ options.add(StandardSocketOptions.SO_KEEPALIVE);
+ options.add(StandardSocketOptions.SO_SNDBUF);
+ options.add(StandardSocketOptions.SO_RCVBUF);
+ options.add(StandardSocketOptions.SO_REUSEADDR);
+ options.add(StandardSocketOptions.SO_LINGER);
+ options.add(StandardSocketOptions.IP_TOS);
+ options.add(StandardSocketOptions.TCP_NODELAY);
+ if (isReusePortAvailable())
+ options.add(StandardSocketOptions.SO_REUSEPORT);
+ options.addAll(ExtendedSocketOptions.clientSocketOptions());
+ return Collections.unmodifiableSet(options);
+ }
+
+ private static Set<SocketOption<?>> serverSocketOptions() {
+ HashSet<SocketOption<?>> options = new HashSet<>();
+ options.add(StandardSocketOptions.SO_RCVBUF);
+ options.add(StandardSocketOptions.SO_REUSEADDR);
+ options.add(StandardSocketOptions.IP_TOS);
+ if (isReusePortAvailable())
+ options.add(StandardSocketOptions.SO_REUSEPORT);
+ options.addAll(ExtendedSocketOptions.serverSocketOptions());
+ return Collections.unmodifiableSet(options);
+ }
+
+ @Override
+ protected Set<SocketOption<?>> supportedOptions() {
+ if (isServer)
+ return serverSocketOptions;
+ else
+ return clientSocketOptions;
+ }
+
+ @Override
+ protected <T> void setOption(SocketOption<T> name, T value) throws IOException {
+ Objects.requireNonNull(name);
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name + "' not supported");
+
+ if (!name.type().isInstance(value))
+ throw new IllegalArgumentException("Invalid value '" + value + "'");
+
+ if (isClosedOrPending())
+ throw new SocketException("Socket closed");
+
+ if (name == StandardSocketOptions.SO_KEEPALIVE) {
+ setOption(SocketOptions.SO_KEEPALIVE, value);
+ } else if (name == StandardSocketOptions.SO_SNDBUF) {
+ if (((Integer)value).intValue() < 0)
+ throw new IllegalArgumentException("Invalid send buffer size:" + value);
+ setOption(SocketOptions.SO_SNDBUF, value);
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ if (((Integer)value).intValue() < 0)
+ throw new IllegalArgumentException("Invalid recv buffer size:" + value);
+ setOption(SocketOptions.SO_RCVBUF, value);
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ setOption(SocketOptions.SO_REUSEADDR, value);
+ } else if (name == StandardSocketOptions.SO_REUSEPORT) {
+ setOption(SocketOptions.SO_REUSEPORT, value);
+ } else if (name == StandardSocketOptions.SO_LINGER ) {
+ setOption(SocketOptions.SO_LINGER, value);
+ } else if (name == StandardSocketOptions.IP_TOS) {
+ int i = ((Integer)value).intValue();
+ if (i < 0 || i > 255)
+ throw new IllegalArgumentException("Invalid IP_TOS value: " + value);
+ setOption(SocketOptions.IP_TOS, value);
+ } else if (name == StandardSocketOptions.TCP_NODELAY) {
+ setOption(SocketOptions.TCP_NODELAY, value);
+ } else if (extendedOptions.isOptionSupported(name)) {
+ extendedOptions.setOption(fd, name, value);
+ } else {
+ throw new AssertionError("unknown option: " + name);
+ }
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected <T> T getOption(SocketOption<T> name) throws IOException {
+ Objects.requireNonNull(name);
+ if (!supportedOptions().contains(name))
+ throw new UnsupportedOperationException("'" + name + "' not supported");
+
+ if (isClosedOrPending())
+ throw new SocketException("Socket closed");
+
+ if (name == StandardSocketOptions.SO_KEEPALIVE) {
+ return (T)getOption(SocketOptions.SO_KEEPALIVE);
+ } else if (name == StandardSocketOptions.SO_SNDBUF) {
+ return (T)getOption(SocketOptions.SO_SNDBUF);
+ } else if (name == StandardSocketOptions.SO_RCVBUF) {
+ return (T)getOption(SocketOptions.SO_RCVBUF);
+ } else if (name == StandardSocketOptions.SO_REUSEADDR) {
+ return (T)getOption(SocketOptions.SO_REUSEADDR);
+ } else if (name == StandardSocketOptions.SO_REUSEPORT) {
+ return (T)getOption(SocketOptions.SO_REUSEPORT);
+ } else if (name == StandardSocketOptions.SO_LINGER) {
+ return (T)getOption(SocketOptions.SO_LINGER);
+ } else if (name == StandardSocketOptions.IP_TOS) {
+ return (T)getOption(SocketOptions.IP_TOS);
+ } else if (name == StandardSocketOptions.TCP_NODELAY) {
+ return (T)getOption(SocketOptions.TCP_NODELAY);
+ } else if (extendedOptions.isOptionSupported(name)) {
+ return (T) extendedOptions.getOption(fd, name);
+ } else {
+ throw new AssertionError("unknown option: " + name);
+ }
+ }
+
/**
* The workhorse of the connection operation. Tries several times to
* establish a connection to the given <host, port>. If unsuccessful,