mptcp.lists.linux.dev archive mirror
 help / color / mirror / Atom feed
* [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API
@ 2025-08-28  8:47 Geliang Tang
  2025-08-28  8:47 ` [PATCH mptcp-next v2 1/3] Add native MPTCP socket creation support Geliang Tang
                   ` (3 more replies)
  0 siblings, 4 replies; 7+ messages in thread
From: Geliang Tang @ 2025-08-28  8:47 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang

From: Geliang Tang <tanggeliang@kylinos.cn>

v2:
 - drop redundant helpers as Matt suggested.
 - squash into fewer patches.
 - use "JNI_TRUE" and "(void)mptcp" in Java_sun_nio_ch_Net_socket0 as
   Xiang Gao suggested.

The Multipath TCP (MPTCP) protocol (v1 / RFC 8684) has been added in
the upstream Linux kernel since v5.6. See https://mptcp.dev.

This patch series introduces comprehensive Multipath TCP (MPTCP)
support to the Java Networking API, enabling applications to leverage
MPTCP's capabilities for improved reliability and throughput.

Geliang Tang (3):
  Add native MPTCP socket creation support
  Add MPTCP support to Java Socket/ServerSocket APIs
  Add test cases for MPTCP socket functionality

 .../share/classes/java/net/ServerSocket.java  | 52 +++++++++++++--
 .../share/classes/java/net/Socket.java        | 65 +++++++++++++++++--
 .../share/classes/java/net/SocketImpl.java    |  4 +-
 .../share/classes/sun/nio/ch/Net.java         | 19 ++++--
 .../classes/sun/nio/ch/NioSocketImpl.java     | 11 +++-
 src/java.base/unix/native/libnio/ch/Net.c     | 14 +++-
 src/java.base/windows/native/libnio/ch/Net.c  |  4 +-
 .../java/net/ServerSocket/MPTCPServer.java    | 58 +++++++++++++++++
 test/jdk/java/net/Socket/MPTCPClient.java     | 62 ++++++++++++++++++
 9 files changed, 264 insertions(+), 25 deletions(-)
 create mode 100644 test/jdk/java/net/ServerSocket/MPTCPServer.java
 create mode 100644 test/jdk/java/net/Socket/MPTCPClient.java

-- 
2.48.1


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH mptcp-next v2 1/3] Add native MPTCP socket creation support
  2025-08-28  8:47 [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Geliang Tang
@ 2025-08-28  8:47 ` Geliang Tang
  2025-08-28  8:47 ` [PATCH mptcp-next v2 2/3] Add MPTCP support to Java Socket/ServerSocket APIs Geliang Tang
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 7+ messages in thread
From: Geliang Tang @ 2025-08-28  8:47 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang, Gang Yan, Xiang Gao

This patch introduces native-level support for creating MPTCP sockets by:

1. Extending the socket0 native method in both Unix and Windows
   implementations to accept an mptcp parameter
2. Adding new overloaded socket() and serverSocket() methods in
   Net.java that support explicit MPTCP enabling
3. Introducing convenience methods mptcpSocket() and mptcpServerSocket()
   for easier MPTCP socket creation

When MPTCP is enabled and supported by the OS, the socket is created with
the IPPROTO_MPTCP protocol for stream sockets. All existing call sites
are updated to pass 'false' for the mptcp parameter to maintain backward
compatibility.

Co-Developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Co-Developed-by: Xiang Gao <gaoxiang@kylinos.cn>
Signed-off-by: Xiang Gao <gaoxiang@kylinos.cn>
Signed-off-by: Geliang Tang <geliang@kernel.org>
---
 .../share/classes/sun/nio/ch/Net.java         | 19 ++++++++++++++-----
 src/java.base/unix/native/libnio/ch/Net.c     | 14 ++++++++++++--
 src/java.base/windows/native/libnio/ch/Net.c  |  4 +++-
 3 files changed, 29 insertions(+), 8 deletions(-)

diff --git a/src/java.base/share/classes/sun/nio/ch/Net.java b/src/java.base/share/classes/sun/nio/ch/Net.java
index 9ec7975a35c..20caa62859f 100644
--- a/src/java.base/share/classes/sun/nio/ch/Net.java
+++ b/src/java.base/share/classes/sun/nio/ch/Net.java
@@ -485,25 +485,34 @@ static FileDescriptor socket() throws IOException {
         return socket(UNSPEC, true);
     }
 
-    static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOException {
+    static FileDescriptor socket(ProtocolFamily family, boolean stream, boolean mptcp)
+	throws IOException {
         boolean preferIPv6 = isIPv6Available() &&
             (family != StandardProtocolFamily.INET);
-        return IOUtil.newFD(socket0(preferIPv6, stream, false, FAST_LOOPBACK));
+        return IOUtil.newFD(socket0(preferIPv6, stream, false, FAST_LOOPBACK, mptcp));
+    }
+
+    static FileDescriptor socket(ProtocolFamily family, boolean stream) throws IOException {
+        return socket(family, stream, false);
     }
 
     static FileDescriptor serverSocket() {
         return serverSocket(UNSPEC);
     }
 
-    static FileDescriptor serverSocket(ProtocolFamily family) {
+    static FileDescriptor serverSocket(ProtocolFamily family, boolean mptcp) {
         boolean preferIPv6 = isIPv6Available() &&
             (family != StandardProtocolFamily.INET);
-        return IOUtil.newFD(socket0(preferIPv6, true, true, FAST_LOOPBACK));
+        return IOUtil.newFD(socket0(preferIPv6, true, true, FAST_LOOPBACK, mptcp));
+    }
+
+    static FileDescriptor serverSocket(ProtocolFamily family) {
+        return serverSocket(family, false);
     }
 
     // Due to oddities SO_REUSEADDR on Windows reuse is ignored
     private static native int socket0(boolean preferIPv6, boolean stream, boolean reuse,
-                                      boolean fastLoopback);
+                                      boolean fastLoopback, boolean mptcp);
 
     public static void bind(FileDescriptor fd, InetAddress addr, int port)
         throws IOException
diff --git a/src/java.base/unix/native/libnio/ch/Net.c b/src/java.base/unix/native/libnio/ch/Net.c
index 28c1814f422..1c53c197fd8 100644
--- a/src/java.base/unix/native/libnio/ch/Net.c
+++ b/src/java.base/unix/native/libnio/ch/Net.c
@@ -255,13 +255,23 @@ Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass c
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
-                            jboolean stream, jboolean reuse, jboolean ignored)
+                            jboolean stream, jboolean reuse, jboolean ignored,
+                            jboolean mptcp)
 {
     int fd;
     int type = (stream ? SOCK_STREAM : SOCK_DGRAM);
     int domain = (ipv6_available() && preferIPv6) ? AF_INET6 : AF_INET;
+    int protocol = 0;
 
-    fd = socket(domain, type, 0);
+#if defined(__linux__) && defined(IPPROTO_MPTCP)
+    if (stream == JNI_TRUE && mptcp == JNI_TRUE) {
+        protocol = IPPROTO_MPTCP;
+    }
+#else
+    (void)mptcp; /* Avoid compile warning when MPTCP is not supported */
+#endif
+
+    fd = socket(domain, type, protocol);
     if (fd < 0) {
         return handleSocketError(env, errno);
     }
diff --git a/src/java.base/windows/native/libnio/ch/Net.c b/src/java.base/windows/native/libnio/ch/Net.c
index 814f502c48a..5b9ecdd2c77 100644
--- a/src/java.base/windows/native/libnio/ch/Net.c
+++ b/src/java.base/windows/native/libnio/ch/Net.c
@@ -152,11 +152,13 @@ Java_sun_nio_ch_Net_canUseIPv6OptionsWithIPv4LocalAddress0(JNIEnv* env, jclass c
 
 JNIEXPORT jint JNICALL
 Java_sun_nio_ch_Net_socket0(JNIEnv *env, jclass cl, jboolean preferIPv6,
-                            jboolean stream, jboolean reuse, jboolean fastLoopback)
+                            jboolean stream, jboolean reuse, jboolean fastLoopback,
+                            jboolean mptcp)
 {
     SOCKET s;
     int domain = (preferIPv6) ? AF_INET6 : AF_INET;
 
+    (void)mptcp; /* not support MPTCP yet */
     s = socket(domain, (stream ? SOCK_STREAM : SOCK_DGRAM), 0);
     if (s != INVALID_SOCKET) {
         SetHandleInformation((HANDLE)s, HANDLE_FLAG_INHERIT, 0);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH mptcp-next v2 2/3] Add MPTCP support to Java Socket/ServerSocket APIs
  2025-08-28  8:47 [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Geliang Tang
  2025-08-28  8:47 ` [PATCH mptcp-next v2 1/3] Add native MPTCP socket creation support Geliang Tang
@ 2025-08-28  8:47 ` Geliang Tang
  2025-08-28  8:47 ` [PATCH mptcp-next v2 3/3] Add test cases for MPTCP socket functionality Geliang Tang
  2025-08-28  9:57 ` [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Matthieu Baerts
  3 siblings, 0 replies; 7+ messages in thread
From: Geliang Tang @ 2025-08-28  8:47 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang, Gang Yan

This patch integrates MPTCP support into the Java socket API by:

1. Adding new constructors in Socket and ServerSocket that accept an mptcp
   parameter to enable MPTCP explicitly
2. Extending NioSocketImpl to track the MPTCP state and use the appropriate
   native methods for socket creation
3. Propagating the MPTCP flag through the socket creation chain via new
   createImpl() factory methods
4. Ensuring backward compatibility by keeping existing constructors
   unchanged

The implementation allows Java applications to use MPTCP seamlessly while
maintaining full compatibility with existing TCP-based code.

Co-Developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <geliang@kernel.org>
---
 .../share/classes/java/net/ServerSocket.java  | 52 +++++++++++++--
 .../share/classes/java/net/Socket.java        | 65 +++++++++++++++++--
 .../share/classes/java/net/SocketImpl.java    |  4 +-
 .../classes/sun/nio/ch/NioSocketImpl.java     | 11 +++-
 4 files changed, 115 insertions(+), 17 deletions(-)

diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java
index 945693ef65e..bc3c81a3663 100644
--- a/src/java.base/share/classes/java/net/ServerSocket.java
+++ b/src/java.base/share/classes/java/net/ServerSocket.java
@@ -107,7 +107,7 @@ protected ServerSocket(SocketImpl impl) {
      * @throws    IOException IO error when opening the socket.
      */
     public ServerSocket() throws IOException {
-        this.impl = createImpl();
+        this.impl = createImpl(false);
     }
 
     /**
@@ -212,12 +212,52 @@ public ServerSocket(int port, int backlog) throws IOException {
      */
     @SuppressWarnings("this-escape")
     public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException {
+        this(port, backlog, bindAddr, false);
+    }
+
+    /**
+     * Create a server using <i>mptcp</i> (Multipath TCP) or TCP protocol with
+     * the specified port, listen backlog, and local IP address to bind to.
+     * The <i>bindAddr</i> argument can be used on a multi-homed host for a
+     * ServerSocket that will only accept connect requests to one of its addresses.
+     * If <i>bindAddr</i> is null, it will default accepting
+     * connections on any/all local addresses.
+     * The port must be between 0 and 65535, inclusive.
+     * A port number of {@code 0} means that the port number is
+     * automatically allocated, typically from an ephemeral port range.
+     * This port number can then be retrieved by calling
+     * {@link #getLocalPort getLocalPort}.
+     *
+     * The {@code backlog} argument is the requested maximum number of
+     * pending connections on the socket. Its exact semantics are implementation
+     * specific. In particular, an implementation may impose a maximum length
+     * or may choose to ignore the parameter altogether. The value provided
+     * should be greater than {@code 0}. If it is less than or equal to
+     * {@code 0}, then an implementation specific default will be used.
+     *
+     * The {@code mptcp} argument is used to control whether to create a socket
+     * with MPTCP or TCP protocol.
+     *
+     * @param port  the port number, or {@code 0} to use a port
+     *              number that is automatically allocated.
+     * @param backlog requested maximum length of the queue of incoming
+     *                connections.
+     * @param bindAddr the local InetAddress the server will bind to
+     * @param mptcp create a socket with MPTCP or TCP protocol.
+     *
+     * @throws  IOException if an I/O error occurs when opening the socket.
+     * @throws     IllegalArgumentException if the port parameter is outside
+     *             the specified range of valid port values, which is between
+     *             0 and 65535, inclusive.
+     */
+    @SuppressWarnings("this-escape")
+    public ServerSocket(int port, int backlog, InetAddress bindAddr, boolean mptcp) throws IOException {
         if (port < 0 || port > 0xFFFF)
             throw new IllegalArgumentException("Port value out of range: " + port);
         if (backlog < 1)
             backlog = 50;
 
-        this.impl = createImpl();
+        this.impl = createImpl(mptcp);
         try {
             bind(new InetSocketAddress(bindAddr, port), backlog);
         } catch (IOException e) {
@@ -229,13 +269,15 @@ public ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOExcept
     /**
      * Create a SocketImpl for a server socket. The SocketImpl is created
      * without an underlying socket.
+     *
+     * @param mptcp create a socket with MPTCP or TCP protocol.
      */
-    private static SocketImpl createImpl() {
+    private static SocketImpl createImpl(boolean mptcp) {
         SocketImplFactory factory = ServerSocket.factory;
         if (factory != null) {
             return factory.createSocketImpl();
         } else {
-            return SocketImpl.createPlatformSocketImpl(true);
+            return SocketImpl.createPlatformSocketImpl(true, mptcp);
         }
     }
 
@@ -556,7 +598,7 @@ private SocketImpl platformImplAccept() throws IOException {
         assert impl instanceof PlatformSocketImpl;
 
         // create a new platform SocketImpl and accept the connection
-        SocketImpl psi = SocketImpl.createPlatformSocketImpl(false);
+        SocketImpl psi = SocketImpl.createPlatformSocketImpl(false, false);
         implAccept(psi);
         return psi;
     }
diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java
index 692c3395f78..c58ad348fd6 100644
--- a/src/java.base/share/classes/java/net/Socket.java
+++ b/src/java.base/share/classes/java/net/Socket.java
@@ -168,7 +168,7 @@ private static boolean isOutputShutdown(int s) {
      * @since   1.1
      */
     public Socket() {
-        this.impl = createImpl();
+        this.impl = createImpl(false);
     }
 
     /**
@@ -207,7 +207,7 @@ public Socket(Proxy proxy) {
                 checkAddress (epoint.getAddress(), "Socket");
             }
             // create a SOCKS or HTTP SocketImpl that delegates to a platform SocketImpl
-            SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
+            SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false, false);
             impl = (type == Proxy.Type.SOCKS) ? new SocksSocketImpl(p, delegate)
                                               : new HttpConnectSocketImpl(p, delegate, this);
         } else {
@@ -215,7 +215,7 @@ public Socket(Proxy proxy) {
                 // create a platform or custom SocketImpl for the DIRECT case
                 SocketImplFactory factory = Socket.factory;
                 if (factory == null) {
-                    impl = SocketImpl.createPlatformSocketImpl(false);
+                    impl = SocketImpl.createPlatformSocketImpl(false, false);
                 } else {
                     impl = factory.createSocketImpl();
                 }
@@ -403,6 +403,39 @@ public Socket(String host, int port, boolean stream) throws IOException {
              (SocketAddress) null, stream);
     }
 
+    /**
+     * Creates a stream socket and connects it to the specified port
+     * number on the named host using Multipath TCP (MPTCP) or TCP
+     * protocol.
+     * <p>
+     * If the specified host is {@code null} it is the equivalent of
+     * specifying the address as
+     * {@link java.net.InetAddress#getByName InetAddress.getByName}{@code (null)}.
+     * In other words, it is equivalent to specifying an address of the
+     * loopback interface. </p>
+     * <p>
+     * If the application has specified a {@linkplain SocketImplFactory client
+     * socket implementation factory}, that factory's
+     * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl}
+     * method is called to create the actual socket implementation. Otherwise
+     * a system-default socket implementation is created.
+     *
+     * @param      host     the host name, or {@code null} for the loopback address.
+     * @param      port     the port number.
+     * @param      stream   must be true, false is not allowed.
+     * @param      mptcp    create a socket with MPTCP or TCP protocol.
+     * @throws     IOException  if an I/O error occurs when creating the socket.
+     * @throws     IllegalArgumentException if the stream parameter is {@code false}
+     *             or if the port parameter is outside the specified range of valid
+     *             port values, which is between 0 and 65535, inclusive.
+     */
+    @SuppressWarnings("this-escape")
+    public Socket(String host, int port, boolean stream, boolean mptcp) throws IOException {
+        this(host != null ? new InetSocketAddress(host, port) :
+               new InetSocketAddress(InetAddress.getByName(null), port),
+             (SocketAddress) null, stream, mptcp);
+    }
+
     /**
      * Creates a socket and connects it to the specified port number at
      * the specified IP address.
@@ -442,6 +475,22 @@ public Socket(InetAddress host, int port, boolean stream) throws IOException {
      */
     private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)
         throws IOException
+    {
+        this(address, localAddr, stream, false);
+    }
+
+    /**
+     * Initialize a new Socket that is connected to the given remote address.
+     * The MPTCP or TCP protocol socket is optionally bound to a local address
+     * before connecting.
+     *
+     * @param address the remote address to connect to
+     * @param localAddr the local address to bind to, can be null
+     * @param stream true for a stream socket, false for a datagram socket
+     * @param mptcp create a socket with MPTCP or TCP protocol
+     */
+    private Socket(SocketAddress address, SocketAddress localAddr, boolean stream, boolean mptcp)
+        throws IOException
     {
         Objects.requireNonNull(address);
         if (!stream) {
@@ -451,7 +500,7 @@ private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)
         assert address instanceof InetSocketAddress;
 
         // create the SocketImpl and the underlying socket
-        SocketImpl impl = createImpl();
+        SocketImpl impl = createImpl(mptcp);
         impl.create(stream);
 
         this.impl = impl;
@@ -471,14 +520,16 @@ private Socket(SocketAddress address, SocketAddress localAddr, boolean stream)
     /**
      * Create a new SocketImpl for a connecting/client socket. The SocketImpl
      * is created without an underlying socket.
+     *
+     * @param mptcp create a socket with MPTCP or TCP protocol.
      */
-    private static SocketImpl createImpl() {
+    private static SocketImpl createImpl(boolean mptcp) {
         SocketImplFactory factory = Socket.factory;
         if (factory != null) {
             return factory.createSocketImpl();
         } else {
             // create a SOCKS SocketImpl that delegates to a platform SocketImpl
-            SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false);
+            SocketImpl delegate = SocketImpl.createPlatformSocketImpl(false, mptcp);
             return new SocksSocketImpl(delegate);
         }
     }
@@ -498,7 +549,7 @@ private SocketImpl getImpl() throws SocketException {
                     }
                     SocketImpl impl = this.impl;
                     if (impl == null) {
-                        this.impl = impl = createImpl();
+                        this.impl = impl = createImpl(false);
                     }
                     try {
                         impl.create(true);
diff --git a/src/java.base/share/classes/java/net/SocketImpl.java b/src/java.base/share/classes/java/net/SocketImpl.java
index 15c12457aac..f55034fb720 100644
--- a/src/java.base/share/classes/java/net/SocketImpl.java
+++ b/src/java.base/share/classes/java/net/SocketImpl.java
@@ -48,8 +48,8 @@ public abstract class SocketImpl implements SocketOptions {
      * Creates an instance of platform's SocketImpl
      */
     @SuppressWarnings("unchecked")
-    static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server) {
-        return (S) new NioSocketImpl(server);
+    static <S extends SocketImpl & PlatformSocketImpl> S createPlatformSocketImpl(boolean server, boolean mptcp) {
+        return (S) new NioSocketImpl(server, mptcp);
     }
 
     /**
diff --git a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
index dd81b356738..2916560f1b6 100644
--- a/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
+++ b/src/java.base/share/classes/sun/nio/ch/NioSocketImpl.java
@@ -86,6 +86,9 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp
     // true if this is a SocketImpl for a ServerSocket
     private final boolean server;
 
+    // true if this is a SocketImpl for a MptcpServerSocket
+    private final boolean mptcp;
+
     // Lock held when reading (also used when accepting or connecting)
     private final ReentrantLock readLock = new ReentrantLock();
 
@@ -128,9 +131,11 @@ public final class NioSocketImpl extends SocketImpl implements PlatformSocketImp
     /**
      * Creates an instance of this SocketImpl.
      * @param server true if this is a SocketImpl for a ServerSocket
+     * @param mptcp enable MPTCP
      */
-    public NioSocketImpl(boolean server) {
+    public NioSocketImpl(boolean server, boolean mptcp) {
         this.server = server;
+        this.mptcp = mptcp;
     }
 
     /**
@@ -468,9 +473,9 @@ protected void create(boolean stream) throws IOException {
                 throw new IOException("Already created");
             FileDescriptor fd;
             if (server) {
-                fd = Net.serverSocket();
+                fd = Net.serverSocket(Net.UNSPEC, mptcp);
             } else {
-                fd = Net.socket();
+                fd = Net.socket(Net.UNSPEC, true, mptcp);
             }
             Runnable closer = closerFor(fd);
             this.fd = fd;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH mptcp-next v2 3/3] Add test cases for MPTCP socket functionality
  2025-08-28  8:47 [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Geliang Tang
  2025-08-28  8:47 ` [PATCH mptcp-next v2 1/3] Add native MPTCP socket creation support Geliang Tang
  2025-08-28  8:47 ` [PATCH mptcp-next v2 2/3] Add MPTCP support to Java Socket/ServerSocket APIs Geliang Tang
@ 2025-08-28  8:47 ` Geliang Tang
  2025-08-28  9:57 ` [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Matthieu Baerts
  3 siblings, 0 replies; 7+ messages in thread
From: Geliang Tang @ 2025-08-28  8:47 UTC (permalink / raw)
  To: mptcp; +Cc: Geliang Tang, Gang Yan

This patch adds comprehensive test coverage for the MPTCP socket
implementation by introducing two test programs:

1. MPTCPServer.java - an echo server that uses MPTCP-enabled ServerSocket
2. MPTCPClient.java - a client that connects to the server using MPTCP
   Socket

The tests verify:
- MPTCP socket creation and connection establishment
- Bidirectional communication over MPTCP subflows
- Proper stream handling and error conditions
- Graceful shutdown and resource cleanup

These tests demonstrate the usage of the new MPTCP-enabled constructors and
provide a functional validation of the MPTCP implementation.

Co-Developed-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Gang Yan <yangang@kylinos.cn>
Signed-off-by: Geliang Tang <geliang@kernel.org>
---
 .../java/net/ServerSocket/MPTCPServer.java    | 58 +++++++++++++++++
 test/jdk/java/net/Socket/MPTCPClient.java     | 62 +++++++++++++++++++
 2 files changed, 120 insertions(+)
 create mode 100644 test/jdk/java/net/ServerSocket/MPTCPServer.java
 create mode 100644 test/jdk/java/net/Socket/MPTCPClient.java

diff --git a/test/jdk/java/net/ServerSocket/MPTCPServer.java b/test/jdk/java/net/ServerSocket/MPTCPServer.java
new file mode 100644
index 00000000000..a28e4963943
--- /dev/null
+++ b/test/jdk/java/net/ServerSocket/MPTCPServer.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2025, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.net.*;
+
+public class MPTCPServer {
+	public static void main(String[] args) {
+		final int PORT = 12345;
+
+		try (ServerSocket serverSocket = new ServerSocket(PORT, 50, null, true)) {
+			System.out.println("Server started, waiting for client connection ...");
+
+			Socket clientSocket = serverSocket.accept();
+			System.out.println("Client connected: " + clientSocket.getInetAddress());
+
+			BufferedReader in = new BufferedReader(
+					new InputStreamReader(clientSocket.getInputStream()));
+			PrintWriter out = new PrintWriter(
+					clientSocket.getOutputStream(), true);
+
+			String inputLine;
+			while ((inputLine = in.readLine()) != null) {
+				System.out.println("Received from client: " + inputLine);
+				out.println("Server response: " + inputLine);
+
+				if ("exit".equalsIgnoreCase(inputLine)) {
+					break;
+				}
+			}
+
+			clientSocket.close();
+			System.out.println("Connection closed");
+		} catch (IOException e) {
+			System.err.println("Server exception: " + e.getMessage());
+		}
+	}
+}
diff --git a/test/jdk/java/net/Socket/MPTCPClient.java b/test/jdk/java/net/Socket/MPTCPClient.java
new file mode 100644
index 00000000000..18d815c39e7
--- /dev/null
+++ b/test/jdk/java/net/Socket/MPTCPClient.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, 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.
+ *
+ * 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.
+ */
+
+import java.io.*;
+import java.net.*;
+
+public class MPTCPClient {
+    public static void main(String[] args) {
+        final String HOST = "localhost";
+        final int PORT = 12345;
+        
+        try (Socket socket = new Socket(HOST, PORT, true, true)) {
+            System.out.println("Connected to server");
+            
+            BufferedReader in = new BufferedReader(
+                new InputStreamReader(socket.getInputStream()));
+            PrintWriter out = new PrintWriter(
+                socket.getOutputStream(), true);
+            
+            BufferedReader stdIn = new BufferedReader(
+                new InputStreamReader(System.in));
+            
+            String userInput;
+            System.out.println("Enter message (type 'exit' to quit):");
+            while ((userInput = stdIn.readLine()) != null) {
+                out.println(userInput);
+                
+                System.out.println("Server response: " + in.readLine());
+                
+                if ("exit".equalsIgnoreCase(userInput)) {
+                    break;
+                }
+            }
+            
+            System.out.println("Connection closed");
+        } catch (UnknownHostException e) {
+            System.err.println("Host not found: " + HOST);
+        } catch (IOException e) {
+            System.err.println("Client I/O error: " + e.getMessage());
+        }
+    }
+}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API
  2025-08-28  8:47 [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Geliang Tang
                   ` (2 preceding siblings ...)
  2025-08-28  8:47 ` [PATCH mptcp-next v2 3/3] Add test cases for MPTCP socket functionality Geliang Tang
@ 2025-08-28  9:57 ` Matthieu Baerts
  2025-09-03  6:16   ` Geliang Tang
  3 siblings, 1 reply; 7+ messages in thread
From: Matthieu Baerts @ 2025-08-28  9:57 UTC (permalink / raw)
  To: Geliang Tang, mptcp; +Cc: Geliang Tang

Hi Geliang,

On 28/08/2025 10:47, Geliang Tang wrote:
> From: Geliang Tang <tanggeliang@kylinos.cn>
> 
> v2:
>  - drop redundant helpers as Matt suggested.
>  - squash into fewer patches.
>  - use "JNI_TRUE" and "(void)mptcp" in Java_sun_nio_ch_Net_socket0 as
>    Xiang Gao suggested.
> 
> The Multipath TCP (MPTCP) protocol (v1 / RFC 8684) has been added in
> the upstream Linux kernel since v5.6. See https://mptcp.dev.
> 
> This patch series introduces comprehensive Multipath TCP (MPTCP)
> support to the Java Networking API, enabling applications to leverage
> MPTCP's capabilities for improved reliability and throughput.

Thank you for the new version! Feel free to start the process to
upstream these patches [1]. Don't hesitate to share here the link to the
new ticket.

[1] https://openjdk.org/guide/#i-have-a-patch-what-do-i-do

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API
  2025-08-28  9:57 ` [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Matthieu Baerts
@ 2025-09-03  6:16   ` Geliang Tang
  2025-09-03 10:49     ` Matthieu Baerts
  0 siblings, 1 reply; 7+ messages in thread
From: Geliang Tang @ 2025-09-03  6:16 UTC (permalink / raw)
  To: Matthieu Baerts, mptcp

Hi Matt,

On Thu, 2025-08-28 at 11:57 +0200, Matthieu Baerts wrote:
> Hi Geliang,
> 
> On 28/08/2025 10:47, Geliang Tang wrote:
> > From: Geliang Tang <tanggeliang@kylinos.cn>
> > 
> > v2:
> >  - drop redundant helpers as Matt suggested.
> >  - squash into fewer patches.
> >  - use "JNI_TRUE" and "(void)mptcp" in Java_sun_nio_ch_Net_socket0
> > as
> >    Xiang Gao suggested.
> > 
> > The Multipath TCP (MPTCP) protocol (v1 / RFC 8684) has been added
> > in
> > the upstream Linux kernel since v5.6. See https://mptcp.dev.
> > 
> > This patch series introduces comprehensive Multipath TCP (MPTCP)
> > support to the Java Networking API, enabling applications to
> > leverage
> > MPTCP's capabilities for improved reliability and throughput.
> 
> Thank you for the new version! Feel free to start the process to
> upstream these patches [1]. Don't hesitate to share here the link to
> the
> new ticket.
> 
> [1] https://openjdk.org/guide/#i-have-a-patch-what-do-i-do
> 

I followed the instructions and "Signed the OCA" on August 1st, but it
is still in the "Under Review" status.

For the second step, "Socialize your change", I would like to send the
following letter to net-dev@openjdk.org:

'''
Hi OpenJDK maintainers,

I hope this message finds you well. The purpose of this letter is to
propose the integration of Multipath TCP (MPTCP) support into OpenJDK.
We have developed a set of patches to enable this functionality and are
eager to submit it for upstream inclusion. We would greatly appreciate
your feedback and opinions on this contribution.

1. Introduction

Multipath TCP (MPTCP), as standardized in RFC 8684, is a major
evolution of the TCP protocol. It enables a transport connection to use
multiple network paths simultaneously for redundancy, resilience, and
bandwidth aggregation. Since its introduction in Linux kernel v5.6, it
has become a key technology for modern networking, particularly on
mobile devices with multiple interfaces (e.g., Wi-Fi and cellular).

Key benefits include:

    Bandwidth Aggregation: Combine the bandwidth of multiple network
links.

    Seamless Handover: Maintain connections when switching networks
without dropping the session.

    Improved Resilience: Traffic is automatically rerouted if one path
fails.

For more details, see the project website: https://mptcp.dev.

2. Technical Background

On a supporting system like Linux, an MPTCP socket is created by
specifying the IPPROTO_MPTCP protocol in the socket() system call:

    int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP);

This creates a socket that looks like a standard TCP socket to the
application but uses the MPTCP protocol stack underneath.

3. Proposed Java API Changes

The goal is to allow Java applications to opt-in to using MPTCP when
creating sockets, without breaking existing code. The proposed changes
are additive and backward-compatible.

The core idea is to add a boolean mptcp parameter through the API
layers, from the public Socket class down to the native system call.

4. Implementation Plan

The implementation involves changes across four layers of the JDK:

JNI Layer (sun.nio.ch.Net):

Modify Java_sun_nio_ch_Net_socket0 to accept a new jboolean mptcp
parameter.

    The native implementation will be updated to use this parameter:

    int protocol = mptcp == JNI_TRUE ? IPPROTO_MPTCP : 0;
    fd = socket(domain, type, protocol);

NIO Layer (sun.nio.ch):

    Add the mptcp parameter to the Net.socket() and Net.serverSocket()
methods.

    Propagate the parameter down to the JNI call.

Socket Implementation Layer (java.net):

    Add the mptcp parameter to the constructor of NioSocketImpl.

    Within NioSocketImpl, pass the parameter to the Net.socket() or
Net.serverSocket() calls.

Public API Layer (java.net.Socket & java.net.ServerSocket):

    Add new constructors that accept the mptcp parameter.

    Example:

        // Proposed new constructor
        public Socket(String host, int port, boolean stream, boolean
mptcp) throws IOException {
            // ... implementation that passes 'mptcp' to NioSocketImpl
        }

5. Full Implementation

The complete working implementation for this proposal is available for
review:

https://github.com/openjdk/jdk/compare/master...geliangtang:jdk:master

We look forward to your valuable feedback and suggestions on this
proposal.

Best regards,
The MPTCP Upstream Developers
'''

Please review this letter for me.

Thanks,
-Geliang

> Cheers,
> Matt

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API
  2025-09-03  6:16   ` Geliang Tang
@ 2025-09-03 10:49     ` Matthieu Baerts
  0 siblings, 0 replies; 7+ messages in thread
From: Matthieu Baerts @ 2025-09-03 10:49 UTC (permalink / raw)
  To: Geliang Tang, mptcp

Hi Geliang,

On 03/09/2025 08:16, Geliang Tang wrote:
> Hi Matt,
> 
> On Thu, 2025-08-28 at 11:57 +0200, Matthieu Baerts wrote:
>> Hi Geliang,
>>
>> On 28/08/2025 10:47, Geliang Tang wrote:
>>> From: Geliang Tang <tanggeliang@kylinos.cn>
>>>
>>> v2:
>>>  - drop redundant helpers as Matt suggested.
>>>  - squash into fewer patches.
>>>  - use "JNI_TRUE" and "(void)mptcp" in Java_sun_nio_ch_Net_socket0
>>> as
>>>    Xiang Gao suggested.
>>>
>>> The Multipath TCP (MPTCP) protocol (v1 / RFC 8684) has been added
>>> in
>>> the upstream Linux kernel since v5.6. See https://mptcp.dev.
>>>
>>> This patch series introduces comprehensive Multipath TCP (MPTCP)
>>> support to the Java Networking API, enabling applications to
>>> leverage
>>> MPTCP's capabilities for improved reliability and throughput.
>>
>> Thank you for the new version! Feel free to start the process to
>> upstream these patches [1]. Don't hesitate to share here the link to
>> the
>> new ticket.
>>
>> [1] https://openjdk.org/guide/#i-have-a-patch-what-do-i-do
>>
> 
> I followed the instructions and "Signed the OCA" on August 1st, but it
> is still in the "Under Review" status.

Thank you for having started this! This is a shame it takes time, that's
not helping to get new contributors.
> For the second step, "Socialize your change", I would like to send the
> following letter to net-dev@openjdk.org:

Good idea, thank you for sharing this.

> '''
> Hi OpenJDK maintainers,
> 
> I hope this message finds you well. The purpose of this letter is to
> propose the integration of Multipath TCP (MPTCP) support into OpenJDK.
> We have developed a set of patches to enable this functionality and are
> eager to submit it for upstream inclusion. We would greatly appreciate
> your feedback and opinions on this contribution.
> 
> 1. Introduction
> 
> Multipath TCP (MPTCP), as standardized in RFC 8684, is a major
> evolution of the TCP protocol. It enables a transport connection to use
> multiple network paths simultaneously for redundancy, resilience, and
> bandwidth aggregation. Since its introduction in Linux kernel v5.6, it
> has become a key technology for modern networking, particularly on
> mobile devices with multiple interfaces (e.g., Wi-Fi and cellular).
> 
> Key benefits include:
> 
>     Bandwidth Aggregation: Combine the bandwidth of multiple network
> links.
> 
>     Seamless Handover: Maintain connections when switching networks
> without dropping the session.
> 
>     Improved Resilience: Traffic is automatically rerouted if one path
> fails.
> 
> For more details, see the project website: https://mptcp.dev.
> 
> 2. Technical Background
> 
> On a supporting system like Linux, an MPTCP socket is created by
> specifying the IPPROTO_MPTCP protocol in the socket() system call:

Maybe add something like: "instead of IPPROTO_TCP (or 0)"
> 
>     int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP);
> 
> This creates a socket that looks like a standard TCP socket to the
> application but uses the MPTCP protocol stack underneath.

It might be interesting to add something here to say that with the Java
API, it is possible to create "stream" sockets, but it is not possible
to change the last argument, which blocks apps to ask to use MPTCP.

> 3. Proposed Java API Changes
> 
> The goal is to allow Java applications to opt-in to using MPTCP when
> creating sockets, without breaking existing code. The proposed changes
> are additive and backward-compatible.
> 
> The core idea is to add a boolean mptcp parameter through the API
> layers, from the public Socket class down to the native system call.
> 
> 4. Implementation Plan
> 
> The implementation involves changes across four layers of the JDK:
> 
> JNI Layer (sun.nio.ch.Net):
> 
> Modify Java_sun_nio_ch_Net_socket0 to accept a new jboolean mptcp
> parameter.
> 
>     The native implementation will be updated to use this parameter:
> 
>     int protocol = mptcp == JNI_TRUE ? IPPROTO_MPTCP : 0;
>     fd = socket(domain, type, protocol);
> 
> NIO Layer (sun.nio.ch):
> 
>     Add the mptcp parameter to the Net.socket() and Net.serverSocket()
> methods.
> 
>     Propagate the parameter down to the JNI call.
> 
> Socket Implementation Layer (java.net):
> 
>     Add the mptcp parameter to the constructor of NioSocketImpl.
> 
>     Within NioSocketImpl, pass the parameter to the Net.socket() or
> Net.serverSocket() calls.
> 
> Public API Layer (java.net.Socket & java.net.ServerSocket):
> 
>     Add new constructors that accept the mptcp parameter.
> 
>     Example:
> 
>         // Proposed new constructor
>         public Socket(String host, int port, boolean stream, boolean
> mptcp) throws IOException {
>             // ... implementation that passes 'mptcp' to NioSocketImpl
>         }
> 
> 5. Full Implementation
> 
> The complete working implementation for this proposal is available for
> review:
> 
> https://github.com/openjdk/jdk/compare/master...geliangtang:jdk:master
> 
> We look forward to your valuable feedback and suggestions on this
> proposal.

Maybe good to add something like: we can create a new issue for this
feature, and submit a proper pull request after if that's OK for you. We
didn't do that yet because we noticed that it is recommended to send
more explanations to this list first.

Thanks, it looks good!

> Best regards,
> The MPTCP Upstream Developers
> '''
> 
> Please review this letter for me.
> 
> Thanks,
> -Geliang
> 
>> Cheers,
>> Matt

Cheers,
Matt
-- 
Sponsored by the NGI0 Core fund.


^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-09-03 10:49 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-28  8:47 [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Geliang Tang
2025-08-28  8:47 ` [PATCH mptcp-next v2 1/3] Add native MPTCP socket creation support Geliang Tang
2025-08-28  8:47 ` [PATCH mptcp-next v2 2/3] Add MPTCP support to Java Socket/ServerSocket APIs Geliang Tang
2025-08-28  8:47 ` [PATCH mptcp-next v2 3/3] Add test cases for MPTCP socket functionality Geliang Tang
2025-08-28  9:57 ` [PATCH mptcp-next v2 0/3] Add MPTCP support to Java Networking API Matthieu Baerts
2025-09-03  6:16   ` Geliang Tang
2025-09-03 10:49     ` Matthieu Baerts

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).