Skip to content

Commit

Permalink
fix blocking select on donec
Browse files Browse the repository at this point in the history
Signed-off-by: Abhilash Gnan <abhilashgnan@gmail.com>
  • Loading branch information
jan25 authored and soheilhy committed Jan 14, 2021
1 parent 3c0ee78 commit ae889c5
Showing 1 changed file with 27 additions and 15 deletions.
42 changes: 27 additions & 15 deletions cmux.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package cmux

import (
"errors"
"fmt"
"io"
"net"
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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 {
Expand All @@ -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) {
Expand Down Expand Up @@ -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) {
Expand All @@ -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
if !ok {
return nil, ErrListenerClosed
select {
case c, ok := <-l.connc:
if !ok {
return nil, ErrListenerClosed
}
return c, nil
case <-l.donec:
return nil, ErrServerClosed
default:
// do nothing
}
return c, nil
return nil, ErrServerClosed
}

// MuxConn wraps a net.Conn and provides transparent sniffing of connection data.
Expand Down

0 comments on commit ae889c5

Please sign in to comment.