From 7dc10dbf45db5a361e0ace376dedb5578f6a5642 Mon Sep 17 00:00:00 2001 From: Matthieu Baerts Date: Fri, 24 Feb 2023 17:51:58 +0100 Subject: [PATCH] net: mptcp: implement listenMPTCP Similar to dialMPTCP, this listenMPTCP function is called when the user has requested MPTCP via SetMultipathTCP in the ListenConfig. This function falls back to listenTCP on operating systems that do not support MPTCP or if MPTCP is not supported. On ListenConfig side, MultipathTCP function can be used to know if the package will try to use MPTCP or not when Listen is called. Note that this new listenMPTCP function returns a TCPListener object and not a new MPTCP dedicated one. The reasons are similar as the ones explained in the parent commit introducing dialTCP: if MPTCP is used by default later, Listen will return a different object that could break existing applications expecting TCPListener. This work has been co-developped by Gregory Detal . Updates #56539 Change-Id: I010f1d87f921bbac9e157cef2212c51917852353 Reviewed-on: https://go-review.googlesource.com/c/go/+/471137 TryBot-Result: Gopher Robot Reviewed-by: Emmanuel Odeke Reviewed-by: Ian Lance Taylor Run-TryBot: Ian Lance Taylor Auto-Submit: Ian Lance Taylor Reviewed-by: Matthew Dempsky --- api/next/56539.txt | 2 ++ src/net/dial.go | 29 ++++++++++++++++++++++++++++- src/net/mptcpsock_linux.go | 9 +++++++++ src/net/mptcpsock_stub.go | 4 ++++ src/net/tcpsock_posix.go | 6 +++++- 5 files changed, 48 insertions(+), 2 deletions(-) diff --git a/api/next/56539.txt b/api/next/56539.txt index ad1dfb7251..65d0418aff 100644 --- a/api/next/56539.txt +++ b/api/next/56539.txt @@ -1,2 +1,4 @@ pkg net, method (*Dialer) MultipathTCP() bool #56539 pkg net, method (*Dialer) SetMultipathTCP(bool) #56539 +pkg net, method (*ListenConfig) MultipathTCP() bool #56539 +pkg net, method (*ListenConfig) SetMultipathTCP(bool) #56539 diff --git a/src/net/dial.go b/src/net/dial.go index 3cc8f840c5..58e3b392d9 100644 --- a/src/net/dial.go +++ b/src/net/dial.go @@ -673,6 +673,29 @@ type ListenConfig struct { // that do not support keep-alives ignore this field. // If negative, keep-alives are disabled. KeepAlive time.Duration + + // If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be + // used, any call to Listen with "tcp(4|6)" as network will use MPTCP if + // supported by the operating system. + mptcpStatus mptcpStatus +} + +// MultipathTCP reports whether MPTCP will be used. +// +// This method doesn't check if MPTCP is supported by the operating +// system or not. +func (lc *ListenConfig) MultipathTCP() bool { + return lc.mptcpStatus.get() +} + +// SetMultipathTCP directs the Listen method to use, or not use, MPTCP, +// if supported by the operating system. This method overrides the +// system default. +// +// If MPTCP is not available on the host or not supported by the client, +// the Listen method will fall back to TCP. +func (lc *ListenConfig) SetMultipathTCP(use bool) { + lc.mptcpStatus.set(use) } // Listen announces on the local network address. @@ -693,7 +716,11 @@ func (lc *ListenConfig) Listen(ctx context.Context, network, address string) (Li la := addrs.first(isIPv4) switch la := la.(type) { case *TCPAddr: - l, err = sl.listenTCP(ctx, la) + if sl.MultipathTCP() { + l, err = sl.listenMPTCP(ctx, la) + } else { + l, err = sl.listenTCP(ctx, la) + } case *UnixAddr: l, err = sl.listenUnix(ctx, la) default: diff --git a/src/net/mptcpsock_linux.go b/src/net/mptcpsock_linux.go index a1c3805795..4663d28b4b 100644 --- a/src/net/mptcpsock_linux.go +++ b/src/net/mptcpsock_linux.go @@ -51,3 +51,12 @@ func (sd *sysDialer) dialMPTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCP return sd.doDialTCPProto(ctx, laddr, raddr, _IPPROTO_MPTCP) } + +func (sl *sysListener) listenMPTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) { + // Fallback to listenTCP if Multipath TCP isn't supported on this operating system. + if !supportsMultipathTCP() { + return sl.listenTCP(ctx, laddr) + } + + return sl.listenTCPProto(ctx, laddr, _IPPROTO_MPTCP) +} diff --git a/src/net/mptcpsock_stub.go b/src/net/mptcpsock_stub.go index 62f5d49731..ae06772896 100644 --- a/src/net/mptcpsock_stub.go +++ b/src/net/mptcpsock_stub.go @@ -13,3 +13,7 @@ import ( func (sd *sysDialer) dialMPTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) { return sd.dialTCP(ctx, laddr, raddr) } + +func (sl *sysListener) listenMPTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) { + return sl.listenTCP(ctx, laddr) +} diff --git a/src/net/tcpsock_posix.go b/src/net/tcpsock_posix.go index f8d4b3e4d0..ed144a6ddc 100644 --- a/src/net/tcpsock_posix.go +++ b/src/net/tcpsock_posix.go @@ -169,13 +169,17 @@ func (ln *TCPListener) file() (*os.File, error) { } func (sl *sysListener) listenTCP(ctx context.Context, laddr *TCPAddr) (*TCPListener, error) { + return sl.listenTCPProto(ctx, laddr, 0) +} + +func (sl *sysListener) listenTCPProto(ctx context.Context, laddr *TCPAddr, proto int) (*TCPListener, error) { var ctrlCtxFn func(cxt context.Context, network, address string, c syscall.RawConn) error if sl.ListenConfig.Control != nil { ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error { return sl.ListenConfig.Control(network, address, c) } } - fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, 0, "listen", ctrlCtxFn) + fd, err := internetSocket(ctx, sl.network, laddr, nil, syscall.SOCK_STREAM, proto, "listen", ctrlCtxFn) if err != nil { return nil, err } -- 2.48.1