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 }