@@ -21,6 +21,7 @@ import (
21
21
"fmt"
22
22
"math/big"
23
23
"sync"
24
+ "time"
24
25
25
26
"github.com/ethereum/go-ethereum/common"
26
27
"github.com/ethereum/go-ethereum/core/types"
38
39
)
39
40
40
41
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
43
45
)
44
46
45
47
type peer struct {
@@ -267,8 +269,8 @@ func (p *peer) RequestReceipts(hashes []common.Hash) error {
267
269
// Handshake executes the eth protocol handshake, negotiating version number,
268
270
// network IDs, difficulties, head and genesis blocks.
269
271
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
272
274
go func () {
273
275
errc <- p2p .Send (p .rw , StatusMsg , & statusData {
274
276
ProtocolVersion : uint32 (p .version ),
@@ -278,7 +280,26 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
278
280
GenesisBlock : genesis ,
279
281
})
280
282
}()
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 ) {
282
303
msg , err := p .rw .ReadMsg ()
283
304
if err != nil {
284
305
return err
@@ -290,7 +311,6 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
290
311
return errResp (ErrMsgTooLarge , "%v > %v" , msg .Size , ProtocolMaxMsgSize )
291
312
}
292
313
// Decode the handshake and make sure everything matches
293
- var status statusData
294
314
if err := msg .Decode (& status ); err != nil {
295
315
return errResp (ErrDecode , "msg %v: %v" , msg , err )
296
316
}
@@ -303,9 +323,7 @@ func (p *peer) Handshake(td *big.Int, head common.Hash, genesis common.Hash) err
303
323
if int (status .ProtocolVersion ) != p .version {
304
324
return errResp (ErrProtocolVersionMismatch , "%d (!= %d)" , status .ProtocolVersion , p .version )
305
325
}
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
309
327
}
310
328
311
329
// String implements fmt.Stringer.
0 commit comments