Don't relay on deadline to stop the server.

We just send ourselves an UDP or TCP packet so that the listener fails
through and picks up the quit bool send on the channel.
This commit is contained in:
Miek Gieben 2014-08-19 21:46:00 +01:00
parent 263a337674
commit f912994258
3 changed files with 12 additions and 21 deletions

View File

@ -223,8 +223,6 @@ type Server struct {
WriteTimeout time.Duration
// TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
IdleTimeout func() time.Duration
// Listener deadline timeout, defaults to 1 * time.Second.
Deadline time.Duration
// Secret(s) for Tsig map[<zonename>]<base64 secret>.
TsigSecret map[string]string
@ -305,12 +303,15 @@ func (srv *Server) ActivateAndServe() error {
// Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and
// ActivateAndServe will return.
func (srv *Server) Shutdown() {
c := new(Client)
switch srv.Net {
case "tcp", "tcp4", "tcp6":
srv.stopTCP <- true
c.Net = "tcp"
go func() { srv.stopTCP <- true }()
c.Exchange(new(Msg), srv.Addr)
case "udp", "udp4", "udp6":
// TODO(miek): does not work for udp
// srv.stopUDP <- true
go func() { srv.stopUDP <- true }()
c.Exchange(new(Msg), srv.Addr)
}
}
@ -326,12 +327,7 @@ func (srv *Server) serveTCP(l *net.TCPListener) error {
if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout
}
deadline := 1 * time.Second
if srv.Deadline != 0 {
deadline = srv.Deadline
}
for {
l.SetDeadline(time.Now().Add(deadline))
rw, e := l.AcceptTCP()
select {
case <-srv.stopTCP:
@ -365,12 +361,8 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout
}
deadline := 1 * time.Second
if srv.Deadline != 0 {
deadline = srv.Deadline
}
// deadline is not used here
for {
l.SetDeadline(time.Now().Add(deadline))
m, s, e := srv.readUDP(l, rtimeout)
select {
case <-srv.stopUDP:
@ -488,7 +480,6 @@ func (srv *Server) readTCP(conn *net.TCPConn, timeout time.Duration) ([]byte, er
func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) {
conn.SetReadDeadline(time.Now().Add(timeout))
m := make([]byte, srv.UDPSize)
// TODO(miek): deadline and timeout seem not to be honered
n, s, e := readFromSessionUDP(conn, m)
if e != nil || n == 0 {
if e != nil {

View File

@ -273,6 +273,8 @@ func TestServingLargeResponses(t *testing.T) {
}
}
// TODO(miek): These tests should actually fail when the server does
// not shut down.
func TestShutdownTCP(t *testing.T) {
server := Server{Addr: ":8055", Net: "tcp"}
go func() {
@ -285,10 +287,9 @@ func TestShutdownTCP(t *testing.T) {
}()
time.Sleep(4e8)
server.Shutdown()
time.Sleep(1 * time.Second)
time.Sleep(4e8)
}
// TODO(miek): does not work for udp
func TestShutdownUDP(t *testing.T) {
server := Server{Addr: ":8054", Net: "udp"}
go func() {
@ -301,5 +302,5 @@ func TestShutdownUDP(t *testing.T) {
}()
time.Sleep(4e8)
server.Shutdown()
time.Sleep(1 * time.Second)
time.Sleep(4e8)
}

3
udp.go
View File

@ -49,8 +49,7 @@ func readFromSessionUDP(conn *net.UDPConn, b []byte) (int, *sessionUDP, error) {
if err != nil {
return n, nil, err
}
session := &sessionUDP{raddr, oob[:oobn]}
return n, session, err
return n, &sessionUDP{raddr, oob[:oobn]}, err
}
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.