1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 import java.io.IOException; 25 import java.net.DatagramSocket; 26 import java.net.MulticastSocket; 27 import java.net.ServerSocket; 28 import java.net.Socket; 29 import java.net.SocketOption; 30 import java.nio.channels.DatagramChannel; 31 import java.nio.channels.NetworkChannel; 32 import java.nio.channels.ServerSocketChannel; 33 import java.nio.channels.SocketChannel; 34 import java.util.Set; 35 import java.util.stream.Stream; 36 import org.testng.annotations.Test; 37 import org.testng.annotations.DataProvider; 38 39 import static java.net.StandardSocketOptions.*; 40 41 /* 42 * @test 43 * @bug 8235141 44 * @summary verifies that our implementation supports the set 45 * of SocketOptions that are required by the API documentation. 46 * @run testng/othervm -Djdk.net.usePlainSocketImpl RequiredOptions 47 * @run testng/othervm RequiredOptions 48 */ 49 public class RequiredOptions { 50 51 static final Set<SocketOption<?>> DATAGRAM_OPTIONS = 52 Set.of(SO_BROADCAST, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, IP_TOS); 53 static final Set<SocketOption<?>> MULTICAST_OPTIONS = 54 concat(DATAGRAM_OPTIONS, Set.of(IP_MULTICAST_IF, IP_MULTICAST_LOOP, IP_MULTICAST_TTL)); 55 static final Set<SocketOption<?>> SOCKET_OPTIONS = 56 Set.of(SO_KEEPALIVE, SO_LINGER, SO_SNDBUF, SO_RCVBUF, SO_REUSEADDR, TCP_NODELAY); 57 static final Set<SocketOption<?>> SERVER_OPTIONS = 58 Set.of(SO_RCVBUF, SO_REUSEADDR); 59 60 static Set<SocketOption<?>> concat(Set<SocketOption<?>> ...options) { 61 return Set.of(Stream.of(options).flatMap(Set::stream).distinct().toArray(SocketOption[]::new)); 62 } 63 64 @DataProvider(name = "sockets") 65 static Object[][] provider() throws IOException { 66 return new Object[][] { 67 // UDP 68 { Configurable.of(new DatagramSocket(null)), DATAGRAM_OPTIONS }, 69 { Configurable.of(new MulticastSocket(null)), MULTICAST_OPTIONS }, 70 // TCP 71 { Configurable.of(new Socket()), SOCKET_OPTIONS }, 72 { Configurable.of(new ServerSocket()), SERVER_OPTIONS }, 73 // Channels 74 { Configurable.of(DatagramChannel.open()), MULTICAST_OPTIONS }, 75 { Configurable.of(SocketChannel.open()), SOCKET_OPTIONS }, 76 { Configurable.of(ServerSocketChannel.open()), SERVER_OPTIONS }, 77 // Adaptors 78 { Configurable.of(DatagramChannel.open().socket()), MULTICAST_OPTIONS }, 79 { Configurable.of(SocketChannel.open().socket()), SOCKET_OPTIONS }, 80 { Configurable.of(ServerSocketChannel.open().socket()), SERVER_OPTIONS }, 81 }; 82 } 83 84 @Test(dataProvider = "sockets") 85 public <R, E extends Exception> 86 void test(Configurable<R,E> socket, Set<SocketOption<?>> options) throws E { 87 try (var s = socket) { 88 var impl = socket.socket().getClass(); 89 System.out.println("Testing " + impl + " with " + options); 90 Set<SocketOption<?>> supported = socket.supportedOptions(); 91 if (!supported.containsAll(options)) { 92 for (var option : options) { 93 if (!supported.contains(option)) { 94 System.err.println("Option " + option + " not supported by " + impl); 95 } 96 } 97 throw new AssertionError("Not all documented options are supported by " + impl); 98 } 99 } 100 } 101 102 static interface Configurable<R, E extends Exception> extends AutoCloseable { 103 <T> R setOption(SocketOption<T> name, T value) throws E; 104 <T> T getOption(SocketOption<T> name) throws E; 105 Set<SocketOption<?>> supportedOptions() throws E; 106 R socket(); 107 void close() throws E; 108 109 static Configurable<DatagramSocket, IOException> of(DatagramSocket socket) { 110 return new ConfigurableImpl<>(socket, socket::setOption, 111 socket::getOption, socket::supportedOptions, socket::close); 112 } 113 static Configurable<NetworkChannel, IOException> of(NetworkChannel socket) { 114 return new ConfigurableImpl<>(socket, socket::setOption, 115 socket::getOption, socket::supportedOptions, socket::close); 116 } 117 static Configurable<Socket, IOException> of(Socket socket) { 118 return new ConfigurableImpl<>(socket, socket::setOption, 119 socket::getOption, socket::supportedOptions, socket::close); 120 } 121 static Configurable<ServerSocket, IOException> of(ServerSocket socket) { 122 return new ConfigurableImpl<>(socket, socket::setOption, 123 socket::getOption, socket::supportedOptions, socket::close); 124 } 125 } 126 127 static final class ConfigurableImpl<R, E extends Exception> implements Configurable<R, E> { 128 @FunctionalInterface 129 interface SetOption<R, E extends Exception> { 130 <T> R setOption(SocketOption<T> name, T value) throws E; 131 } 132 @FunctionalInterface 133 interface GetOption<E extends Exception> { 134 <T> T getOption(SocketOption<T> name) throws E; 135 } 136 @FunctionalInterface 137 interface SupportedOption<E extends Exception> { 138 Set<SocketOption<?>> supportedOptions() throws E; 139 } 140 @FunctionalInterface 141 interface Closer<E extends Exception> { 142 void close() throws E; 143 } 144 145 private final R socket; 146 private final SetOption<R, E> setter; 147 private final GetOption<E> getter; 148 private final SupportedOption<E> support; 149 private final Closer<E> closer; 150 151 public ConfigurableImpl(R socket, SetOption<R, E> setter, GetOption<E> getter, 152 SupportedOption<E> support, Closer<E> closer) { 153 this.socket = socket; 154 this.setter = setter; 155 this.getter = getter; 156 this.support = support; 157 this.closer = closer; 158 } 159 160 @Override 161 public <T> R setOption(SocketOption<T> name, T value) throws E { 162 return setter.setOption(name, value); 163 } 164 @Override 165 public <T> T getOption(SocketOption<T> name) throws E { 166 return getter.getOption(name); 167 } 168 @Override 169 public Set<SocketOption<?>> supportedOptions() throws E { 170 return support.supportedOptions(); 171 } 172 @Override 173 public R socket() { 174 return socket; 175 } 176 @Override 177 public void close() throws E { 178 closer.close(); 179 } 180 } 181 182 183 }