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