-
Notifications
You must be signed in to change notification settings - Fork 5
/
listener_unix.go
99 lines (82 loc) · 1.9 KB
/
listener_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
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// +build linux darwin netbsd freebsd openbsd dragonfly
package evnio
import (
"errors"
"net"
"syscall"
"github.com/dreamans/evnio/util"
"github.com/dreamans/evnio/evlog"
"github.com/dreamans/evnio/poller"
)
type ListenHandler func(ncfd int, sa syscall.Sockaddr)
type Listener struct {
ln net.Listener
fd int
newConnHandler ListenHandler
evLoop *EventLoop
}
func NewListener(addr string, evLoop *EventLoop, handler ListenHandler) (*Listener, error) {
listener := &Listener{
newConnHandler: handler,
evLoop: evLoop,
}
network, addr := util.ParseListenerAddr(addr)
ln, err := net.Listen(network, addr)
if err != nil {
return nil, err
}
listener.ln = ln
fd, err := listener.getNonblockFd()
if err != nil {
return nil, err
}
listener.fd = fd
return listener, nil
}
func (l *Listener) Fd() int {
return l.fd
}
func (l *Listener) EventHandler(fd int, events poller.Event) {
if events&poller.EventRead != 0 {
ncfd, sa, err := syscall.Accept(fd)
if err != nil {
if err != syscall.EAGAIN {
evlog.Errorf("[syscall.Accept]: %s", err.Error())
}
return
}
if err := syscall.SetNonblock(ncfd, true); err != nil {
_ = syscall.Close(ncfd)
evlog.Errorf("[syscall.SetNonblock]: %s", err.Error())
return
}
l.callNewConnHandler(ncfd, sa)
}
}
func (l *Listener) Close() error {
l.evLoop.Trigger(func() {
_ = l.evLoop.DelFdHandler(l.fd)
_ = l.ln.Close()
})
return nil
}
func (l *Listener) callNewConnHandler(ncfd int, sa syscall.Sockaddr) {
if l.newConnHandler != nil {
l.newConnHandler(ncfd, sa)
}
}
func (l *Listener) getNonblockFd() (int, error) {
tcpln, ok := l.ln.(*net.TCPListener)
if !ok {
return 0, errors.New("could not get file descriptor")
}
file, err := tcpln.File()
if err != nil {
return 0, err
}
fd := int(file.Fd())
if err = syscall.SetNonblock(fd, true); err != nil {
return 0, err
}
return fd, nil
}