From d8023a5e399128f1a7a72f1c328cd2aa6caa512b Mon Sep 17 00:00:00 2001 From: =?utf8?q?luffyma=28=E9=A9=AC=E6=9E=97=29?= Date: Wed, 10 May 2017 11:04:31 +0800 Subject: [PATCH] bug fix: race condition between outgoing connection and incoming connection --- client.go | 8 ++++---- torrent.go | 13 ++++++++++++- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/client.go b/client.go index e49f39bb..a24e0aeb 100644 --- a/client.go +++ b/client.go @@ -899,7 +899,7 @@ func (cl *Client) runInitiatedHandshookConn(c *connection, t *Torrent) { cl.dopplegangerAddrs[addr] = struct{}{} return } - cl.runHandshookConn(c, t) + cl.runHandshookConn(c, t, true) } func (cl *Client) runReceivedConn(c *connection) { @@ -926,14 +926,14 @@ func (cl *Client) runReceivedConn(c *connection) { // doppleganger. return } - cl.runHandshookConn(c, t) + cl.runHandshookConn(c, t, false) } -func (cl *Client) runHandshookConn(c *connection, t *Torrent) { +func (cl *Client) runHandshookConn(c *connection, t *Torrent, outgoing bool) { c.conn.SetWriteDeadline(time.Time{}) c.r = deadlineReader{c.conn, c.r} completedHandshakeConnectionFlags.Add(c.connectionFlags(), 1) - if !t.addConnection(c) { + if !t.addConnection(c, outgoing) { return } defer t.dropConnection(c) diff --git a/torrent.go b/torrent.go index 4d36209c..ba350025 100644 --- a/torrent.go +++ b/torrent.go @@ -1296,7 +1296,7 @@ func (t *Torrent) numTotalPeers() int { } // Returns true if the connection is added. -func (t *Torrent) addConnection(c *connection) bool { +func (t *Torrent) addConnection(c *connection, outgoing bool) bool { if t.cl.closed.IsSet() { return false } @@ -1305,8 +1305,19 @@ func (t *Torrent) addConnection(c *connection) bool { } for c0 := range t.conns { if c.PeerID == c0.PeerID { + // Retain the connection from lower peer ID to higher. + lower := string(t.cl.peerID[:]) < string(c.PeerID[:]) + if (outgoing && lower) || (!outgoing && !lower) { + c0.Close() + t.deleteConnection(c0) + duplicateClientConns.Add(1) + log.Printf("Drop connection: %s, %s, %s", t.name(), c0.localAddr(), c0.remoteAddr()) + continue + } + // Already connected to a client with that ID. duplicateClientConns.Add(1) + log.Printf("Drop connection: %s, %s, %s", t.name(), c.localAddr(), c.remoteAddr()) return false } } -- 2.48.1