浏览代码

p2p/discover: fix deadlock in discv5 message dispatch (#21858)

This fixes a deadlock that could occur when a response packet arrived
after a call had already received enough responses and was about to
signal completion to the dispatch loop.

Co-authored-by: Felix Lange <fjl@twurst.com>
Nishant Das 5 年之前
父节点
当前提交
9e8ee517d7
共有 1 个文件被更改,包括 14 次插入3 次删除
  1. 14 3
      p2p/discover/v5_udp.go

+ 14 - 3
p2p/discover/v5_udp.go

@@ -419,9 +419,20 @@ func (t *UDPv5) call(node *enode.Node, responseType byte, packet packetV5) *call
 
 // callDone tells dispatch that the active call is done.
 func (t *UDPv5) callDone(c *callV5) {
-	select {
-	case t.callDoneCh <- c:
-	case <-t.closeCtx.Done():
+	// This needs a loop because further responses may be incoming until the
+	// send to callDoneCh has completed. Such responses need to be discarded
+	// in order to avoid blocking the dispatch loop.
+	for {
+		select {
+		case <-c.ch:
+			// late response, discard.
+		case <-c.err:
+			// late error, discard.
+		case t.callDoneCh <- c:
+			return
+		case <-t.closeCtx.Done():
+			return
+		}
 	}
 }