Summary
-------
Replace the underlying implementation used by the `java.net.DatagramSocket` and `java.net.MulticastSocket` APIs with a simpler and more modern implementation that are easier to maintain and debug. The new implementation will be easy to adapt to work with virtual threads, currently being explored in [Project Loom.][1] This is a follow-on to [JEP 353][2], which already reimplemented the legacy `Socket` API.
Problem
-------
The `java.net.DatagramSocket` and `java.net.MulticastSocket` APIs, and their underlying implementation, date back to JDK 1.0. The implementation is a mix of legacy Java and C code that is painful to maintain and debug. In the context of a future world of virtual threads that park instead of block underlying kernel threads in system calls, the current implementation is not fit for purpose. As datagram-based transports gain traction again (e.g. [QUIC][3]), a simpler and more maintainable implementation is needed.
Solution
--------
Currently, the `DatagramSocket` and `MulticastSocket` classes delegate all socket calls to a `java.net.DatagramSocketImpl` implementation, for which different platform-specific concrete implementations exist: `PlainDatagramSocketImpl` on Unix platforms, and `TwoStackPlainDatagramSocketImpl` and `DualPlainDatagramSocketImpl` on Windows platforms.
Rather than provide a drop-in replacement for implementations of `DatagramSocketImpl`, similar to what was done in JEP 353 for `SocketImpl`, this JEP proposes to make `DatagramSocket` internally wrap another instance of `DatagramSocket` to which it delegates all calls directly. The wrapped instance is either a socket adapter created from a NIO `DatagramChannel::socket` (the new implementation), or else a clone of the legacy `DatagramSocket` class which then delegates to the legacy `DatagramSocketImpl` implementation (for the purpose of implementing a backward compatibility switch). If a `DatagramSocketImplFactory` is installed by an application, the old legacy implementation is selected. Otherwise, the new implementation is selected and used by default. To reduce the risk of switching the implementation after more than twenty years, the legacy implementation will not be removed.
Specification
-------------
There are no Java SE specification changes. Some preparatory work to clarify the specifications of `DatagramSocket` and `MulticastSocket`, and to minimize the behavioral differences between these classes and the `DatagramChannel::socket` adapter, has already been done in JDK 14 and JDK 15, such as [JDK-8222829][4], [JDK-8233191][5], etc.
A JDK-specific system property, `jdk.net.usePlainDatagramSocketImpl`, is introduced to configure the JDK to use the legacy implementation. If set with no value or set to the value "true" at startup, the legacy implementation is used. Otherwise, the new (NIO-based) implementation is used. The new implementation is enabled by default. It provides non-interruptible behavior for datagram and multicast sockets by directly using the platform-default implementation of the selector provider (`sun.nio.ch.SelectorProviderImpl` and `sun.nio.ch.DatagramChannelImpl`). Installing a custom selector provider will thus have no effect on `DatagramSocket` and `MulticastSocket`.
In addition, an implementation note will be added to the `DatagramSocketImpl` class description:
/**
* Abstract datagram and multicast socket implementation base class.
+ *
+ * @implNote Sockets created with the {@code DatagramSocket} and {@code
+ * MulticastSocket} public constructors historically delegated all socket
+ * operations to a {@code DatagramSocketImpl} implementation named
+ * "PlainDatagramSocketImpl". {@code DatagramSocket} and {@code MulticastSocket}
+ * have since been changed to a new implementation based on {@code DatagramChannel}.
+ * The JDK continues to ship with the older implementation to allow code to run
+ * that depends on unspecified behavior that differs between the old and new
+ * implementations. The old implementation will be used if the Java virtual
+ * machine is started with the system property {@systemProperty
+ * jdk.net.usePlainDatagramSocketImpl} set to use the old implementation. It may
+ * also be set in the JDK's network configuration file, located in {@code
+ * ${java.home}/conf/net.properties}. The value of the property is the string
+ * representation of a boolean. If set without a value then it defaults to {@code
+ * true}, hence running with {@code -Djdk.net.usePlainDatagramSocketImpl} or
+ * {@code -Djdk.net.usePlainDatagramSocketImpl=true} will configure the Java
+ * virtual machine to use the old implementation. The property and old
+ * implementation will be removed in a future version.
+ *
* @author Pavani Diwanji
* @since 1.1
*/
[1]: https://openjdk.java.net/projects/loom/
[2]: https://openjdk.java.net/jeps/353
[3]: https://en.wikipedia.org/wiki/QUIC
[4]: https://bugs.openjdk.java.net/browse/JDK-8222829
[5]: https://bugs.openjdk.java.net/browse/JDK-8233191