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