-
Notifications
You must be signed in to change notification settings - Fork 10
/
tfo_linux.go
93 lines (80 loc) · 2.46 KB
/
tfo_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
package tfo
import (
"context"
"errors"
"net"
"os"
"syscall"
"golang.org/x/sys/unix"
)
const setTFODialerFromSocketSockoptName = "unreachable"
func setTFODialerFromSocket(_ uintptr) error {
return nil
}
const sendtoImplicitConnectFlag = unix.MSG_FASTOPEN
// doConnectCanFallback returns whether err from [doConnect] indicates lack of TFO support.
func doConnectCanFallback(err error) bool {
// On Linux, calling sendto() on an unconnected TCP socket with zero or invalid flags
// returns -EPIPE. This indicates that the MSG_FASTOPEN flag is not recognized by the kernel.
//
// -EOPNOTSUPP is returned if the kernel recognizes the flag, but TFO is disabled via sysctl.
return err == unix.EPIPE || err == unix.EOPNOTSUPP
}
func (a *atomicDialTFOSupport) casLinuxSendto() bool {
return a.v.CompareAndSwap(uint32(dialTFOSupportDefault), uint32(dialTFOSupportLinuxSendto))
}
func (d *Dialer) dialTFO(ctx context.Context, network, address string, b []byte) (*net.TCPConn, error) {
if d.Fallback {
switch runtimeDialTFOSupport.load() {
case dialTFOSupportNone:
return d.dialAndWriteTCPConn(ctx, network, address, b)
case dialTFOSupportLinuxSendto:
return d.dialTFOFromSocket(ctx, network, address, b)
}
}
var canFallback bool
ctrlCtxFn := d.ControlContext
ctrlFn := d.Control
ld := *d
ld.ControlContext = func(ctx context.Context, network, address string, c syscall.RawConn) (err error) {
switch {
case ctrlCtxFn != nil:
if err = ctrlCtxFn(ctx, network, address, c); err != nil {
return err
}
case ctrlFn != nil:
if err = ctrlFn(network, address, c); err != nil {
return err
}
}
if cerr := c.Control(func(fd uintptr) {
err = setTFODialer(fd)
}); cerr != nil {
return cerr
}
if err != nil {
if d.Fallback && errors.Is(err, errors.ErrUnsupported) {
canFallback = true
}
return os.NewSyscallError("setsockopt(TCP_FASTOPEN_CONNECT)", err)
}
return nil
}
nc, err := ld.Dialer.DialContext(ctx, network, address)
if err != nil {
if d.Fallback && canFallback {
runtimeDialTFOSupport.casLinuxSendto()
return d.dialTFOFromSocket(ctx, network, address, b)
}
return nil, err
}
if err = netConnWriteBytes(ctx, nc, b); err != nil {
nc.Close()
return nil, err
}
return nc.(*net.TCPConn), nil
}
func dialTCPAddr(network string, laddr, raddr *net.TCPAddr, b []byte) (*net.TCPConn, error) {
d := Dialer{Dialer: net.Dialer{LocalAddr: laddr}}
return d.dialTFO(context.Background(), network, raddr.String(), b)
}