Merge pull request #1924 from fjl/eth-status-timeout

eth: time out status message exchange after 5s
This commit is contained in:
Jeffrey Wilcke 2015-10-23 16:43:10 -07:00
commit c43db8a2ee
1 changed files with 27 additions and 9 deletions

View File

@ -21,6 +21,7 @@ import (
"fmt" "fmt"
"math/big" "math/big"
"sync" "sync"
"time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
@ -38,8 +39,9 @@ var (
) )
const ( const (
maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS) maxKnownTxs = 32768 // Maximum transactions hashes to keep in the known list (prevent DOS)
maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS) maxKnownBlocks = 1024 // Maximum block hashes to keep in the known list (prevent DOS)
handshakeTimeout = 5 * time.Second
) )
type peer struct { type peer struct {
@ -267,8 +269,8 @@ func (p *peer) RequestReceipts(hashes []common.Hash) error {
// Handshake executes the eth protocol handshake, negotiating version number, // Handshake executes the eth protocol handshake, negotiating version number,
// network IDs, difficulties, head and genesis blocks. // network IDs, difficulties, head and genesis blocks.
func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) error { func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) error {
// Send out own handshake in a new thread errc := make(chan error, 2)
errc := make(chan error, 1) var status statusData // safe to read after two values have been received from errc
go func() { go func() {
errc <- p2p.Send(p.rw, StatusMsg, &statusData{ errc <- p2p.Send(p.rw, StatusMsg, &statusData{
ProtocolVersion: uint32(p.version), ProtocolVersion: uint32(p.version),
@ -278,7 +280,26 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
GenesisBlock: genesis, GenesisBlock: genesis,
}) })
}() }()
// In the mean time retrieve the remote status message go func() {
errc <- p.readStatus(&status, genesis)
}()
timeout := time.NewTimer(handshakeTimeout)
defer timeout.Stop()
for i := 0; i < 2; i++ {
select {
case err := <-errc:
if err != nil {
return err
}
case <-timeout.C:
return p2p.DiscReadTimeout
}
}
p.td, p.head = status.TD, status.CurrentBlock
return nil
}
func (p *peer) readStatus(status *statusData, genesis common.Hash) (err error) {
msg, err := p.rw.ReadMsg() msg, err := p.rw.ReadMsg()
if err != nil { if err != nil {
return err return err
@ -290,7 +311,6 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize) return errResp(ErrMsgTooLarge, "%v > %v", msg.Size, ProtocolMaxMsgSize)
} }
// Decode the handshake and make sure everything matches // Decode the handshake and make sure everything matches
var status statusData
if err := msg.Decode(&status); err != nil { if err := msg.Decode(&status); err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err) return errResp(ErrDecode, "msg %v: %v", msg, err)
} }
@ -303,9 +323,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
if int(status.ProtocolVersion) != p.version { if int(status.ProtocolVersion) != p.version {
return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version) return errResp(ErrProtocolVersionMismatch, "%d (!= %d)", status.ProtocolVersion, p.version)
} }
// Configure the remote peer, and sanity check out handshake too return nil
p.td, p.head = status.TD, status.CurrentBlock
return <-errc
} }
// String implements fmt.Stringer. // String implements fmt.Stringer.