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