aboutsummaryrefslogtreecommitdiff
path: root/reuseport
diff options
context:
space:
mode:
authorGravatar Aliaksandr Valialkin <valyala@gmail.com> 2016-09-13 18:52:22 +0300
committerGravatar Aliaksandr Valialkin <valyala@gmail.com> 2016-09-13 18:52:22 +0300
commit95be7a58499b79d1a42a4e9880fb90645345c021 (patch)
tree809a19eb429be957543a6645e03f1003ad5730f2 /reuseport
parentDo not busy wait on free connection in DoDeadline and DoTimeout, since this m... (diff)
downloadfasthttp-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.go112
-rw-r--r--reuseport/reuseport_bsd.go19
-rw-r--r--reuseport/reuseport_linux.go29
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