Skip to content

Commit

Permalink
socket: add MPTCP support
Browse files Browse the repository at this point in the history
Multipath TCP (MPTCP), standardized in RFC8684 [1], is a TCP extension
that enables a TCP connection to use different paths.

Multipath TCP has been used for several use cases. On smartphones, MPTCP
enables seamless handovers between cellular and Wi-Fi networks while
preserving established connections. This use-case is what pushed Apple
to use MPTCP since 2013 in multiple applications [2]. On dual-stack
hosts, Multipath TCP enables the TCP connection to automatically use the
best performing path, either IPv4 or IPv6. If one path fails, MPTCP
automatically uses the other path.

To benefit from MPTCP, both the client and the server have to support
it. Multipath TCP is a backward-compatible TCP extension that is enabled
by default on recent Linux distributions (Debian, Ubuntu, Redhat, ...).
Multipath TCP is included in the Linux kernel since version 5.6 [3]. To
use it on Linux, an application must explicitly enable it when creating
the socket. No need to change anything else in the application.

This attached patch adds an --mptcp option which allows the creation of
an MPTCP socket instead of TCP on Linux. If Multipath TCP is not
supported on the system, an error will be reported. It is important to
note that if the end server doesn't support MPTCP, the connection will
continue after a seamless fallback to TCP.

Link: https://www.rfc-editor.org/rfc/rfc8684.html [1]
Link: https://www.tessares.net/apples-mptcp-story-so-far/ [2]
Link: https://www.mptcp.dev [3]
Co-developed-by: Dorian Craps <doriancraps@gmail.com>
Co-developed-by: Olivier Bonaventure <Olivier.Bonaventure@uclouvain.be>
Co-developed-by: Matthieu Baerts <matttbe@kernel.org>
Signed-off-by: Dorian Craps <dorian.craps@student.vinci.be>
  • Loading branch information
CrapsDorian committed Apr 4, 2024
1 parent 721941a commit 9a7791f
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .github/scripts/spellcheck.words
Expand Up @@ -485,6 +485,7 @@ monospace
MorphOS
MPE
MPL
MPTCP
mprintf
MQTT
mqtt
Expand All @@ -505,6 +506,7 @@ mTLS
MUA
multicwd
multiparts
multipath
MultiSSL
mumbo
musedev
Expand Down
1 change: 1 addition & 0 deletions docs/cmdline-opts/Makefile.inc
Expand Up @@ -160,6 +160,7 @@ DPAGES = \
max-redirs.md \
max-time.md \
metalink.md \
mptcp.md \
negotiate.md \
netrc-file.md \
netrc-optional.md \
Expand Down
38 changes: 38 additions & 0 deletions docs/cmdline-opts/mptcp.md
@@ -0,0 +1,38 @@
---
c: Copyright (C) Dorian Craps, <dorian.craps@student.vinci.be>
SPDX-License-Identifier: curl
Long: mptcp
Added: 8.8.0
Help: Enable Multipath TCP (MPTCP)
Category: connection
Multi: boolean
See-also:
- tcp-fastopen
Example:
- --mptcp $URL
---

# `--mptcp`

Enables the use of Multipath TCP (MPTCP) for connections. MPTCP is an extension
to the standard TCP that allows multiple TCP streams over different network
paths between the same source and destination. This can enhance bandwidth and
improve reliability by using multiple paths simultaneously.

MPTCP is beneficial in networks where multiple paths exist between clients and
servers, such as mobile networks where a device may switch between WiFi and
cellular data or in wired networks with multiple Internet Service Providers.

## Usage

