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