github.com/sagernet/tfo-go@v0.0.0-20231209031829-7b5343ac1dc6/tfo_darwin.go (about)

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