@@ -54,7 +54,7 @@ type Ouroboros struct {
5454 handshakeFinishedChan chan interface {}
5555 doneChan chan interface {}
5656 waitGroup sync.WaitGroup
57- closeMutex sync.Mutex
57+ onceClose sync.Once
5858 sendKeepAlives bool
5959 delayMuxerStart bool
6060 fullDuplex bool
@@ -130,47 +130,40 @@ func (o *Ouroboros) Dial(proto string, address string) error {
130130
131131// Close will shutdown the Ouroboros connection
132132func (o * Ouroboros ) Close () error {
133- // We use a mutex to prevent this function from being called multiple times
134- // concurrently, which would cause a race condition
135- o .closeMutex .Lock ()
136- defer o .closeMutex .Unlock ()
137- // Immediately return if we're already shutting down
138- select {
139- case <- o .doneChan :
140- return nil
141- default :
142- }
143- // Close doneChan to signify that we're shutting down
144- close (o .doneChan )
145- // Gracefully stop the muxer
146- if o .muxer != nil {
147- o .muxer .Stop ()
148- }
149- // Close the underlying connection
150- if o .conn != nil {
151- if err := o .conn .Close (); err != nil {
152- return err
133+ var err error
134+ o .onceClose .Do (func () {
135+ // Close doneChan to signify that we're shutting down
136+ close (o .doneChan )
137+ // Gracefully stop the muxer
138+ if o .muxer != nil {
139+ o .muxer .Stop ()
153140 }
154- }
155- // Wait for other goroutines to finish
156- o .waitGroup .Wait ()
157- // Close channels
158- close (o .errorChan )
159- close (o .protoErrorChan )
160- // We can only close a channel once, so we have to jump through a few hoops
161- select {
162- // The channel is either closed or has an item pending
163- case _ , ok := <- o .handshakeFinishedChan :
164- // We successfully retrieved an item
165- // This will probably never happen, but it doesn't hurt to cover this case
166- if ok {
141+ // Close the underlying connection
142+ if o .conn != nil {
143+ if err = o .conn .Close (); err != nil {
144+ return
145+ }
146+ }
147+ // Wait for other goroutines to finish
148+ o .waitGroup .Wait ()
149+ // Close channels
150+ close (o .errorChan )
151+ close (o .protoErrorChan )
152+ // We can only close a channel once, so we have to jump through a few hoops
153+ select {
154+ // The channel is either closed or has an item pending
155+ case _ , ok := <- o .handshakeFinishedChan :
156+ // We successfully retrieved an item
157+ // This will probably never happen, but it doesn't hurt to cover this case
158+ if ok {
159+ close (o .handshakeFinishedChan )
160+ }
161+ // The channel is open and has no pending items
162+ default :
167163 close (o .handshakeFinishedChan )
168164 }
169- // The channel is open and has no pending items
170- default :
171- close (o .handshakeFinishedChan )
172- }
173- return nil
165+ })
166+ return err
174167}
175168
176169// ChainSync returns the chain-sync protocol handler
0 commit comments