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