This reverts commit 8223ae840e
.
This commit is contained in:
parent
8223ae840e
commit
4bb60ce4d8
|
@ -525,7 +525,7 @@ func TestTimeout(t *testing.T) {
|
||||||
length := time.Since(start)
|
length := time.Since(start)
|
||||||
|
|
||||||
if length > allowable {
|
if length > allowable {
|
||||||
t.Errorf("exchange took longer (%v) than specified Timeout (%v)", length, allowable)
|
t.Errorf("exchange took longer (%v) than specified Timeout (%v)", length, timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
104
server.go
104
server.go
|
@ -296,10 +296,22 @@ type Server struct {
|
||||||
DecorateReader DecorateReader
|
DecorateReader DecorateReader
|
||||||
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
// DecorateWriter is optional, allows customization of the process that writes raw DNS messages.
|
||||||
DecorateWriter DecorateWriter
|
DecorateWriter DecorateWriter
|
||||||
|
|
||||||
|
// Graceful shutdown handling
|
||||||
|
|
||||||
|
inFlight sync.WaitGroup
|
||||||
|
|
||||||
|
lock sync.RWMutex
|
||||||
|
started bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// ListenAndServe starts a nameserver on the configured address in *Server.
|
// ListenAndServe starts a nameserver on the configured address in *Server.
|
||||||
func (srv *Server) ListenAndServe() error {
|
func (srv *Server) ListenAndServe() error {
|
||||||
|
srv.lock.Lock()
|
||||||
|
defer srv.lock.Unlock()
|
||||||
|
if srv.started {
|
||||||
|
return &Error{err: "server already started"}
|
||||||
|
}
|
||||||
addr := srv.Addr
|
addr := srv.Addr
|
||||||
if addr == "" {
|
if addr == "" {
|
||||||
addr = ":domain"
|
addr = ":domain"
|
||||||
|
@ -318,7 +330,10 @@ func (srv *Server) ListenAndServe() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
srv.Listener = l
|
srv.Listener = l
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
err = srv.serveTCP(l)
|
err = srv.serveTCP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
return err
|
return err
|
||||||
case "tcp-tls", "tcp4-tls", "tcp6-tls":
|
case "tcp-tls", "tcp4-tls", "tcp6-tls":
|
||||||
network := "tcp"
|
network := "tcp"
|
||||||
|
@ -333,7 +348,10 @@ func (srv *Server) ListenAndServe() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
srv.Listener = l
|
srv.Listener = l
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
err = srv.serveTCP(l)
|
err = srv.serveTCP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
return err
|
return err
|
||||||
case "udp", "udp4", "udp6":
|
case "udp", "udp4", "udp6":
|
||||||
a, err := net.ResolveUDPAddr(srv.Net, addr)
|
a, err := net.ResolveUDPAddr(srv.Net, addr)
|
||||||
|
@ -348,7 +366,10 @@ func (srv *Server) ListenAndServe() error {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
srv.PacketConn = l
|
srv.PacketConn = l
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
err = srv.serveUDP(l)
|
err = srv.serveUDP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
return &Error{err: "bad network"}
|
return &Error{err: "bad network"}
|
||||||
|
@ -357,38 +378,72 @@ func (srv *Server) ListenAndServe() error {
|
||||||
// ActivateAndServe starts a nameserver with the PacketConn or Listener
|
// ActivateAndServe starts a nameserver with the PacketConn or Listener
|
||||||
// configured in *Server. Its main use is to start a server from systemd.
|
// configured in *Server. Its main use is to start a server from systemd.
|
||||||
func (srv *Server) ActivateAndServe() error {
|
func (srv *Server) ActivateAndServe() error {
|
||||||
|
srv.lock.Lock()
|
||||||
|
defer srv.lock.Unlock()
|
||||||
|
if srv.started {
|
||||||
|
return &Error{err: "server already started"}
|
||||||
|
}
|
||||||
pConn := srv.PacketConn
|
pConn := srv.PacketConn
|
||||||
l := srv.Listener
|
l := srv.Listener
|
||||||
|
if pConn != nil {
|
||||||
if srv.UDPSize == 0 {
|
if srv.UDPSize == 0 {
|
||||||
srv.UDPSize = MinMsgSize
|
srv.UDPSize = MinMsgSize
|
||||||
}
|
}
|
||||||
// Check PacketConn interface's type is valid and value
|
// Check PacketConn interface's type is valid and value
|
||||||
// is not nil
|
// is not nil
|
||||||
if t, ok := pConn.(*net.UDPConn); ok && t != nil {
|
if t, ok := pConn.(*net.UDPConn); ok && t != nil {
|
||||||
if e := setUDPSocketOptions(t); e != nil {
|
if e := setUDPSocketOptions(t); e != nil {
|
||||||
|
return e
|
||||||
|
}
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
|
e := srv.serveUDP(t)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
e := srv.serveUDP(t)
|
|
||||||
return e
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if l != nil {
|
if l != nil {
|
||||||
|
srv.started = true
|
||||||
|
srv.lock.Unlock()
|
||||||
e := srv.serveTCP(l)
|
e := srv.serveTCP(l)
|
||||||
|
srv.lock.Lock() // to satisfy the defer at the top
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
return &Error{err: "bad listeners"}
|
return &Error{err: "bad listeners"}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Shutdown shuts down a server. After a call to Shutdown, ListenAndServe and ActivateAndServe will return.
|
// Shutdown gracefully shuts down a server. After a call to Shutdown, ListenAndServe and
|
||||||
|
// ActivateAndServe will return. All in progress queries are completed before the server
|
||||||
|
// is taken down. If the Shutdown is taking longer than the reading timeout an error
|
||||||
|
// is returned.
|
||||||
func (srv *Server) Shutdown() error {
|
func (srv *Server) Shutdown() error {
|
||||||
|
srv.lock.Lock()
|
||||||
|
if !srv.started {
|
||||||
|
srv.lock.Unlock()
|
||||||
|
return &Error{err: "server not started"}
|
||||||
|
}
|
||||||
|
srv.started = false
|
||||||
|
srv.lock.Unlock()
|
||||||
|
|
||||||
if srv.PacketConn != nil {
|
if srv.PacketConn != nil {
|
||||||
srv.PacketConn.Close()
|
srv.PacketConn.Close()
|
||||||
}
|
}
|
||||||
if srv.Listener != nil {
|
if srv.Listener != nil {
|
||||||
srv.Listener.Close()
|
srv.Listener.Close()
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
fin := make(chan bool)
|
||||||
|
go func() {
|
||||||
|
srv.inFlight.Wait()
|
||||||
|
fin <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-time.After(srv.getReadTimeout()):
|
||||||
|
return &Error{err: "server shutdown is pending"}
|
||||||
|
case <-fin:
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
|
// getReadTimeout is a helper func to use system timeout if server did not intend to change it.
|
||||||
|
@ -429,9 +484,16 @@ func (srv *Server) serveTCP(l net.Listener) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
m, err := reader.ReadTCP(rw, rtimeout)
|
m, err := reader.ReadTCP(rw, rtimeout)
|
||||||
|
srv.lock.RLock()
|
||||||
|
if !srv.started {
|
||||||
|
srv.lock.RUnlock()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
srv.lock.RUnlock()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
srv.inFlight.Add(1)
|
||||||
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
go srv.serve(rw.RemoteAddr(), handler, m, nil, nil, rw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,18 +520,24 @@ func (srv *Server) serveUDP(l *net.UDPConn) error {
|
||||||
// deadline is not used here
|
// deadline is not used here
|
||||||
for {
|
for {
|
||||||
m, s, err := reader.ReadUDP(l, rtimeout)
|
m, s, err := reader.ReadUDP(l, rtimeout)
|
||||||
if err != nil {
|
srv.lock.RLock()
|
||||||
if neterr, ok := err.(net.Error); ok && neterr.Temporary() {
|
if !srv.started {
|
||||||
continue
|
srv.lock.RUnlock()
|
||||||
}
|
return nil
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
srv.lock.RUnlock()
|
||||||
|
if err != nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
srv.inFlight.Add(1)
|
||||||
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
go srv.serve(s.RemoteAddr(), handler, m, l, s, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve a new connection.
|
// Serve a new connection.
|
||||||
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
|
func (srv *Server) serve(a net.Addr, h Handler, m []byte, u *net.UDPConn, s *SessionUDP, t net.Conn) {
|
||||||
|
defer srv.inFlight.Done()
|
||||||
|
|
||||||
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
w := &response{tsigSecret: srv.TsigSecret, udp: u, tcp: t, remoteAddr: a, udpSession: s}
|
||||||
if srv.DecorateWriter != nil {
|
if srv.DecorateWriter != nil {
|
||||||
w.writer = srv.DecorateWriter(w)
|
w.writer = srv.DecorateWriter(w)
|
||||||
|
|
Loading…
Reference in New Issue