From ba4d8db984ee663521a595dbd45e780d560facc1 Mon Sep 17 00:00:00 2001 From: Olivier Bonaventure Date: Thu, 8 Sep 2022 16:01:15 +0200 Subject: [PATCH 1/3] Update of python example --- python/mptcp-hello.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/python/mptcp-hello.py b/python/mptcp-hello.py index 1e038c4..e9f810a 100644 --- a/python/mptcp-hello.py +++ b/python/mptcp-hello.py @@ -1,14 +1,36 @@ import socket +import errno -# On Python 3.10 and above, socket.IPPROTO_MPTCP is defined. -# If not, we set it manually -try: - mptcp_protocol = socket.IPPROTO_MPTCP -except AttributeError: - mptcp_protocol = 262 +# By default, the application wishes to use Multipath TCP for all sockets +# provided that it is running on a system that supports Multipath TCP +_use_mptcp = True -s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, mptcp_protocol) +def create_socket(sockaf): + global _use_mptcp + # On Python 3.10 and above, socket.IPPROTO_MPTCP is defined. + # If not, we set it manually + try: + mptcp_protocol = socket.IPPROTO_MPTCP + except AttributeError: + mptcp_protocol = 262 + # If Multipath TCP is enabled on this system, we create a Multipath TCP + # socket + if _use_mptcp : + try: + return socket.socket(sockaf, socket.SOCK_STREAM, mptcp_protocol) + except OSError as e: + # Multipath TCP is not supported, we fall back to regular TCP + # and remember that Multipath TCP is not enabled + if e.errno == errno.ENOPROTOOPT or e.errno == errno.ENOPROTONOSUPPORT : + _use_mptcp = False + return socket.socket(sockaf, socket.SOCK_STREAM, socket.IPPROTO_TCP) + else: + # We already know that Multipath TCP does not work on this system + return socket.socket(sockaf, socket.SOCK_STREAM, socket.IPPROTO_TCP) + + +s = create_socket(socket.AF_INET) s.connect(("test.multipath-tcp.org" , 80)) # use the socket as you wish From 87ec170f60a49ed54cace258226a686e6d30b17d Mon Sep 17 00:00:00 2001 From: Olivier Bonaventure Date: Thu, 8 Sep 2022 18:18:01 +0200 Subject: [PATCH 2/3] Example showing how to create Multipath TCP sockets in python in a portable manner and by falling back to TCP if used on a system that does not support Multipath TCP --- python/README.md | 21 ++++++++++++++++++++- python/mptcp-hello.py | 33 +++++++++++++++++---------------- 2 files changed, 37 insertions(+), 17 deletions(-) diff --git a/python/README.md b/python/README.md index be9639f..e99f402 100644 --- a/python/README.md +++ b/python/README.md @@ -1,6 +1,25 @@ # Using Multipath TCP in python +To use Multipath TCP in python, you need to pass IPPROTO_MPTCP as the third argument of the socket.socket call as in C. On python 3.10+, this is as +simple as : -To use Multipath TCP in python, simply pass Multipath TCP's protocol number (262) as the third argument of the socket system call. On python 3.10+, you can even use IPPROTO_MPTCP as the third argument since this constant is defined in python 3.10+. +``` +socket.socket(sockaf, socket.SOCK_STREAM, IPPROTO_MPTCP) +``` + +However, if you want your code to be portable and to run on hosts using older Linux kernels or where Multipath TCP is disabled, you need to take some care. Here are some hints that you might find useful : + +1. Do not simply use IPPROTO_MPTCP, use a try ... except and set a variable to the expected value of IPPROTO_MPTCP like + + ``` + try: + _mptcp_protocol = socket.IPPROTO_MPTCP + except AttributeError: + _mptcp_protocol = 262 + ``` + + Although 262 alone would work, using it directly in your make would make it unreadable. + +2. Since the Multipath TCP support is a system property, you should only test it once. If your application creates several TCP sockets and you want to add support for Multipath TCP, you should use a function that creates all the sockets that you need. When first called, this function will try to create a Multipath TCP socket. If this socket fails with either ```ENOPROTOOPT 92 Protocol not available``` or ```EPROTONOSUPPORT 93 Protocol not supported```, this means that it runs on a system that does not support Multipath TCP. You should fallback to TCP and return a regular TCP socket and cache this information such you automatically create TCP sockets at the next calls. [simple example](mptcp-hello.py) \ No newline at end of file diff --git a/python/mptcp-hello.py b/python/mptcp-hello.py index e9f810a..9944dc6 100644 --- a/python/mptcp-hello.py +++ b/python/mptcp-hello.py @@ -1,35 +1,36 @@ import socket import errno +# On Python 3.10 and above, socket.IPPROTO_MPTCP is defined. +# If not, we set it manually +try: + _mptcp_protocol = socket.IPPROTO_MPTCP +except AttributeError: + _mptcp_protocol = 262 + # By default, the application wishes to use Multipath TCP for all sockets # provided that it is running on a system that supports Multipath TCP _use_mptcp = True - - + def create_socket(sockaf): - global _use_mptcp - # On Python 3.10 and above, socket.IPPROTO_MPTCP is defined. - # If not, we set it manually - try: - mptcp_protocol = socket.IPPROTO_MPTCP - except AttributeError: - mptcp_protocol = 262 + global _use_mptcp + global _mptcp_protocol # If Multipath TCP is enabled on this system, we create a Multipath TCP # socket if _use_mptcp : try: - return socket.socket(sockaf, socket.SOCK_STREAM, mptcp_protocol) - except OSError as e: + return socket.socket(sockaf, socket.SOCK_STREAM, _mptcp_protocol) + except socket.error as e: # Multipath TCP is not supported, we fall back to regular TCP # and remember that Multipath TCP is not enabled if e.errno == errno.ENOPROTOOPT or e.errno == errno.ENOPROTONOSUPPORT : _use_mptcp = False - return socket.socket(sockaf, socket.SOCK_STREAM, socket.IPPROTO_TCP) - else: - # We already know that Multipath TCP does not work on this system - return socket.socket(sockaf, socket.SOCK_STREAM, socket.IPPROTO_TCP) + # Multipath TCP does not work or socket failed, we try TCP + return socket.socket(sockaf, socket.SOCK_STREAM, socket.IPPROTO_TCP) - +# +# Example usage +# s = create_socket(socket.AF_INET) s.connect(("test.multipath-tcp.org" , 80)) From 20cde97db3767fa8c1f2859bb5b77e70360457d7 Mon Sep 17 00:00:00 2001 From: Olivier Bonaventure Date: Fri, 9 Sep 2022 10:51:09 +0200 Subject: [PATCH 3/3] New C example and README showing how to create a Multipath TCP socket and fall back to TCP if Multipath TCP is not supported on this system --- c/README.md | 8 +++++--- c/mptcphello.c | 48 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/c/README.md b/c/README.md index 6c62e1c..29fd716 100644 --- a/c/README.md +++ b/c/README.md @@ -1,7 +1,7 @@ # Using Multipath TCP in C -It is pretty simple to use Multipath TCP with the C language. You simply need to pass IPPROTO_MPTCP as the third argument of the [socket()](https://www.man7.org/linux/man-pages/man3/socket.3p.html) system call. Make sure that IPPROTO_MPTCP is correctly defined and if you, define it as follows : +It is pretty simple to use Multipath TCP with the C language. You simply need to pass IPPROTO_MPTCP as the third argument of the [socket()](https://www.man7.org/linux/man-pages/man3/socket.3p.html) system call. Make sure that IPPROTO_MPTCP is correctly defined and if not, define it as follows : ``` #ifndef IPPROTO_MPTCP @@ -9,7 +9,9 @@ It is pretty simple to use Multipath TCP with the C language. You simply need to #endif ``` -A typical socket call for Multipath TCP will look like: ` s = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP); ` +A typical socket call for Multipath TCP will look like: `s = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP); ` -The [simple project](mptcphello.c) in this repository also illustrates how to automatically check with autoconf whether the compilation is on a Multipath TCP enabled host, see [configure.ac](configure.ac) +Most networked applications abstract the creation of a TCP socket in a specific function that is called instead of calling [socket()](https://www.man7.org/linux/man-pages/man3/socket.3p.html) directly. This is a good opportunity to make the code portable and useable on hosts that support Multipath TCP or not. In practice, to efficiently enable Multipath TCP, your code should try to use Multipath TCP when creating the first TCP socket. If this socket is successfully created, then Multipath TCP is enabled on the host and you can continue to use Multipath TCP. Otherwise, the application is running on a host that does not yet support Multipath TCP. In this unfortunate case, you should fall back to regular TCP and always create TCP sockets. You might print an error message to encourage the user to upgrade his/her system to support Multipath TCP... + +The [simple project](mptcphello.c) in this repository illustrates this strategy. If you want to automatically check with autoconf whether the compilation is on a Multipath TCP enabled host, see [configure.ac](configure.ac) diff --git a/c/mptcphello.c b/c/mptcphello.c index 2e8c27a..7c9be12 100644 --- a/c/mptcphello.c +++ b/c/mptcphello.c @@ -5,7 +5,9 @@ #include #include #include +#include +// IPPROTO_MPTCP is defined in on recent kernels only #ifndef IPPROTO_MPTCP #define IPPROTO_MPTCP 262 @@ -13,26 +15,42 @@ +/* + * Create a Multipath TCP socket for the specified domain + * If the creation fails because Multipath TCP is not supported + * on this system, falls back to regular TCP + */ +int socket_create(int domain) { -bool use_mptcp = true; + // if true, try always enable Multipath TCP for TCP sockets + static bool use_mptcp = true; + int s; + if(use_mptcp) { + s = socket(domain, SOCK_STREAM, IPPROTO_MPTCP); + if(s==-1 && ( errno==EPROTONOSUPPORT || errno==ENOPROTOOPT) ) { + // Multipath TCP is not supported on this system + use_mptcp = false; + // Fall back to regular TCP + } else { + // Multipath TCP socket was created or another error occured + return s; + } + } + // Multipath TCP is not supported on this system, return a TCP socket + return(socket(domain, SOCK_STREAM, IPPROTO_TCP)); + +} int main(int argc, char **argv) { int s; - if (use_mptcp) { - s = socket(AF_INET, SOCK_STREAM, IPPROTO_MPTCP); - if (s == -1) { - use_mptcp = false; - fprintf(stderr, "Could not create MPTCP socket, falling back to TCP \n"); - s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); - if (s ==-1) { - fprintf(stderr, "Could not create TCP socket\n"); - exit(-1); - } - } - close(s); - exit(0); - } + + s = socket_create(AF_INET); + + // do something useful with the socket + + close(s); + }