|
|
@@ -2,7 +2,6 @@ package p2p
|
|
|
|
|
|
import (
|
|
|
"bytes"
|
|
|
- "net"
|
|
|
"time"
|
|
|
|
|
|
"github.com/ethereum/go-ethereum/ethutil"
|
|
|
@@ -90,30 +89,18 @@ type baseProtocol struct {
|
|
|
|
|
|
func runBaseProtocol(peer *Peer, rw MsgReadWriter) error {
|
|
|
bp := &baseProtocol{rw, peer}
|
|
|
-
|
|
|
- // do handshake
|
|
|
- if err := rw.WriteMsg(bp.handshakeMsg()); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- msg, err := rw.ReadMsg()
|
|
|
- if err != nil {
|
|
|
+ if err := bp.doHandshake(rw); err != nil {
|
|
|
return err
|
|
|
}
|
|
|
- if msg.Code != handshakeMsg {
|
|
|
- return newPeerError(errProtocolBreach, "first message must be handshake, got %x", msg.Code)
|
|
|
- }
|
|
|
- data, err := msg.Data()
|
|
|
- if err != nil {
|
|
|
- return newPeerError(errInvalidMsg, "%v", err)
|
|
|
- }
|
|
|
- if err := bp.handleHandshake(data); err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
-
|
|
|
// run main loop
|
|
|
quit := make(chan error, 1)
|
|
|
go func() {
|
|
|
- quit <- MsgLoop(rw, baseProtocolMaxMsgSize, bp.handle)
|
|
|
+ for {
|
|
|
+ if err := bp.handle(rw); err != nil {
|
|
|
+ quit <- err
|
|
|
+ break
|
|
|
+ }
|
|
|
+ }
|
|
|
}()
|
|
|
return bp.loop(quit)
|
|
|
}
|
|
|
@@ -151,13 +138,27 @@ func (bp *baseProtocol) loop(quit <-chan error) error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-func (bp *baseProtocol) handle(code uint64, data *ethutil.Value) error {
|
|
|
- switch code {
|
|
|
+func (bp *baseProtocol) handle(rw MsgReadWriter) error {
|
|
|
+ msg, err := rw.ReadMsg()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if msg.Size > baseProtocolMaxMsgSize {
|
|
|
+ return newPeerError(errMisc, "message too big")
|
|
|
+ }
|
|
|
+ // make sure that the payload has been fully consumed
|
|
|
+ defer msg.Discard()
|
|
|
+
|
|
|
+ switch msg.Code {
|
|
|
case handshakeMsg:
|
|
|
return newPeerError(errProtocolBreach, "extra handshake received")
|
|
|
|
|
|
case discMsg:
|
|
|
- bp.peer.Disconnect(DiscReason(data.Get(0).Uint()))
|
|
|
+ var reason DiscReason
|
|
|
+ if err := msg.Decode(&reason); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ bp.peer.Disconnect(reason)
|
|
|
return nil
|
|
|
|
|
|
case pingMsg:
|
|
|
@@ -178,35 +179,45 @@ func (bp *baseProtocol) handle(code uint64, data *ethutil.Value) error {
|
|
|
}
|
|
|
|
|
|
case peersMsg:
|
|
|
- bp.handlePeers(data)
|
|
|
+ var peers []*peerAddr
|
|
|
+ if err := msg.Decode(&peers); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ for _, addr := range peers {
|
|
|
+ bp.peer.Debugf("received peer suggestion: %v", addr)
|
|
|
+ bp.peer.newPeerAddr <- addr
|
|
|
+ }
|
|
|
|
|
|
default:
|
|
|
- return newPeerError(errInvalidMsgCode, "unknown message code %v", code)
|
|
|
+ return newPeerError(errInvalidMsgCode, "unknown message code %v", msg.Code)
|
|
|
}
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-func (bp *baseProtocol) handlePeers(data *ethutil.Value) {
|
|
|
- it := data.NewIterator()
|
|
|
- for it.Next() {
|
|
|
- addr := &peerAddr{
|
|
|
- IP: net.IP(it.Value().Get(0).Bytes()),
|
|
|
- Port: it.Value().Get(1).Uint(),
|
|
|
- Pubkey: it.Value().Get(2).Bytes(),
|
|
|
- }
|
|
|
- bp.peer.Debugf("received peer suggestion: %v", addr)
|
|
|
- bp.peer.newPeerAddr <- addr
|
|
|
+func (bp *baseProtocol) doHandshake(rw MsgReadWriter) error {
|
|
|
+ // send our handshake
|
|
|
+ if err := rw.WriteMsg(bp.handshakeMsg()); err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+
|
|
|
+ // read and handle remote handshake
|
|
|
+ msg, err := rw.ReadMsg()
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ if msg.Code != handshakeMsg {
|
|
|
+ return newPeerError(errProtocolBreach, "first message must be handshake, got %x", msg.Code)
|
|
|
+ }
|
|
|
+ if msg.Size > baseProtocolMaxMsgSize {
|
|
|
+ return newPeerError(errMisc, "message too big")
|
|
|
}
|
|
|
-}
|
|
|
|
|
|
-func (bp *baseProtocol) handleHandshake(c *ethutil.Value) error {
|
|
|
- hs := handshake{
|
|
|
- Version: c.Get(0).Uint(),
|
|
|
- ID: c.Get(1).Str(),
|
|
|
- Caps: nil, // decoded below
|
|
|
- ListenPort: c.Get(3).Uint(),
|
|
|
- NodeID: c.Get(4).Bytes(),
|
|
|
+ var hs handshake
|
|
|
+ if err := msg.Decode(&hs); err != nil {
|
|
|
+ return err
|
|
|
}
|
|
|
+
|
|
|
+ // validate handshake info
|
|
|
if hs.Version != baseProtocolVersion {
|
|
|
return newPeerError(errP2PVersionMismatch, "Require protocol %d, received %d\n",
|
|
|
baseProtocolVersion, hs.Version)
|
|
|
@@ -228,14 +239,8 @@ func (bp *baseProtocol) handleHandshake(c *ethutil.Value) error {
|
|
|
if err := bp.peer.pubkeyHook(pa); err != nil {
|
|
|
return newPeerError(errPubkeyForbidden, "%v", err)
|
|
|
}
|
|
|
- capsIt := c.Get(2).NewIterator()
|
|
|
- for capsIt.Next() {
|
|
|
- cap := capsIt.Value()
|
|
|
- name := cap.Get(0).Str()
|
|
|
- if name != "" {
|
|
|
- hs.Caps = append(hs.Caps, Cap{Name: name, Version: uint(cap.Get(1).Uint())})
|
|
|
- }
|
|
|
- }
|
|
|
+
|
|
|
+ // TODO: remove Caps with empty name
|
|
|
|
|
|
var addr *peerAddr
|
|
|
if hs.ListenPort != 0 {
|