forked from libp2p/go-reuseport
-
Notifications
You must be signed in to change notification settings - Fork 0
/
available_unix.go
47 lines (39 loc) · 1.13 KB
/
available_unix.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// +build darwin freebsd dragonfly netbsd openbsd linux
package reuseport
import (
"golang.org/x/sys/unix"
"sync"
"syscall"
"time"
sockaddrnet "github.com/libp2p/go-sockaddr/net"
)
var (
hasReusePort bool
didReusePort sync.Once
)
// Available returns whether or not SO_REUSEPORT is available in the OS.
// It does so by attepting to open a tcp socket, setting the option, and
// checking ENOPROTOOPT on error. After checking, the decision is cached
// for the rest of the process run.
func available() bool {
didReusePort.Do(checkReusePort)
return hasReusePort
}
func checkReusePort() {
// there may be fluke reasons to fail to open a socket.
// so we give it 5 shots. if not, give up and call it not avail.
for i := 0; i < 5; i++ {
// try to setup a TCP socket.
fd, err := socket(sockaddrnet.AF_INET, sockaddrnet.SOCK_STREAM, sockaddrnet.IPPROTO_TCP)
if err == nil {
unix.Close(fd)
hasReusePort = true
return
}
if errno, ok := err.(syscall.Errno); ok && errno == unix.ENOPROTOOPT {
return // :( that's all folks.
}
// not an errno? or not ENOPROTOOPT? retry.
time.Sleep(20 * time.Millisecond) // wait a bit
}
}