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:
parent
4f1d2e7121
commit
19fd6406e8
1 changed files with 21 additions and 14 deletions
35
sockets.go
35
sockets.go
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue