Prevent a send on closed chan panic.

The select statement does not guarantee selecting a better case if one
might panic for sending to a closed channel.  This case was hit during
client disconnect due to having multiple senders on a single channel
with one of the senders closing the chan to notify the next goroutine
to finish.  This change gives each writes its own unique channel to
prevent this error.
This commit is contained in:
Josh Rickmar 2014-03-20 16:10:42 -05:00
parent 4f1d2e7121
commit 19fd6406e8

View file

@ -451,7 +451,9 @@ func (s *server) WSSendRecv(ws *websocket.Conn, authenticated bool) {
go stringQueue(recvQueueIn, recvQueueOut, cc.quit)
badAuth := make(chan struct{})
sendResp := make(chan []byte)
go func() {
out:
for m := range recvQueueOut {
resp, err := s.ReplyToFrontend([]byte(m), true, authenticated)
if err == ErrBadAuth {
@ -459,24 +461,28 @@ func (s *server) WSSendRecv(ws *websocket.Conn, authenticated bool) {
case badAuth <- struct{}{}:
case <-cc.quit:
}
return
break out
}
// Authentication passed.
authenticated = true
select {
case cc.send <- resp:
case sendResp <- resp:
case <-cc.quit:
break out
}
}
close(cc.send)
close(sendResp)
}()
const deadline time.Duration = 2 * time.Second
out:
for {
var m []byte
var ok bool
select {
case <-badAuth:
// Bad auth. Disconnect.
@ -484,22 +490,23 @@ out:
ws.Close()
break out
case m, ok := <-cc.send:
case m = <-cc.send: // sends from external writers. never closes.
case m, ok = <-sendResp:
if !ok {
// Nothing left to send. Return so the handler exits.
break out
}
}
err := ws.SetWriteDeadline(time.Now().Add(deadline))
if err != nil {
log.Errorf("Cannot set write deadline: %v", err)
break out
}
err = websocket.Message.Send(ws, string(m))
if err != nil {
log.Infof("Cannot complete client websocket send: %v", err)
break out
}
err := ws.SetWriteDeadline(time.Now().Add(deadline))
if err != nil {
log.Errorf("Cannot set write deadline: %v", err)
break out
}
err = websocket.Message.Send(ws, string(m))
if err != nil {
log.Infof("Cannot complete client websocket send: %v", err)
break out
}
}
close(sendQuit)