-
Notifications
You must be signed in to change notification settings - Fork 9
/
tfo_darwin.go
124 lines (104 loc) · 2.63 KB
/
tfo_darwin.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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
package tfo
import (
"context"
"errors"
"net"
"os"
"syscall"
"golang.org/x/sys/unix"
)
func (lc *ListenConfig) listenTFO(ctx context.Context, network, address string) (net.Listener, error) {
// When setting TCP_FASTOPEN_FORCE_ENABLE, the socket must be in the TCPS_CLOSED state.
// This means setting it before listen().
//
// However, setting TCP_FASTOPEN requires being in the TCPS_LISTEN state,
// which means setting it after listen().
ctrlFn := lc.Control
llc := *lc
llc.Control = func(network, address string, c syscall.RawConn) (err error) {
if ctrlFn != nil {
if err = ctrlFn(network, address, c); err != nil {
return err
}
}
if cerr := c.Control(func(fd uintptr) {
err = setTFOForceEnable(fd)
}); cerr != nil {
return cerr
}
if err != nil {
if !lc.Fallback || !errors.Is(err, errors.ErrUnsupported) {
return os.NewSyscallError("setsockopt(TCP_FASTOPEN_FORCE_ENABLE)", err)
}
runtimeListenNoTFO.Store(true)
}
return nil
}
ln, err := llc.ListenConfig.Listen(ctx, network, address)
if err != nil {
return nil, err
}
rawConn, err := ln.(*net.TCPListener).SyscallConn()
if err != nil {
ln.Close()
return nil, err
}
if cerr := rawConn.Control(func(fd uintptr) {
err = setTFOListener(fd)
}); cerr != nil {
ln.Close()
return nil, cerr
}
if err != nil {
ln.Close()
if !lc.Fallback || !errors.Is(err, errors.ErrUnsupported) {
return nil, os.NewSyscallError("setsockopt(TCP_FASTOPEN)", err)
}
runtimeListenNoTFO.Store(true)
}
return ln, nil
}
const AF_MULTIPATH = 39
func (d *Dialer) socket(domain int) (fd int, err error) {
if d.MultipathTCP() {
domain = AF_MULTIPATH
}
syscall.ForkLock.RLock()
fd, err = unix.Socket(domain, unix.SOCK_STREAM, unix.IPPROTO_TCP)
if err != nil {
syscall.ForkLock.RUnlock()
return 0, os.NewSyscallError("socket", err)
}
unix.CloseOnExec(fd)
syscall.ForkLock.RUnlock()
if err = unix.SetNonblock(fd, true); err != nil {
unix.Close(fd)
return 0, os.NewSyscallError("setnonblock", err)
}
return fd, nil
}
func (d *Dialer) setIPv6Only(fd int, family int, ipv6only bool) error {
if d.MultipathTCP() {
return nil
}
return setIPv6Only(fd, family, ipv6only)
}
const setTFODialerFromSocketSockoptName = "TCP_FASTOPEN_FORCE_ENABLE"
const connectSyscallName = "connectx"
func doConnect(fd uintptr, rsa unix.Sockaddr, b []byte) (int, error) {
var (
flags uint32
iov []unix.Iovec
)
if len(b) > 0 {
flags = unix.CONNECT_DATA_IDEMPOTENT
iov = []unix.Iovec{
{
Base: &b[0],
Len: uint64(len(b)),
},
}
}
n, err := unix.Connectx(int(fd), 0, nil, rsa, unix.SAE_ASSOCID_ANY, flags, iov, nil)
return int(n), err
}