Skip to content

Commit c43db8a

Browse files
committed
Merge pull request ethereum#1924 from fjl/eth-status-timeout
eth: time out status message exchange after 5s
2 parents 0aeab5f + 3cf7433 commit c43db8a

File tree

1 file changed

+27
-9
lines changed

1 file changed

+27
-9
lines changed

eth/peer.go

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"fmt"
2222
"math/big"
2323
"sync"
24+
"time"
2425

2526
"github.com/ethereum/go-ethereum/common"
2627
"github.com/ethereum/go-ethereum/core/types"
@@ -38,8 +39,9 @@ var (
3839
)
3940

4041
const (
41-
maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
42-
maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS)
42+
maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
43+
maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS)
44+
handshakeTimeout = 5 * time.Second
4345
)
4446

4547
type peer struct {
@@ -267,8 +269,8 @@ func (p *peer) RequestReceipts(hashes []common.Hash) error {
267269
// Handshake executes the eth protocol handshake, negotiating version number,
268270
// network IDs, difficulties, head and genesis blocks.
269271
func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) error {
270-
// Send out own handshake in a new thread
271-
errc := make(chan error, 1)
272+
errc := make(chan error, 2)
273+
var status statusData // safe to read after two values have been received from errc
272274
go func() {
273275
errc <- p2p.Send(p.rw, StatusMsg, &statusData{
274276
ProtocolVersion: uint32(p.version),
@@ -278,7 +280,26 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
278280
GenesisBlock: genesis,
279281
})
280282
}()
281-
// In the mean time retrieve the remote status message
283+
go func() {
284+
errc <- p.readStatus(&status, genesis)
285+
}()
286+
timeout := time.NewTimer(handshakeTimeout)
287+
defer timeout.Stop()
288+
for i := 0; i < 2; i++ {
289+
select {
290+
case err := <-errc:
291+
if err != nil {
292+
return err
293+
}
294+
case <-timeout.C:
295+
return p2p.DiscReadTimeout
296+
}
297+
}
298+
p.td, p.head = status.TD, status.CurrentBlock
299+
return nil
300+
}
301+
302+
func (p *peer) readStatus(status *statusData, genesis common.Hash) (err error) {
282303
msg, err := p.rw.ReadMsg()
283304
if err != nil {
284305
return err
@@ -290,7 +311,6 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
290311
return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
291312
}
292313
// Decode the handshake and make sure everything matches
293-
var status statusData
294314
if err := msg.Decode(&status); err != nil {
295315
return errResp(ErrDecode, "msg %v: %v", msg, err)
296316
}
@@ -303,9 +323,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
303323
if int(status.ProtocolVersion) != p.version {
304324
return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version)
305325
}
306-
// Configure the remote peer, and sanity check out handshake too
307-
p.td, p.head = status.TD, status.CurrentBlock
308-
return <-errc
326+
return nil
309327
}
310328

311329
// String implements fmt.Stringer.

0 commit comments

Comments
 (0)