--- /dev/null
+pkg net, method (*Dialer) MultipathTCP() bool #56539
+pkg net, method (*Dialer) SetMultipathTCP(bool) #56539
//
// 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 }
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),
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)
package net
import (
+ "context"
"errors"
"internal/poll"
"sync"
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)
+}
//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)
+}
}
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
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 {