--- old/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java 2019-05-27 11:33:54.497804693 +0100 +++ new/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java 2019-05-27 11:33:54.225804703 +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> supportedOptions() { - Set> 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> clientSocketOptions = clientSocketOptions(); + private static final Set> serverSocketOptions = serverSocketOptions(); + + private static Set> clientSocketOptions() { + HashSet> 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> serverSocketOptions() { + HashSet> 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> supportedOptions() { + if (isServer) + return serverSocketOptions; + else + return clientSocketOptions; + } + + @Override + protected void setOption(SocketOption 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 getOption(SocketOption 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 . If unsuccessful,