-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathserver.go
153 lines (129 loc) · 3.12 KB
/
server.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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
package api
import (
"net"
"os"
"sync"
"time"
log "github.com/sirupsen/logrus"
)
const (
// serverTimeout is the timeout for an entire request/response exchange
// initiated by a client
serverTimeout = 30 * time.Second
)
// Server is a Daemon API server
type Server struct {
sockFile string
listen net.Listener
requests chan *Request
mutex sync.Mutex
stop bool
}
// setStopping marks the server as stopping
func (s *Server) setStopping() {
s.mutex.Lock()
defer s.mutex.Unlock()
s.stop = true
}
// isStopping returns whether the server is stopping
func (s *Server) isStopping() bool {
s.mutex.Lock()
defer s.mutex.Unlock()
return s.stop
}
// handleRequest handles a request from the client
func (s *Server) handleRequest(conn net.Conn) {
// set timeout for entire request/response exchange
deadline := time.Now().Add(serverTimeout)
if err := conn.SetDeadline(deadline); err != nil {
log.WithError(err).Error("Daemon error setting deadline")
_ = conn.Close()
return
}
// read message from client
msg, err := ReadMessage(conn)
if err != nil {
log.WithError(err).Error("Daemon receive message error")
_ = conn.Close()
return
}
// check if its a known message type
switch msg.Type {
case TypeVPNConfigUpdate:
default:
// send Error and disconnect
e := NewError([]byte("invalid message"))
if err := WriteMessage(conn, e); err != nil {
log.WithError(err).Error("Daemon message send error")
}
_ = conn.Close()
}
// forward client's request to daemon
s.requests <- &Request{
msg: msg,
conn: conn,
}
}
// handleClients handles client connections
func (s *Server) handleClients() {
defer func() {
_ = s.listen.Close()
close(s.requests)
}()
for {
// wait for new client connection
conn, err := s.listen.Accept()
if err != nil {
if s.isStopping() {
// ignore error when shutting down
return
}
log.WithError(err).Error("Daemon listener error")
return
}
// read request from client connection and handle it
s.handleRequest(conn)
}
}
// Start starts the API server
func (s *Server) Start() {
// cleanup existing sock file, this should normally fail
if err := os.Remove(s.sockFile); err == nil {
log.Warn("Removed existing unix socket file")
}
// start listener
listen, err := net.Listen("unix", s.sockFile)
if err != nil {
log.WithError(err).Fatal("Daemon could not start unix listener")
}
s.listen = listen
// make sure only we can access the sock file
if err := os.Chmod(s.sockFile, 0700); err != nil {
log.WithError(err).Error("Daemon could not set permissions of sock file")
}
// handle client connections
go s.handleClients()
}
// Stop stops the API server
func (s *Server) Stop() {
// stop listener
s.setStopping()
err := s.listen.Close()
if err != nil {
log.WithError(err).Fatal("Daemon could not close unix listener")
}
for range s.requests {
// wait for clients channel close
}
}
// Requests returns the clients channel
func (s *Server) Requests() chan *Request {
return s.requests
}
// NewServer returns a new API server
func NewServer(sockFile string) *Server {
return &Server{
sockFile: sockFile,
requests: make(chan *Request),
}
}