agent/grpc: use a separate channel for closing the Accept

Closing l.conns can lead to a race and a 'panic: send on closed chan' when a
connection is in the middle of being handled when the server is shutting down.

Found using '-race -count=800'
This commit is contained in:
Daniel Nephin 2020-10-13 19:21:02 -04:00
parent d8299670cc
commit 19da9c3a9b
1 changed files with 11 additions and 11 deletions

View File

@ -22,7 +22,7 @@ func NewHandler(addr net.Addr, register func(server *grpc.Server)) *Handler {
)
register(srv)
lis := &chanListener{addr: addr, conns: make(chan net.Conn)}
lis := &chanListener{addr: addr, conns: make(chan net.Conn), done: make(chan struct{})}
return &Handler{srv: srv, listener: lis}
}
@ -51,22 +51,22 @@ func (h *Handler) Shutdown() error {
type chanListener struct {
conns chan net.Conn
addr net.Addr
done chan struct{}
}
// Accept blocks until a connection is received from Handle, and then returns the
// connection. Accept implements part of the net.Listener interface for grpc.Server.
func (l *chanListener) Accept() (net.Conn, error) {
select {
case c, ok := <-l.conns:
if !ok {
return nil, &net.OpError{
Op: "accept",
Net: l.addr.Network(),
Addr: l.addr,
Err: fmt.Errorf("listener closed"),
}
}
case c := <-l.conns:
return c, nil
case <-l.done:
return nil, &net.OpError{
Op: "accept",
Net: l.addr.Network(),
Addr: l.addr,
Err: fmt.Errorf("listener closed"),
}
}
}
@ -75,7 +75,7 @@ func (l *chanListener) Addr() net.Addr {
}
func (l *chanListener) Close() error {
close(l.conns)
close(l.done)
return nil
}