Skip to content

Commit 09a45f1

Browse files
Merge pull request #402 from StephenButtolph/close-without-lock
close network connections without the state lock held
2 parents f06256f + 8ee88b6 commit 09a45f1

File tree

2 files changed

+35
-27
lines changed

2 files changed

+35
-27
lines changed

network/network.go

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
package network
55

66
import (
7+
"errors"
78
"fmt"
89
"math/rand"
910
"net"
@@ -47,6 +48,12 @@ const (
4748
defaultPingFrequency = 3 * defaultPingPongTimeout / 4
4849
)
4950

51+
var (
52+
errNetworkClosed = errors.New("network closed")
53+
errPeerIsMyself = errors.New("peer is myself")
54+
errDuplicatedConnection = errors.New("duplicated connection")
55+
)
56+
5057
func init() { rand.Seed(time.Now().UnixNano()) }
5158

5259
// Network defines the functionality of the networking library.
@@ -635,15 +642,15 @@ func (n *network) Dispatch() error {
635642
for {
636643
conn, err := n.listener.Accept()
637644
if err != nil {
638-
n.stateLock.Lock()
639-
closed := n.closed
640-
n.stateLock.Unlock()
641-
642-
if closed {
643-
return err
645+
if netErr, ok := err.(net.Error); ok && netErr.Temporary() {
646+
// Sleep for a small amount of time to try to wait for the
647+
// temporary error to go away.
648+
time.Sleep(time.Millisecond)
649+
continue
644650
}
651+
645652
n.log.Debug("error during server accept: %s", err)
646-
continue
653+
return err
647654
}
648655
go n.upgrade(&peer{
649656
net: n,
@@ -675,17 +682,17 @@ func (n *network) Peers() []PeerID {
675682

676683
// Close implements the Network interface
677684
func (n *network) Close() error {
685+
err := n.listener.Close()
686+
if err != nil {
687+
n.log.Debug("closing network listener failed with: %s", err)
688+
}
689+
678690
n.stateLock.Lock()
679691
if n.closed {
680692
n.stateLock.Unlock()
681693
return nil
682694
}
683-
684695
n.closed = true
685-
err := n.listener.Close()
686-
if err != nil {
687-
n.log.Debug("closing network listener failed with: %s", err)
688-
}
689696

690697
peersToClose := []*peer(nil)
691698
for _, peer := range n.peers {
@@ -935,21 +942,28 @@ func (n *network) upgrade(p *peer, upgrader Upgrader) error {
935942
p.id = id
936943
p.conn = conn
937944

938-
key := id.Key()
945+
if err := n.tryAddPeer(p); err != nil {
946+
_ = p.conn.Close()
947+
n.log.Debug("dropping peer connection due to: %s", err)
948+
}
949+
return nil
950+
}
951+
952+
func (n *network) tryAddPeer(p *peer) error {
953+
key := p.id.Key()
939954

940955
n.stateLock.Lock()
941956
defer n.stateLock.Unlock()
942957

943958
if n.closed {
944959
// the network is closing, so make sure that no further reconnect
945960
// attempts are made.
946-
_ = p.conn.Close()
947-
return nil
961+
return errNetworkClosed
948962
}
949963

950964
// if this connection is myself, then I should delete the connection and
951965
// mark the IP as one of mine.
952-
if id.Equals(n.id) {
966+
if p.id.Equals(n.id) {
953967
if !p.ip.IsZero() {
954968
// if n.ip is less useful than p.ip set it to this IP
955969
if n.ip.IsZero() {
@@ -962,10 +976,7 @@ func (n *network) upgrade(p *peer, upgrader Upgrader) error {
962976
delete(n.retryDelay, str)
963977
n.myIPs[str] = struct{}{}
964978
}
965-
// don't attempt to reconnect to myself, so return nil even if closing
966-
// returns an error
967-
_ = p.conn.Close()
968-
return nil
979+
return errPeerIsMyself
969980
}
970981

971982
// If I am already connected to this peer, then I should close this new
@@ -976,10 +987,7 @@ func (n *network) upgrade(p *peer, upgrader Upgrader) error {
976987
delete(n.disconnectedIPs, str)
977988
delete(n.retryDelay, str)
978989
}
979-
// I'm already connected to this peer, so don't attempt to reconnect to
980-
// this ip, even if an error occurres during closing
981-
_ = p.conn.Close()
982-
return nil
990+
return errDuplicatedConnection
983991
}
984992

985993
n.peers[key] = p

network/peer.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,13 @@ func (p *peer) Close() { p.once.Do(p.close) }
322322

323323
// assumes only `peer.Close` calls this
324324
func (p *peer) close() {
325-
p.net.stateLock.Lock()
326-
defer p.net.stateLock.Unlock()
327-
328325
if err := p.conn.Close(); err != nil {
329326
p.net.log.Debug("closing peer %s resulted in an error: %s", p.id, err)
330327
}
331328

329+
p.net.stateLock.Lock()
330+
defer p.net.stateLock.Unlock()
331+
332332
p.closed = true
333333
close(p.sender)
334334
p.net.disconnected(p)

0 commit comments

Comments
 (0)