// +build linux darwin dragonfly freebsd netbsd openbsd rumprun

// Package tcplisten provides customizable TCP net.Listener with various // performance-related options: // // - SO_REUSEPORT. This option allows linear scaling server performance // on multi-CPU servers. // See https://www.nginx.com/blog/socket-sharding-nginx-release-1-9-1/ for details. // // - TCP_DEFER_ACCEPT. This option expects the server reads from the accepted // connection before writing to them. // // - TCP_FASTOPEN. See https://lwn.net/Articles/508865/ for details. // // The package is derived from https://github.com/kavu/go_reuseport .
package tcplisten import ( ) // Config provides options to enable on the returned listener. type Config struct { // ReusePort enables SO_REUSEPORT. ReusePort bool // DeferAccept enables TCP_DEFER_ACCEPT. DeferAccept bool // FastOpen enables TCP_FASTOPEN. FastOpen bool // Backlog is the maximum number of pending TCP connections the listener // may queue before passing them to Accept. // See man 2 listen for details. // // By default system-level backlog value is used. Backlog int } // NewListener returns TCP listener with options set in the Config. // // The function may be called many times for creating distinct listeners // with the given config. // // Only tcp4 and tcp6 networks are supported. func ( *Config) (, string) (net.Listener, error) { , , := getSockaddr(, ) if != nil { return nil, } , := newSocketCloexec(, syscall.SOCK_STREAM, syscall.IPPROTO_TCP) if != nil { return nil, } if = .fdSetup(, , ); != nil { syscall.Close() return nil, } := fmt.Sprintf("reuseport.%d.%s.%s", os.Getpid(), , ) := os.NewFile(uintptr(), ) , := net.FileListener() if != nil { .Close() return nil, } if = .Close(); != nil { .Close() return nil, } return , nil } func ( *Config) ( int, syscall.Sockaddr, string) error { var error if = syscall.SetsockoptInt(, syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); != nil { return fmt.Errorf("cannot enable SO_REUSEADDR: %s", ) } // This should disable Nagle's algorithm in all accepted sockets by default. // Users may enable it with net.TCPConn.SetNoDelay(false). if = syscall.SetsockoptInt(, syscall.IPPROTO_TCP, syscall.TCP_NODELAY, 1); != nil { return fmt.Errorf("cannot disable Nagle's algorithm: %s", ) } if .ReusePort { if = syscall.SetsockoptInt(, syscall.SOL_SOCKET, soReusePort, 1); != nil { return fmt.Errorf("cannot enable SO_REUSEPORT: %s", ) } } if .DeferAccept { if = enableDeferAccept(); != nil { return } } if .FastOpen { if = enableFastOpen(); != nil { return } } if = syscall.Bind(, ); != nil { return fmt.Errorf("cannot bind to %q: %s", , ) } := .Backlog if <= 0 { if , = soMaxConn(); != nil { return fmt.Errorf("cannot determine backlog to pass to listen(2): %s", ) } } if = syscall.Listen(, ); != nil { return fmt.Errorf("cannot listen on %q: %s", , ) } return nil } func getSockaddr(, string) ( syscall.Sockaddr, int, error) { if != "tcp4" && != "tcp6" { return nil, -1, errors.New("only tcp4 and tcp6 network is supported") } , := net.ResolveTCPAddr(, ) if != nil { return nil, -1, } switch { case "tcp4": var syscall.SockaddrInet4 .Port = .Port copy(.Addr[:], .IP.To4()) return &, syscall.AF_INET, nil case "tcp6": var syscall.SockaddrInet6 .Port = .Port copy(.Addr[:], .IP.To16()) if .Zone != "" { , := net.InterfaceByName(.Zone) if != nil { return nil, -1, } .ZoneId = uint32(.Index) } return &, syscall.AF_INET6, nil default: return nil, -1, errors.New("Unknown network type " + ) } }