From 4dfed6652630593769bf049be7ac2213ca47b69f Mon Sep 17 00:00:00 2001 From: Yingqi Lu Date: Tue, 23 Feb 2016 17:41:00 +0000 Subject: [PATCH] 6432031: Add support for SO_REUSEPORT Reviewed-by: alanb, simonis, chegar --- jdk/make/mapfiles/libnet/mapfile-vers | 6 +- jdk/make/mapfiles/libnio/mapfile-linux | 3 +- jdk/make/mapfiles/libnio/mapfile-macosx | 3 +- jdk/make/mapfiles/libnio/mapfile-solaris | 3 +- .../genconstants/ch/genSocketOptionRegistry.c | 18 ++++- .../net/AbstractPlainDatagramSocketImpl.java | 60 +++++++++++++- .../java/net/AbstractPlainSocketImpl.java | 59 +++++++++++++- .../classes/java/net/DatagramSocketImpl.java | 8 +- .../classes/java/net/MulticastSocket.java | 14 +++- .../share/classes/java/net/SocketImpl.java | 8 +- .../share/classes/java/net/SocketOptions.java | 13 +++- .../java/net/StandardSocketOptions.java | 25 +++++- .../share/classes/jdk/net/Sockets.java | 32 +++++++- .../AsynchronousServerSocketChannelImpl.java | 5 +- .../nio/ch/AsynchronousSocketChannelImpl.java | 5 +- .../sun/nio/ch/DatagramChannelImpl.java | 5 +- .../share/classes/sun/nio/ch/Net.java | 17 +++- .../sun/nio/ch/ServerSocketChannelImpl.java | 6 +- .../classes/sun/nio/ch/SocketChannelImpl.java | 5 +- .../java.base/share/native/libnet/net_util.c | 13 +++- .../java.base/share/native/libnet/net_util.h | 4 +- .../java/net/PlainDatagramSocketImpl.java | 25 +++++- .../classes/java/net/PlainSocketImpl.java | 25 +++++- .../native/libnet/PlainDatagramSocketImpl.c | 6 +- .../java.base/unix/native/libnet/SdpSupport.c | 7 +- .../java.base/unix/native/libnet/SocketImpl.c | 47 +++++++++++ .../unix/native/libnet/net_util_md.c | 22 +++++- .../unix/native/libnet/net_util_md.h | 15 +++- jdk/src/java.base/unix/native/libnio/ch/Net.c | 8 +- .../unix/native/libnio/ch/nio_util.h | 14 +++- .../net/DualStackPlainDatagramSocketImpl.java | 10 ++- .../java/net/DualStackPlainSocketImpl.java | 10 ++- .../classes/java/net/PlainSocketImpl.java | 23 +++++- .../net/TwoStacksPlainDatagramSocketImpl.java | 8 +- .../java/net/TwoStacksPlainSocketImpl.java | 9 ++- .../windows/native/libnet/SocketImpl.c | 47 +++++++++++ .../windows/native/libnet/net_util_md.c | 7 +- .../windows/native/libnet/net_util_md.h | 4 + .../java.base/windows/native/libnio/ch/Net.c | 9 ++- .../java/net/SocketOption/OptionsTest.java | 78 +++++++++++++------ .../Basic.java | 12 ++- .../AsynchronousSocketChannel/Basic.java | 12 ++- .../DatagramChannel/SocketOptionTests.java | 23 ++++-- .../SocketOptionTests.java | 11 ++- 44 files changed, 669 insertions(+), 75 deletions(-) create mode 100644 jdk/src/java.base/unix/native/libnet/SocketImpl.c create mode 100644 jdk/src/java.base/windows/native/libnet/SocketImpl.c diff --git a/jdk/make/mapfiles/libnet/mapfile-vers b/jdk/make/mapfiles/libnet/mapfile-vers index a37668a8418..82247780181 100644 --- a/jdk/make/mapfiles/libnet/mapfile-vers +++ b/jdk/make/mapfiles/libnet/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -87,6 +87,9 @@ SUNWprivate_1.1 { Java_java_net_PlainSocketImpl_socketConnect; Java_java_net_PlainDatagramSocketImpl_getTimeToLive; Java_java_net_PlainDatagramSocketImpl_setTimeToLive; + Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0; + Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0; + Java_jdk_net_Sockets_isReusePortAvailable0; Java_sun_net_PortConfig_getUpper0; Java_sun_net_PortConfig_getLower0; Java_sun_net_dns_ResolverConfigurationImpl_localDomain0; @@ -112,6 +115,7 @@ SUNWprivate_1.1 { NET_EnableFastTcpLoopback; NET_ThrowNew; ipv6_available; + reuseport_available; initInetAddressIDs; local: diff --git a/jdk/make/mapfiles/libnio/mapfile-linux b/jdk/make/mapfiles/libnio/mapfile-linux index b9b059a80c2..e4563b10c12 100644 --- a/jdk/make/mapfiles/libnio/mapfile-linux +++ b/jdk/make/mapfiles/libnio/mapfile-linux @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -109,6 +109,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_Net_setIntOption0; Java_sun_nio_ch_Net_initIDs; Java_sun_nio_ch_Net_isIPv6Available0; + Java_sun_nio_ch_Net_isReusePortAvailable0; Java_sun_nio_ch_Net_joinOrDrop4; Java_sun_nio_ch_Net_blockOrUnblock4; Java_sun_nio_ch_Net_joinOrDrop6; diff --git a/jdk/make/mapfiles/libnio/mapfile-macosx b/jdk/make/mapfiles/libnio/mapfile-macosx index 6e4a7fb594c..daee0371e3c 100644 --- a/jdk/make/mapfiles/libnio/mapfile-macosx +++ b/jdk/make/mapfiles/libnio/mapfile-macosx @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -102,6 +102,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_Net_setIntOption0; Java_sun_nio_ch_Net_initIDs; Java_sun_nio_ch_Net_isIPv6Available0; + Java_sun_nio_ch_Net_isReusePortAvailable0; Java_sun_nio_ch_Net_joinOrDrop4; Java_sun_nio_ch_Net_blockOrUnblock4; Java_sun_nio_ch_Net_joinOrDrop6; diff --git a/jdk/make/mapfiles/libnio/mapfile-solaris b/jdk/make/mapfiles/libnio/mapfile-solaris index 6834bd221d4..a1e0d99b0e6 100644 --- a/jdk/make/mapfiles/libnio/mapfile-solaris +++ b/jdk/make/mapfiles/libnio/mapfile-solaris @@ -1,5 +1,5 @@ # -# Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -97,6 +97,7 @@ SUNWprivate_1.1 { Java_sun_nio_ch_Net_setIntOption0; Java_sun_nio_ch_Net_initIDs; Java_sun_nio_ch_Net_isIPv6Available0; + Java_sun_nio_ch_Net_isReusePortAvailable0; Java_sun_nio_ch_Net_joinOrDrop4; Java_sun_nio_ch_Net_blockOrUnblock4; Java_sun_nio_ch_Net_joinOrDrop6; diff --git a/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c b/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c index 41bd5484ab7..aab692f1f19 100644 --- a/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c +++ b/jdk/make/src/native/genconstants/ch/genSocketOptionRegistry.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,21 @@ #include #endif +/* Defines SO_REUSEPORT */ +#if !defined(SO_REUSEPORT) +#ifdef _WIN32 +#define SO_REUSEPORT 0 +#elif __linux__ +#define SO_REUSEPORT 15 +#elif __solaris__ +#define SO_REUSEPORT 0x100e +#elif defined(AIX) || defined(MACOSX) +#define SO_REUSEPORT 0x0200 +#else +#define SO_REUSEPORT 0 +#endif +#endif + /** * Generates sun.nio.ch.SocketOptionRegistry, a class that maps Java-level * socket options to the platform specific level and option. @@ -102,6 +117,7 @@ int main(int argc, const char* argv[]) { emit_unspec("StandardSocketOptions.SO_SNDBUF", SOL_SOCKET, SO_SNDBUF); emit_unspec("StandardSocketOptions.SO_RCVBUF", SOL_SOCKET, SO_RCVBUF); emit_unspec("StandardSocketOptions.SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR); + emit_unspec("StandardSocketOptions.SO_REUSEPORT", SOL_SOCKET, SO_REUSEPORT); emit_unspec("StandardSocketOptions.TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY); emit_inet("StandardSocketOptions.IP_TOS", IPPROTO_IP, IP_TOS); diff --git a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java index 1f9eba1300e..7a9b7fc17ed 100644 --- a/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,9 @@ import java.io.FileDescriptor; import java.io.IOException; import java.security.AccessController; import sun.net.ResourceManager; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; /** * Abstract datagram and multicast socket implementation base class. @@ -70,6 +73,45 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl }); } + private static volatile boolean checkedReusePort; + private static volatile boolean isReusePortAvailable; + + /** + * Tells whether SO_REUSEPORT is supported. + */ + static boolean isReusePortAvailable() { + if (!checkedReusePort) { + isReusePortAvailable = isReusePortAvailable0(); + checkedReusePort = true; + } + return isReusePortAvailable; + } + + private static volatile Set> socketOptions; + + /** + * 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 = socketOptions; + if (options == null) { + if (isReusePortAvailable()) { + options = new HashSet<>(); + options.addAll(super.supportedOptions()); + options.add(StandardSocketOptions.SO_REUSEPORT); + options = Collections.unmodifiableSet(options); + } else { + options = super.supportedOptions(); + } + socketOptions = options; + } + return options; + } + /** * Creates a datagram socket */ @@ -303,6 +345,14 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl if (o == null || !(o instanceof Boolean)) throw new SocketException("bad argument for IP_MULTICAST_LOOP"); break; + case SO_REUSEPORT: + if (o == null || !(o instanceof Boolean)) { + throw new SocketException("bad argument for SO_REUSEPORT"); + } + if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + throw new UnsupportedOperationException("unsupported option"); + } + break; default: throw new SocketException("invalid option: " + optID); } @@ -343,6 +393,13 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl result = socketGetOption(optID); break; + case SO_REUSEPORT: + if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + throw new UnsupportedOperationException("unsupported option"); + } + result = socketGetOption(optID); + break; + default: throw new SocketException("invalid option: " + optID); } @@ -364,4 +421,5 @@ abstract class AbstractPlainDatagramSocketImpl extends DatagramSocketImpl } abstract int dataAvailable(); + private static native boolean isReusePortAvailable0(); } diff --git a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java index 8841e4fe724..c9afa2657a2 100644 --- a/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/AbstractPlainSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,9 @@ import java.io.FileDescriptor; import sun.net.ConnectionResetException; import sun.net.NetHooks; import sun.net.ResourceManager; +import java.util.Set; +import java.util.HashSet; +import java.util.Collections; /** * Default Socket Implementation. This implementation does @@ -87,6 +90,45 @@ abstract class AbstractPlainSocketImpl extends SocketImpl }); } + private static volatile boolean checkedReusePort; + private static volatile boolean isReusePortAvailable; + + /** + * Tells whether SO_REUSEPORT is supported. + */ + static boolean isReusePortAvailable() { + if (!checkedReusePort) { + isReusePortAvailable = isReusePortAvailable0(); + checkedReusePort = true; + } + return isReusePortAvailable; + } + + private static volatile Set> socketOptions; + + /** + * 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 = socketOptions; + if (options == null) { + if (isReusePortAvailable()) { + options = new HashSet<>(); + options.addAll(super.supportedOptions()); + options.add(StandardSocketOptions.SO_REUSEPORT); + options = Collections.unmodifiableSet(options); + } else { + options = super.supportedOptions(); + } + socketOptions = options; + } + return options; + } + /** * Creates a socket with a boolean that specifies whether this * is a stream socket (true) or an unconnected UDP socket (false). @@ -269,6 +311,13 @@ abstract class AbstractPlainSocketImpl extends SocketImpl throw new SocketException("bad parameter for SO_REUSEADDR"); on = ((Boolean)val).booleanValue(); break; + case SO_REUSEPORT: + if (val == null || !(val instanceof Boolean)) + throw new SocketException("bad parameter for SO_REUSEPORT"); + if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) + throw new UnsupportedOperationException("unsupported option"); + on = ((Boolean)val).booleanValue(); + break; default: throw new SocketException("unrecognized TCP option: " + opt); } @@ -326,6 +375,12 @@ abstract class AbstractPlainSocketImpl extends SocketImpl case SO_KEEPALIVE: ret = socketGetOption(opt, null); return Boolean.valueOf(ret != -1); + case SO_REUSEPORT: + if (!supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + throw new UnsupportedOperationException("unsupported option"); + } + ret = socketGetOption(opt, null); + return Boolean.valueOf(ret != -1); // should never get here default: return null; @@ -723,4 +778,6 @@ abstract class AbstractPlainSocketImpl extends SocketImpl public static final int SHUT_RD = 0; public static final int SHUT_WR = 1; + + private static native boolean isReusePortAvailable0(); } diff --git a/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java b/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java index 97526bc3712..5621ea3a608 100644 --- a/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/DatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -287,6 +287,9 @@ public abstract class DatagramSocketImpl implements SocketOptions { setOption(SocketOptions.SO_RCVBUF, value); } else if (name == StandardSocketOptions.SO_REUSEADDR) { setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + setOption(SocketOptions.SO_REUSEPORT, value); } else if (name == StandardSocketOptions.IP_TOS) { setOption(SocketOptions.IP_TOS, value); } else if (name == StandardSocketOptions.IP_MULTICAST_IF && @@ -329,6 +332,9 @@ public abstract class DatagramSocketImpl implements SocketOptions { return (T) getOption(SocketOptions.SO_RCVBUF); } else if (name == StandardSocketOptions.SO_REUSEADDR) { return (T) getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + return (T) getOption(SocketOptions.SO_REUSEPORT); } else if (name == StandardSocketOptions.IP_TOS) { return (T) getOption(SocketOptions.IP_TOS); } else if (name == StandardSocketOptions.IP_MULTICAST_IF && diff --git a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java index 77c6e198ab0..365092b1e07 100644 --- a/jdk/src/java.base/share/classes/java/net/MulticastSocket.java +++ b/jdk/src/java.base/share/classes/java/net/MulticastSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -98,7 +98,11 @@ class MulticastSocket extends DatagramSocket { *

* When the socket is created the * {@link DatagramSocket#setReuseAddress(boolean)} method is - * called to enable the SO_REUSEADDR socket option. + * called to enable the SO_REUSEADDR socket option. When + * {@link StandardSocketOptions#SO_REUSEPORT SO_REUSEPORT} is + * supported then + * {@link DatagramSocketImpl#setOption(SocketOption, Object)} + * is called to enable the socket option. * * @exception IOException if an I/O exception occurs * while creating the MulticastSocket @@ -106,6 +110,7 @@ class MulticastSocket extends DatagramSocket { * {@code checkListen} method doesn't allow the operation. * @see SecurityManager#checkListen * @see java.net.DatagramSocket#setReuseAddress(boolean) + * @see java.net.DatagramSocketImpl#setOption(SocketOption, Object) */ public MulticastSocket() throws IOException { this(new InetSocketAddress(0)); @@ -167,6 +172,11 @@ class MulticastSocket extends DatagramSocket { // Enable SO_REUSEADDR before binding setReuseAddress(true); + // Enable SO_REUSEPORT if supported before binding + if (supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + this.setOption(StandardSocketOptions.SO_REUSEPORT, true); + } + if (bindaddr != null) { try { bind(bindaddr); diff --git a/jdk/src/java.base/share/classes/java/net/SocketImpl.java b/jdk/src/java.base/share/classes/java/net/SocketImpl.java index eef92f30b6e..7a30173a597 100644 --- a/jdk/src/java.base/share/classes/java/net/SocketImpl.java +++ b/jdk/src/java.base/share/classes/java/net/SocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -386,6 +386,9 @@ public abstract class SocketImpl implements SocketOptions { setOption(SocketOptions.SO_RCVBUF, value); } else if (name == StandardSocketOptions.SO_REUSEADDR) { setOption(SocketOptions.SO_REUSEADDR, value); + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + setOption(SocketOptions.SO_REUSEPORT, value); } else if (name == StandardSocketOptions.SO_LINGER && (getSocket() != null)) { setOption(SocketOptions.SO_LINGER, value); @@ -426,6 +429,9 @@ public abstract class SocketImpl implements SocketOptions { return (T)getOption(SocketOptions.SO_RCVBUF); } else if (name == StandardSocketOptions.SO_REUSEADDR) { return (T)getOption(SocketOptions.SO_REUSEADDR); + } else if (name == StandardSocketOptions.SO_REUSEPORT && + supportedOptions().contains(name)) { + return (T)getOption(SocketOptions.SO_REUSEPORT); } else if (name == StandardSocketOptions.SO_LINGER && (getSocket() != null)) { return (T)getOption(SocketOptions.SO_LINGER); diff --git a/jdk/src/java.base/share/classes/java/net/SocketOptions.java b/jdk/src/java.base/share/classes/java/net/SocketOptions.java index c846bbb9b12..fbfb81eca1a 100644 --- a/jdk/src/java.base/share/classes/java/net/SocketOptions.java +++ b/jdk/src/java.base/share/classes/java/net/SocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -170,6 +170,17 @@ public interface SocketOptions { @Native public static final int SO_REUSEADDR = 0x04; + /** Sets SO_REUSEPORT for a socket. This option enables and disables + * the ability to have multiple sockets listen to the same address + * and port. + *

+ * Valid for: SocketImpl, DatagramSocketImpl + * + * @since 9 + * @see StandardSocketOptions#SO_REUSEPORT + */ + @Native public static final int SO_REUSEPORT = 0x0E; + /** * Sets SO_BROADCAST for a socket. This option enables and disables * the ability of the process to send broadcast messages. It is supported diff --git a/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java b/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java index 7fdd5f075d6..ae47845fae3 100644 --- a/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java +++ b/jdk/src/java.base/share/classes/java/net/StandardSocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -186,6 +186,29 @@ public final class StandardSocketOptions { public static final SocketOption SO_REUSEADDR = new StdSocketOption("SO_REUSEADDR", Boolean.class); + /** + * Re-use port. + * + *

The value of this socket option is a {@code Boolean} that represents + * whether the option is enabled or disabled. The exact semantics of this + * socket option are socket type and system dependent. + * + *

In the case of stream-oriented sockets, this socket option usually allows + * multiple listening sockets to be bound to both same address + * and same port. + * + *

For datagram-oriented sockets the socket option usually allows + * multiple UDP sockets to be bound to the same address and port. + * + *

An implementation allows this socket option to be set before the + * socket is bound or connected. Changing the value of this socket option + * after the socket is bound has no effect. + * + * @since 9 + */ + public static final SocketOption SO_REUSEPORT = + new StdSocketOption("SO_REUSEPORT", Boolean.class); + /** * Linger on close if data is present. * diff --git a/jdk/src/java.base/share/classes/jdk/net/Sockets.java b/jdk/src/java.base/share/classes/jdk/net/Sockets.java index 1ba53f29a15..a8b78b044d8 100644 --- a/jdk/src/java.base/share/classes/jdk/net/Sockets.java +++ b/jdk/src/java.base/share/classes/jdk/net/Sockets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -251,9 +251,23 @@ public class Sockets { } } + private static volatile boolean checkedReusePort; + private static volatile boolean isReusePortAvailable; + + /** + * Tells whether SO_REUSEPORT is supported. + */ + static boolean isReusePortAvailable() { + if (!checkedReusePort) { + isReusePortAvailable = isReusePortAvailable0(); + checkedReusePort = true; + } + return isReusePortAvailable; + } + private static void initOptionSets() { boolean flowsupported = ExtendedOptionsImpl.flowSupported(); - + boolean reuseportsupported = isReusePortAvailable(); // Socket Set> set = new HashSet<>(); @@ -261,6 +275,9 @@ public class Sockets { set.add(StandardSocketOptions.SO_SNDBUF); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (reuseportsupported) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.SO_LINGER); set.add(StandardSocketOptions.IP_TOS); set.add(StandardSocketOptions.TCP_NODELAY); @@ -275,6 +292,9 @@ public class Sockets { set = new HashSet<>(); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (reuseportsupported) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.IP_TOS); set = Collections.unmodifiableSet(set); options.put(ServerSocket.class, set); @@ -285,6 +305,9 @@ public class Sockets { set.add(StandardSocketOptions.SO_SNDBUF); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (reuseportsupported) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.IP_TOS); if (flowsupported) { set.add(ExtendedSocketOptions.SO_FLOW_SLA); @@ -298,6 +321,9 @@ public class Sockets { set.add(StandardSocketOptions.SO_SNDBUF); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (reuseportsupported) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.IP_TOS); set.add(StandardSocketOptions.IP_MULTICAST_IF); set.add(StandardSocketOptions.IP_MULTICAST_TTL); @@ -308,4 +334,6 @@ public class Sockets { set = Collections.unmodifiableSet(set); options.put(MulticastSocket.class, set); } + + private static native boolean isReusePortAvailable0(); } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java index 8ed2c9f1317..39b19b42204 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousServerSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,6 +231,9 @@ abstract class AsynchronousServerSocketChannelImpl HashSet> set = new HashSet<>(2); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (Net.isReusePortAvailable()) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } return Collections.unmodifiableSet(set); } } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java index 3122b96a29f..36b3c1b7ab9 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/AsynchronousSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -508,6 +508,9 @@ abstract class AsynchronousSocketChannelImpl set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_KEEPALIVE); set.add(StandardSocketOptions.SO_REUSEADDR); + if (Net.isReusePortAvailable()) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.TCP_NODELAY); if (ExtendedOptionsImpl.flowSupported()) { set.add(jdk.net.ExtendedSocketOptions.SO_FLOW_SLA); diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 7eb987991c9..77d14619222 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -298,6 +298,9 @@ class DatagramChannelImpl set.add(StandardSocketOptions.SO_SNDBUF); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (Net.isReusePortAvailable()) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.SO_BROADCAST); set.add(StandardSocketOptions.IP_TOS); set.add(StandardSocketOptions.IP_MULTICAST_IF); diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java index 27c46a9ca2c..062ce35468e 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/Net.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/Net.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,6 +56,8 @@ public class Net { private static volatile boolean checkedIPv6; private static volatile boolean isIPv6Available; + private static volatile boolean checkedReusePort; + private static volatile boolean isReusePortAvailable; /** * Tells whether dual-IPv4/IPv6 sockets should be used. @@ -68,6 +70,17 @@ public class Net { return isIPv6Available; } + /** + * Tells whether SO_REUSEPORT is supported. + */ + static boolean isReusePortAvailable() { + if (!checkedReusePort) { + isReusePortAvailable = isReusePortAvailable0(); + checkedReusePort = true; + } + return isReusePortAvailable; + } + /** * Returns true if exclusive binding is on */ @@ -389,6 +402,8 @@ public class Net { private static native boolean isIPv6Available0(); + private static native boolean isReusePortAvailable0(); + /* * Returns 1 for Windows and -1 for Solaris/Linux/Mac OS */ diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java index 2a427f1a352..9cfe7c43c4d 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/ServerSocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import java.nio.channels.spi.*; import java.util.*; import sun.net.NetHooks; - /** * An implementation of ServerSocketChannels */ @@ -185,6 +184,9 @@ class ServerSocketChannelImpl HashSet> set = new HashSet<>(2); set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_REUSEADDR); + if (Net.isReusePortAvailable()) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.IP_TOS); return Collections.unmodifiableSet(set); } diff --git a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java index c4965e1111b..c4644920c3e 100644 --- a/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java +++ b/jdk/src/java.base/share/classes/sun/nio/ch/SocketChannelImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -234,6 +234,9 @@ class SocketChannelImpl set.add(StandardSocketOptions.SO_RCVBUF); set.add(StandardSocketOptions.SO_KEEPALIVE); set.add(StandardSocketOptions.SO_REUSEADDR); + if (Net.isReusePortAvailable()) { + set.add(StandardSocketOptions.SO_REUSEPORT); + } set.add(StandardSocketOptions.SO_LINGER); set.add(StandardSocketOptions.TCP_NODELAY); // additional options required by socket adaptor diff --git a/jdk/src/java.base/share/native/libnet/net_util.c b/jdk/src/java.base/share/native/libnet/net_util.c index e94903fd720..c2d4b002b04 100644 --- a/jdk/src/java.base/share/native/libnet/net_util.c +++ b/jdk/src/java.base/share/native/libnet/net_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,14 +29,21 @@ #include "net_util.h" int IPv6_supported() ; +int reuseport_supported() ; static int IPv6_available; +static int REUSEPORT_available; JNIEXPORT jint JNICALL ipv6_available() { return IPv6_available ; } +JNIEXPORT jint JNICALL reuseport_available() +{ + return REUSEPORT_available; +} + JNIEXPORT jint JNICALL DEF_JNI_OnLoad(JavaVM *vm, void *reserved) { @@ -45,7 +52,6 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved) jmethodID mid; jstring s; jint preferIPv4Stack; - if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_2) != JNI_OK) { return JNI_EVERSION; /* JNI version not supported */ } @@ -64,6 +70,9 @@ DEF_JNI_OnLoad(JavaVM *vm, void *reserved) supporting socket APIs are available */ IPv6_available = IPv6_supported() & (!preferIPv4Stack); + + /* check if SO_REUSEPORT is supported on this platform */ + REUSEPORT_available = reuseport_supported(); platformInit(); parseExclusiveBindProperty(env); diff --git a/jdk/src/java.base/share/native/libnet/net_util.h b/jdk/src/java.base/share/native/libnet/net_util.h index f6b29297ecf..1d7b2a2c51e 100644 --- a/jdk/src/java.base/share/native/libnet/net_util.h +++ b/jdk/src/java.base/share/native/libnet/net_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -131,6 +131,8 @@ jfieldID NET_GetFileDescriptorID(JNIEnv *env); JNIEXPORT jint JNICALL ipv6_available() ; +JNIEXPORT jint JNICALL reuseport_available() ; + void NET_AllocSockaddr(struct sockaddr **him, int *len); diff --git a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java index 31715d40c82..f7c65931613 100644 --- a/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java +++ b/jdk/src/java.base/unix/classes/java/net/PlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,15 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl protected void setOption(SocketOption name, T value) throws IOException { if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { - super.setOption(name, value); + if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { + super.setOption(name, value); + } else { + if (supportedOptions().contains(name)) { + super.setOption(name, value); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } } else { if (!flowSupported()) { throw new UnsupportedOperationException("unsupported option"); @@ -62,7 +70,15 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { - return super.getOption(name); + if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { + return super.getOption(name); + } else { + if (supportedOptions().contains(name)) { + return super.getOption(name); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } } if (!flowSupported()) { throw new UnsupportedOperationException("unsupported option"); @@ -87,6 +103,9 @@ class PlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl } protected void socketSetOption(int opt, Object val) throws SocketException { + if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + throw new UnsupportedOperationException("unsupported option"); + } try { socketSetOption0(opt, val); } catch (SocketException se) { diff --git a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java index 272130bd6b9..2ec573ea5a9 100644 --- a/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/java.base/unix/classes/java/net/PlainSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,7 +59,15 @@ class PlainSocketImpl extends AbstractPlainSocketImpl protected void setOption(SocketOption name, T value) throws IOException { if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { - super.setOption(name, value); + if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { + super.setOption(name, value); + } else { + if (supportedOptions().contains(name)) { + super.setOption(name, value); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } } else { if (getSocket() == null || !flowSupported()) { throw new UnsupportedOperationException("unsupported option"); @@ -76,7 +84,15 @@ class PlainSocketImpl extends AbstractPlainSocketImpl @SuppressWarnings("unchecked") protected T getOption(SocketOption name) throws IOException { if (!name.equals(ExtendedSocketOptions.SO_FLOW_SLA)) { - return super.getOption(name); + if (!name.equals(StandardSocketOptions.SO_REUSEPORT)) { + return super.getOption(name); + } else { + if (supportedOptions().contains(name)) { + return super.getOption(name); + } else { + throw new UnsupportedOperationException("unsupported option"); + } + } } if (getSocket() == null || !flowSupported()) { throw new UnsupportedOperationException("unsupported option"); @@ -101,6 +117,9 @@ class PlainSocketImpl extends AbstractPlainSocketImpl } protected void socketSetOption(int opt, boolean b, Object val) throws SocketException { + if (opt == SocketOptions.SO_REUSEPORT && !supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT)) { + throw new UnsupportedOperationException("unsupported option"); + } try { socketSetOption0(opt, b, val); } catch (SocketException se) { diff --git a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c index e6f18428769..034040baf83 100644 --- a/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c +++ b/jdk/src/java.base/unix/native/libnet/PlainDatagramSocketImpl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1392,6 +1392,7 @@ Java_java_net_PlainDatagramSocketImpl_socketSetOption0(JNIEnv *env, } case java_net_SocketOptions_SO_REUSEADDR: + case java_net_SocketOptions_SO_REUSEPORT: case java_net_SocketOptions_SO_BROADCAST: { jclass cls; @@ -1769,6 +1770,9 @@ Java_java_net_PlainDatagramSocketImpl_socketGetOption(JNIEnv *env, jobject this, case java_net_SocketOptions_SO_REUSEADDR: return createBoolean(env, optval.i); + case java_net_SocketOptions_SO_REUSEPORT: + return createBoolean(env, optval.i); + case java_net_SocketOptions_SO_SNDBUF: case java_net_SocketOptions_SO_RCVBUF: case java_net_SocketOptions_IP_TOS: diff --git a/jdk/src/java.base/unix/native/libnet/SdpSupport.c b/jdk/src/java.base/unix/native/libnet/SdpSupport.c index be8c46464fa..1fe5353fcd6 100644 --- a/jdk/src/java.base/unix/native/libnet/SdpSupport.c +++ b/jdk/src/java.base/unix/native/libnet/SdpSupport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,6 +108,11 @@ Java_sun_net_sdp_SdpSupport_convert0(JNIEnv *env, jclass cls, int fd) len = sizeof(arg); if (getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, &len) == 0) setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&arg, len); +#ifdef SO_REUSEPORT + len = sizeof(arg); + if (getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, &len) == 0) + setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (char*)&arg, len); +#endif len = sizeof(arg); if (getsockopt(fd, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, &len) == 0) setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (char*)&arg, len); diff --git a/jdk/src/java.base/unix/native/libnet/SocketImpl.c b/jdk/src/java.base/unix/native/libnet/SocketImpl.c new file mode 100644 index 00000000000..3427b0ef405 --- /dev/null +++ b/jdk/src/java.base/unix/native/libnet/SocketImpl.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include + +#include "net_util.h" + +JNIEXPORT jboolean JNICALL +Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; +} diff --git a/jdk/src/java.base/unix/native/libnet/net_util_md.c b/jdk/src/java.base/unix/native/libnet/net_util_md.c index f5645699d29..abad413e39c 100644 --- a/jdk/src/java.base/unix/native/libnet/net_util_md.c +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -439,6 +439,25 @@ jint IPv6_supported() } #endif /* DONT_ENABLE_IPV6 */ +jint reuseport_supported() +{ + /* Do a simple dummy call, and try to figure out from that */ + int one = 1; + int rv, s; + s = socket(PF_INET, SOCK_STREAM, 0); + if (s < 0) { + return JNI_FALSE; + } + rv = setsockopt(s, SOL_SOCKET, SO_REUSEPORT, (void *)&one, sizeof(one)); + if (rv != 0) { + rv = JNI_FALSE; + } else { + rv = JNI_TRUE; + } + close(s); + return rv; +} + void NET_ThrowUnknownHostExceptionWithGaiError(JNIEnv *env, const char* hostname, int gai_error) @@ -1014,6 +1033,7 @@ NET_MapSocketOption(jint cmd, int *level, int *optname) { { java_net_SocketOptions_SO_RCVBUF, SOL_SOCKET, SO_RCVBUF }, { java_net_SocketOptions_SO_KEEPALIVE, SOL_SOCKET, SO_KEEPALIVE }, { java_net_SocketOptions_SO_REUSEADDR, SOL_SOCKET, SO_REUSEADDR }, + { java_net_SocketOptions_SO_REUSEPORT, SOL_SOCKET, SO_REUSEPORT }, { java_net_SocketOptions_SO_BROADCAST, SOL_SOCKET, SO_BROADCAST }, { java_net_SocketOptions_IP_TOS, IPPROTO_IP, IP_TOS }, { java_net_SocketOptions_IP_MULTICAST_IF, IPPROTO_IP, IP_MULTICAST_IF }, diff --git a/jdk/src/java.base/unix/native/libnet/net_util_md.h b/jdk/src/java.base/unix/native/libnet/net_util_md.h index 31ed3f808eb..f440bd8ae6a 100644 --- a/jdk/src/java.base/unix/native/libnet/net_util_md.h +++ b/jdk/src/java.base/unix/native/libnet/net_util_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,19 @@ void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name, #define NET_WAIT_WRITE 0x02 #define NET_WAIT_CONNECT 0x04 +/* Defines SO_REUSEPORT */ +#ifndef SO_REUSEPORT +#ifdef __linux__ +#define SO_REUSEPORT 15 +#elif __solaris__ +#define SO_REUSEPORT 0x100e +#elif defined(AIX) || defined(MACOSX) +#define SO_REUSEPORT 0x0200 +#else +#define SO_REUSEPORT 0 +#endif +#endif + jint NET_Wait(JNIEnv *env, jint fd, jint flags, jint timeout); /************************************************************************ diff --git a/jdk/src/java.base/unix/native/libnio/ch/Net.c b/jdk/src/java.base/unix/native/libnio/ch/Net.c index 1010355bb76..a4032d69652 100644 --- a/jdk/src/java.base/unix/native/libnio/ch/Net.c +++ b/jdk/src/java.base/unix/native/libnio/ch/Net.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -161,6 +161,12 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) return (ipv6_available()) ? JNI_TRUE : JNI_FALSE; } +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + return (reuseport_available()) ? JNI_TRUE : JNI_FALSE; +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { return -1; diff --git a/jdk/src/java.base/unix/native/libnio/ch/nio_util.h b/jdk/src/java.base/unix/native/libnio/ch/nio_util.h index 441ea20cc7c..c769dfbd49c 100644 --- a/jdk/src/java.base/unix/native/libnio/ch/nio_util.h +++ b/jdk/src/java.base/unix/native/libnio/ch/nio_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,6 +36,18 @@ } while((_result == -1) && (errno == EINTR)); \ } while(0) +/* Defines SO_REUSEPORT */ +#ifndef SO_REUSEPORT +#ifdef __linux__ +#define SO_REUSEPORT 15 +#elif __solaris__ +#define SO_REUSEPORT 0x100e +#elif defined(AIX) || defined(MACOSX) +#define SO_REUSEPORT 0x0200 +#else +#define SO_REUSEPORT 0 +#endif +#endif /* NIO utility procedures */ diff --git a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java index 88a7ddcfdb0..8f464ddfd07 100644 --- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -167,6 +167,11 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl int optionValue = 0; + // SO_REUSEPORT is not supported on Windows. + if (opt == SO_REUSEPORT) { + throw new UnsupportedOperationException("unsupported option"); + } + switch(opt) { case IP_TOS : case SO_RCVBUF : @@ -200,6 +205,9 @@ class DualStackPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl } if (opt == SO_REUSEADDR && reuseAddressEmulated) return isReuseAddress; + // SO_REUSEPORT is not supported on Windows. + if (opt == SO_REUSEPORT) + throw new UnsupportedOperationException("unsupported option"); int value = socketGetIntOption(nativefd, opt); Object returnValue = null; diff --git a/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java index 6792a411842..3d681db1dd6 100644 --- a/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/DualStackPlainSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -181,6 +181,10 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl if (opt == SO_TIMEOUT) { // timeout implemented through select. return; } + // SO_REUSEPORT is not supported on Windows. + if (opt == SO_REUSEPORT) { + throw new UnsupportedOperationException("unsupported option"); + } int optionValue = 0; @@ -224,6 +228,10 @@ class DualStackPlainSocketImpl extends AbstractPlainSocketImpl localAddress(nativefd, (InetAddressContainer)iaContainerObj); return 0; // return value doesn't matter. } + // SO_REUSEPORT is not supported on Windows. + if (opt == SO_REUSEPORT) { + throw new UnsupportedOperationException("unsupported option"); + } // SO_REUSEADDR emulated when using exclusive bind if (opt == SO_REUSEADDR && exclusiveBind) diff --git a/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java index 938d995593b..259a39ac195 100644 --- a/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/PlainSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -173,10 +173,18 @@ class PlainSocketImpl extends AbstractPlainSocketImpl } public void setOption(int opt, Object val) throws SocketException { + if (opt == SocketOptions.SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); + } impl.setOption(opt, val); } public Object getOption(int opt) throws SocketException { + if (opt == SocketOptions.SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); + } return impl.getOption(opt); } @@ -332,14 +340,27 @@ class PlainSocketImpl extends AbstractPlainSocketImpl void socketSetOption(int cmd, boolean on, Object value) throws SocketException { + if (cmd == SocketOptions.SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); + } impl.socketSetOption(cmd, on, value); } int socketGetOption(int opt, Object iaContainerObj) throws SocketException { + if (opt == SocketOptions.SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); + } return impl.socketGetOption(opt, iaContainerObj); } void socketSendUrgentData(int data) throws IOException { impl.socketSendUrgentData(data); } + + static boolean isReusePortAvailable() { + // SO_REUSEPORT is not supported on Windows. + return false; + } } diff --git a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java index 9bdb8d5c6e1..7198b49671e 100644 --- a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainDatagramSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -130,6 +130,9 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl return socketLocalAddress(family); } else if (optID == SO_REUSEADDR && reuseAddressEmulated) { return isReuseAddress; + } else if (optID == SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); } else { return super.getOption(optID); } @@ -142,6 +145,9 @@ class TwoStacksPlainDatagramSocketImpl extends AbstractPlainDatagramSocketImpl // socket already bound, emulate reuseAddressEmulated = true; isReuseAddress = (Boolean)val; + } else if (opt == SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); } else { socketNativeSetOption(opt, val); } diff --git a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java index a8be4000d93..4f0b132520e 100644 --- a/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java +++ b/jdk/src/java.base/windows/classes/java/net/TwoStacksPlainSocketImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -128,6 +128,9 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl } else if (opt == SO_REUSEADDR && exclusiveBind) { // SO_REUSEADDR emulated when using exclusive bind return isReuseAddress; + } else if (opt == SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); } else return super.getOption(opt); } @@ -144,6 +147,10 @@ class TwoStacksPlainSocketImpl extends AbstractPlainSocketImpl // SO_REUSEADDR emulated when using exclusive bind if (opt == SO_REUSEADDR && exclusiveBind) isReuseAddress = on; + else if (opt == SO_REUSEPORT) { + // SO_REUSEPORT is not supported on Windows. + throw new UnsupportedOperationException("unsupported option"); + } else socketNativeSetOption(opt, on, value); } diff --git a/jdk/src/java.base/windows/native/libnet/SocketImpl.c b/jdk/src/java.base/windows/native/libnet/SocketImpl.c new file mode 100644 index 00000000000..8e5745de8d3 --- /dev/null +++ b/jdk/src/java.base/windows/native/libnet/SocketImpl.c @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include + +JNIEXPORT jboolean JNICALL +Java_java_net_AbstractPlainSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + // SO_REUSEPORT is not supported on Windows + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_java_net_AbstractPlainDatagramSocketImpl_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + // SO_REUSEPORT is not supported on Windows + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_jdk_net_Sockets_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + // SO_REUSEPORT is not supported on Windows + return JNI_FALSE; +} diff --git a/jdk/src/java.base/windows/native/libnet/net_util_md.c b/jdk/src/java.base/windows/native/libnet/net_util_md.c index 8a0f5c15275..4868201c1f3 100644 --- a/jdk/src/java.base/windows/native/libnet/net_util_md.c +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -242,6 +242,11 @@ jint IPv6_supported() return JNI_TRUE; } +jint reuseport_supported() +{ + /* SO_REUSEPORT is not supported onn Windows */ + return JNI_FALSE; +} /* * Return the default TOS value */ diff --git a/jdk/src/java.base/windows/native/libnet/net_util_md.h b/jdk/src/java.base/windows/native/libnet/net_util_md.h index db6971616bf..5ac48046f3b 100644 --- a/jdk/src/java.base/windows/native/libnet/net_util_md.h +++ b/jdk/src/java.base/windows/native/libnet/net_util_md.h @@ -54,6 +54,9 @@ #else +/*SO_REUSEPORT is not supported on Windows, define it to 0*/ +#define SO_REUSEPORT 0 + /* Retain this code a little longer to support building in * old environments. _MSC_VER is defined as: * 1200 for MSVC++ 6.0 @@ -353,3 +356,4 @@ JNIEXPORT jint JNICALL Java_java_net_NetworkInterface_getMTU0_XP JNIEXPORT jboolean JNICALL Java_java_net_NetworkInterface_isLoopback0_XP (JNIEnv *env, jclass cls, jstring name, jint index); + diff --git a/jdk/src/java.base/windows/native/libnio/ch/Net.c b/jdk/src/java.base/windows/native/libnio/ch/Net.c index 12f3c190c49..c7702006d27 100644 --- a/jdk/src/java.base/windows/native/libnio/ch/Net.c +++ b/jdk/src/java.base/windows/native/libnio/ch/Net.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,6 +93,13 @@ Java_sun_nio_ch_Net_isIPv6Available0(JNIEnv* env, jclass cl) return ipv6_available() ? JNI_TRUE : JNI_FALSE; } +JNIEXPORT jboolean JNICALL +Java_sun_nio_ch_Net_isReusePortAvailable0(JNIEnv* env, jclass c1) +{ + // SO_REUSEPORT is not supported on Windows + return JNI_FALSE; +} + JNIEXPORT jint JNICALL Java_sun_nio_ch_Net_isExclusiveBindAvailable(JNIEnv *env, jclass clazz) { return 1; diff --git a/jdk/test/java/net/SocketOption/OptionsTest.java b/jdk/test/java/net/SocketOption/OptionsTest.java index 947d784aa9d..5b109d533ac 100644 --- a/jdk/test/java/net/SocketOption/OptionsTest.java +++ b/jdk/test/java/net/SocketOption/OptionsTest.java @@ -54,6 +54,7 @@ public class OptionsTest { Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE), Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)), Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) }; @@ -61,6 +62,7 @@ public class OptionsTest { static Test[] serverSocketTests = new Test[] { Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE), Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) }; @@ -68,6 +70,7 @@ public class OptionsTest { Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), + Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE), Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)) }; @@ -97,15 +100,19 @@ public class OptionsTest { Socket c = new Socket("127.0.0.1", srv.getLocalPort()); Socket s = srv.accept(); ) { + Set> options = c.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); for (int i=0; i> options = c.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); for (int i=0; i> options = c.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); for (int i=0; i> options = socket.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) { return Boolean.valueOf(socket.getKeepAlive()); @@ -183,6 +200,8 @@ public class OptionsTest { return Integer.valueOf(socket.getReceiveBufferSize()); } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { + return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); } else if (option.equals(StandardSocketOptions.SO_LINGER)) { return Integer.valueOf(socket.getSoLinger()); } else if (option.equals(StandardSocketOptions.IP_TOS)) { @@ -194,10 +213,15 @@ public class OptionsTest { } } else if (type.equals(ServerSocket.class)) { ServerSocket socket = (ServerSocket)s; + Set> options = socket.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); + if (option.equals(StandardSocketOptions.SO_RCVBUF)) { return Integer.valueOf(socket.getReceiveBufferSize()); } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { + return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); } else if (option.equals(StandardSocketOptions.IP_TOS)) { return Integer.valueOf(jdk.net.Sockets.getOption( socket, StandardSocketOptions.IP_TOS)); @@ -206,6 +230,8 @@ public class OptionsTest { } } else if (type.equals(DatagramSocket.class)) { DatagramSocket socket = (DatagramSocket)s; + Set> options = socket.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); if (option.equals(StandardSocketOptions.SO_SNDBUF)) { return Integer.valueOf(socket.getSendBufferSize()); @@ -213,6 +239,8 @@ public class OptionsTest { return Integer.valueOf(socket.getReceiveBufferSize()); } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { + return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); } else if (option.equals(StandardSocketOptions.IP_TOS)) { return Integer.valueOf(socket.getTrafficClass()); } else { @@ -221,6 +249,8 @@ public class OptionsTest { } else if (type.equals(MulticastSocket.class)) { MulticastSocket socket = (MulticastSocket)s; + Set> options = socket.supportedOptions(); + boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); if (option.equals(StandardSocketOptions.SO_SNDBUF)) { return Integer.valueOf(socket.getSendBufferSize()); @@ -228,6 +258,8 @@ public class OptionsTest { return Integer.valueOf(socket.getReceiveBufferSize()); } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { return Boolean.valueOf(socket.getReuseAddress()); + } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { + return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); } else if (option.equals(StandardSocketOptions.IP_TOS)) { return Integer.valueOf(socket.getTrafficClass()); } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) { diff --git a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java index 753629f8e1b..c3450df7d23 100644 --- a/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java +++ b/jdk/test/java/nio/channels/AsynchronousServerSocketChannel/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -141,8 +141,11 @@ public class Basic { try { // check supported options Set> options = ch.supportedOptions(); + boolean reuseport = options.contains(SO_REUSEPORT); if (!options.contains(SO_REUSEADDR)) throw new RuntimeException("SO_REUSEADDR should be supported"); + if (!options.contains(SO_REUSEPORT) && reuseport) + throw new RuntimeException("SO_REUSEPORT should be supported"); if (!options.contains(SO_RCVBUF)) throw new RuntimeException("SO_RCVBUF should be supported"); @@ -156,6 +159,13 @@ public class Basic { checkOption(ch, SO_REUSEADDR, true); ch.setOption(SO_REUSEADDR, false); checkOption(ch, SO_REUSEADDR, false); + + if (reuseport) { + ch.setOption(SO_REUSEPORT, true); + checkOption(ch, SO_REUSEPORT, true); + ch.setOption(SO_REUSEPORT, false); + checkOption(ch, SO_REUSEPORT, false); + } } finally { ch.close(); } diff --git a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java index 23d9eb36e4e..c833735eb0f 100644 --- a/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java +++ b/jdk/test/java/nio/channels/AsynchronousSocketChannel/Basic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +37,7 @@ import java.util.concurrent.*; import java.util.concurrent.atomic.*; import java.io.Closeable; import java.io.IOException; +import java.util.Set; public class Basic { static final Random rand = new Random(); @@ -165,6 +166,15 @@ public class Basic { // read others (can't check as actual value is implementation dependent) ch.getOption(SO_RCVBUF); ch.getOption(SO_SNDBUF); + + Set> options = ch.supportedOptions(); + boolean reuseport = options.contains(SO_REUSEPORT); + if (reuseport) { + if (ch.getOption(SO_REUSEPORT)) + throw new RuntimeException("Default of SO_REUSEPORT should be 'false'"); + if (!ch.setOption(SO_REUSEPORT, true).getOption(SO_REUSEPORT)) + throw new RuntimeException("SO_REUSEPORT did not change"); + } } } diff --git a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java index bc7146cc982..40aef3282ac 100644 --- a/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/DatagramChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,9 +50,17 @@ public class SocketOptionTests { // check supported options Set> options = dc.supportedOptions(); - List> expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, - SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL, - IP_MULTICAST_LOOP); + boolean reuseport = options.contains(SO_REUSEPORT); + List> expected; + if (reuseport) { + expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, + SO_REUSEADDR, SO_REUSEPORT, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, + IP_MULTICAST_TTL, IP_MULTICAST_LOOP); + } else { + expected = Arrays.asList(SO_SNDBUF, SO_RCVBUF, + SO_REUSEADDR, SO_BROADCAST, IP_TOS, IP_MULTICAST_IF, IP_MULTICAST_TTL, + IP_MULTICAST_LOOP); + } for (SocketOption opt: expected) { if (!options.contains(opt)) throw new RuntimeException(opt.name() + " should be supported"); @@ -83,7 +91,12 @@ public class SocketOptionTests { checkOption(dc, SO_REUSEADDR, true); dc.setOption(SO_REUSEADDR, false); checkOption(dc, SO_REUSEADDR, false); - + if (reuseport) { + dc.setOption(SO_REUSEPORT, true); + checkOption(dc, SO_REUSEPORT, true); + dc.setOption(SO_REUSEPORT, false); + checkOption(dc, SO_REUSEPORT, false); + } // bind socket dc.bind(new InetSocketAddress(0)); diff --git a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java index a7756989290..0a3aa9dee32 100644 --- a/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java +++ b/jdk/test/java/nio/channels/ServerSocketChannel/SocketOptionTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -49,8 +49,11 @@ public class SocketOptionTests { // check supported options Set> options = ssc.supportedOptions(); + boolean reuseport = options.contains(SO_REUSEPORT); if (!options.contains(SO_REUSEADDR)) throw new RuntimeException("SO_REUSEADDR should be supported"); + if (!options.contains(SO_REUSEPORT) && reuseport) + throw new RuntimeException("SO_REUSEPORT should be supported"); if (!options.contains(SO_RCVBUF)) throw new RuntimeException("SO_RCVBUF should be supported"); @@ -64,6 +67,12 @@ public class SocketOptionTests { checkOption(ssc, SO_REUSEADDR, true); ssc.setOption(SO_REUSEADDR, false); checkOption(ssc, SO_REUSEADDR, false); + if (reuseport) { + ssc.setOption(SO_REUSEPORT, true); + checkOption(ssc, SO_REUSEPORT, true); + ssc.setOption(SO_REUSEPORT, false); + checkOption(ssc, SO_REUSEPORT, false); + } // NullPointerException try {