github.com/codingfuture/orig-energi3@v0.8.4/p2p/protocols/protocol.go (about) 1 // Copyright 2018 The Energi Core Authors 2 // Copyright 2018 The go-ethereum Authors 3 // This file is part of the Energi Core library. 4 // 5 // The Energi Core library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The Energi Core library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the Energi Core library. If not, see <http://www.gnu.org/licenses/>. 17 18 /* 19 Package protocols is an extension to p2p. It offers a user friendly simple way to define 20 devp2p subprotocols by abstracting away code standardly shared by protocols. 21 22 * automate assigments of code indexes to messages 23 * automate RLP decoding/encoding based on reflecting 24 * provide the forever loop to read incoming messages 25 * standardise error handling related to communication 26 * standardised handshake negotiation 27 * TODO: automatic generation of wire protocol specification for peers 28 29 */ 30 package protocols 31 32 import ( 33 "bufio" 34 "bytes" 35 "context" 36 "fmt" 37 "io" 38 "reflect" 39 "sync" 40 "time" 41 42 "github.com/ethereum/go-ethereum/log" 43 "github.com/ethereum/go-ethereum/metrics" 44 "github.com/ethereum/go-ethereum/p2p" 45 "github.com/ethereum/go-ethereum/rlp" 46 "github.com/ethereum/go-ethereum/swarm/spancontext" 47 "github.com/ethereum/go-ethereum/swarm/tracing" 48 opentracing "github.com/opentracing/opentracing-go" 49 ) 50 51 // error codes used by this protocol scheme 52 const ( 53 ErrMsgTooLong = iota 54 ErrDecode 55 ErrWrite 56 ErrInvalidMsgCode 57 ErrInvalidMsgType 58 ErrHandshake 59 ErrNoHandler 60 ErrHandler 61 ) 62 63 // error description strings associated with the codes 64 var errorToString = map[int]string{ 65 ErrMsgTooLong: "Message too long", 66 ErrDecode: "Invalid message (RLP error)", 67 ErrWrite: "Error sending message", 68 ErrInvalidMsgCode: "Invalid message code", 69 ErrInvalidMsgType: "Invalid message type", 70 ErrHandshake: "Handshake error", 71 ErrNoHandler: "No handler registered error", 72 ErrHandler: "Message handler error", 73 } 74 75 /* 76 Error implements the standard go error interface. 77 Use: 78 79 errorf(code, format, params ...interface{}) 80 81 Prints as: 82 83 <description>: <details> 84 85 where description is given by code in errorToString 86 and details is fmt.Sprintf(format, params...) 87 88 exported field Code can be checked 89 */ 90 type Error struct { 91 Code int 92 message string 93 format string 94 params []interface{} 95 } 96 97 func (e Error) Error() (message string) { 98 if len(e.message) == 0 { 99 name, ok := errorToString[e.Code] 100 if !ok { 101 panic("invalid message code") 102 } 103 e.message = name 104 if e.format != "" { 105 e.message += ": " + fmt.Sprintf(e.format, e.params...) 106 } 107 } 108 return e.message 109 } 110 111 func errorf(code int, format string, params ...interface{}) *Error { 112 return &Error{ 113 Code: code, 114 format: format, 115 params: params, 116 } 117 } 118 119 // WrappedMsg is used to propagate marshalled context alongside message payloads 120 type WrappedMsg struct { 121 Context []byte 122 Size uint32 123 Payload []byte 124 } 125 126 //For accounting, the design is to allow the Spec to describe which and how its messages are priced 127 //To access this functionality, we provide a Hook interface which will call accounting methods 128 //NOTE: there could be more such (horizontal) hooks in the future 129 type Hook interface { 130 //A hook for sending messages 131 Send(peer *Peer, size uint32, msg interface{}) error 132 //A hook for receiving messages 133 Receive(peer *Peer, size uint32, msg interface{}) error 134 } 135 136 // Spec is a protocol specification including its name and version as well as 137 // the types of messages which are exchanged 138 type Spec struct { 139 // Name is the name of the protocol, often a three-letter word 140 Name string 141 142 // Version is the version number of the protocol 143 Version uint 144 145 // MaxMsgSize is the maximum accepted length of the message payload 146 MaxMsgSize uint32 147 148 // Messages is a list of message data types which this protocol uses, with 149 // each message type being sent with its array index as the code (so 150 // [&foo{}, &bar{}, &baz{}] would send foo, bar and baz with codes 151 // 0, 1 and 2 respectively) 152 // each message must have a single unique data type 153 Messages []interface{} 154 155 //hook for accounting (could be extended to multiple hooks in the future) 156 Hook Hook 157 158 initOnce sync.Once 159 codes map[reflect.Type]uint64 160 types map[uint64]reflect.Type 161 } 162 163 func (s *Spec) init() { 164 s.initOnce.Do(func() { 165 s.codes = make(map[reflect.Type]uint64, len(s.Messages)) 166 s.types = make(map[uint64]reflect.Type, len(s.Messages)) 167 for i, msg := range s.Messages { 168 code := uint64(i) 169 typ := reflect.TypeOf(msg) 170 if typ.Kind() == reflect.Ptr { 171 typ = typ.Elem() 172 } 173 s.codes[typ] = code 174 s.types[code] = typ 175 } 176 }) 177 } 178 179 // Length returns the number of message types in the protocol 180 func (s *Spec) Length() uint64 { 181 return uint64(len(s.Messages)) 182 } 183 184 // GetCode returns the message code of a type, and boolean second argument is 185 // false if the message type is not found 186 func (s *Spec) GetCode(msg interface{}) (uint64, bool) { 187 s.init() 188 typ := reflect.TypeOf(msg) 189 if typ.Kind() == reflect.Ptr { 190 typ = typ.Elem() 191 } 192 code, ok := s.codes[typ] 193 return code, ok 194 } 195 196 // NewMsg construct a new message type given the code 197 func (s *Spec) NewMsg(code uint64) (interface{}, bool) { 198 s.init() 199 typ, ok := s.types[code] 200 if !ok { 201 return nil, false 202 } 203 return reflect.New(typ).Interface(), true 204 } 205 206 // Peer represents a remote peer or protocol instance that is running on a peer connection with 207 // a remote peer 208 type Peer struct { 209 *p2p.Peer // the p2p.Peer object representing the remote 210 rw p2p.MsgReadWriter // p2p.MsgReadWriter to send messages to and read messages from 211 spec *Spec 212 } 213 214 // NewPeer constructs a new peer 215 // this constructor is called by the p2p.Protocol#Run function 216 // the first two arguments are the arguments passed to p2p.Protocol.Run function 217 // the third argument is the Spec describing the protocol 218 func NewPeer(p *p2p.Peer, rw p2p.MsgReadWriter, spec *Spec) *Peer { 219 return &Peer{ 220 Peer: p, 221 rw: rw, 222 spec: spec, 223 } 224 } 225 226 // Run starts the forever loop that handles incoming messages 227 // called within the p2p.Protocol#Run function 228 // the handler argument is a function which is called for each message received 229 // from the remote peer, a returned error causes the loop to exit 230 // resulting in disconnection 231 func (p *Peer) Run(handler func(ctx context.Context, msg interface{}) error) error { 232 for { 233 if err := p.handleIncoming(handler); err != nil { 234 if err != io.EOF { 235 metrics.GetOrRegisterCounter("peer.handleincoming.error", nil).Inc(1) 236 log.Error("peer.handleIncoming", "err", err) 237 } 238 239 return err 240 } 241 } 242 } 243 244 // Drop disconnects a peer. 245 // TODO: may need to implement protocol drop only? don't want to kick off the peer 246 // if they are useful for other protocols 247 func (p *Peer) Drop(err error) { 248 p.Disconnect(p2p.DiscSubprotocolError) 249 } 250 251 // Send takes a message, encodes it in RLP, finds the right message code and sends the 252 // message off to the peer 253 // this low level call will be wrapped by libraries providing routed or broadcast sends 254 // but often just used to forward and push messages to directly connected peers 255 func (p *Peer) Send(ctx context.Context, msg interface{}) error { 256 defer metrics.GetOrRegisterResettingTimer("peer.send_t", nil).UpdateSince(time.Now()) 257 metrics.GetOrRegisterCounter("peer.send", nil).Inc(1) 258 259 var b bytes.Buffer 260 if tracing.Enabled { 261 writer := bufio.NewWriter(&b) 262 263 tracer := opentracing.GlobalTracer() 264 265 sctx := spancontext.FromContext(ctx) 266 267 if sctx != nil { 268 err := tracer.Inject( 269 sctx, 270 opentracing.Binary, 271 writer) 272 if err != nil { 273 return err 274 } 275 } 276 277 writer.Flush() 278 } 279 280 r, err := rlp.EncodeToBytes(msg) 281 if err != nil { 282 return err 283 } 284 285 wmsg := WrappedMsg{ 286 Context: b.Bytes(), 287 Size: uint32(len(r)), 288 Payload: r, 289 } 290 291 //if the accounting hook is set, call it 292 if p.spec.Hook != nil { 293 err := p.spec.Hook.Send(p, wmsg.Size, msg) 294 if err != nil { 295 p.Drop(err) 296 return err 297 } 298 } 299 300 code, found := p.spec.GetCode(msg) 301 if !found { 302 return errorf(ErrInvalidMsgType, "%v", code) 303 } 304 return p2p.Send(p.rw, code, wmsg) 305 } 306 307 // handleIncoming(code) 308 // is called each cycle of the main forever loop that dispatches incoming messages 309 // if this returns an error the loop returns and the peer is disconnected with the error 310 // this generic handler 311 // * checks message size, 312 // * checks for out-of-range message codes, 313 // * handles decoding with reflection, 314 // * call handlers as callbacks 315 func (p *Peer) handleIncoming(handle func(ctx context.Context, msg interface{}) error) error { 316 msg, err := p.rw.ReadMsg() 317 if err != nil { 318 return err 319 } 320 // make sure that the payload has been fully consumed 321 defer msg.Discard() 322 323 if msg.Size > p.spec.MaxMsgSize { 324 return errorf(ErrMsgTooLong, "%v > %v", msg.Size, p.spec.MaxMsgSize) 325 } 326 327 // unmarshal wrapped msg, which might contain context 328 var wmsg WrappedMsg 329 err = msg.Decode(&wmsg) 330 if err != nil { 331 log.Error(err.Error()) 332 return err 333 } 334 335 ctx := context.Background() 336 337 // if tracing is enabled and the context coming within the request is 338 // not empty, try to unmarshal it 339 if tracing.Enabled && len(wmsg.Context) > 0 { 340 var sctx opentracing.SpanContext 341 342 tracer := opentracing.GlobalTracer() 343 sctx, err = tracer.Extract( 344 opentracing.Binary, 345 bytes.NewReader(wmsg.Context)) 346 if err != nil { 347 log.Error(err.Error()) 348 return err 349 } 350 351 ctx = spancontext.WithContext(ctx, sctx) 352 } 353 354 val, ok := p.spec.NewMsg(msg.Code) 355 if !ok { 356 return errorf(ErrInvalidMsgCode, "%v", msg.Code) 357 } 358 if err := rlp.DecodeBytes(wmsg.Payload, val); err != nil { 359 return errorf(ErrDecode, "<= %v: %v", msg, err) 360 } 361 362 //if the accounting hook is set, call it 363 if p.spec.Hook != nil { 364 err := p.spec.Hook.Receive(p, wmsg.Size, val) 365 if err != nil { 366 return err 367 } 368 } 369 370 // call the registered handler callbacks 371 // a registered callback take the decoded message as argument as an interface 372 // which the handler is supposed to cast to the appropriate type 373 // it is entirely safe not to check the cast in the handler since the handler is 374 // chosen based on the proper type in the first place 375 if err := handle(ctx, val); err != nil { 376 return errorf(ErrHandler, "(msg code %v): %v", msg.Code, err) 377 } 378 return nil 379 } 380 381 // Handshake negotiates a handshake on the peer connection 382 // * arguments 383 // * context 384 // * the local handshake to be sent to the remote peer 385 // * function to be called on the remote handshake (can be nil) 386 // * expects a remote handshake back of the same type 387 // * the dialing peer needs to send the handshake first and then waits for remote 388 // * the listening peer waits for the remote handshake and then sends it 389 // returns the remote handshake and an error 390 func (p *Peer) Handshake(ctx context.Context, hs interface{}, verify func(interface{}) error) (rhs interface{}, err error) { 391 if _, ok := p.spec.GetCode(hs); !ok { 392 return nil, errorf(ErrHandshake, "unknown handshake message type: %T", hs) 393 } 394 errc := make(chan error, 2) 395 handle := func(ctx context.Context, msg interface{}) error { 396 rhs = msg 397 if verify != nil { 398 return verify(rhs) 399 } 400 return nil 401 } 402 send := func() { errc <- p.Send(ctx, hs) } 403 receive := func() { errc <- p.handleIncoming(handle) } 404 405 go func() { 406 if p.Inbound() { 407 receive() 408 send() 409 } else { 410 send() 411 receive() 412 } 413 }() 414 415 for i := 0; i < 2; i++ { 416 select { 417 case err = <-errc: 418 case <-ctx.Done(): 419 err = ctx.Err() 420 } 421 if err != nil { 422 return nil, errorf(ErrHandshake, err.Error()) 423 } 424 } 425 return rhs, nil 426 } 427 428 // HasCap returns true if Peer has a capability 429 // with provided name. 430 func (p *Peer) HasCap(capName string) (yes bool) { 431 if p == nil || p.Peer == nil { 432 return false 433 } 434 for _, c := range p.Caps() { 435 if c.Name == capName { 436 return true 437 } 438 } 439 return false 440 }