github.com/database64128/tfo-go/v2@v2.2.0/tfo_darwin.go (about) 1 package tfo 2 3 import ( 4 "context" 5 "errors" 6 "net" 7 "syscall" 8 9 "golang.org/x/sys/unix" 10 ) 11 12 func (lc *ListenConfig) listenTFO(ctx context.Context, network, address string) (net.Listener, error) { 13 // When setting TCP_FASTOPEN_FORCE_ENABLE, the socket must be in the TCPS_CLOSED state. 14 // This means setting it before listen(). 15 // 16 // However, setting TCP_FASTOPEN requires being in the TCPS_LISTEN state, 17 // which means setting it after listen(). 18 19 ctrlFn := lc.Control 20 llc := *lc 21 llc.Control = func(network, address string, c syscall.RawConn) (err error) { 22 if ctrlFn != nil { 23 if err = ctrlFn(network, address, c); err != nil { 24 return err 25 } 26 } 27 28 if cerr := c.Control(func(fd uintptr) { 29 err = setTFOForceEnable(fd) 30 }); cerr != nil { 31 return cerr 32 } 33 34 if err != nil { 35 if !lc.Fallback || !errors.Is(err, errors.ErrUnsupported) { 36 return wrapSyscallError("setsockopt(TCP_FASTOPEN_FORCE_ENABLE)", err) 37 } 38 runtimeListenNoTFO.Store(true) 39 } 40 return nil 41 } 42 43 ln, err := llc.ListenConfig.Listen(ctx, network, address) 44 if err != nil { 45 return nil, err 46 } 47 48 rawConn, err := ln.(*net.TCPListener).SyscallConn() 49 if err != nil { 50 ln.Close() 51 return nil, err 52 } 53 54 if cerr := rawConn.Control(func(fd uintptr) { 55 err = setTFOListener(fd) 56 }); cerr != nil { 57 ln.Close() 58 return nil, cerr 59 } 60 61 if err != nil { 62 ln.Close() 63 if !lc.Fallback || !errors.Is(err, errors.ErrUnsupported) { 64 return nil, wrapSyscallError("setsockopt(TCP_FASTOPEN)", err) 65 } 66 runtimeListenNoTFO.Store(true) 67 } 68 69 return ln, nil 70 } 71 72 const AF_MULTIPATH = 39 73 74 func (d *Dialer) socket(domain int) (fd int, err error) { 75 if d.MultipathTCP() { 76 domain = AF_MULTIPATH 77 } 78 fd, err = unix.Socket(domain, unix.SOCK_STREAM, unix.IPPROTO_TCP) 79 if err != nil { 80 return 81 } 82 unix.CloseOnExec(fd) 83 err = unix.SetNonblock(fd, true) 84 if err != nil { 85 unix.Close(fd) 86 fd = 0 87 } 88 return 89 } 90 91 func (d *Dialer) setIPv6Only(fd int, family int, ipv6only bool) error { 92 if d.MultipathTCP() { 93 return nil 94 } 95 return setIPv6Only(fd, family, ipv6only) 96 } 97 98 const setTFODialerFromSocketSockoptName = "TCP_FASTOPEN_FORCE_ENABLE" 99 100 const connectSyscallName = "connectx" 101 102 func doConnect(fd uintptr, rsa syscall.Sockaddr, b []byte) (int, error) { 103 n, err := Connectx(int(fd), 0, nil, rsa, b) 104 return int(n), err 105 }