]> Cypherpunks.ru repositories - gostls13.git/commitdiff
net: mptcp: implement dialMPTCP
authorMatthieu Baerts <matthieu.baerts@tessares.net>
Fri, 24 Feb 2023 16:51:57 +0000 (17:51 +0100)
committerGopher Robot <gobot@golang.org>
Wed, 29 Mar 2023 22:12:18 +0000 (22:12 +0000)
This function is called when the user has requested MPTCP via
SetMultipathTCP in the Dialer.

This new function falls back to dialTCP on operating systems that do not
support MPTCP or if MPTCP is not supported.

On Dialer side, MultipathTCP function can be used to know if the package
will try to use MPTCP or not when Dial is called.

Note that this new dialMPTCP function returns a TCPConn object, like
dialTCP. A new MPTCPConn object using the following composition could
have been returned:

    type MPTCPConn struct {
        *TCPConn
    }

But the drawback is that if MPTCP is used by default one day (see #56539
issue on GitHub), Dial will return a different object: this new
MPTCPConn type instead of the previously expected TCPConn. This can
cause issues for apps checking the returned object.

This work has been co-developped by Gregory Detal
<gregory.detal@tessares.net>.

Updates #56539

Change-Id: I0f9b5b81f630b39142bdd553d4f1b4c775f1dff0
Reviewed-on: https://go-review.googlesource.com/c/go/+/471136
Reviewed-by: Ian Lance Taylor <iant@google.com>
Auto-Submit: Ian Lance Taylor <iant@google.com>
Run-TryBot: Emmanuel Odeke <emmanuel@orijtech.com>
Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com>
Run-TryBot: Ian Lance Taylor <iant@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
api/next/56539.txt [new file with mode: 0644]
src/net/dial.go
src/net/mptcpsock_linux.go
src/net/mptcpsock_stub.go
src/net/tcpsock_posix.go

diff --git a/api/next/56539.txt b/api/next/56539.txt
new file mode 100644 (file)
index 0000000..ad1dfb7
--- /dev/null
@@ -0,0 +1,2 @@
+pkg net, method (*Dialer) MultipathTCP() bool #56539
+pkg net, method (*Dialer) SetMultipathTCP(bool) #56539
index 35c2761d2906b2c4fc447b47d6ae8aabcf5e424e..3cc8f840c5fcf71e040b8e4142d5b46602388d0e 100644 (file)
@@ -141,6 +141,11 @@ type Dialer struct {
        //
        // If ControlContext is not nil, Control is ignored.
        ControlContext func(ctx context.Context, network, address string, c syscall.RawConn) error
+
+       // If mptcpStatus is set to a value allowing Multipath TCP (MPTCP) to be
+       // used, any call to Dial with "tcp(4|6)" as network will use MPTCP if
+       // supported by the operating system.
+       mptcpStatus mptcpStatus
 }
 
 func (d *Dialer) dualStack() bool { return d.FallbackDelay >= 0 }
@@ -314,6 +319,24 @@ func (r *Resolver) resolveAddrList(ctx context.Context, op, network, addr string
        return naddrs, nil
 }
 
+// MultipathTCP reports whether MPTCP will be used.
+//
+// This method doesn't check if MPTCP is supported by the operating
+// system or not.
+func (d *Dialer) MultipathTCP() bool {
+       return d.mptcpStatus.get()
+}
+
+// SetMultipathTCP directs the Dial methods 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 server,
+// the Dial methods will fall back to TCP.
+func (d *Dialer) SetMultipathTCP(use bool) {
+       d.mptcpStatus.set(use)
+}
+
 // Dial connects to the address on the named network.
 //
 // Known networks are "tcp", "tcp4" (IPv4-only), "tcp6" (IPv6-only),
@@ -610,7 +633,11 @@ func (sd *sysDialer) dialSingle(ctx context.Context, ra Addr) (c Conn, err error
        switch ra := ra.(type) {
        case *TCPAddr:
                la, _ := la.(*TCPAddr)
-               c, err = sd.dialTCP(ctx, la, ra)
+               if sd.MultipathTCP() {
+                       c, err = sd.dialMPTCP(ctx, la, ra)
+               } else {
+                       c, err = sd.dialTCP(ctx, la, ra)
+               }
        case *UDPAddr:
                la, _ := la.(*UDPAddr)
                c, err = sd.dialUDP(ctx, la, ra)
index c88b07c907c74528dd54d3007faafda21b312a1e..a1c3805795459b78814d75f142f0443a4a82ee97 100644 (file)
@@ -5,6 +5,7 @@
 package net
 
 import (
+       "context"
        "errors"
        "internal/poll"
        "sync"
@@ -41,3 +42,12 @@ func initMPTCPavailable() {
                mptcpAvailable = true
        }
 }
+
+func (sd *sysDialer) dialMPTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+       // Fallback to dialTCP if Multipath TCP isn't supported on this operating system.
+       if !supportsMultipathTCP() {
+               return sd.dialTCP(ctx, laddr, raddr)
+       }
+
+       return sd.doDialTCPProto(ctx, laddr, raddr, _IPPROTO_MPTCP)
+}
index 5508288ef5d7c1899f1500d524e9044c6a51c4f5..62f5d4973137174389c67e2d5e9d57d2024d93cf 100644 (file)
@@ -5,3 +5,11 @@
 //go:build !linux
 
 package net
+
+import (
+       "context"
+)
+
+func (sd *sysDialer) dialMPTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+       return sd.dialTCP(ctx, laddr, raddr)
+}
index 0b3fa1ae0c3ae6424096dadbc26bffb518602d7c..f8d4b3e4d0e434f0215d2b9efa321eeacded599b 100644 (file)
@@ -65,13 +65,17 @@ func (sd *sysDialer) dialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPCo
 }
 
 func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCPConn, error) {
+       return sd.doDialTCPProto(ctx, laddr, raddr, 0)
+}
+
+func (sd *sysDialer) doDialTCPProto(ctx context.Context, laddr, raddr *TCPAddr, proto int) (*TCPConn, error) {
        ctrlCtxFn := sd.Dialer.ControlContext
        if ctrlCtxFn == nil && sd.Dialer.Control != nil {
                ctrlCtxFn = func(cxt context.Context, network, address string, c syscall.RawConn) error {
                        return sd.Dialer.Control(network, address, c)
                }
        }
-       fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", ctrlCtxFn)
+       fd, err := internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, proto, "dial", ctrlCtxFn)
 
        // TCP has a rarely used mechanism called a 'simultaneous connection' in
        // which Dial("tcp", addr1, addr2) run on the machine at addr1 can
@@ -101,7 +105,7 @@ func (sd *sysDialer) doDialTCP(ctx context.Context, laddr, raddr *TCPAddr) (*TCP
                if err == nil {
                        fd.Close()
                }
-               fd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, 0, "dial", ctrlCtxFn)
+               fd, err = internetSocket(ctx, sd.network, laddr, raddr, syscall.SOCK_STREAM, proto, "dial", ctrlCtxFn)
        }
 
        if err != nil {