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 WriteTimeout time.Duration
// TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966). // TCP idle timeout for multiple queries, if nil, defaults to 8 * time.Second (RFC 5966).
IdleTimeout func() time.Duration IdleTimeout func() time.Duration
// Listener deadline timeout, defaults to 1 * time.Second.
Deadline time.Duration
// Secret(s) for Tsig map[<zonename>]<base64 secret>. // Secret(s) for Tsig map[<zonename>]<base64 secret>.
TsigSecret map[string]string 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 // Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and
// ActivateAndServe will return. // ActivateAndServe will return.
func (srv *Server) Shutdown() { func (srv *Server) Shutdown() {
c := new(Client)
switch srv.Net { switch srv.Net {
case "tcp", "tcp4", "tcp6": 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": case "udp", "udp4", "udp6":
// TODO(miek): does not work for udp go func() { srv.stopUDP <- true }()
// 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 { if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout rtimeout = srv.ReadTimeout
} }
deadline := 1 * time.Second
if srv.Deadline != 0 {
deadline = srv.Deadline
}
for { for {
l.SetDeadline(time.Now().Add(deadline))
rw, e := l.AcceptTCP() rw, e := l.AcceptTCP()
select { select {
case <-srv.stopTCP: case <-srv.stopTCP:
@ -365,12 +361,8 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
if srv.ReadTimeout != 0 { if srv.ReadTimeout != 0 {
rtimeout = srv.ReadTimeout rtimeout = srv.ReadTimeout
} }
deadline := 1 * time.Second // deadline is not used here
if srv.Deadline != 0 {
deadline = srv.Deadline
}
for { for {
l.SetDeadline(time.Now().Add(deadline))
m, s, e := srv.readUDP(l, rtimeout) m, s, e := srv.readUDP(l, rtimeout)
select { select {
case <-srv.stopUDP: 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) { func (srv *Server) readUDP(conn *net.UDPConn, timeout time.Duration) ([]byte, *sessionUDP, error) {
conn.SetReadDeadline(time.Now().Add(timeout)) conn.SetReadDeadline(time.Now().Add(timeout))
m := make([]byte, srv.UDPSize) m := make([]byte, srv.UDPSize)
// TODO(miek): deadline and timeout seem not to be honered
n, s, e := readFromSessionUDP(conn, m) n, s, e := readFromSessionUDP(conn, m)
if e != nil || n == 0 { if e != nil || n == 0 {
if e != nil { 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) { func TestShutdownTCP(t *testing.T) {
server := Server{Addr: ":8055", Net: "tcp"} server := Server{Addr: ":8055", Net: "tcp"}
go func() { go func() {
@ -285,10 +287,9 @@ func TestShutdownTCP(t *testing.T) {
}() }()
time.Sleep(4e8) time.Sleep(4e8)
server.Shutdown() server.Shutdown()
time.Sleep(1 * time.Second) time.Sleep(4e8)
} }
// TODO(miek): does not work for udp
func TestShutdownUDP(t *testing.T) { func TestShutdownUDP(t *testing.T) {
server := Server{Addr: ":8054", Net: "udp"} server := Server{Addr: ":8054", Net: "udp"}
go func() { go func() {
@ -301,5 +302,5 @@ func TestShutdownUDP(t *testing.T) {
}() }()
time.Sleep(4e8) time.Sleep(4e8)
server.Shutdown() 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 { if err != nil {
return n, nil, err return n, nil, err
} }
session := &sessionUDP{raddr, oob[:oobn]} return n, &sessionUDP{raddr, oob[:oobn]}, err
return n, session, err
} }
// writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr. // writeToSessionUDP acts just like net.UDPConn.WritetTo(), but uses a *sessionUDP instead of a net.Addr.