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