github.com/sixexorg/magnetic-ring@v0.0.0-20191119090307-31705a21e419/p2pserver/net/netserver/message.go (about) 1 package netserver 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 "io/ioutil" 9 "net" 10 "sync" 11 "sync/atomic" 12 "time" 13 14 "github.com/ethereum/go-ethereum/event" 15 "github.com/sixexorg/magnetic-ring/p2pserver/common" 16 "github.com/sixexorg/magnetic-ring/p2pserver/discover" 17 "github.com/sixexorg/magnetic-ring/rlp" 18 ) 19 20 // Msg defines the structure of a p2p message. 21 // 22 // Note that a Msg can only be sent once since the Payload reader is 23 // consumed during sending. It is not possible to create a Msg and 24 // send it any number of times. If you want to reuse an encoded 25 // structure, encode the payload into a byte array and create a 26 // separate Msg with a bytes.Reader as Payload for each send. 27 // type Msg struct { 28 // Code uint64 29 // Size uint32 // size of the paylod 30 // Payload io.Reader 31 // ReceivedAt time.Time 32 // } 33 34 // // Decode parses the RLP content of a message into 35 // // the given value, which must be a pointer. 36 // // 37 // // For the decoding rules, please see package rlp. 38 // func (msg Msg) Decode(val interface{}) error { 39 // s := rlp.NewStream(msg.Payload, uint64(msg.Size)) 40 // if err := s.Decode(val); err != nil { 41 // return newPeerError(errInvalidMsg, "(code %x) (size %d) %v", msg.Code, msg.Size, err) 42 // } 43 // return nil 44 // } 45 46 // func (msg Msg) String() string { 47 // return fmt.Sprintf("msg #%v (%v bytes)", msg.Code, msg.Size) 48 // } 49 50 // // Discard reads any remaining payload data into a black hole. 51 // func (msg Msg) Discard() error { 52 // _, err := io.Copy(ioutil.Discard, msg.Payload) 53 // return err 54 // } 55 56 // type MsgReader interface { 57 // ReadMsg() (Msg, error) 58 // } 59 60 // type MsgWriter interface { 61 // // WriteMsg sends a message. It will block until the message's 62 // // Payload has been consumed by the other end. 63 // // 64 // // Note that messages can be sent only once because their 65 // // payload reader is drained. 66 // WriteMsg(Msg) error 67 // } 68 69 // // MsgReadWriter provides reading and writing of encoded messages. 70 // // Implementations should ensure that ReadMsg and WriteMsg can be 71 // // called simultaneously from multiple goroutines. 72 // type MsgReadWriter interface { 73 // MsgReader 74 // MsgWriter 75 // } 76 77 // Send writes an RLP-encoded message with the given code. 78 // data should encode as an RLP list. 79 func Send(w common.MsgWriter, msgcode uint64, data interface{}) error { 80 size, r, err := rlp.EncodeToReader(data) 81 if err != nil { 82 return err 83 } 84 return w.WriteMsg(common.Msg{Code: msgcode, Size: uint32(size), Payload: r}) 85 } 86 87 // SendItems writes an RLP with the given code and data elements. 88 // For a call such as: 89 // 90 // SendItems(w, code, e1, e2, e3) 91 // 92 // the message payload will be an RLP list containing the items: 93 // 94 // [e1, e2, e3] 95 // 96 func SendItems(w common.MsgWriter, msgcode uint64, elems ...interface{}) error { 97 return Send(w, msgcode, elems) 98 } 99 100 // netWrapper wraps a MsgReadWriter with locks around 101 // ReadMsg/WriteMsg and applies read/write deadlines. 102 type netWrapper struct { 103 rmu, wmu sync.Mutex 104 105 rtimeout, wtimeout time.Duration 106 conn net.Conn 107 wrapped common.MsgReadWriter 108 } 109 110 func (rw *netWrapper) ReadMsg() (common.Msg, error) { 111 rw.rmu.Lock() 112 defer rw.rmu.Unlock() 113 rw.conn.SetReadDeadline(time.Now().Add(rw.rtimeout)) 114 return rw.wrapped.ReadMsg() 115 } 116 117 func (rw *netWrapper) WriteMsg(msg common.Msg) error { 118 rw.wmu.Lock() 119 defer rw.wmu.Unlock() 120 rw.conn.SetWriteDeadline(time.Now().Add(rw.wtimeout)) 121 return rw.wrapped.WriteMsg(msg) 122 } 123 124 // eofSignal wraps a reader with eof signaling. the eof channel is 125 // closed when the wrapped reader returns an error or when count bytes 126 // have been read. 127 type eofSignal struct { 128 wrapped io.Reader 129 count uint32 // number of bytes left 130 eof chan<- struct{} 131 } 132 133 // note: when using eofSignal to detect whether a message payload 134 // has been read, Read might not be called for zero sized messages. 135 func (r *eofSignal) Read(buf []byte) (int, error) { 136 if r.count == 0 { 137 if r.eof != nil { 138 r.eof <- struct{}{} 139 r.eof = nil 140 } 141 return 0, io.EOF 142 } 143 144 max := len(buf) 145 if int(r.count) < len(buf) { 146 max = int(r.count) 147 } 148 n, err := r.wrapped.Read(buf[:max]) 149 r.count -= uint32(n) 150 if (err != nil || r.count == 0) && r.eof != nil { 151 r.eof <- struct{}{} // tell Peer that msg has been consumed 152 r.eof = nil 153 } 154 return n, err 155 } 156 157 // MsgPipe creates a message pipe. Reads on one end are matched 158 // with writes on the other. The pipe is full-duplex, both ends 159 // implement MsgReadWriter. 160 func MsgPipe() (*MsgPipeRW, *MsgPipeRW) { 161 var ( 162 c1, c2 = make(chan common.Msg), make(chan common.Msg) 163 closing = make(chan struct{}) 164 closed = new(int32) 165 rw1 = &MsgPipeRW{c1, c2, closing, closed} 166 rw2 = &MsgPipeRW{c2, c1, closing, closed} 167 ) 168 return rw1, rw2 169 } 170 171 // ErrPipeClosed is returned from pipe operations after the 172 // pipe has been closed. 173 var ErrPipeClosed = errors.New("p2p: read or write on closed message pipe") 174 175 // MsgPipeRW is an endpoint of a MsgReadWriter pipe. 176 type MsgPipeRW struct { 177 w chan<- common.Msg 178 r <-chan common.Msg 179 closing chan struct{} 180 closed *int32 181 } 182 183 // WriteMsg sends a messsage on the pipe. 184 // It blocks until the receiver has consumed the message payload. 185 func (p *MsgPipeRW) WriteMsg(msg common.Msg) error { 186 if atomic.LoadInt32(p.closed) == 0 { 187 consumed := make(chan struct{}, 1) 188 msg.Payload = &eofSignal{msg.Payload, msg.Size, consumed} 189 select { 190 case p.w <- msg: 191 if msg.Size > 0 { 192 // wait for payload read or discard 193 select { 194 case <-consumed: 195 case <-p.closing: 196 } 197 } 198 return nil 199 case <-p.closing: 200 } 201 } 202 return ErrPipeClosed 203 } 204 205 // ReadMsg returns a message sent on the other end of the pipe. 206 func (p *MsgPipeRW) ReadMsg() (common.Msg, error) { 207 if atomic.LoadInt32(p.closed) == 0 { 208 select { 209 case msg := <-p.r: 210 return msg, nil 211 case <-p.closing: 212 } 213 } 214 return common.Msg{}, ErrPipeClosed 215 } 216 217 // Close unblocks any pending ReadMsg and WriteMsg calls on both ends 218 // of the pipe. They will return ErrPipeClosed. Close also 219 // interrupts any reads from a message payload. 220 func (p *MsgPipeRW) Close() error { 221 if atomic.AddInt32(p.closed, 1) != 1 { 222 // someone else is already closing 223 atomic.StoreInt32(p.closed, 1) // avoid overflow 224 return nil 225 } 226 close(p.closing) 227 return nil 228 } 229 230 // ExpectMsg reads a message from r and verifies that its 231 // code and encoded RLP content match the provided values. 232 // If content is nil, the payload is discarded and not verified. 233 func ExpectMsg(r common.MsgReader, code uint64, content interface{}) error { 234 msg, err := r.ReadMsg() 235 if err != nil { 236 return err 237 } 238 if msg.Code != code { 239 return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) 240 } 241 if content == nil { 242 return msg.Discard() 243 } else { 244 contentEnc, err := rlp.EncodeToBytes(content) 245 if err != nil { 246 panic("content encode error: " + err.Error()) 247 } 248 if int(msg.Size) != len(contentEnc) { 249 return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) 250 } 251 actualContent, err := ioutil.ReadAll(msg.Payload) 252 if err != nil { 253 return err 254 } 255 if !bytes.Equal(actualContent, contentEnc) { 256 return fmt.Errorf("message payload mismatch:\ngot: %x\nwant: %x", actualContent, contentEnc) 257 } 258 } 259 return nil 260 } 261 262 // msgEventer wraps a MsgReadWriter and sends events whenever a message is sent 263 // or received 264 type msgEventer struct { 265 common.MsgReadWriter 266 267 feed *event.Feed 268 peerID discover.NodeID 269 Protocol string 270 } 271 272 // newMsgEventer returns a msgEventer which sends message events to the given 273 // feed 274 func newMsgEventer(rw common.MsgReadWriter, feed *event.Feed, peerID discover.NodeID, proto string) *msgEventer { 275 return &msgEventer{ 276 MsgReadWriter: rw, 277 feed: feed, 278 peerID: peerID, 279 Protocol: proto, 280 } 281 } 282 283 // ReadMsg reads a message from the underlying MsgReadWriter and emits a 284 // "message received" event 285 func (self *msgEventer) ReadMsg() (common.Msg, error) { 286 msg, err := self.MsgReadWriter.ReadMsg() 287 if err != nil { 288 return msg, err 289 } 290 // self.feed.Send(&PeerEvent{ 291 // Type: PeerEventTypeMsgRecv, 292 // Peer: self.peerID, 293 // Protocol: self.Protocol, 294 // MsgCode: &msg.Code, 295 // MsgSize: &msg.Size, 296 // }) 297 return msg, nil 298 } 299 300 // WriteMsg writes a message to the underlying MsgReadWriter and emits a 301 // "message sent" event 302 func (self *msgEventer) WriteMsg(msg common.Msg) error { 303 err := self.MsgReadWriter.WriteMsg(msg) 304 if err != nil { 305 return err 306 } 307 // self.feed.Send(&PeerEvent{ 308 // Type: PeerEventTypeMsgSend, 309 // Peer: self.peerID, 310 // Protocol: self.Protocol, 311 // MsgCode: &msg.Code, 312 // MsgSize: &msg.Size, 313 // }) 314 return nil 315 } 316 317 // Close closes the underlying MsgReadWriter if it implements the io.Closer 318 // interface 319 func (self *msgEventer) Close() error { 320 if v, ok := self.MsgReadWriter.(io.Closer); ok { 321 return v.Close() 322 } 323 return nil 324 }