| /* | |
| * Copyright (c) 2016, 2024, 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 jdk.net.ExtendedSocketOptions.PlatformSocketOptions; | |
| import java.io.IOException; | |
| import java.net.DatagramSocket; | |
| import java.net.MulticastSocket; | |
| import java.net.ServerSocket; | |
| import java.net.Socket; | |
| import java.net.SocketOption; | |
| import java.net.StandardSocketOptions; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.HashSet; | |
| import java.util.Map; | |
| import java.util.Set; | |
| /** | |
| * 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. | |
| * | |
| * @deprecated | |
| * Java SE 9 added standard methods to set/get socket options, and retrieve the per-Socket | |
| * supported options effectively rendering this API redundant. Please refer to the corresponding | |
| * socket's class for the equivalent method to set/get a socket option or retrieve available socket options. | |
| * | |
| * @see java.nio.channels.NetworkChannel | |
| * | |
| * @since 1.8 | |
| */ | |
| @Deprecated(since = "16") | |
| 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. | |
| * @param <T> The type 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, or socket is closed. | |
| * | |
| * @throws NullPointerException if name is null | |
| * | |
| * @deprecated use {@link java.net.Socket#setOption(SocketOption, Object)} instead. | |
| * | |
| * @see java.net.StandardSocketOptions | |
| */ | |
| @Deprecated(since = "16") | |
| 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 | |
| * @param <T> The type of 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 | |
| * | |
| * @deprecated use {@link java.net.Socket#getOption(SocketOption)} instead. | |
| * | |
| * @see java.net.StandardSocketOptions | |
| */ | |
| @Deprecated(since = "16") | |
| 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 | |
| * @param <T> The type 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 | |
| * | |
| * @deprecated use {@link java.net.ServerSocket#setOption(SocketOption, Object)} instead. | |
| * | |
| * @see java.net.StandardSocketOptions | |
| */ | |
| @Deprecated(since = "16") | |
| 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 | |
| * @param <T> The type of 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 | |
| * | |
| * @deprecated use {@link java.net.ServerSocket#getOption(SocketOption)} instead. | |
| * | |
| * @see java.net.StandardSocketOptions | |
| */ | |
| @Deprecated(since = "16") | |
| 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 | |
| * @param <T> The type 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 | |
| * | |
| * @deprecated use {@link java.net.DatagramSocket#setOption(SocketOption, Object)} instead. | |
| * | |
| * @see java.net.StandardSocketOptions | |
| */ | |
| @Deprecated(since = "16") | |
| 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 | |
| * @param <T> The type of 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 | |
| * | |
| * @deprecated use {@link java.net.DatagramSocket#getOption(SocketOption)} instead. | |
| * | |
| * @see java.net.StandardSocketOptions | |
| */ | |
| @Deprecated(since = "16") | |
| 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 | |
| * | |
| * @return A set of socket options | |
| * | |
| * @throws IllegalArgumentException if socketType is not a valid | |
| * socket type from the java.net package. | |
| * | |
| * @deprecated use {@link Socket#supportedOptions()}, {@link ServerSocket#supportedOptions()}, | |
| * or {@link DatagramSocket#supportedOptions()} instead. | |
| */ | |
| @Deprecated(since = "16", forRemoval=true) | |
| 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 incomingNapiIdsupported = PlatformSocketOptions.get().incomingNapiIdSupported(); | |
| 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 (QuickAck.available) { | |
| set.add(ExtendedSocketOptions.TCP_QUICKACK); | |
| } | |
| if (KeepAliveOptions.AVAILABLE) { | |
| set.addAll(Set.of(ExtendedSocketOptions.TCP_KEEPCOUNT, | |
| ExtendedSocketOptions.TCP_KEEPIDLE, | |
| ExtendedSocketOptions.TCP_KEEPINTERVAL)); | |
| } | |
| if (incomingNapiIdsupported) { | |
| set.add(ExtendedSocketOptions.SO_INCOMING_NAPI_ID); | |
| } | |
| 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); | |
| if (incomingNapiIdsupported) { | |
| set.add(ExtendedSocketOptions.SO_INCOMING_NAPI_ID); | |
| } | |
| 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 (incomingNapiIdsupported) { | |
| set.add(ExtendedSocketOptions.SO_INCOMING_NAPI_ID); | |
| } | |
| 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); | |
| set = Collections.unmodifiableSet(set); | |
| options.put(MulticastSocket.class, set); | |
| return Collections.unmodifiableMap(options); | |
| } | |
| /** | |
| * 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. | |
| */ | |
| 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)); | |
| } | |
| } | |
| } |