-
Notifications
You must be signed in to change notification settings - Fork 0
/
listener.go
76 lines (70 loc) · 1.55 KB
/
listener.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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package net
import (
"context"
"net"
"os"
"syscall"
"time"
"github.com/pkg/errors"
)
//Listen listen net address
func Listen(endpoint *Endpoint) (net.Listener, error) {
addr, err := endpoint.Address()
if err != nil {
return nil, err
}
switch endpoint.endpointAddress.(type) {
case endpointAddressTCP:
return net.Listen(endpoint.Network(), addr)
case endpointAddressUnix:
return ListenUnixDomain(addr)
}
return nil, errors.Errorf("Listen: unsupported network '%s'", endpoint.Network())
}
//ListenUnixDomain safe listen unix domain socket
func ListenUnixDomain(addr string) (net.Listener, error) {
const (
unix = "unix"
connect = "connect"
check = "check-socket"
un = "unlink"
)
retErr := &net.OpError{
Net: unix,
Addr: &net.UnixAddr{
Net: unix,
Name: addr,
},
}
if st, e := os.Stat(addr); e == nil {
mode := st.Mode()
if mode&os.ModeSocket != os.ModeSocket {
retErr.Op = check
retErr.Err = syscall.ENOTSOCK
return nil, retErr
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
var c net.Conn
c, e = (&net.Dialer{}).DialContext(ctx, unix, addr)
cancel()
if e == nil {
_ = c.Close()
retErr.Op = connect
retErr.Err = syscall.EADDRINUSE
return nil, retErr
}
if netErr := new(net.OpError); errors.As(e, &netErr) {
if netErr.Timeout() {
retErr.Op = connect
retErr.Err = syscall.EADDRINUSE
return nil, retErr
}
}
if e = syscall.Unlink(addr); e != nil {
retErr.Op = un
retErr.Err = e
return nil, retErr
}
}
return net.Listen(unix, addr)
}