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 }