/*
* Copyright (c) 2016, 2018, 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 SocketOption
interface. All of the standard options defined by Socket
, ServerSocket
, and DatagramSocket
can be set this way, as well as additional or platform specific options supported by each socket type. The supportedOptions(Class<?>)
method can be called to determine the complete set of options available (per socket type) on the current system.
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 ExtendedSocketOptions
. No permission is required for StandardSocketOptions
.
See Also:
/**
* 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 Socket
Params: - s – the socket
- name – The socket option
- value – The value of the socket option. May be null for some
options.
Throws: - UnsupportedOperationException – if the socket does not support
the option.
- IllegalArgumentException – if the value is not valid for
the option.
- IOException – if an I/O error occurs, or socket is closed.
- SecurityException – if a security manager is set and the
caller does not have any required permission.
- NullPointerException – if name is null
See Also:
/**
* 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 Socket
Params: - s – the socket
- name – The socket option
Throws: - UnsupportedOperationException – if the socket does not support
the option.
- IOException – if an I/O error occurs
- SecurityException – if a security manager is set and the
caller does not have any required permission.
- NullPointerException – if name is null
See Also: Returns: The value of the socket option.
/**
* 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 ServerSocket
Params: - s – the socket
- name – The socket option
- value – The value of the socket option.
Throws: - UnsupportedOperationException – if the socket does not support
the option.
- IllegalArgumentException – if the value is not valid for
the option.
- IOException – if an I/O error occurs
- NullPointerException – if name is null
- SecurityException – if a security manager is set and the
caller does not have any required permission.
See Also:
/**
* 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 ServerSocket
Params: - s – the socket
- name – The socket option
Throws: - UnsupportedOperationException – if the socket does not support
the option.
- IOException – if an I/O error occurs
- NullPointerException – if name is null
- SecurityException – if a security manager is set and the
caller does not have any required permission.
See Also: Returns: The value of the socket option.
/**
* 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 DatagramSocket
or MulticastSocket
Params: - s – the socket
- name – The socket option
- value – The value of the socket option.
Throws: - UnsupportedOperationException – if the socket does not support
the option.
- IllegalArgumentException – if the value is not valid for
the option.
- IOException – if an I/O error occurs
- NullPointerException – if name is null
- SecurityException – if a security manager is set and the
caller does not have any required permission.
See Also:
/**
* 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 DatagramSocket
or MulticastSocket
Params: - s – the socket
- name – The socket option
Throws: - UnsupportedOperationException – if the socket does not support
the option.
- IOException – if an I/O error occurs
- NullPointerException – if name is null
- SecurityException – if a security manager is set and the
caller does not have any required permission.
See Also: Returns: The value of the socket option.
/**
* 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 SocketOption
s supported by the given socket type. This set may include standard options and also non standard extended options. Params: - socketType – the type of java.net socket
Throws: - IllegalArgumentException – if socketType is not a valid
socket type from the java.net package.
/**
* 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.
/**
* 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);
}
if (QuickAck.available) {
set.add(ExtendedSocketOptions.TCP_QUICKACK);
}
if (KeepAliveOptions.AVAILABLE) {
set.addAll(Set.of(ExtendedSocketOptions.TCP_KEEPCOUNT,
ExtendedSocketOptions.TCP_KEEPIDLE,
ExtendedSocketOptions.TCP_KEEPINTERVAL));
}
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);
}
if (QuickAck.available) {
set.add(ExtendedSocketOptions.TCP_QUICKACK);
}
if (KeepAliveOptions.AVAILABLE) {
set.addAll(Set.of(ExtendedSocketOptions.TCP_KEEPCOUNT,
ExtendedSocketOptions.TCP_KEEPIDLE,
ExtendedSocketOptions.TCP_KEEPINTERVAL));
}
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);
}
Tells whether TCP_QUICKACK is supported.
/**
* Tells whether TCP_QUICKACK is supported.
*/
static class QuickAck {
static final boolean available;
static {
Set<SocketOption<?>> s = new Socket().supportedOptions();
available = s.contains(ExtendedSocketOptions.TCP_QUICKACK);
}
}
Tells whether TCP_KEEPALIVE options are supported.
/**
* Tells whether TCP_KEEPALIVE options are supported.
*/
static class KeepAliveOptions {
static final boolean AVAILABLE;
static {
Set<SocketOption<?>> s = new Socket().supportedOptions();
AVAILABLE = s.containsAll(Set.of(ExtendedSocketOptions.TCP_KEEPCOUNT,
ExtendedSocketOptions.TCP_KEEPIDLE,
ExtendedSocketOptions.TCP_KEEPINTERVAL));
}
}
}