Skip to content
This repository was archived by the owner on Jul 8, 2020. It is now read-only.

Commit 114653a

Browse files
folbrichtlunny
authored andcommitted
Improve shutdown behaviour (#42)
1 parent c63d319 commit 114653a

File tree

3 files changed

+36
-7
lines changed

3 files changed

+36
-7
lines changed

logger.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,11 @@ func (logger *StdLogger) PrintCommand(sessionId string, command string, params s
3838
func (logger *StdLogger) PrintResponse(sessionId string, code int, message string) {
3939
log.Printf("%s < %d %s", sessionId, code, message)
4040
}
41+
42+
// Silent logger, produces no output
43+
type DiscardLogger struct{}
44+
45+
func (logger *DiscardLogger) Print(sessionId string, message interface{}) {}
46+
func (logger *DiscardLogger) Printf(sessionId string, format string, v ...interface{}) {}
47+
func (logger *DiscardLogger) PrintCommand(sessionId string, command string, params string) {}
48+
func (logger *DiscardLogger) PrintResponse(sessionId string, code int, message string) {}

server.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ package server
66

77
import (
88
"bufio"
9+
"context"
910
"crypto/tls"
11+
"errors"
1012
"net"
1113
"strconv"
1214
)
@@ -69,8 +71,14 @@ type Server struct {
6971
logger Logger
7072
listener net.Listener
7173
tlsConfig *tls.Config
74+
ctx context.Context
75+
cancel context.CancelFunc
7276
}
7377

78+
// ErrServerClosed is returned by ListenAndServe() or Serve() when a shutdown
79+
// was requested.
80+
var ErrServerClosed = errors.New("ftp: Server closed")
81+
7482
// serverOptsWithDefaults copies an ServerOpts struct into a new struct,
7583
// then adds any default values that are missing and returns the new data.
7684
func serverOptsWithDefaults(opts *ServerOpts) *ServerOpts {
@@ -223,12 +231,21 @@ func (server *Server) ListenAndServe() error {
223231
//
224232
func (server *Server) Serve(l net.Listener) error {
225233
server.listener = l
234+
server.ctx, server.cancel = context.WithCancel(context.Background())
226235
sessionID := ""
227236
for {
228237
tcpConn, err := server.listener.Accept()
229238
if err != nil {
239+
select {
240+
case <-server.ctx.Done():
241+
return ErrServerClosed
242+
default:
243+
}
230244
server.logger.Printf(sessionID, "listening error: %v", err)
231-
break
245+
if ne, ok := err.(net.Error); ok && ne.Temporary() {
246+
continue
247+
}
248+
return err
232249
}
233250
driver, err := server.Factory.NewDriver()
234251
if err != nil {
@@ -239,11 +256,13 @@ func (server *Server) Serve(l net.Listener) error {
239256
go ftpConn.Serve()
240257
}
241258
}
242-
return nil
243259
}
244260

245261
// Shutdown will gracefully stop a server. Already connected clients will retain their connections
246262
func (server *Server) Shutdown() error {
263+
if server.cancel != nil {
264+
server.cancel()
265+
}
247266
if server.listener != nil {
248267
return server.listener.Close()
249268
}

server_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,18 @@ func runServer(t *testing.T, execute func()) {
3232
Name: "admin",
3333
Password: "admin",
3434
},
35+
Logger: new(server.DiscardLogger),
3536
}
3637

37-
server := server.NewServer(opt)
38+
s := server.NewServer(opt)
3839
go func() {
39-
err := server.ListenAndServe()
40-
assert.NoError(t, err)
40+
err := s.ListenAndServe()
41+
assert.EqualError(t, err, server.ErrServerClosed.Error())
4142
}()
4243

4344
execute()
4445

45-
assert.NoError(t, server.Shutdown())
46+
assert.NoError(t, s.Shutdown())
4647
}
4748

4849
func TestConnect(t *testing.T) {
@@ -127,6 +128,7 @@ func TestServe(t *testing.T) {
127128
Name: "admin",
128129
Password: "admin",
129130
},
131+
Logger: new(server.DiscardLogger),
130132
}
131133

132134
// Start the listener
@@ -137,7 +139,7 @@ func TestServe(t *testing.T) {
137139
s := server.NewServer(opt)
138140
go func() {
139141
err := s.Serve(l)
140-
assert.NoError(t, err)
142+
assert.EqualError(t, err, server.ErrServerClosed.Error())
141143
}()
142144

143145
// Give server 0.5 seconds to get to the listening state

0 commit comments

Comments
 (0)