2
0
mirror of https://github.com/soheilhy/cmux.git synced 2024-11-10 03:31:52 +08:00

fix blocking select on donec

Signed-off-by: Abhilash Gnan <abhilashgnan@gmail.com>
This commit is contained in:
Abhilash Gnan 2020-05-21 09:16:06 +02:00 committed by Soheil Hassas Yeganeh
parent 3c0ee784ab
commit ae889c5259

36
cmux.go
View File

@ -15,6 +15,7 @@
package cmux
import (
"errors"
"fmt"
"io"
"net"
@ -61,6 +62,9 @@ func (e errListenerClosed) Timeout() bool { return false }
// listener is closed.
var ErrListenerClosed = errListenerClosed("mux: listener closed")
// ErrServerClosed is returned from muxListener.Accept when mux server is closed.
var ErrServerClosed = errors.New("mux: server closed")
// for readability of readTimeout
var noTimeout time.Duration
@ -148,7 +152,7 @@ func (m *cMux) Serve() error {
var wg sync.WaitGroup
defer func() {
m.closeDoneChan()
m.closeDoneChans()
wg.Wait()
for _, sl := range m.sls {
@ -161,14 +165,6 @@ func (m *cMux) Serve() error {
}()
for {
select {
case <-m.donec:
// cmux was closed with cmux.Close()
return nil
default:
// do nothing
}
c, err := m.root.Accept()
if err != nil {
if !m.handleErr(err) {
@ -215,16 +211,24 @@ func (m *cMux) serve(c net.Conn, donec <-chan struct{}, wg *sync.WaitGroup) {
}
func (m *cMux) Close() {
m.closeDoneChan()
m.closeDoneChans()
}
func (m *cMux) closeDoneChan() {
func (m *cMux) closeDoneChans() {
select {
case <-m.donec:
// Already closed. Don't close again
default:
close(m.donec)
}
for _, sl := range m.sls {
select {
case <-sl.l.donec:
// Already closed. Don't close again
default:
close(sl.l.donec)
}
}
}
func (m *cMux) HandleError(h ErrorHandler) {
@ -246,14 +250,22 @@ func (m *cMux) handleErr(err error) bool {
type muxListener struct {
net.Listener
connc chan net.Conn
donec chan struct{}
}
func (l muxListener) Accept() (net.Conn, error) {
c, ok := <-l.connc
select {
case c, ok := <-l.connc:
if !ok {
return nil, ErrListenerClosed
}
return c, nil
case <-l.donec:
return nil, ErrServerClosed
default:
// do nothing
}
return nil, ErrServerClosed
}
// MuxConn wraps a net.Conn and provides transparent sniffing of connection data.