github.com/cristalhq/netx@v0.0.0-20221116164110-442313ef3309/listener_linux.go (about)

     1  //go:build linux
     2  
     3  package netx
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"strconv"
    10  	"strings"
    11  	"syscall"
    12  )
    13  
    14  const (
    15  	soReusePort = 0x0F
    16  	tcpFastOpen = 0x17
    17  )
    18  
    19  func disableNoDelay(fd int) error {
    20  	return newError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1))
    21  }
    22  
    23  func enableReusePort(fd int) error {
    24  	return newError("setsockopt", syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1))
    25  }
    26  
    27  func enableDeferAccept(fd int) error {
    28  	return newError("setsockopt", syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_DEFER_ACCEPT, 1))
    29  }
    30  
    31  const fastOpenQueueLen = 16 * 1024
    32  
    33  func enableFastOpen(fd int, queueLen int) error {
    34  	return newError("setsockopt", syscall.SetsockoptInt(fd, syscall.SOL_TCP, tcpFastOpen, queueLen))
    35  }
    36  
    37  func soMaxConn() (int, error) {
    38  	data, err := ioutil.ReadFile(soMaxConnFilePath)
    39  	if err != nil {
    40  		// This error may trigger on travis build. Just use SOMAXCONN
    41  		if os.IsNotExist(err) {
    42  			return syscall.SOMAXCONN, nil
    43  		}
    44  		return -1, err
    45  	}
    46  	s := strings.TrimSpace(string(data))
    47  	n, err := strconv.Atoi(s)
    48  	if err != nil || n <= 0 {
    49  		return -1, fmt.Errorf("cannot parse somaxconn %q read from %s: %s", s, soMaxConnFilePath, err)
    50  	}
    51  
    52  	// Linux stores the backlog in a uint16.
    53  	// Truncate number to avoid wrapping.
    54  	// See https://github.com/golang/go/issues/5030 .
    55  	if n > 1<<16-1 {
    56  		n = 1<<16 - 1
    57  	}
    58  	return n, nil
    59  }
    60  
    61  const soMaxConnFilePath = "/proc/sys/net/core/somaxconn"
    62  
    63  func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
    64  	if family == syscall.AF_INET6 && sotype != syscall.SOCK_RAW {
    65  		// Allow both IP versions even if the OS default
    66  		// is otherwise. Note that some operating systems
    67  		// never admit this option.
    68  		err := newError("setsockopt", syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only)))
    69  		if err != nil {
    70  			return err
    71  		}
    72  	}
    73  
    74  	// Allow broadcast.
    75  	return newError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
    76  }
    77  
    78  func boolint(b bool) int {
    79  	if b {
    80  		return 1
    81  	}
    82  	return 0
    83  }