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