1 /* 2 * Copyright (c) 2014, 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 /* 25 * @test 26 * @bug 8036979 8072384 8044773 8225214 27 * @library /test/lib 28 * @requires !vm.graal.enabled 29 * @run main/othervm -Xcheck:jni OptionsTest 30 * @run main/othervm -Djdk.net.usePlainSocketImpl OptionsTest 31 * @run main/othervm -Xcheck:jni -Djava.net.preferIPv4Stack=true OptionsTest 32 * @run main/othervm --limit-modules=java.base OptionsTest 33 */ 34 35 import java.lang.reflect.Method; 36 import java.net.*; 37 import java.util.*; 38 import jdk.test.lib.net.IPSupport; 39 40 public class OptionsTest { 41 42 static class Test<T> { 43 final SocketOption<T> option; 44 final T value; 45 Test(SocketOption<T> option, T value) { 46 this.option = option; 47 this.value = value; 48 } 49 static <T> Test<T> create(SocketOption<T> option, T value) { 50 return new Test<T>(option, value); 51 } 52 53 } 54 55 // The tests set the option using the new API, read back the set value 56 // which could be different, and then use the legacy get API to check 57 // these values are the same 58 59 static Test<?>[] socketTests = new Test<?>[] { 60 Test.create(StandardSocketOptions.SO_KEEPALIVE, Boolean.TRUE), 61 Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), 62 Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), 63 Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), 64 Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE), 65 Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(-1)), 66 Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(0)), 67 Test.create(StandardSocketOptions.SO_LINGER, Integer.valueOf(80)), 68 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(0)), // lower-bound 69 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)), 70 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound 71 }; 72 73 static Test<?>[] serverSocketTests = new Test<?>[] { 74 Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), 75 Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), 76 Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE), 77 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(0)), // lower-bound 78 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)), 79 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound 80 }; 81 82 static Test<?>[] datagramSocketTests = new Test<?>[] { 83 Test.create(StandardSocketOptions.SO_SNDBUF, Integer.valueOf(10 * 100)), 84 Test.create(StandardSocketOptions.SO_RCVBUF, Integer.valueOf(8 * 100)), 85 Test.create(StandardSocketOptions.SO_REUSEADDR, Boolean.FALSE), 86 Test.create(StandardSocketOptions.SO_REUSEPORT, Boolean.FALSE), 87 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(0)), // lower-bound 88 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(100)), 89 Test.create(StandardSocketOptions.IP_TOS, Integer.valueOf(255)) //upper-bound 90 }; 91 92 static Test<?>[] multicastSocketTests = new Test<?>[] { 93 Test.create(StandardSocketOptions.IP_MULTICAST_IF, getNetworkInterface()), 94 Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(0)), // lower-bound 95 Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(10)), 96 Test.create(StandardSocketOptions.IP_MULTICAST_TTL, Integer.valueOf(255)), //upper-bound 97 Test.create(StandardSocketOptions.IP_MULTICAST_LOOP, Boolean.TRUE) 98 }; 99 100 static NetworkInterface getNetworkInterface() { 101 try { 102 Enumeration<NetworkInterface> nifs = NetworkInterface.getNetworkInterfaces(); 103 while (nifs.hasMoreElements()) { 104 NetworkInterface ni = nifs.nextElement(); 105 if (ni.supportsMulticast()) { 106 return ni; 107 } 108 } 109 } catch (Exception e) { 110 } 111 return null; 112 } 113 114 static boolean okayToTest(Socket s, SocketOption<?> option) { 115 if (option == StandardSocketOptions.SO_REUSEPORT) { 116 // skip SO_REUSEPORT if option is not supported 117 return s.supportedOptions().contains(StandardSocketOptions.SO_REUSEPORT); 118 } 119 if (option == StandardSocketOptions.IP_TOS && s.isConnected()) { 120 // skip IP_TOS if connected 121 return false; 122 } 123 return true; 124 } 125 126 static <T> void testEqual(SocketOption<T> option, T value1, T value2) { 127 if (!value1.equals(value2)) { 128 throw new RuntimeException("Test of " + option.name() + " failed: " 129 + value1 + " != " + value2); 130 } 131 } 132 133 static <T> void test(Socket s, Test<T> test) throws Exception { 134 SocketOption<T> option = test.option; 135 s.setOption(option, test.value); 136 T value1 = s.getOption(test.option); 137 T value2 = (T) legacyGetOption(Socket.class, s, test.option); 138 testEqual(option, value1, value2); 139 } 140 141 static <T> void test(ServerSocket ss, Test<T> test) throws Exception { 142 SocketOption<T> option = test.option; 143 ss.setOption(option, test.value); 144 T value1 = ss.getOption(test.option); 145 T value2 = (T) legacyGetOption(ServerSocket.class, ss, test.option); 146 testEqual(option, value1, value2); 147 } 148 149 static <T> void test(DatagramSocket ds, Test<T> test) throws Exception { 150 SocketOption<T> option = test.option; 151 ds.setOption(option, test.value); 152 T value1 = ds.getOption(test.option); 153 T value2 = (T) legacyGetOption(ds.getClass(), ds, test.option); 154 testEqual(option, value1, value2); 155 } 156 157 @SuppressWarnings("try") 158 static void doSocketTests() throws Exception { 159 // unconnected socket 160 try (Socket s = new Socket()) { 161 for (Test<?> test : socketTests) { 162 if (okayToTest(s, test.option)) { 163 test(s, test); 164 } 165 } 166 } 167 168 // connected socket 169 try (ServerSocket ss = new ServerSocket()) { 170 var loopback = InetAddress.getLoopbackAddress(); 171 ss.bind(new InetSocketAddress(loopback, 0)); 172 try (Socket s1 = new Socket()) { 173 s1.connect(ss.getLocalSocketAddress()); 174 try (Socket s2 = ss.accept()) { 175 for (Test<?> test : socketTests) { 176 if (okayToTest(s1, test.option)) { 177 test(s1, test); 178 } 179 } 180 } 181 } 182 } 183 } 184 185 static void doServerSocketTests() throws Exception { 186 try (ServerSocket ss = new ServerSocket(0)) { 187 Set<SocketOption<?>> options = ss.supportedOptions(); 188 boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); 189 for (Test<?> test : serverSocketTests) { 190 if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) { 191 test(ss, test); 192 } 193 } 194 } 195 } 196 197 static void doDatagramSocketTests() throws Exception { 198 try (DatagramSocket ds = new DatagramSocket(0)) { 199 Set<SocketOption<?>> options = ds.supportedOptions(); 200 boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); 201 for (Test<?> test : datagramSocketTests) { 202 if (!(test.option == StandardSocketOptions.SO_REUSEPORT && !reuseport)) { 203 test(ds, test); 204 } 205 } 206 } 207 } 208 209 static void doMulticastSocketTests() throws Exception { 210 try (MulticastSocket ms = new MulticastSocket(0)) { 211 for (Test<?> test : multicastSocketTests) { 212 test(ms, test); 213 } 214 } 215 } 216 217 static Object legacyGetOption(Class<?> type, Object s, Object option) throws Exception { 218 if (type.equals(Socket.class)) { 219 Socket socket = (Socket)s; 220 Set<SocketOption<?>> options = socket.supportedOptions(); 221 boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); 222 223 if (option.equals(StandardSocketOptions.SO_KEEPALIVE)) { 224 return Boolean.valueOf(socket.getKeepAlive()); 225 } else if (option.equals(StandardSocketOptions.SO_SNDBUF)) { 226 return Integer.valueOf(socket.getSendBufferSize()); 227 } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { 228 return Integer.valueOf(socket.getReceiveBufferSize()); 229 } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { 230 return Boolean.valueOf(socket.getReuseAddress()); 231 } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { 232 return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); 233 } else if (option.equals(StandardSocketOptions.SO_LINGER)) { 234 return Integer.valueOf(socket.getSoLinger()); 235 } else if (option.equals(StandardSocketOptions.IP_TOS)) { 236 return Integer.valueOf(socket.getTrafficClass()); 237 } else if (option.equals(StandardSocketOptions.TCP_NODELAY)) { 238 return Boolean.valueOf(socket.getTcpNoDelay()); 239 } else { 240 throw new RuntimeException("unexpected socket option"); 241 } 242 } else if (type.equals(ServerSocket.class)) { 243 ServerSocket socket = (ServerSocket)s; 244 Set<SocketOption<?>> options = socket.supportedOptions(); 245 boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); 246 247 if (option.equals(StandardSocketOptions.SO_RCVBUF)) { 248 return Integer.valueOf(socket.getReceiveBufferSize()); 249 } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { 250 return Boolean.valueOf(socket.getReuseAddress()); 251 } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { 252 return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); 253 } else if (option.equals(StandardSocketOptions.IP_TOS)) { 254 return getServerSocketTrafficClass(socket); 255 } else { 256 throw new RuntimeException("unexpected socket option"); 257 } 258 } else if (type.equals(DatagramSocket.class)) { 259 DatagramSocket socket = (DatagramSocket)s; 260 Set<SocketOption<?>> options = socket.supportedOptions(); 261 boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); 262 263 if (option.equals(StandardSocketOptions.SO_SNDBUF)) { 264 return Integer.valueOf(socket.getSendBufferSize()); 265 } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { 266 return Integer.valueOf(socket.getReceiveBufferSize()); 267 } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { 268 return Boolean.valueOf(socket.getReuseAddress()); 269 } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { 270 return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); 271 } else if (option.equals(StandardSocketOptions.IP_TOS)) { 272 return Integer.valueOf(socket.getTrafficClass()); 273 } else { 274 throw new RuntimeException("unexpected socket option"); 275 } 276 277 } else if (type.equals(MulticastSocket.class)) { 278 MulticastSocket socket = (MulticastSocket)s; 279 Set<SocketOption<?>> options = socket.supportedOptions(); 280 boolean reuseport = options.contains(StandardSocketOptions.SO_REUSEPORT); 281 282 if (option.equals(StandardSocketOptions.SO_SNDBUF)) { 283 return Integer.valueOf(socket.getSendBufferSize()); 284 } else if (option.equals(StandardSocketOptions.SO_RCVBUF)) { 285 return Integer.valueOf(socket.getReceiveBufferSize()); 286 } else if (option.equals(StandardSocketOptions.SO_REUSEADDR)) { 287 return Boolean.valueOf(socket.getReuseAddress()); 288 } else if (option.equals(StandardSocketOptions.SO_REUSEPORT) && reuseport) { 289 return Boolean.valueOf(socket.getOption(StandardSocketOptions.SO_REUSEPORT)); 290 } else if (option.equals(StandardSocketOptions.IP_TOS)) { 291 return Integer.valueOf(socket.getTrafficClass()); 292 } else if (option.equals(StandardSocketOptions.IP_MULTICAST_IF)) { 293 return socket.getNetworkInterface(); 294 } else if (option.equals(StandardSocketOptions.IP_MULTICAST_TTL)) { 295 return Integer.valueOf(socket.getTimeToLive()); 296 } else if (option.equals(StandardSocketOptions.IP_MULTICAST_LOOP)) { 297 return Boolean.valueOf(socket.getLoopbackMode()); 298 } else { 299 throw new RuntimeException("unexpected socket option"); 300 } 301 } 302 throw new RuntimeException("unexpected socket type"); 303 } 304 305 // Tests default and negative values of SO_LINGER. All negative values should 306 // retrieve as -1. 307 public static void soLinger() throws Exception { 308 try (Socket s = new Socket()) { 309 // retrieve without set 310 int ignoreValue = s.getOption(StandardSocketOptions.SO_LINGER); 311 312 for (int v : List.of(-1, -2, -100, -65534, -65535, -65536, -100000)) { 313 System.out.println("Testing SO_LINGER with:" + v); 314 s.setOption(StandardSocketOptions.SO_LINGER, v); 315 int value = s.getOption(StandardSocketOptions.SO_LINGER); 316 testEqual(StandardSocketOptions.SO_LINGER, -1, value); 317 } 318 } 319 } 320 321 public static void main(String args[]) throws Exception { 322 IPSupport.throwSkippedExceptionIfNonOperational(); 323 doSocketTests(); 324 doServerSocketTests(); 325 doDatagramSocketTests(); 326 doMulticastSocketTests(); 327 soLinger(); 328 } 329 330 // Reflectively access jdk.net.Sockets.getOption so that the test can run 331 // without the jdk.net module. 332 static Object getServerSocketTrafficClass(ServerSocket ss) throws Exception { 333 try { 334 Class<?> c = Class.forName("jdk.net.Sockets"); 335 Method m = c.getDeclaredMethod("getOption", ServerSocket.class, SocketOption.class); 336 return m.invoke(null, ss, StandardSocketOptions.IP_TOS); 337 } catch (ClassNotFoundException e) { 338 // Ok, jdk.net module not present, just fall back 339 System.out.println("jdk.net module not present, falling back."); 340 return Integer.valueOf(ss.getOption(StandardSocketOptions.IP_TOS)); 341 } catch (ReflectiveOperationException e) { 342 throw new AssertionError(e); 343 } 344 } 345 }