From: luffyma(马林) Date: Wed, 10 May 2017 03:04:31 +0000 (+0800) Subject: bug fix: race condition between outgoing connection and incoming connection X-Git-Tag: v1.0.0~472^2 X-Git-Url: http://www.git.stargrave.org/?a=commitdiff_plain;h=d8023a5e399128f1a7a72f1c328cd2aa6caa512b;p=btrtrc.git bug fix: race condition between outgoing connection and incoming connection --- 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 } }