To use MPTCP for your connections, add the `--mptcp` option when using `curl'.

## Requirements

- This feature is currently only supported on Linux starting from kernel 5.6.
- The server you are connecting to must also support MPTCP. If not, the
connection seamlessly falls back to TCP.

## Availability

The `--mptcp` option is available starting from `curl` version 8.8.0.
4 changes: 4 additions & 0 deletions docs/libcurl/curl_easy_setopt.md
Expand Up @@ -425,6 +425,10 @@ Path to a Unix domain socket. See CURLOPT_UNIX_SOCKET_PATH(3)
Path to an abstract Unix domain socket. See CURLOPT_ABSTRACT_UNIX_SOCKET(3)
## CURLOPT_MPTCP
Enable Multipath TCP (MPTCP). See CURLOPT_MPTCP(3)
# NAMES and PASSWORDS OPTIONS (Authentication)
## CURLOPT_NETRC
Expand Down
76 changes: 76 additions & 0 deletions docs/libcurl/opts/CURLOPT_MPTCP.md
@@ -0,0 +1,76 @@
---
c: Copyright (C) Dorian Craps, <dorian.craps@student.vinci.be>, et al.
SPDX-License-Identifier: curl
Title: CURLOPT_MPTCP
Section: 3
Source: libcurl
See-also:
- CURLOPT_TCP_FASTOPEN (3)
Protocol:
- All
---

# NAME

CURLOPT_MPTCP - enable Multipath TCP

# SYNOPSIS

~~~c
#include <curl/curl.h>

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_MPTCP, long enable);
~~~
# DESCRIPTION
Pass a long as parameter set to 1L to enable or 0 to disable.
MPTCP is an extension to the standard TCP that allows multiple TCP streams
over different network paths between the same source and destination.
This can enhance bandwidth and improve reliability by using multiple paths
simultaneously.
MPTCP is beneficial in networks where multiple paths exist between clients
and servers, such as mobile networks where a device may switch between WiFi
and cellular data or in wired networks with multiple Internet Service Providers.
Enabling MPTCP can improve the performance and reliability of network requests,
particularly in environments where multiple network paths (e.g., WiFi and
cellular) are available.
Note: MPTCP support depends on the underlying operating system and network
infrastructure. Some networks might drop unknown MPTCP, and its
effectiveness varies based on the network configuration and conditions.
If MPTCP is not supported by the network or the end server,
the connection seamlessly falls back to TCP.
# DEFAULT
0
# EXAMPLE
~~~c
int main(void)
{
CURL *curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "https://example.com");
curl_easy_setopt(curl, CURLOPT_MPTCP, 1L);
curl_easy_perform(curl);
}
}
~~~

# AVAILABILITY

Support for MPTCP in libcurl requires Linux 5.6 or later.
The features availability in libcurl can also depend on the version of libcurl.
Added in 8.8.0.

# RETURN VALUE

Returns CURLE_OK if MPTCP is successfully enabled for the connection,
otherwise returns an error code specific to the reason it could not be enabled,
which might include lack of operating system support or libcurl not being built
with MPTCP support.
1 change: 1 addition & 0 deletions docs/libcurl/opts/CURLOPT_TCP_FASTOPEN.md
Expand Up @@ -6,6 +6,7 @@ Section: 3
Source: libcurl
See-also:
- CURLOPT_SSL_FALSESTART (3)
- CURLOPT_MPTCP (3)
Protocol:
- All
---
Expand Down
1 change: 1 addition & 0 deletions docs/libcurl/opts/Makefile.inc
Expand Up @@ -244,6 +244,7 @@ man_MANS = \
CURLOPT_MAXREDIRS.3 \
CURLOPT_MIME_OPTIONS.3 \
CURLOPT_MIMEPOST.3 \
CURLOPT_MPTCP.3 \
CURLOPT_NETRC.3 \
CURLOPT_NETRC_FILE.3 \
CURLOPT_NEW_DIRECTORY_PERMS.3 \
Expand Down
1 change: 1 addition & 0 deletions docs/libcurl/symbols-in-versions
Expand Up @@ -708,6 +708,7 @@ CURLOPT_MAXREDIRS 7.5
CURLOPT_MIME_OPTIONS 7.81.0
CURLOPT_MIMEPOST 7.56.0
CURLOPT_MUTE 7.1 7.8 7.15.5
CURLOPT_MPTCP 8.8.0
CURLOPT_NETRC 7.1
CURLOPT_NETRC_FILE 7.11.0
CURLOPT_NEW_DIRECTORY_PERMS 7.16.4
Expand Down
1 change: 1 addition & 0 deletions docs/options-in-versions
Expand Up @@ -125,6 +125,7 @@
--max-redirs 7.5
--max-time (-m) 4.0
--metalink 7.27.0
--mptcp 8.8.0
--negotiate 7.10.6
--netrc (-n) 4.6
--netrc-file 7.21.5
Expand Down
3 changes: 3 additions & 0 deletions include/curl/curl.h
Expand Up @@ -2206,6 +2206,9 @@ typedef enum {
/* millisecond version */
CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),

/* Set MPTCP */
CURLOPT(CURLOPT_MPTCP, CURLOPTTYPE_LONG, 325),

CURLOPT_LASTENTRY /* the last unused */
} CURLoption;

Expand Down
13 changes: 13 additions & 0 deletions lib/cf-socket.c
Expand Up @@ -244,6 +244,13 @@ void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
dest->socktype = SOCK_STREAM;
dest->protocol = IPPROTO_IP;
break;
case TRNSPRT_MPTCP:
#ifndef IPPROTO_MPTCP
#define IPPROTO_MPTCP 262
#endif
dest->socktype = SOCK_STREAM;
dest->protocol = IPPROTO_MPTCP;
break;
default: /* UDP and QUIC */
dest->socktype = SOCK_DGRAM;
dest->protocol = IPPROTO_UDP;
Expand Down Expand Up @@ -1602,6 +1609,12 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}

#ifdef __linux__
if(data->set.mptcp)
transport = TRNSPRT_MPTCP;
#endif

cf_socket_ctx_init(ctx, ai, transport);

result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
Expand Down
3 changes: 2 additions & 1 deletion lib/easyoptions.c
Expand Up @@ -178,6 +178,7 @@ struct curl_easyoption Curl_easyopts[] = {
{"MAX_SEND_SPEED_LARGE", CURLOPT_MAX_SEND_SPEED_LARGE, CURLOT_OFF_T, 0},
{"MIMEPOST", CURLOPT_MIMEPOST, CURLOT_OBJECT, 0},
{"MIME_OPTIONS", CURLOPT_MIME_OPTIONS, CURLOT_LONG, 0},
{"MPTCP", CURLOPT_MPTCP, CURLOT_LONG, 0},
{"NETRC", CURLOPT_NETRC, CURLOT_VALUES, 0},
{"NETRC_FILE", CURLOPT_NETRC_FILE, CURLOT_STRING, 0},
{"NEW_DIRECTORY_PERMS", CURLOPT_NEW_DIRECTORY_PERMS, CURLOT_LONG, 0},
Expand Down Expand Up @@ -375,6 +376,6 @@ struct curl_easyoption Curl_easyopts[] = {
*/
int Curl_easyopts_check(void)
{
return ((CURLOPT_LASTENTRY%10000) != (324 + 1));
return ((CURLOPT_LASTENTRY%10000) != (325 + 1));
}
#endif
3 changes: 3 additions & 0 deletions lib/setopt.c
Expand Up @@ -2931,6 +2931,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = CURLE_NOT_BUILT_IN;
#endif
break;
case CURLOPT_MPTCP:
data->set.mptcp = TRUE;
break;
case CURLOPT_SSL_ENABLE_NPN:
break;
case CURLOPT_SSL_ENABLE_ALPN:
Expand Down
2 changes: 2 additions & 0 deletions lib/urldata.h
Expand Up @@ -788,6 +788,7 @@ struct ldapconninfo;
#define TRNSPRT_UDP 4
#define TRNSPRT_QUIC 5
#define TRNSPRT_UNIX 6
#define TRNSPRT_MPTCP 7

/*
* The connectdata struct contains all fields and variables that should be
Expand Down Expand Up @@ -1811,6 +1812,7 @@ struct UserDefined {
#ifdef USE_WEBSOCKETS
BIT(ws_raw_mode);
#endif
BIT(mptcp); /* enable MPTCP support */
};

#ifndef CURL_DISABLE_MIME
Expand Down
1 change: 1 addition & 0 deletions src/tool_cfgable.h
Expand Up @@ -292,6 +292,7 @@ struct OperationConfig {
CLOBBER_NEVER, /* If the file exists, always fail */
CLOBBER_ALWAYS /* If the file exists, always overwrite it */
} file_clobber_mode;
bool mptcp; /* enable MPTCP support */
struct GlobalConfig *global;
struct OperationConfig *prev;
struct OperationConfig *next; /* Always last in the struct */
Expand Down
5 changes: 5 additions & 0 deletions src/tool_getparam.c
Expand Up @@ -199,6 +199,7 @@ typedef enum {
C_MAX_REDIRS,
C_MAX_TIME,
C_METALINK,
C_MPTCP,
C_NEGOTIATE,
C_NETRC,
C_NETRC_FILE,
Expand Down Expand Up @@ -480,6 +481,7 @@ static const struct LongShort aliases[]= {
{"max-redirs", ARG_STRG, ' ', C_MAX_REDIRS},
{"max-time", ARG_STRG, 'm', C_MAX_TIME},
{"metalink", ARG_BOOL, ' ', C_METALINK},
{"mptcp", ARG_BOOL, ' ', C_MPTCP},
{"negotiate", ARG_BOOL, ' ', C_NEGOTIATE},
{"netrc", ARG_BOOL, 'n', C_NETRC},
{"netrc-file", ARG_FILE, ' ', C_NETRC_FILE},
Expand Down Expand Up @@ -2747,6 +2749,9 @@ ParameterError getparameter(const char *flag, /* f or -long-flag */
}
}
break;
case C_MPTCP: /* --mptcp */
config->mptcp = TRUE;
break;
default: /* unknown flag */
err = PARAM_OPTION_UNKNOWN;
break;
Expand Down
3 changes: 3 additions & 0 deletions src/tool_listhelp.c
Expand Up @@ -378,6 +378,9 @@ const struct helptxt helptext[] = {
{" --metalink",
"Process given URLs as metalink XML file",
CURLHELP_MISC},
{" --mptcp",
"Enable Multipath TCP (MPTCP)",
CURLHELP_CONNECTION},
{" --negotiate",
"Use HTTP Negotiate (SPNEGO) authentication",
CURLHELP_AUTH | CURLHELP_HTTP},
Expand Down
3 changes: 3 additions & 0 deletions src/tool_operate.c
Expand Up @@ -1291,6 +1291,9 @@ static CURLcode single_transfer(struct GlobalConfig *global,
if(config->tcp_fastopen)
my_setopt(curl, CURLOPT_TCP_FASTOPEN, 1L);

if(config->mptcp)
my_setopt(curl, CURLOPT_MPTCP, 1L);

/* where to store */
my_setopt(curl, CURLOPT_WRITEDATA, per);
my_setopt(curl, CURLOPT_INTERLEAVEDATA, per);
Expand Down

0 comments on commit 9a7791f

Please sign in to comment.