1 /*
   2  * Copyright (c) 2020, 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 /*
  25  * @test
  26  * @bug 8241988
  27  * @summary Checks that the caching of options does not affect other impls
  28  * @run testng/othervm CachedImplOptions
  29  * @run testng/othervm -Djava.net.preferIPv4Stack=true CachedImplOptions
  30  */
  31 
  32 import java.io.IOException;
  33 import java.io.InputStream;
  34 import java.io.OutputStream;
  35 import java.net.DatagramPacket;
  36 import java.net.DatagramSocket;
  37 import java.net.DatagramSocketImpl;
  38 import java.net.MulticastSocket;
  39 import java.net.InetAddress;
  40 import java.net.NetworkInterface;
  41 import java.net.ServerSocket;
  42 import java.net.Socket;
  43 import java.net.SocketAddress;
  44 import java.net.SocketException;
  45 import java.net.SocketImpl;
  46 import java.net.SocketOption;
  47 import java.net.StandardSocketOptions;
  48 import java.util.Set;
  49 import org.testng.annotations.Test;
  50 import static org.testng.Assert.*;
  51 
  52 public class CachedImplOptions {
  53 
  54     @Test
  55     public void testDatagramSocket() throws IOException {
  56         try (var impl = new DatagramSocket()) {
  57             Set<SocketOption<?>> options = impl.supportedOptions();
  58             assertTrue(options.contains(StandardSocketOptions.SO_SNDBUF));
  59         }
  60         try (var impl = new DatagramSocket(new FooDatagramSocketImpl()) {}) {
  61             Set<SocketOption<?>> options = impl.supportedOptions();
  62             assertEquals(options, Set.of(FooDatagramSocketImpl.FOO_OPTION));
  63         }
  64         try (var impl = new DatagramSocket(new BarDatagramSocketImpl()) {}) {
  65             Set<SocketOption<?>> options = impl.supportedOptions();
  66             assertEquals(options, Set.of(BarDatagramSocketImpl.BAR_OPTION));
  67         }
  68         try (var impl = new DatagramSocket(new BazDatagramSocketImpl()) {}) {
  69             Set<SocketOption<?>> options = impl.supportedOptions();
  70             assertEquals(options, Set.of(BazDatagramSocketImpl.BAZ_OPTION));
  71         }
  72         try (var impl = new DatagramSocket()) {
  73             Set<SocketOption<?>> options = impl.supportedOptions();
  74             assertTrue(options.contains(StandardSocketOptions.SO_SNDBUF));
  75         }
  76     }
  77 
  78     @Test
  79     public void testMulticastSocket() throws IOException {
  80         try (var impl = new MulticastSocket()) {
  81             Set<SocketOption<?>> options = impl.supportedOptions();
  82             assertTrue(options.contains(StandardSocketOptions.SO_SNDBUF));
  83         }
  84 
  85         // Use the factory to inject an alternative impl
  86         DatagramSocket.setDatagramSocketImplFactory(() -> new FooDatagramSocketImpl());
  87 
  88         try (var impl = new MulticastSocket()) {
  89             Set<SocketOption<?>> options = impl.supportedOptions();
  90             assertEquals(options, Set.of(FooDatagramSocketImpl.FOO_OPTION));
  91         }
  92     }
  93 
  94     static class FooDatagramSocketImpl extends AbstractDatagramSocketImpl {
  95         public static final SocketOption<Boolean> FOO_OPTION = new SocketOption<>() {
  96             @Override public String name() { return "FOO_OPTION"; }
  97             @Override public Class<Boolean> type() { return Boolean.class; }
  98         };
  99         @Override public Set<SocketOption<?>> supportedOptions() { return Set.of(FOO_OPTION); }
 100     }
 101 
 102     static class BarDatagramSocketImpl extends AbstractDatagramSocketImpl {
 103         public static final SocketOption<Integer> BAR_OPTION = new SocketOption<>() {
 104             @Override public String name() { return "BAR_OPTION"; }
 105             @Override public Class<Integer> type() { return Integer.class; }
 106         };
 107         @Override public Set<SocketOption<?>> supportedOptions() { return Set.of(BAR_OPTION); }
 108     }
 109 
 110     static class BazDatagramSocketImpl extends AbstractDatagramSocketImpl {
 111         public static final SocketOption<Long> BAZ_OPTION = new SocketOption<>() {
 112             @Override public String name() { return "BAZ_OPTION"; }
 113             @Override public Class<Long> type() { return Long.class; }
 114         };
 115         @Override public Set<SocketOption<?>> supportedOptions() { return Set.of(BAZ_OPTION); }
 116     }
 117 
 118     static abstract class AbstractDatagramSocketImpl extends DatagramSocketImpl {
 119 
 120         @Override public Set<SocketOption<?>> supportedOptions() { return null; }
 121         @Override protected void create() throws SocketException { }
 122         @Override protected void bind(int lport, InetAddress laddr){ }
 123         @Override protected void send(DatagramPacket p) { }
 124         @Override protected int peek(InetAddress i) { return 0; }
 125         @Override protected int peekData(DatagramPacket p) { return 0; }
 126         @Override protected void receive(DatagramPacket p) { }
 127         @Override protected void setTTL(byte ttl) { }
 128         @Override protected byte getTTL() { return 0; }
 129         @Override protected void setTimeToLive(int ttl) { }
 130         @Override protected int getTimeToLive() { return 0; }
 131         @Override protected void join(InetAddress inetaddr)  { }
 132         @Override protected void leave(InetAddress inetaddr) { }
 133         @Override protected void joinGroup(SocketAddress x, NetworkInterface y) { }
 134         @Override protected void leaveGroup(SocketAddress x, NetworkInterface y) { }
 135         @Override protected void close() { }
 136         @Override public void setOption(int optID, Object value) { }
 137         @Override public Object getOption(int optID) { return null; }
 138     }
 139 
 140     // -- socket
 141 
 142     @Test
 143     public void testSocket() throws IOException {
 144         try (var impl = new Socket()) {
 145             Set<SocketOption<?>> options = impl.supportedOptions();
 146             assertTrue(options.contains(StandardSocketOptions.SO_SNDBUF));
 147         }
 148         try (var impl = new Socket(new LarrySocketImpl()) {}) {
 149             Set<SocketOption<?>> options = impl.supportedOptions();
 150             assertEquals(options, Set.of(LarrySocketImpl.LARRY_OPTION));
 151         }
 152         try (var impl = new Socket(new CurlySocketImpl()) {}) {
 153             Set<SocketOption<?>> options = impl.supportedOptions();
 154             assertEquals(options, Set.of(CurlySocketImpl.CURLY_OPTION));
 155         }
 156         try (var impl = new Socket(new MoeSocketImpl()) {}) {
 157             Set<SocketOption<?>> options = impl.supportedOptions();
 158             assertEquals(options, Set.of(MoeSocketImpl.MOE_OPTION));
 159         }
 160         try (var impl = new Socket()) {
 161             Set<SocketOption<?>> options = impl.supportedOptions();
 162             assertTrue(options.contains(StandardSocketOptions.SO_SNDBUF));
 163         }
 164     }
 165 
 166     @Test
 167     public void testServerSocket() throws IOException {
 168         try (var impl = new ServerSocket()) {
 169             Set<SocketOption<?>> options = impl.supportedOptions();
 170             assertTrue(options.contains(StandardSocketOptions.SO_RCVBUF));
 171         }
 172         try (var impl = new ServerSocket(new LarrySocketImpl()) {}) {
 173             Set<SocketOption<?>> options = impl.supportedOptions();
 174             assertEquals(options, Set.of(LarrySocketImpl.LARRY_OPTION));
 175         }
 176         try (var impl = new ServerSocket(new CurlySocketImpl()) {}) {
 177             Set<SocketOption<?>> options = impl.supportedOptions();
 178             assertEquals(options, Set.of(CurlySocketImpl.CURLY_OPTION));
 179         }
 180         try (var impl = new ServerSocket(new MoeSocketImpl()) {}) {
 181             Set<SocketOption<?>> options = impl.supportedOptions();
 182             assertEquals(options, Set.of(MoeSocketImpl.MOE_OPTION));
 183         }
 184         try (var impl = new ServerSocket()) {
 185             Set<SocketOption<?>> options = impl.supportedOptions();
 186             assertTrue(options.contains(StandardSocketOptions.SO_RCVBUF));
 187         }
 188     }
 189 
 190     static class LarrySocketImpl extends AbstractSocketImpl {
 191         public static final SocketOption<Boolean> LARRY_OPTION = new SocketOption<>() {
 192             @Override public String name() { return "LARRY_OPTION"; }
 193             @Override public Class<Boolean> type() { return Boolean.class; }
 194         };
 195         @Override public Set<SocketOption<?>> supportedOptions() { return Set.of(LARRY_OPTION); }
 196     }
 197 
 198     static class CurlySocketImpl extends AbstractSocketImpl {
 199         public static final SocketOption<Integer> CURLY_OPTION = new SocketOption<>() {
 200             @Override public String name() { return "CURLY_OPTION"; }
 201             @Override public Class<Integer> type() { return Integer.class; }
 202         };
 203         @Override public Set<SocketOption<?>> supportedOptions() { return Set.of(CURLY_OPTION); }
 204     }
 205 
 206     static class MoeSocketImpl extends AbstractSocketImpl {
 207         public static final SocketOption<Long> MOE_OPTION = new SocketOption<>() {
 208             @Override public String name() { return "MOE_OPTION"; }
 209             @Override public Class<Long> type() { return Long.class; }
 210         };
 211         @Override public Set<SocketOption<?>> supportedOptions() { return Set.of(MOE_OPTION); }
 212     }
 213 
 214     static abstract class AbstractSocketImpl extends SocketImpl {
 215 
 216         @Override protected void create(boolean stream) { }
 217         @Override protected void connect(String host, int port) { }
 218         @Override protected void connect(InetAddress address, int port) { }
 219         @Override protected void connect(SocketAddress address, int timeout) { }
 220         @Override protected void bind(InetAddress host, int port) { }
 221         @Override protected void listen(int backlog) { }
 222         @Override protected void accept(SocketImpl s) { }
 223         @Override protected InputStream getInputStream() { return null; }
 224         @Override protected OutputStream getOutputStream() { return null;  }
 225         @Override protected int available() { return 0; }
 226         @Override protected void close() { }
 227         @Override protected void sendUrgentData(int data) { }
 228         @Override public void setOption(int optID, Object value) { }
 229         @Override public Object getOption(int optID) { return null; }
 230     }
 231 }