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  }