1 /* 2 * Copyright (c) 2014, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.net; 27 28 import java.net.*; 29 import java.io.IOException; 30 import java.io.FileDescriptor; 31 import java.security.PrivilegedAction; 32 import java.security.AccessController; 33 import java.lang.reflect.*; 34 import java.util.Set; 35 import java.util.HashSet; 36 import java.util.HashMap; 37 import java.util.Collections; 38 import sun.net.ExtendedOptionsImpl; 39 40 /** 41 * Defines static methods to set and get socket options defined by the 42 * {@link java.net.SocketOption} interface. All of the standard options defined 43 * by {@link java.net.Socket}, {@link java.net.ServerSocket}, and 44 * {@link java.net.DatagramSocket} can be set this way, as well as additional 45 * or platform specific options supported by each socket type. 46 * <p> 47 * The {@link #supportedOptions(Class)} method can be called to determine 48 * the complete set of options available (per socket type) on the 49 * current system. 50 * <p> 51 * When a security manager is installed, some non-standard socket options 52 * may require a security permission before being set or get. 53 * The details are specified in {@link ExtendedSocketOptions}. No permission 54 * is required for {@link java.net.StandardSocketOptions}. 55 * 56 * @see java.nio.channels.NetworkChannel 57 */ 58 // Android-removed: @jdk.Exported, not present on Android. 59 // @jdk.Exported 60 public class Sockets { 61 62 private final static HashMap<Class<?>,Set<SocketOption<?>>> 63 options = new HashMap<>(); 64 65 static { initOptionSets()66 initOptionSets(); AccessController.doPrivileged( new java.security.PrivilegedAction<Void>() { public Void run() { initMethods(); return null; } } )67 AccessController.doPrivileged( 68 new java.security.PrivilegedAction<Void>() { 69 public Void run() { 70 initMethods(); 71 return null; 72 } 73 } 74 ); 75 } 76 77 private static Method siSetOption; 78 private static Method siGetOption; 79 private static Method dsiSetOption; 80 private static Method dsiGetOption; 81 initMethods()82 private static void initMethods() { 83 try { 84 Class<?> clazz = Class.forName("java.net.SocketSecrets"); 85 86 siSetOption = clazz.getDeclaredMethod( 87 "setOption", Object.class, 88 SocketOption.class, Object.class 89 ); 90 siSetOption.setAccessible(true); 91 92 siGetOption = clazz.getDeclaredMethod( 93 "getOption", Object.class, SocketOption.class 94 ); 95 siGetOption.setAccessible(true); 96 97 dsiSetOption = clazz.getDeclaredMethod( 98 "setOption", DatagramSocket.class, 99 SocketOption.class, Object.class 100 ); 101 dsiSetOption.setAccessible(true); 102 103 dsiGetOption = clazz.getDeclaredMethod( 104 "getOption", DatagramSocket.class, SocketOption.class 105 ); 106 dsiGetOption.setAccessible(true); 107 } catch (ReflectiveOperationException e) { 108 throw new InternalError(e); 109 } 110 } 111 invokeSet( Method method, Object socket, SocketOption<T> option, T value)112 private static <T> void invokeSet( 113 Method method, Object socket, 114 SocketOption<T> option, T value) throws IOException 115 { 116 try { 117 method.invoke(null, socket, option, value); 118 } catch (Exception e) { 119 if (e instanceof InvocationTargetException) { 120 Throwable t = ((InvocationTargetException)e).getTargetException(); 121 if (t instanceof IOException) { 122 throw (IOException)t; 123 } else if (t instanceof RuntimeException) { 124 throw (RuntimeException)t; 125 } 126 } 127 throw new RuntimeException(e); 128 } 129 } 130 invokeGet( Method method, Object socket, SocketOption<T> option)131 private static <T> T invokeGet( 132 Method method, Object socket, SocketOption<T> option) throws IOException 133 { 134 try { 135 return (T)method.invoke(null, socket, option); 136 } catch (Exception e) { 137 if (e instanceof InvocationTargetException) { 138 Throwable t = ((InvocationTargetException)e).getTargetException(); 139 if (t instanceof IOException) { 140 throw (IOException)t; 141 } else if (t instanceof RuntimeException) { 142 throw (RuntimeException)t; 143 } 144 } 145 throw new RuntimeException(e); 146 } 147 } 148 Sockets()149 private Sockets() {} 150 151 /** 152 * Sets the value of a socket option on a {@link java.net.Socket} 153 * 154 * @param s the socket 155 * @param name The socket option 156 * @param value The value of the socket option. May be null for some 157 * options. 158 * 159 * @throws UnsupportedOperationException if the socket does not support 160 * the option. 161 * 162 * @throws IllegalArgumentException if the value is not valid for 163 * the option. 164 * 165 * @throws IOException if an I/O error occurs, or socket is closed. 166 * 167 * @throws SecurityException if a security manager is set and the 168 * caller does not have any required permission. 169 * 170 * @throws NullPointerException if name is null 171 * 172 * @see java.net.StandardSocketOptions 173 */ setOption(Socket s, SocketOption<T> name, T value)174 public static <T> void setOption(Socket s, SocketOption<T> name, T value) throws IOException 175 { 176 if (!isSupported(Socket.class, name)) { 177 throw new UnsupportedOperationException(name.name()); 178 } 179 invokeSet(siSetOption, s, name, value); 180 } 181 182 /** 183 * Returns the value of a socket option from a {@link java.net.Socket} 184 * 185 * @param s the socket 186 * @param name The socket option 187 * 188 * @return The value of the socket option. 189 * 190 * @throws UnsupportedOperationException if the socket does not support 191 * the option. 192 * 193 * @throws IOException if an I/O error occurs 194 * 195 * @throws SecurityException if a security manager is set and the 196 * caller does not have any required permission. 197 * 198 * @throws NullPointerException if name is null 199 * 200 * @see java.net.StandardSocketOptions 201 */ getOption(Socket s, SocketOption<T> name)202 public static <T> T getOption(Socket s, SocketOption<T> name) throws IOException 203 { 204 if (!isSupported(Socket.class, name)) { 205 throw new UnsupportedOperationException(name.name()); 206 } 207 return invokeGet(siGetOption, s, name); 208 } 209 210 /** 211 * Sets the value of a socket option on a {@link java.net.ServerSocket} 212 * 213 * @param s the socket 214 * @param name The socket option 215 * @param value The value of the socket option. 216 * 217 * @throws UnsupportedOperationException if the socket does not support 218 * the option. 219 * 220 * @throws IllegalArgumentException if the value is not valid for 221 * the option. 222 * 223 * @throws IOException if an I/O error occurs 224 * 225 * @throws NullPointerException if name is null 226 * 227 * @throws SecurityException if a security manager is set and the 228 * caller does not have any required permission. 229 * 230 * @see java.net.StandardSocketOptions 231 */ setOption(ServerSocket s, SocketOption<T> name, T value)232 public static <T> void setOption(ServerSocket s, SocketOption<T> name, T value) throws IOException 233 { 234 if (!isSupported(ServerSocket.class, name)) { 235 throw new UnsupportedOperationException(name.name()); 236 } 237 invokeSet(siSetOption, s, name, value); 238 } 239 240 /** 241 * Returns the value of a socket option from a {@link java.net.ServerSocket} 242 * 243 * @param s the socket 244 * @param name The socket option 245 * 246 * @return The value of the socket option. 247 * 248 * @throws UnsupportedOperationException if the socket does not support 249 * the option. 250 * 251 * @throws IOException if an I/O error occurs 252 * 253 * @throws NullPointerException if name is null 254 * 255 * @throws SecurityException if a security manager is set and the 256 * caller does not have any required permission. 257 * 258 * @see java.net.StandardSocketOptions 259 */ getOption(ServerSocket s, SocketOption<T> name)260 public static <T> T getOption(ServerSocket s, SocketOption<T> name) throws IOException 261 { 262 if (!isSupported(ServerSocket.class, name)) { 263 throw new UnsupportedOperationException(name.name()); 264 } 265 return invokeGet(siGetOption, s, name); 266 } 267 268 /** 269 * Sets the value of a socket option on a {@link java.net.DatagramSocket} 270 * or {@link java.net.MulticastSocket} 271 * 272 * @param s the socket 273 * @param name The socket option 274 * @param value The value of the socket option. 275 * 276 * @throws UnsupportedOperationException if the socket does not support 277 * the option. 278 * 279 * @throws IllegalArgumentException if the value is not valid for 280 * the option. 281 * 282 * @throws IOException if an I/O error occurs 283 * 284 * @throws NullPointerException if name is null 285 * 286 * @throws SecurityException if a security manager is set and the 287 * caller does not have any required permission. 288 * 289 * @see java.net.StandardSocketOptions 290 */ setOption(DatagramSocket s, SocketOption<T> name, T value)291 public static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException 292 { 293 if (!isSupported(s.getClass(), name)) { 294 throw new UnsupportedOperationException(name.name()); 295 } 296 invokeSet(dsiSetOption, s, name, value); 297 } 298 299 /** 300 * Returns the value of a socket option from a 301 * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket} 302 * 303 * @param s the socket 304 * @param name The socket option 305 * 306 * @return The value of the socket option. 307 * 308 * @throws UnsupportedOperationException if the socket does not support 309 * the option. 310 * 311 * @throws IOException if an I/O error occurs 312 * 313 * @throws NullPointerException if name is null 314 * 315 * @throws SecurityException if a security manager is set and the 316 * caller does not have any required permission. 317 * 318 * @see java.net.StandardSocketOptions 319 */ getOption(DatagramSocket s, SocketOption<T> name)320 public static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException 321 { 322 if (!isSupported(s.getClass(), name)) { 323 throw new UnsupportedOperationException(name.name()); 324 } 325 return invokeGet(dsiGetOption, s, name); 326 } 327 328 /** 329 * Returns a set of {@link java.net.SocketOption}s supported by the 330 * given socket type. This set may include standard options and also 331 * non standard extended options. 332 * 333 * @param socketType the type of java.net socket 334 * 335 * @throws IllegalArgumentException if socketType is not a valid 336 * socket type from the java.net package. 337 */ supportedOptions(Class<?> socketType)338 public static Set<SocketOption<?>> supportedOptions(Class<?> socketType) { 339 Set<SocketOption<?>> set = options.get(socketType); 340 if (set == null) { 341 throw new IllegalArgumentException("unknown socket type"); 342 } 343 return set; 344 } 345 isSupported(Class<?> type, SocketOption<?> option)346 private static boolean isSupported(Class<?> type, SocketOption<?> option) { 347 Set<SocketOption<?>> options = supportedOptions(type); 348 return options.contains(option); 349 } 350 initOptionSets()351 private static void initOptionSets() { 352 boolean flowsupported = ExtendedOptionsImpl.flowSupported(); 353 354 // Socket 355 356 Set<SocketOption<?>> set = new HashSet<>(); 357 set.add(StandardSocketOptions.SO_KEEPALIVE); 358 set.add(StandardSocketOptions.SO_SNDBUF); 359 set.add(StandardSocketOptions.SO_RCVBUF); 360 set.add(StandardSocketOptions.SO_REUSEADDR); 361 set.add(StandardSocketOptions.SO_LINGER); 362 set.add(StandardSocketOptions.IP_TOS); 363 set.add(StandardSocketOptions.TCP_NODELAY); 364 if (flowsupported) { 365 set.add(ExtendedSocketOptions.SO_FLOW_SLA); 366 } 367 set = Collections.unmodifiableSet(set); 368 options.put(Socket.class, set); 369 370 // ServerSocket 371 372 set = new HashSet<>(); 373 set.add(StandardSocketOptions.SO_RCVBUF); 374 set.add(StandardSocketOptions.SO_REUSEADDR); 375 set.add(StandardSocketOptions.IP_TOS); 376 set = Collections.unmodifiableSet(set); 377 options.put(ServerSocket.class, set); 378 379 // DatagramSocket 380 381 set = new HashSet<>(); 382 set.add(StandardSocketOptions.SO_SNDBUF); 383 set.add(StandardSocketOptions.SO_RCVBUF); 384 set.add(StandardSocketOptions.SO_REUSEADDR); 385 set.add(StandardSocketOptions.IP_TOS); 386 if (flowsupported) { 387 set.add(ExtendedSocketOptions.SO_FLOW_SLA); 388 } 389 set = Collections.unmodifiableSet(set); 390 options.put(DatagramSocket.class, set); 391 392 // MulticastSocket 393 394 set = new HashSet<>(); 395 set.add(StandardSocketOptions.SO_SNDBUF); 396 set.add(StandardSocketOptions.SO_RCVBUF); 397 set.add(StandardSocketOptions.SO_REUSEADDR); 398 set.add(StandardSocketOptions.IP_TOS); 399 set.add(StandardSocketOptions.IP_MULTICAST_IF); 400 set.add(StandardSocketOptions.IP_MULTICAST_TTL); 401 set.add(StandardSocketOptions.IP_MULTICAST_LOOP); 402 if (flowsupported) { 403 set.add(ExtendedSocketOptions.SO_FLOW_SLA); 404 } 405 set = Collections.unmodifiableSet(set); 406 options.put(MulticastSocket.class, set); 407 } 408 } 409