From 8b8e5a2a1d238e35a6faa46184e383a503eafd58 Mon Sep 17 00:00:00 2001 From: doriancraps Date: Tue, 2 Apr 2024 14:55:41 +0200 Subject: [PATCH] socket: add MPTCP support 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 Co-developed-by: Olivier Bonaventure Co-developed-by: Matthieu Baerts Signed-off-by: Dorian Craps --- docs/cmdline-opts/Makefile.inc | 1 + docs/cmdline-opts/mptcp.md | 38 ++++++++++++++ docs/libcurl/curl_easy_setopt.md | 4 ++ docs/libcurl/opts/CURLOPT_MPTCP.md | 80 ++++++++++++++++++++++++++++++ docs/libcurl/symbols-in-versions | 1 + docs/options-in-versions | 1 + include/curl/curl.h | 3 ++ lib/cf-socket.c | 13 +++++ lib/easyoptions.c | 3 +- lib/setopt.c | 3 ++ lib/urldata.h | 2 + src/tool_cfgable.c | 1 + src/tool_cfgable.h | 1 + src/tool_getparam.c | 5 ++ src/tool_listhelp.c | 3 ++ src/tool_operate.c | 3 ++ 16 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 docs/cmdline-opts/mptcp.md create mode 100644 docs/libcurl/opts/CURLOPT_MPTCP.md diff --git a/docs/cmdline-opts/Makefile.inc b/docs/cmdline-opts/Makefile.inc index 428cc3bab2a066..c546a18c8f89d0 100644 --- a/docs/cmdline-opts/Makefile.inc +++ b/docs/cmdline-opts/Makefile.inc @@ -160,6 +160,7 @@ DPAGES = \ max-redirs.md \ max-time.md \ metalink.md \ + mptcp.md \ negotiate.md \ netrc-file.md \ netrc-optional.md \ diff --git a/docs/cmdline-opts/mptcp.md b/docs/cmdline-opts/mptcp.md new file mode 100644 index 00000000000000..2d4921b6d636cf --- /dev/null +++ b/docs/cmdline-opts/mptcp.md @@ -0,0 +1,38 @@ +--- +c: Copyright (C) Dorian Craps, +SPDX-License-Identifier: curl +Long: mptcp +Added: 8.7.2 +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 Wi-Fi and +cellular data or in wired networks with multiple ISPs. + +## 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 falls back to TCP.. + +## Availability + +The `--mptcp` option is available starting from `curl` version 8.7.0. diff --git a/docs/libcurl/curl_easy_setopt.md b/docs/libcurl/curl_easy_setopt.md index 770fdc91bc7d69..fcd3fd13915cf0 100644 --- a/docs/libcurl/curl_easy_setopt.md +++ b/docs/libcurl/curl_easy_setopt.md @@ -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 diff --git a/docs/libcurl/opts/CURLOPT_MPTCP.md b/docs/libcurl/opts/CURLOPT_MPTCP.md new file mode 100644 index 00000000000000..c6bf5f9ec88590 --- /dev/null +++ b/docs/libcurl/opts/CURLOPT_MPTCP.md @@ -0,0 +1,80 @@ +--- +c: Copyright (C) Dorian Craps, +SPDX-License-Identifier: curl +Title: CURLOPT_MPTCP +Section: 3 +Source: libcurl +See-also: + - tcp-fastopen (3) +--- + +# NAME + +CURLOPT_MPTCP - enable Multipath TCP + +# SYNOPSIS + +~~~c + +#include + +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 Wi-Fi +and cellular data or in wired networks with multiple ISPs. + +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 falls back to TCP.. + +# DEFAULT + +0 + +# PROTOCOLS + +All + +# 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 feature's availability in libcurl can also depend on the version of libcurl. +Added in 8.7.2. + +# 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. \ No newline at end of file diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index a627dd68b6c37d..ceebab1f7bb202 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -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.7.2 CURLOPT_NETRC 7.1 CURLOPT_NETRC_FILE 7.11.0 CURLOPT_NEW_DIRECTORY_PERMS 7.16.4 diff --git a/docs/options-in-versions b/docs/options-in-versions index 0905809439c35b..79a89250a0af7c 100644 --- a/docs/options-in-versions +++ b/docs/options-in-versions @@ -125,6 +125,7 @@ --max-redirs 7.5 --max-time (-m) 4.0 --metalink 7.27.0 +--mptcp 8.7.2 --negotiate 7.10.6 --netrc (-n) 4.6 --netrc-file 7.21.5 diff --git a/include/curl/curl.h b/include/curl/curl.h index b2377b7895b988..7ab968c6572768 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -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; diff --git a/lib/cf-socket.c b/lib/cf-socket.c index a5feb6b95ab2b6..a852a523193115 100644 --- a/lib/cf-socket.c +++ b/lib/cf-socket.c @@ -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; @@ -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); diff --git a/lib/easyoptions.c b/lib/easyoptions.c index 9c4438a100e2bc..ea284970d33b38 100644 --- a/lib/easyoptions.c +++ b/lib/easyoptions.c @@ -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}, @@ -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 diff --git a/lib/setopt.c b/lib/setopt.c index 8a5a5d7c33d21d..2226ea553d79c0 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -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: diff --git a/lib/urldata.h b/lib/urldata.h index ce28f25bba59e9..185e2442307430 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -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 @@ -1811,6 +1812,7 @@ struct UserDefined { #ifdef USE_WEBSOCKETS BIT(ws_raw_mode); #endif + BIT(mptcp); /* enable MPTCP support */ }; #ifndef CURL_DISABLE_MIME diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c index 3259bc7a5f0562..48601c18512036 100644 --- a/src/tool_cfgable.c +++ b/src/tool_cfgable.c @@ -45,6 +45,7 @@ void config_init(struct OperationConfig *config) config->http09_allowed = FALSE; config->ftp_skip_ip = TRUE; config->file_clobber_mode = CLOBBER_DEFAULT; + config->mptcp = FALSE; curlx_dyn_init(&config->postdata, MAX_FILE2MEMORY); } diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index dfa74d81ff4b81..be7b4beffdc904 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -298,6 +298,7 @@ struct OperationConfig { struct State state; /* for create_transfer() */ bool rm_partial; /* on error, remove partially written output files */ + bool mptcp; /* enable MPTCP support */ }; struct GlobalConfig { diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 5cb898852b5e46..d1b4e2b8688081 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -199,6 +199,7 @@ typedef enum { C_MAX_REDIRS, C_MAX_TIME, C_METALINK, + C_MPTCP, C_NEGOTIATE, C_NETRC, C_NETRC_FILE, @@ -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}, @@ -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; diff --git a/src/tool_listhelp.c b/src/tool_listhelp.c index 5d9364405448bf..1a2d98ccfecbb1 100644 --- a/src/tool_listhelp.c +++ b/src/tool_listhelp.c @@ -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}, diff --git a/src/tool_operate.c b/src/tool_operate.c index 49ec7d835cfedb..849c8985860ff3 100644 --- a/src/tool_operate.c +++ b/src/tool_operate.c @@ -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);