diff options
author | Aliaksandr Valialkin <valyala@gmail.com> | 2016-09-13 18:52:22 +0300 |
---|---|---|
committer | Aliaksandr Valialkin <valyala@gmail.com> | 2016-09-13 18:52:22 +0300 |
commit | 95be7a58499b79d1a42a4e9880fb90645345c021 (patch) | |
tree | 809a19eb429be957543a6645e03f1003ad5730f2 /reuseport | |
parent | Do not busy wait on free connection in DoDeadline and DoTimeout, since this m... (diff) | |
download | fasthttp-95be7a58499b79d1a42a4e9880fb90645345c021.tar.gz fasthttp-95be7a58499b79d1a42a4e9880fb90645345c021.tar.bz2 fasthttp-95be7a58499b79d1a42a4e9880fb90645345c021.zip |
switch reuseport to github.com/valyala/tcplisten
Diffstat (limited to 'reuseport')
-rw-r--r-- | reuseport/reuseport.go | 112 | ||||
-rw-r--r-- | reuseport/reuseport_bsd.go | 19 | ||||
-rw-r--r-- | reuseport/reuseport_linux.go | 29 |
3 files changed, 13 insertions, 147 deletions
diff --git a/reuseport/reuseport.go b/reuseport/reuseport.go index f93179e..fe80eae 100644 --- a/reuseport/reuseport.go +++ b/reuseport/reuseport.go @@ -9,11 +9,10 @@ package reuseport import ( - "errors" "fmt" + "github.com/valyala/tcplisten" "net" - "os" - "syscall" + "strings" ) // ErrNoReusePort is returned if the OS doesn't support SO_REUSEPORT. @@ -36,107 +35,22 @@ func (e *ErrNoReusePort) Error() string { // // - TCP_FASTOPEN. See https://lwn.net/Articles/508865/ for details. // +// Use https://github.com/valyala/tcplisten if you want customizing +// these options. +// // Only tcp4 and tcp6 networks are supported. // // ErrNoReusePort error is returned if the system doesn't support SO_REUSEPORT. func Listen(network, addr string) (net.Listener, error) { - sa, soType, err := getSockaddr(network, addr) - if err != nil { - return nil, err - } - - syscall.ForkLock.RLock() - fd, err := syscall.Socket(soType, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) - if err == nil { - syscall.CloseOnExec(fd) - } - syscall.ForkLock.RUnlock() - if err != nil { - return nil, err - } - - if err = fdSetup(fd, sa, addr); err != nil { - syscall.Close(fd) - return nil, err - } - - name := fmt.Sprintf("reuseport.%d.%s.%s", os.Getpid(), network, addr) - file := os.NewFile(uintptr(fd), name) - ln, err := net.FileListener(file) - if err != nil { - file.Close() - return nil, err - } - - if err = file.Close(); err != nil { - ln.Close() - return nil, err - } - - return ln, nil -} - -func fdSetup(fd int, sa syscall.Sockaddr, addr string) error { - var err error - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil { - return fmt.Errorf("cannot enable SO_REUSEADDR: %s", err) - } - - if err = syscall.SetsockoptInt(fd, syscall.SOL_SOCKET, soReusePort, 1); err != nil { - return &ErrNoReusePort{err} - } - - if err = enableDeferAccept(fd); err != nil { - return err - } - - if err = enableFastOpen(fd); err != nil { - return err - } - - if err = syscall.Bind(fd, sa); err != nil { - return fmt.Errorf("cannot bind to %q: %s", addr, err) - } - - if err = syscall.Listen(fd, syscall.SOMAXCONN); err != nil { - return fmt.Errorf("cannot listen on %q: %s", addr, err) + ln, err := cfg.NewListener(network, addr) + if err != nil && strings.Contains(err.Error(), "SO_REUSEPORT") { + return nil, &ErrNoReusePort{err} } - - return nil + return ln, err } -func getSockaddr(network, addr string) (sa syscall.Sockaddr, soType int, err error) { - // TODO: add support for tcp networks. - - if network != "tcp4" && network != "tcp6" { - return nil, -1, errors.New("only tcp4 and tcp6 network is supported") - } - - tcpAddr, err := net.ResolveTCPAddr(network, addr) - if err != nil { - return nil, -1, err - } - - switch network { - case "tcp4": - var sa4 syscall.SockaddrInet4 - sa4.Port = tcpAddr.Port - copy(sa4.Addr[:], tcpAddr.IP.To4()) - return &sa4, syscall.AF_INET, nil - case "tcp6": - var sa6 syscall.SockaddrInet6 - sa6.Port = tcpAddr.Port - copy(sa6.Addr[:], tcpAddr.IP.To16()) - if tcpAddr.Zone != "" { - ifi, err := net.InterfaceByName(tcpAddr.Zone) - if err != nil { - return nil, -1, err - } - sa6.ZoneId = uint32(ifi.Index) - } - return &sa6, syscall.AF_INET6, nil - default: - return nil, -1, errors.New("Unknown network type " + network) - } +var cfg = &tcplisten.Config{ + ReusePort: true, + DeferAccept: true, + FastOpen: true, } diff --git a/reuseport/reuseport_bsd.go b/reuseport/reuseport_bsd.go deleted file mode 100644 index 03b75dc..0000000 --- a/reuseport/reuseport_bsd.go +++ /dev/null @@ -1,19 +0,0 @@ -// +build darwin dragonfly freebsd netbsd openbsd rumprun - -package reuseport - -import ( - "syscall" -) - -const soReusePort = syscall.SO_REUSEPORT - -func enableDeferAccept(fd int) error { - // TODO: implement SO_ACCEPTFILTER:dataready here - return nil -} - -func enableFastOpen(fd int) error { - // TODO: implement TCP_FASTOPEN when it will be ready - return nil -} diff --git a/reuseport/reuseport_linux.go b/reuseport/reuseport_linux.go deleted file mode 100644 index 0f39d11..0000000 --- a/reuseport/reuseport_linux.go +++ /dev/null @@ -1,29 +0,0 @@ -// +build linux - -package reuseport - -import ( - "fmt" - "syscall" -) - -const ( - soReusePort = 0x0F - tcpFastOpen = 0x17 -) - -func enableDeferAccept(fd int) error { - if err := syscall.SetsockoptInt(fd, syscall.IPPROTO_TCP, syscall.TCP_DEFER_ACCEPT, 1); err != nil { - return fmt.Errorf("cannot enable TCP_DEFER_ACCEPT: %s", err) - } - return nil -} - -func enableFastOpen(fd int) error { - if err := syscall.SetsockoptInt(fd, syscall.SOL_TCP, tcpFastOpen, fastOpenQlen); err != nil { - return fmt.Errorf("cannot enable TCP_FASTOPEN(qlen=%d): %s", fastOpenQlen, err) - } - return nil -} - -const fastOpenQlen = 16 * 1024 |