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 }