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.Field;
  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 @jdk.Exported
  59 public class Sockets {
  60 
  61     private static final HashMap<Class<?>,Set<SocketOption<?>>>
  62         options = new HashMap<>();
  63 
  64     static {
  65         initOptionSets();
  66     }
  67 
  68     private Sockets() {}
  69 
  70     /**
  71      * Sets the value of a socket option on a {@link java.net.Socket}
  72      *
  73      * @param s the socket
  74      * @param name The socket option
  75      * @param value The value of the socket option. May be null for some
  76      *              options.
  77      *
  78      * @throws UnsupportedOperationException if the socket does not support
  79      *         the option.
  80      *
  81      * @throws IllegalArgumentException if the value is not valid for
  82      *         the option.
  83      *
  84      * @throws IOException if an I/O error occurs, or socket is closed.
  85      *
  86      * @throws SecurityException if a security manager is set and the
  87      *         caller does not have any required permission.
  88      *
  89      * @throws NullPointerException if name is null
  90      *
  91      * @see java.net.StandardSocketOptions
  92      */
  93     public static <T> void setOption(Socket s, SocketOption<T> name, T value) throws IOException
  94     {
  95         s.setOption(name, value);
  96     }
  97 
  98     /**
  99      * Returns the value of a socket option from a {@link java.net.Socket}
 100      *
 101      * @param s the socket
 102      * @param name The socket option
 103      *
 104      * @return The value of the socket option.
 105      *
 106      * @throws UnsupportedOperationException if the socket does not support
 107      *         the option.
 108      *
 109      * @throws IOException if an I/O error occurs
 110      *
 111      * @throws SecurityException if a security manager is set and the
 112      *         caller does not have any required permission.
 113      *
 114      * @throws NullPointerException if name is null
 115      *
 116      * @see java.net.StandardSocketOptions
 117      */
 118     public static <T> T getOption(Socket s, SocketOption<T> name) throws IOException
 119     {
 120         return s.getOption(name);
 121     }
 122 
 123     /**
 124      * Sets the value of a socket option on a {@link java.net.ServerSocket}
 125      *
 126      * @param s the socket
 127      * @param name The socket option
 128      * @param value The value of the socket option.
 129      *
 130      * @throws UnsupportedOperationException if the socket does not support
 131      *         the option.
 132      *
 133      * @throws IllegalArgumentException if the value is not valid for
 134      *         the option.
 135      *
 136      * @throws IOException if an I/O error occurs
 137      *
 138      * @throws NullPointerException if name is null
 139      *
 140      * @throws SecurityException if a security manager is set and the
 141      *         caller does not have any required permission.
 142      *
 143      * @see java.net.StandardSocketOptions
 144      */
 145     public static <T> void setOption(ServerSocket s, SocketOption<T> name, T value) throws IOException
 146     {
 147         s.setOption(name, value);
 148     }
 149 
 150     /**
 151      * Returns the value of a socket option from a {@link java.net.ServerSocket}
 152      *
 153      * @param s the socket
 154      * @param name The socket option
 155      *
 156      * @return The value of the socket option.
 157      *
 158      * @throws UnsupportedOperationException if the socket does not support
 159      *         the option.
 160      *
 161      * @throws IOException if an I/O error occurs
 162      *
 163      * @throws NullPointerException if name is null
 164      *
 165      * @throws SecurityException if a security manager is set and the
 166      *         caller does not have any required permission.
 167      *
 168      * @see java.net.StandardSocketOptions
 169      */
 170     public static <T> T getOption(ServerSocket s, SocketOption<T> name) throws IOException
 171     {
 172         return s.getOption(name);
 173     }
 174 
 175     /**
 176      * Sets the value of a socket option on a {@link java.net.DatagramSocket}
 177      * or {@link java.net.MulticastSocket}
 178      *
 179      * @param s the socket
 180      * @param name The socket option
 181      * @param value The value of the socket option.
 182      *
 183      * @throws UnsupportedOperationException if the socket does not support
 184      *         the option.
 185      *
 186      * @throws IllegalArgumentException if the value is not valid for
 187      *         the option.
 188      *
 189      * @throws IOException if an I/O error occurs
 190      *
 191      * @throws NullPointerException if name is null
 192      *
 193      * @throws SecurityException if a security manager is set and the
 194      *         caller does not have any required permission.
 195      *
 196      * @see java.net.StandardSocketOptions
 197      */
 198     public static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException
 199     {
 200         s.setOption(name, value);
 201     }
 202 
 203     /**
 204      * Returns the value of a socket option from a
 205      * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket}
 206      *
 207      * @param s the socket
 208      * @param name The socket option
 209      *
 210      * @return The value of the socket option.
 211      *
 212      * @throws UnsupportedOperationException if the socket does not support
 213      *         the option.
 214      *
 215      * @throws IOException if an I/O error occurs
 216      *
 217      * @throws NullPointerException if name is null
 218      *
 219      * @throws SecurityException if a security manager is set and the
 220      *         caller does not have any required permission.
 221      *
 222      * @see java.net.StandardSocketOptions
 223      */
 224     public static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException
 225     {
 226         return s.getOption(name);
 227     }
 228 
 229     /**
 230      * Returns a set of {@link java.net.SocketOption}s supported by the
 231      * given socket type. This set may include standard options and also
 232      * non standard extended options.
 233      *
 234      * @param socketType the type of java.net socket
 235      *
 236      * @throws IllegalArgumentException if socketType is not a valid
 237      *         socket type from the java.net package.
 238      */
 239     public static Set<SocketOption<?>> supportedOptions(Class<?> socketType) {
 240         Set<SocketOption<?>> set = options.get(socketType);
 241         if (set == null) {
 242             throw new IllegalArgumentException("unknown socket type");
 243         }
 244         return set;
 245     }
 246 
 247     private static void checkValueType(Object value, Class<?> type) {
 248         if (!type.isAssignableFrom(value.getClass())) {
 249             String s = "Found: " + value.getClass().toString() + " Expected: "
 250                         + type.toString();
 251             throw new IllegalArgumentException(s);
 252         }
 253     }
 254 
 255     private static void initOptionSets() {
 256         boolean flowsupported = ExtendedOptionsImpl.flowSupported();
 257         boolean reuseportsupported = ExtendedOptionsImpl.reuseportSupported();
 258 
 259         // Socket
 260 
 261         Set<SocketOption<?>> set = new HashSet<>();
 262         set.add(StandardSocketOptions.SO_KEEPALIVE);
 263         set.add(StandardSocketOptions.SO_SNDBUF);
 264         set.add(StandardSocketOptions.SO_RCVBUF);
 265         set.add(StandardSocketOptions.SO_REUSEADDR);
 266         set.add(StandardSocketOptions.SO_LINGER);
 267         set.add(StandardSocketOptions.IP_TOS);
 268         set.add(StandardSocketOptions.TCP_NODELAY);
 269         if (flowsupported) {
 270             set.add(ExtendedSocketOptions.SO_FLOW_SLA);
 271         }
 272         if (reuseportsupported) {
 273             set.add(ExtendedSocketOptions.SO_REUSEPORT);
 274         }
 275         set = Collections.unmodifiableSet(set);
 276         options.put(Socket.class, set);
 277 
 278         // ServerSocket
 279 
 280         set = new HashSet<>();
 281         set.add(StandardSocketOptions.SO_RCVBUF);
 282         set.add(StandardSocketOptions.SO_REUSEADDR);
 283         set.add(StandardSocketOptions.IP_TOS);
 284         if (reuseportsupported) {
 285             set.add(ExtendedSocketOptions.SO_REUSEPORT);
 286         }
 287         set = Collections.unmodifiableSet(set);
 288         options.put(ServerSocket.class, set);
 289 
 290         // DatagramSocket
 291 
 292         set = new HashSet<>();
 293         set.add(StandardSocketOptions.SO_SNDBUF);
 294         set.add(StandardSocketOptions.SO_RCVBUF);
 295         set.add(StandardSocketOptions.SO_REUSEADDR);
 296         set.add(StandardSocketOptions.IP_TOS);
 297         if (flowsupported) {
 298             set.add(ExtendedSocketOptions.SO_FLOW_SLA);
 299         }
 300         if (reuseportsupported) {
 301             set.add(ExtendedSocketOptions.SO_REUSEPORT);
 302         }
 303         set = Collections.unmodifiableSet(set);
 304         options.put(DatagramSocket.class, set);
 305 
 306         // MulticastSocket
 307 
 308         set = new HashSet<>();
 309         set.add(StandardSocketOptions.SO_SNDBUF);
 310         set.add(StandardSocketOptions.SO_RCVBUF);
 311         set.add(StandardSocketOptions.SO_REUSEADDR);
 312         set.add(StandardSocketOptions.IP_TOS);
 313         set.add(StandardSocketOptions.IP_MULTICAST_IF);
 314         set.add(StandardSocketOptions.IP_MULTICAST_TTL);
 315         set.add(StandardSocketOptions.IP_MULTICAST_LOOP);
 316         if (flowsupported) {
 317             set.add(ExtendedSocketOptions.SO_FLOW_SLA);
 318         }
 319         if (reuseportsupported) {
 320             set.add(ExtendedSocketOptions.SO_REUSEPORT);
 321         }
 322         set = Collections.unmodifiableSet(set);
 323         options.put(MulticastSocket.class, set);
 324     }
 325 }