github.com/chapsuk/go-ethereum@v1.8.12-0.20180615081455-574378edb50c/p2p/protocols/protocol.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  /*
    18  Package protocols is an extension to p2p. It offers a user friendly simple way to define
    19  devp2p subprotocols by abstracting away code standardly shared by protocols.
    20  
    21  * automate assigments of code indexes to messages
    22  * automate RLP decoding/encoding based on reflecting
    23  * provide the forever loop to read incoming messages
    24  * standardise error handling related to communication
    25  * standardised	handshake negotiation
    26  * TODO: automatic generation of wire protocol specification for peers
    27  
    28  */
    29  package protocols
    30  
    31  import (
    32  	"context"
    33  	"fmt"
    34  	"reflect"
    35  	"sync"
    36  	"time"
    37  
    38  	"github.com/ethereum/go-ethereum/metrics"
    39  	"github.com/ethereum/go-ethereum/p2p"
    40  )
    41  
    42  // error codes used by this  protocol scheme
    43  const (
    44  	ErrMsgTooLong = iota
    45  	ErrDecode
    46  	ErrWrite
    47  	ErrInvalidMsgCode
    48  	ErrInvalidMsgType
    49  	ErrHandshake
    50  	ErrNoHandler
    51  	ErrHandler
    52  )
    53  
    54  // error description strings associated with the codes
    55  var errorToString = map[int]string{
    56  	ErrMsgTooLong:     "Message too long",
    57  	ErrDecode:         "Invalid message (RLP error)",
    58  	ErrWrite:          "Error sending message",
    59  	ErrInvalidMsgCode: "Invalid message code",
    60  	ErrInvalidMsgType: "Invalid message type",
    61  	ErrHandshake:      "Handshake error",
    62  	ErrNoHandler:      "No handler registered error",
    63  	ErrHandler:        "Message handler error",
    64  }
    65  
    66  /*
    67  Error implements the standard go error interface.
    68  Use:
    69  
    70    errorf(code, format, params ...interface{})
    71  
    72  Prints as:
    73  
    74   <description>: <details>
    75  
    76  where description is given by code in errorToString
    77  and details is fmt.Sprintf(format, params...)
    78  
    79  exported field Code can be checked
    80  */
    81  type Error struct {
    82  	Code    int
    83  	message string
    84  	format  string
    85  	params  []interface{}
    86  }
    87  
    88  func (e Error) Error() (message string) {
    89  	if len(e.message) == 0 {
    90  		name, ok := errorToString[e.Code]
    91  		if !ok {
    92  			panic("invalid message code")
    93  		}
    94  		e.message = name
    95  		if e.format != "" {
    96  			e.message += ": " + fmt.Sprintf(e.format, e.params...)
    97  		}
    98  	}
    99  	return e.message
   100  }
   101  
   102  func errorf(code int, format string, params ...interface{}) *Error {
   103  	return &Error{
   104  		Code:   code,
   105  		format: format,
   106  		params: params,
   107  	}
   108  }
   109  
   110  // Spec is a protocol specification including its name and version as well as
   111  // the types of messages which are exchanged
   112  type Spec struct {
   113  	// Name is the name of the protocol, often a three-letter word
   114  	Name string
   115  
   116  	// Version is the version number of the protocol
   117  	Version uint
   118  
   119  	// MaxMsgSize is the maximum accepted length of the message payload
   120  	MaxMsgSize uint32
   121  
   122  	// Messages is a list of message data types which this protocol uses, with
   123  	// each message type being sent with its array index as the code (so
   124  	// [&foo{}, &bar{}, &baz{}] would send foo, bar and baz with codes
   125  	// 0, 1 and 2 respectively)
   126  	// each message must have a single unique data type
   127  	Messages []interface{}
   128  
   129  	initOnce sync.Once
   130  	codes    map[reflect.Type]uint64
   131  	types    map[uint64]reflect.Type
   132  }
   133  
   134  func (s *Spec) init() {
   135  	s.initOnce.Do(func() {
   136  		s.codes = make(map[reflect.Type]uint64, len(s.Messages))
   137  		s.types = make(map[uint64]reflect.Type, len(s.Messages))
   138  		for i, msg := range s.Messages {
   139  			code := uint64(i)
   140  			typ := reflect.TypeOf(msg)
   141  			if typ.Kind() == reflect.Ptr {
   142  				typ = typ.Elem()
   143  			}
   144  			s.codes[typ] = code
   145  			s.types[code] = typ
   146  		}
   147  	})
   148  }
   149  
   150  // Length returns the number of message types in the protocol
   151  func (s *Spec) Length() uint64 {
   152  	return uint64(len(s.Messages))
   153  }
   154  
   155  // GetCode returns the message code of a type, and boolean second argument is
   156  // false if the message type is not found
   157  func (s *Spec) GetCode(msg interface{}) (uint64, bool) {
   158  	s.init()
   159  	typ := reflect.TypeOf(msg)
   160  	if typ.Kind() == reflect.Ptr {
   161  		typ = typ.Elem()
   162  	}
   163  	code, ok := s.codes[typ]
   164  	return code, ok
   165  }
   166  
   167  // NewMsg construct a new message type given the code
   168  func (s *Spec) NewMsg(code uint64) (interface{}, bool) {
   169  	s.init()
   170  	typ, ok := s.types[code]
   171  	if !ok {
   172  		return nil, false
   173  	}
   174  	return reflect.New(typ).Interface(), true
   175  }
   176  
   177  // Peer represents a remote peer or protocol instance that is running on a peer connection with
   178  // a remote peer
   179  type Peer struct {
   180  	*p2p.Peer                   // the p2p.Peer object representing the remote
   181  	rw        p2p.MsgReadWriter // p2p.MsgReadWriter to send messages to and read messages from
   182  	spec      *Spec
   183  }
   184  
   185  // NewPeer constructs a new peer
   186  // this constructor is called by the p2p.Protocol#Run function
   187  // the first two arguments are the arguments passed to p2p.Protocol.Run function
   188  // the third argument is the Spec describing the protocol
   189  func NewPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *Spec) *Peer {
   190  	return &Peer{
   191  		Peer: p,
   192  		rw:   rw,
   193  		spec: spec,
   194  	}
   195  }
   196  
   197  // Run starts the forever loop that handles incoming messages
   198  // called within the p2p.Protocol#Run function
   199  // the handler argument is a function which is called for each message received
   200  // from the remote peer, a returned error causes the loop to exit
   201  // resulting in disconnection
   202  func (p *Peer) Run(handler func(msg interface{}) error) error {
   203  	for {
   204  		if err := p.handleIncoming(handler); err != nil {
   205  			return err
   206  		}
   207  	}
   208  }
   209  
   210  // Drop disconnects a peer.
   211  // TODO: may need to implement protocol drop only? don't want to kick off the peer
   212  // if they are useful for other protocols
   213  func (p *Peer) Drop(err error) {
   214  	p.Disconnect(p2p.DiscSubprotocolError)
   215  }
   216  
   217  // Send takes a message, encodes it in RLP, finds the right message code and sends the
   218  // message off to the peer
   219  // this low level call will be wrapped by libraries providing routed or broadcast sends
   220  // but often just used to forward and push messages to directly connected peers
   221  func (p *Peer) Send(msg interface{}) error {
   222  	defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now())
   223  	metrics.GetOrRegisterCounter("peer.send", nil).Inc(1)
   224  	code, found := p.spec.GetCode(msg)
   225  	if !found {
   226  		return errorf(ErrInvalidMsgType, "%v", code)
   227  	}
   228  	return p2p.Send(p.rw, code, msg)
   229  }
   230  
   231  // handleIncoming(code)
   232  // is called each cycle of the main forever loop that dispatches incoming messages
   233  // if this returns an error the loop returns and the peer is disconnected with the error
   234  // this generic handler
   235  // * checks message size,
   236  // * checks for out-of-range message codes,
   237  // * handles decoding with reflection,
   238  // * call handlers as callbacks
   239  func (p *Peer) handleIncoming(handle func(msg interface{}) error) error {
   240  	msg, err := p.rw.ReadMsg()
   241  	if err != nil {
   242  		return err
   243  	}
   244  	// make sure that the payload has been fully consumed
   245  	defer msg.Discard()
   246  
   247  	if msg.Size > p.spec.MaxMsgSize {
   248  		return errorf(ErrMsgTooLong, "%v > %v", msg.Size, p.spec.MaxMsgSize)
   249  	}
   250  
   251  	val, ok := p.spec.NewMsg(msg.Code)
   252  	if !ok {
   253  		return errorf(ErrInvalidMsgCode, "%v", msg.Code)
   254  	}
   255  	if err := msg.Decode(val); err != nil {
   256  		return errorf(ErrDecode, "<= %v: %v", msg, err)
   257  	}
   258  
   259  	// call the registered handler callbacks
   260  	// a registered callback take the decoded message as argument as an interface
   261  	// which the handler is supposed to cast to the appropriate type
   262  	// it is entirely safe not to check the cast in the handler since the handler is
   263  	// chosen based on the proper type in the first place
   264  	if err := handle(val); err != nil {
   265  		return errorf(ErrHandler, "(msg code %v): %v", msg.Code, err)
   266  	}
   267  	return nil
   268  }
   269  
   270  // Handshake negotiates a handshake on the peer connection
   271  // * arguments
   272  //   * context
   273  //   * the local handshake to be sent to the remote peer
   274  //   * funcion to be called on the remote handshake (can be nil)
   275  // * expects a remote handshake back of the same type
   276  // * the dialing peer needs to send the handshake first and then waits for remote
   277  // * the listening peer waits for the remote handshake and then sends it
   278  // returns the remote handshake and an error
   279  func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interface{}) error) (rhs interface{}, err error) {
   280  	if _, ok := p.spec.GetCode(hs); !ok {
   281  		return nil, errorf(ErrHandshake, "unknown handshake message type: %T", hs)
   282  	}
   283  	errc := make(chan error, 2)
   284  	handle := func(msg interface{}) error {
   285  		rhs = msg
   286  		if verify != nil {
   287  			return verify(rhs)
   288  		}
   289  		return nil
   290  	}
   291  	send := func() { errc <- p.Send(hs) }
   292  	receive := func() { errc <- p.handleIncoming(handle) }
   293  
   294  	go func() {
   295  		if p.Inbound() {
   296  			receive()
   297  			send()
   298  		} else {
   299  			send()
   300  			receive()
   301  		}
   302  	}()
   303  
   304  	for i := 0; i < 2; i++ {
   305  		select {
   306  		case err = <-errc:
   307  		case <-ctx.Done():
   308  			err = ctx.Err()
   309  		}
   310  		if err != nil {
   311  			return nil, errorf(ErrHandshake, err.Error())
   312  		}
   313  	}
   314  	return rhs, nil
   315  }