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