diff --git a/api/next/56539.txt b/api/next/56539.txt index ad1dfb72510..65d0418aff1 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 3cc8f840c5f..58e3b392d95 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 a1c38057954..4663d28b4b4 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 62f5d497313..ae06772896a 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 f8d4b3e4d0e..ed144a6ddc2 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 }