diff --git a/connect.c b/connect.c index 3280435331..846fa31853 100644 --- a/connect.c +++ b/connect.c @@ -23,6 +23,9 @@ #include "alias.h" #include "bundle-uri.h" #include "promisor-remote.h" +#ifdef __linux__ +#include +#endif static char *server_capabilities_v1; static struct strvec server_capabilities_v2 = STRVEC_INIT; @@ -793,6 +796,16 @@ static void enable_keepalive(int sockfd) error_errno(_("unable to set SO_KEEPALIVE on socket")); } +static const char *git_enable_mptcp(void) +{ + const char *mptcp; + + if ((mptcp = getenv("GIT_ENABLE_MPTCP"))) + return mptcp; + + return NULL; +} + #ifndef NO_IPV6 static const char *ai_name(const struct addrinfo *ai) @@ -816,6 +829,7 @@ static int git_tcp_connect_sock(char *host, int flags) struct addrinfo hints, *ai0, *ai; int gai; int cnt = 0; + const char *enable_mptcp; get_host_and_port(&host, &port); if (!*port) @@ -827,12 +841,28 @@ static int git_tcp_connect_sock(char *host, int flags) else if (flags & CONNECT_IPV6) hints.ai_family = AF_INET6; hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; +#if defined(__linux__) && defined(IPPROTO_MPTCP) + enable_mptcp = git_enable_mptcp(); + if (enable_mptcp) + hints.ai_protocol = IPPROTO_MPTCP; + else + hints.ai_protocol = IPPROTO_TCP; +#else + hints.ai_protocol = IPPROTO_TCP; +#endif if (flags & CONNECT_VERBOSE) fprintf(stderr, _("Looking up %s ... "), host); - gai = getaddrinfo(host, port, &hints, &ai); + gai = getaddrinfo(host, port, &hints, &ai); + // If system's glibc getaddrinfo() does not have + // IPPROTO_MPTCP as member type in struct (like older + // glibc and other libc), we fallback to IPPROTO_TCP + if (gai == EAI_SOCKTYPE) { + hints.ai_protocol = IPPROTO_TCP; + gai = getaddrinfo(host, port, &hints, &ai); + } + if (gai) die(_("unable to look up %s (port %s) (%s)"), host, port, gai_strerror(gai)); @@ -889,6 +919,7 @@ static int git_tcp_connect_sock(char *host, int flags) char **ap; unsigned int nport; int cnt; + const char *enable_mptcp; get_host_and_port(&host, &port); @@ -917,6 +948,21 @@ static int git_tcp_connect_sock(char *host, int flags) sa.sin_port = htons(nport); memcpy(&sa.sin_addr, *ap, he->h_length); +#ifdef __linux__ + enable_mptcp = git_enable_mptcp(); + if (enable_mptcp) { + sockfd = socket(he->h_addrtype, SOCK_STREAM, IPPROTO_MPTCP); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5,6,0) + // MPTCP check return value for Linux Kernel >= 5.6 + if (sockfd == EPROTONOSUPPORT || sockfd == ENOPROTOOPT) + continue; +#else + // MPTCP check return value for Linux Kernel < 5.6 + if (sockfd == EINVAL || sockfd == ENOPROTOOPT) + continue; +#endif + } +#endif sockfd = socket(he->h_addrtype, SOCK_STREAM, 0); if ((sockfd < 0) || connect(sockfd, (struct sockaddr *)&sa, sizeof sa) < 0) { diff --git a/daemon.c b/daemon.c index d1be61fd57..793f8a4219 100644 --- a/daemon.c +++ b/daemon.c @@ -25,6 +25,7 @@ static enum log_destination { } log_destination = LOG_DESTINATION_UNSET; static int verbose; static int reuseaddr; +static int mptcp; static int informative_errors; static const char daemon_usage[] = @@ -38,6 +39,7 @@ static const char daemon_usage[] = " [--access-hook=]\n" " [--inetd | [--listen=] [--port=]\n" " [--detach] [--user= [--group=]]\n" +" [--mptcp]\n" " [--log-destination=(stderr|syslog|none)]\n" " [...]"; @@ -975,10 +977,24 @@ static int setup_named_sock(char *listen_addr, int listen_port, struct socketlis memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - hints.ai_protocol = IPPROTO_TCP; +#if defined(__linux__) && defined(IPPROTO_MPTCP) + if (mptcp) + hints.ai_protocol = IPPROTO_MPTCP; + else + hints.ai_protocol = IPPROTO_MPTCP; +#else + hints.ai_protocol = IPPROTO_TCP; +#endif hints.ai_flags = AI_PASSIVE; - gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); + gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); + // If system's glibc getaddrinfo() does not have + // IPPROTO_MPTCP as member type in struct (like older + // glibc and other libc), we fallback to IPPROTO_TCP + if (gai == EAI_SOCKTYPE) { + hints.ai_protocol = IPPROTO_TCP; + gai = getaddrinfo(listen_addr, pbuf, &hints, &ai0); + } if (gai) { logerror("getaddrinfo() for %s failed: %s", listen_addr, gai_strerror(gai)); return 0; @@ -1342,6 +1358,10 @@ int cmd_main(int argc, const char **argv) reuseaddr = 1; continue; } + if (!strcmp(arg, "--mptcp")) { + mptcp = 1; + continue; + } if (!strcmp(arg, "--user-path")) { user_path = ""; continue;