| /* |
| * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package jdk.net; |
| |
| import java.net.*; |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Map; |
| import java.util.Set; |
| import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; |
| |
| /** |
| * Defines static methods to set and get socket options defined by the |
| * {@link java.net.SocketOption} interface. All of the standard options defined |
| * by {@link java.net.Socket}, {@link java.net.ServerSocket}, and |
| * {@link java.net.DatagramSocket} can be set this way, as well as additional |
| * or platform specific options supported by each socket type. |
| * <p> |
| * The {@link #supportedOptions(Class)} method can be called to determine |
| * the complete set of options available (per socket type) on the |
| * current system. |
| * <p> |
| * When a security manager is installed, some non-standard socket options |
| * may require a security permission before being set or get. |
| * The details are specified in {@link ExtendedSocketOptions}. No permission |
| * is required for {@link java.net.StandardSocketOptions}. |
| * |
| * @see java.nio.channels.NetworkChannel |
| */ |
| public class Sockets { |
| |
| private static final Map<Class<?>,Set<SocketOption<?>>> |
| options = optionSets(); |
| |
| private Sockets() {} |
| |
| /** |
| * Sets the value of a socket option on a {@link java.net.Socket} |
| * |
| * @param s the socket |
| * @param name The socket option |
| * @param value The value of the socket option. May be null for some |
| * options. |
| * |
| * @throws UnsupportedOperationException if the socket does not support |
| * the option. |
| * |
| * @throws IllegalArgumentException if the value is not valid for |
| * the option. |
| * |
| * @throws IOException if an I/O error occurs, or socket is closed. |
| * |
| * @throws SecurityException if a security manager is set and the |
| * caller does not have any required permission. |
| * |
| * @throws NullPointerException if name is null |
| * |
| * @see java.net.StandardSocketOptions |
| */ |
| public static <T> void setOption(Socket s, SocketOption<T> name, T value) throws IOException |
| { |
| s.setOption(name, value); |
| } |
| |
| /** |
| * Returns the value of a socket option from a {@link java.net.Socket} |
| * |
| * @param s the socket |
| * @param name The socket option |
| * |
| * @return The value of the socket option. |
| * |
| * @throws UnsupportedOperationException if the socket does not support |
| * the option. |
| * |
| * @throws IOException if an I/O error occurs |
| * |
| * @throws SecurityException if a security manager is set and the |
| * caller does not have any required permission. |
| * |
| * @throws NullPointerException if name is null |
| * |
| * @see java.net.StandardSocketOptions |
| */ |
| public static <T> T getOption(Socket s, SocketOption<T> name) throws IOException |
| { |
| return s.getOption(name); |
| } |
| |
| /** |
| * Sets the value of a socket option on a {@link java.net.ServerSocket} |
| * |
| * @param s the socket |
| * @param name The socket option |
| * @param value The value of the socket option. |
| * |
| * @throws UnsupportedOperationException if the socket does not support |
| * the option. |
| * |
| * @throws IllegalArgumentException if the value is not valid for |
| * the option. |
| * |
| * @throws IOException if an I/O error occurs |
| * |
| * @throws NullPointerException if name is null |
| * |
| * @throws SecurityException if a security manager is set and the |
| * caller does not have any required permission. |
| * |
| * @see java.net.StandardSocketOptions |
| */ |
| public static <T> void setOption(ServerSocket s, SocketOption<T> name, T value) throws IOException |
| { |
| s.setOption(name, value); |
| } |
| |
| /** |
| * Returns the value of a socket option from a {@link java.net.ServerSocket} |
| * |
| * @param s the socket |
| * @param name The socket option |
| * |
| * @return The value of the socket option. |
| * |
| * @throws UnsupportedOperationException if the socket does not support |
| * the option. |
| * |
| * @throws IOException if an I/O error occurs |
| * |
| * @throws NullPointerException if name is null |
| * |
| * @throws SecurityException if a security manager is set and the |
| * caller does not have any required permission. |
| * |
| * @see java.net.StandardSocketOptions |
| */ |
| public static <T> T getOption(ServerSocket s, SocketOption<T> name) throws IOException |
| { |
| return s.getOption(name); |
| } |
| |
| /** |
| * Sets the value of a socket option on a {@link java.net.DatagramSocket} |
| * or {@link java.net.MulticastSocket} |
| * |
| * @param s the socket |
| * @param name The socket option |
| * @param value The value of the socket option. |
| * |
| * @throws UnsupportedOperationException if the socket does not support |
| * the option. |
| * |
| * @throws IllegalArgumentException if the value is not valid for |
| * the option. |
| * |
| * @throws IOException if an I/O error occurs |
| * |
| * @throws NullPointerException if name is null |
| * |
| * @throws SecurityException if a security manager is set and the |
| * caller does not have any required permission. |
| * |
| * @see java.net.StandardSocketOptions |
| */ |
| public static <T> void setOption(DatagramSocket s, SocketOption<T> name, T value) throws IOException |
| { |
| s.setOption(name, value); |
| } |
| |
| /** |
| * Returns the value of a socket option from a |
| * {@link java.net.DatagramSocket} or {@link java.net.MulticastSocket} |
| * |
| * @param s the socket |
| * @param name The socket option |
| * |
| * @return The value of the socket option. |
| * |
| * @throws UnsupportedOperationException if the socket does not support |
| * the option. |
| * |
| * @throws IOException if an I/O error occurs |
| * |
| * @throws NullPointerException if name is null |
| * |
| * @throws SecurityException if a security manager is set and the |
| * caller does not have any required permission. |
| * |
| * @see java.net.StandardSocketOptions |
| */ |
| public static <T> T getOption(DatagramSocket s, SocketOption<T> name) throws IOException |
| { |
| return s.getOption(name); |
| } |
| |
| /** |
| * Returns a set of {@link java.net.SocketOption}s supported by the |
| * given socket type. This set may include standard options and also |
| * non standard extended options. |
| * |
| * @param socketType the type of java.net socket |
| * |
| * @throws IllegalArgumentException if socketType is not a valid |
| * socket type from the java.net package. |
| */ |
| public static Set<SocketOption<?>> supportedOptions(Class<?> socketType) { |
| Set<SocketOption<?>> set = options.get(socketType); |
| if (set == null) { |
| throw new IllegalArgumentException("unknown socket type"); |
| } |
| return set; |
| } |
| |
| private static void checkValueType(Object value, Class<?> type) { |
| if (!type.isAssignableFrom(value.getClass())) { |
| String s = "Found: " + value.getClass().toString() + " Expected: " |
| + type.toString(); |
| throw new IllegalArgumentException(s); |
| } |
| } |
| |
| private static volatile boolean checkedReusePort; |
| private static volatile boolean isReusePortAvailable; |
| |
| /** |
| * Tells whether SO_REUSEPORT is supported. |
| */ |
| static boolean isReusePortAvailable() { |
| if (!checkedReusePort) { |
| Set<SocketOption<?>> s = new Socket().supportedOptions(); |
| isReusePortAvailable = s.contains(StandardSocketOptions.SO_REUSEPORT); |
| checkedReusePort = true; |
| } |
| return isReusePortAvailable; |
| } |
| |
| private static Map<Class<?>,Set<SocketOption<?>>> optionSets() { |
| Map<Class<?>,Set<SocketOption<?>>> options = new HashMap<>(); |
| boolean flowsupported = PlatformSocketOptions.get().flowSupported(); |
| boolean reuseportsupported = isReusePortAvailable(); |
| // Socket |
| |
| Set<SocketOption<?>> set = new HashSet<>(); |
| set.add(StandardSocketOptions.SO_KEEPALIVE); |
| set.add(StandardSocketOptions.SO_SNDBUF); |
| set.add(StandardSocketOptions.SO_RCVBUF); |
| set.add(StandardSocketOptions.SO_REUSEADDR); |
| if (reuseportsupported) { |
| set.add(StandardSocketOptions.SO_REUSEPORT); |
| } |
| set.add(StandardSocketOptions.SO_LINGER); |
| set.add(StandardSocketOptions.IP_TOS); |
| set.add(StandardSocketOptions.TCP_NODELAY); |
| if (flowsupported) { |
| set.add(ExtendedSocketOptions.SO_FLOW_SLA); |
| } |
| set = Collections.unmodifiableSet(set); |
| options.put(Socket.class, set); |
| |
| // ServerSocket |
| |
| set = new HashSet<>(); |
| set.add(StandardSocketOptions.SO_RCVBUF); |
| set.add(StandardSocketOptions.SO_REUSEADDR); |
| if (reuseportsupported) { |
| set.add(StandardSocketOptions.SO_REUSEPORT); |
| } |
| set.add(StandardSocketOptions.IP_TOS); |
| set = Collections.unmodifiableSet(set); |
| options.put(ServerSocket.class, set); |
| |
| // DatagramSocket |
| |
| set = new HashSet<>(); |
| set.add(StandardSocketOptions.SO_SNDBUF); |
| set.add(StandardSocketOptions.SO_RCVBUF); |
| set.add(StandardSocketOptions.SO_REUSEADDR); |
| if (reuseportsupported) { |
| set.add(StandardSocketOptions.SO_REUSEPORT); |
| } |
| set.add(StandardSocketOptions.IP_TOS); |
| if (flowsupported) { |
| set.add(ExtendedSocketOptions.SO_FLOW_SLA); |
| } |
| set = Collections.unmodifiableSet(set); |
| options.put(DatagramSocket.class, set); |
| |
| // MulticastSocket |
| |
| set = new HashSet<>(); |
| set.add(StandardSocketOptions.SO_SNDBUF); |
| set.add(StandardSocketOptions.SO_RCVBUF); |
| set.add(StandardSocketOptions.SO_REUSEADDR); |
| if (reuseportsupported) { |
| set.add(StandardSocketOptions.SO_REUSEPORT); |
| } |
| set.add(StandardSocketOptions.IP_TOS); |
| set.add(StandardSocketOptions.IP_MULTICAST_IF); |
| set.add(StandardSocketOptions.IP_MULTICAST_TTL); |
| set.add(StandardSocketOptions.IP_MULTICAST_LOOP); |
| if (flowsupported) { |
| set.add(ExtendedSocketOptions.SO_FLOW_SLA); |
| } |
| set = Collections.unmodifiableSet(set); |
| options.put(MulticastSocket.class, set); |
| |
| return Collections.unmodifiableMap(options); |
| } |
| } |