github.com/m3shine/gochain@v2.2.26+incompatible/p2p/message.go (about) 1 // Copyright 2014 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 package p2p 18 19 import ( 20 "bytes" 21 "context" 22 "errors" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "sync/atomic" 27 "time" 28 29 "go.opencensus.io/trace" 30 31 "github.com/gochain-io/gochain/event" 32 "github.com/gochain-io/gochain/p2p/discover" 33 "github.com/gochain-io/gochain/rlp" 34 ) 35 36 // eth protocol message codes 37 const ( 38 // Protocol messages belonging to eth/62 39 StatusMsg = 0x00 40 NewBlockHashesMsg = 0x01 41 TxMsg = 0x02 42 GetBlockHeadersMsg = 0x03 43 BlockHeadersMsg = 0x04 44 GetBlockBodiesMsg = 0x05 45 BlockBodiesMsg = 0x06 46 NewBlockMsg = 0x07 47 48 // Protocol messages belonging to eth/63 49 GetNodeDataMsg = 0x0d 50 NodeDataMsg = 0x0e 51 GetReceiptsMsg = 0x0f 52 ReceiptsMsg = 0x10 53 ) 54 55 func MsgCodeString(code uint64) string { 56 switch code { 57 case StatusMsg: 58 return "Status" 59 case NewBlockHashesMsg: 60 return "NewBlockHashes" 61 case TxMsg: 62 return "Tx" 63 case GetBlockHeadersMsg: 64 return "GetBlockHeaders" 65 case BlockHeadersMsg: 66 return "BlockHeaders" 67 case GetBlockBodiesMsg: 68 return "GetBlockBodies" 69 case BlockBodiesMsg: 70 return "BlockBodiesMsg" 71 case NewBlockMsg: 72 return "NewBlock" 73 74 case GetNodeDataMsg: 75 return "GetNodeData" 76 case NodeDataMsg: 77 return "NodeData" 78 case GetReceiptsMsg: 79 return "GetReceipts" 80 case ReceiptsMsg: 81 return "Receipts" 82 83 default: 84 return fmt.Sprintf("Unrecognized: %x", code) 85 } 86 } 87 88 // Msg defines the structure of a p2p message. 89 // 90 // Note that a Msg can only be sent once since the Payload reader is 91 // consumed during sending. It is not possible to create a Msg and 92 // send it any number of times. If you want to reuse an encoded 93 // structure, encode the payload into a byte array and create a 94 // separate Msg with a bytes.Reader as Payload for each send. 95 type Msg struct { 96 Code uint64 97 Size uint32 // size of the paylod 98 Payload io.Reader 99 ReceivedAt time.Time 100 } 101 102 // Decode parses the RLP content of a message into 103 // the given value, which must be a pointer. 104 // 105 // For the decoding rules, please see package rlp. 106 func (msg Msg) Decode(val interface{}) error { 107 s := rlp.NewStream(msg.Payload, uint64(msg.Size)) 108 defer rlp.Discard(s) 109 if err := s.Decode(val); err != nil { 110 return newPeerError(errInvalidMsg, "(code %x) (size %d) %v", msg.Code, msg.Size, err) 111 } 112 return nil 113 } 114 115 func (msg Msg) String() string { 116 return fmt.Sprintf("msg #%v (%v bytes)", msg.Code, msg.Size) 117 } 118 119 // Discard reads any remaining payload data into a black hole. 120 func (msg Msg) Discard() error { 121 _, err := io.Copy(ioutil.Discard, msg.Payload) 122 return err 123 } 124 125 type MsgReader interface { 126 ReadMsg() (Msg, error) 127 } 128 129 type MsgWriter interface { 130 // WriteMsg sends a message. It will block until the message's 131 // Payload has been consumed by the other end. 132 // 133 // Note that messages can be sent only once because their 134 // payload reader is drained. 135 WriteMsg(context.Context, Msg) error 136 } 137 138 // MsgReadWriter provides reading and writing of encoded messages. 139 // Implementations should ensure that ReadMsg and WriteMsg can be 140 // called simultaneously from multiple goroutines. 141 type MsgReadWriter interface { 142 MsgReader 143 MsgWriter 144 } 145 146 // Send writes an RLP-encoded message with the given code. 147 // data should encode as an RLP list. 148 // Deprecated. Use SendCtx instead. 149 func Send(w MsgWriter, msgcode uint64, data interface{}) error { 150 return SendCtx(context.Background(), w, msgcode, data) 151 } 152 153 func SendCtx(ctx context.Context, w MsgWriter, msgcode uint64, data interface{}) error { 154 ctx, span := trace.StartSpan(ctx, "Send") 155 defer span.End() 156 157 size, r, err := rlp.EncodeToReader(data) 158 if err != nil { 159 return err 160 } 161 162 return w.WriteMsg(ctx, Msg{Code: msgcode, Size: uint32(size), Payload: r}) 163 } 164 165 // SendItems writes an RLP with the given code and data elements. 166 // For a call such as: 167 // 168 // SendItems(w, code, e1, e2, e3) 169 // 170 // the message payload will be an RLP list containing the items: 171 // 172 // [e1, e2, e3] 173 // 174 func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { 175 return Send(w, msgcode, elems) 176 } 177 178 func SendItemsCtx(ctx context.Context, w MsgWriter, msgcode uint64, elems ...interface{}) error { 179 return SendCtx(ctx, w, msgcode, elems) 180 } 181 182 // eofSignal wraps a reader with eof signaling. the eof channel is 183 // closed when the wrapped reader returns an error or when count bytes 184 // have been read. 185 type eofSignal struct { 186 wrapped io.Reader 187 count uint32 // number of bytes left 188 eof chan<- struct{} 189 } 190 191 // note: when using eofSignal to detect whether a message payload 192 // has been read, Read might not be called for zero sized messages. 193 func (r *eofSignal) Read(buf []byte) (int, error) { 194 if r.count == 0 { 195 if r.eof != nil { 196 r.eof <- struct{}{} 197 r.eof = nil 198 } 199 return 0, io.EOF 200 } 201 202 max := len(buf) 203 if int(r.count) < len(buf) { 204 max = int(r.count) 205 } 206 n, err := r.wrapped.Read(buf[:max]) 207 r.count -= uint32(n) 208 if (err != nil || r.count == 0) && r.eof != nil { 209 r.eof <- struct{}{} // tell Peer that msg has been consumed 210 r.eof = nil 211 } 212 return n, err 213 } 214 215 // MsgPipe creates a message pipe. Reads on one end are matched 216 // with writes on the other. The pipe is full-duplex, both ends 217 // implement MsgReadWriter. 218 func MsgPipe() (*MsgPipeRW, *MsgPipeRW) { 219 var ( 220 c1, c2 = make(chan Msg), make(chan Msg) 221 closing = make(chan struct{}) 222 closed = new(int32) 223 rw1 = &MsgPipeRW{c1, c2, closing, closed} 224 rw2 = &MsgPipeRW{c2, c1, closing, closed} 225 ) 226 return rw1, rw2 227 } 228 229 // ErrPipeClosed is returned from pipe operations after the 230 // pipe has been closed. 231 var ErrPipeClosed = errors.New("p2p: read or write on closed message pipe") 232 233 // MsgPipeRW is an endpoint of a MsgReadWriter pipe. 234 type MsgPipeRW struct { 235 w chan<- Msg 236 r <-chan Msg 237 closing chan struct{} 238 closed *int32 239 } 240 241 // WriteMsg sends a messsage on the pipe. 242 // It blocks until the receiver has consumed the message payload. 243 func (p *MsgPipeRW) WriteMsg(ctx context.Context, msg Msg) error { 244 ctx, span := trace.StartSpan(ctx, "MsgPipeRW.WriteMsg") 245 defer span.End() 246 247 span.AddAttributes( 248 trace.StringAttribute("code", MsgCodeString(msg.Code)), 249 trace.Int64Attribute("size", int64(msg.Size)), 250 ) 251 252 if atomic.LoadInt32(p.closed) == 0 { 253 consumed := make(chan struct{}, 1) 254 msg.Payload = &eofSignal{msg.Payload, msg.Size, consumed} 255 select { 256 case p.w <- msg: 257 if msg.Size > 0 { 258 // wait for payload read or discard 259 select { 260 case <-consumed: 261 case <-p.closing: 262 } 263 } 264 return nil 265 case <-p.closing: 266 } 267 } 268 span.SetStatus(trace.Status{ 269 Code: trace.StatusCodeInternal, 270 Message: ErrPipeClosed.Error(), 271 }) 272 return ErrPipeClosed 273 } 274 275 // ReadMsg returns a message sent on the other end of the pipe. 276 func (p *MsgPipeRW) ReadMsg() (Msg, error) { 277 if atomic.LoadInt32(p.closed) == 0 { 278 select { 279 case msg := <-p.r: 280 return msg, nil 281 case <-p.closing: 282 } 283 } 284 return Msg{}, ErrPipeClosed 285 } 286 287 // Close unblocks any pending ReadMsg and WriteMsg calls on both ends 288 // of the pipe. They will return ErrPipeClosed. Close also 289 // interrupts any reads from a message payload. 290 func (p *MsgPipeRW) Close() error { 291 if atomic.AddInt32(p.closed, 1) != 1 { 292 // someone else is already closing 293 atomic.StoreInt32(p.closed, 1) // avoid overflow 294 return nil 295 } 296 close(p.closing) 297 return nil 298 } 299 300 // ExpectMsg reads a message from r and verifies that its 301 // code and encoded RLP content match the provided values. 302 // If content is nil, the payload is discarded and not verified. 303 func ExpectMsg(r MsgReader, code uint64, content interface{}) error { 304 msg, err := r.ReadMsg() 305 if err != nil { 306 return err 307 } 308 if msg.Code != code { 309 return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) 310 } 311 if content == nil { 312 return msg.Discard() 313 } else { 314 contentEnc, err := rlp.EncodeToBytes(content) 315 if err != nil { 316 panic("content encode error: " + err.Error()) 317 } 318 if int(msg.Size) != len(contentEnc) { 319 return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) 320 } 321 actualContent, err := ioutil.ReadAll(msg.Payload) 322 if err != nil { 323 return err 324 } 325 if !bytes.Equal(actualContent, contentEnc) { 326 return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) 327 } 328 } 329 return nil 330 } 331 332 // msgEventer wraps a MsgReadWriter and sends events whenever a message is sent 333 // or received 334 type msgEventer struct { 335 MsgReadWriter 336 337 feed *event.Feed 338 peerID discover.NodeID 339 Protocol string 340 } 341 342 // newMsgEventer returns a msgEventer which sends message events to the given 343 // feed 344 func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID discover.NodeID, proto string) *msgEventer { 345 return &msgEventer{ 346 MsgReadWriter: rw, 347 feed: feed, 348 peerID: peerID, 349 Protocol: proto, 350 } 351 } 352 353 // ReadMsg reads a message from the underlying MsgReadWriter and emits a 354 // "message received" event 355 func (self *msgEventer) ReadMsg() (Msg, error) { 356 msg, err := self.MsgReadWriter.ReadMsg() 357 if err != nil { 358 return msg, err 359 } 360 self.feed.Send(&PeerEvent{ 361 Type: PeerEventTypeMsgRecv, 362 Peer: self.peerID, 363 Protocol: self.Protocol, 364 MsgCode: &msg.Code, 365 MsgSize: &msg.Size, 366 }) 367 return msg, nil 368 } 369 370 // WriteMsg writes a message to the underlying MsgReadWriter and emits a 371 // "message sent" event 372 func (self *msgEventer) WriteMsg(ctx context.Context, msg Msg) error { 373 ctx, span := trace.StartSpan(ctx, "msgEventer.WriteMsg") 374 defer span.End() 375 376 err := self.MsgReadWriter.WriteMsg(ctx, msg) 377 if err != nil { 378 return err 379 } 380 self.feed.SendCtx(ctx, &PeerEvent{ 381 Type: PeerEventTypeMsgSend, 382 Peer: self.peerID, 383 Protocol: self.Protocol, 384 MsgCode: &msg.Code, 385 MsgSize: &msg.Size, 386 }) 387 return nil 388 } 389 390 // Close closes the underlying MsgReadWriter if it implements the io.Closer 391 // interface 392 func (self *msgEventer) Close() error { 393 if v, ok := self.MsgReadWriter.(io.Closer); ok { 394 return v.Close() 395 } 396 return nil 397 }