| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // Copyright 2014 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-23 18:35:11 +02:00
										 |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							| 
									
										
										
										
											2015-07-22 18:48:40 +02:00
										 |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							| 
									
										
										
										
											2015-07-07 02:54:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | package p2p | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2015-01-05 17:10:42 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 	"sync/atomic" | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/event" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/p2p/discover" | 
					
						
							| 
									
										
										
										
											2014-11-24 19:02:48 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | // Msg defines the structure of a p2p message. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // Note that a Msg can only be sent once since the Payload reader is | 
					
						
							|  |  |  | // consumed during sending. It is not possible to create a Msg and | 
					
						
							|  |  |  | // send it any number of times. If you want to reuse an encoded | 
					
						
							|  |  |  | // structure, encode the payload into a byte array and create a | 
					
						
							|  |  |  | // separate Msg with a bytes.Reader as Payload for each send. | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | type Msg struct { | 
					
						
							| 
									
										
										
										
											2015-04-29 22:49:58 +02:00
										 |  |  | 	Code       uint64 | 
					
						
							|  |  |  | 	Size       uint32 // size of the paylod | 
					
						
							|  |  |  | 	Payload    io.Reader | 
					
						
							|  |  |  | 	ReceivedAt time.Time | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | // Decode parses the RLP content of a message into | 
					
						
							| 
									
										
										
										
											2014-11-25 12:25:31 +01:00
										 |  |  | // the given value, which must be a pointer. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // For the decoding rules, please see package rlp. | 
					
						
							|  |  |  | func (msg Msg) Decode(val interface{}) error { | 
					
						
							| 
									
										
										
										
											2015-03-23 15:08:29 +01:00
										 |  |  | 	s := rlp.NewStream(msg.Payload, uint64(msg.Size)) | 
					
						
							|  |  |  | 	if err := s.Decode(val); err != nil { | 
					
						
							| 
									
										
										
										
											2015-03-20 12:52:03 +01:00
										 |  |  | 		return newPeerError(errInvalidMsg, "(code %x) (size %d) %v", msg.Code, msg.Size, err) | 
					
						
							| 
									
										
										
										
											2015-01-05 17:10:42 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (msg Msg) String() string { | 
					
						
							|  |  |  | 	return fmt.Sprintf("msg #%v (%v bytes)", msg.Code, msg.Size) | 
					
						
							| 
									
										
										
										
											2014-11-25 12:25:31 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | // Discard reads any remaining payload data into a black hole. | 
					
						
							|  |  |  | func (msg Msg) Discard() error { | 
					
						
							|  |  |  | 	_, err := io.Copy(ioutil.Discard, msg.Payload) | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | type MsgReader interface { | 
					
						
							|  |  |  | 	ReadMsg() (Msg, error) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type MsgWriter interface { | 
					
						
							| 
									
										
										
										
											2015-01-06 11:35:09 +01:00
										 |  |  | 	// WriteMsg sends a message. It will block until the message's | 
					
						
							|  |  |  | 	// Payload has been consumed by the other end. | 
					
						
							|  |  |  | 	// | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	// Note that messages can be sent only once because their | 
					
						
							|  |  |  | 	// payload reader is drained. | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	WriteMsg(Msg) error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MsgReadWriter provides reading and writing of encoded messages. | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // Implementations should ensure that ReadMsg and WriteMsg can be | 
					
						
							|  |  |  | // called simultaneously from multiple goroutines. | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | type MsgReadWriter interface { | 
					
						
							|  |  |  | 	MsgReader | 
					
						
							|  |  |  | 	MsgWriter | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | // Send writes an RLP-encoded message with the given code. | 
					
						
							|  |  |  | // data should encode as an RLP list. | 
					
						
							|  |  |  | func Send(w MsgWriter, msgcode uint64, data interface{}) error { | 
					
						
							|  |  |  | 	size, r, err := rlp.EncodeToReader(data) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return w.WriteMsg(Msg{Code: msgcode, Size: uint32(size), Payload: r}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // SendItems writes an RLP with the given code and data elements. | 
					
						
							|  |  |  | // For a call such as: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //    SendItems(w, code, e1, e2, e3) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // the message payload will be an RLP list containing the items: | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //    [e1, e2, e3] | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | func SendItems(w MsgWriter, msgcode uint64, elems ...interface{}) error { | 
					
						
							|  |  |  | 	return Send(w, msgcode, elems) | 
					
						
							| 
									
										
										
										
											2015-01-06 11:35:09 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // eofSignal wraps a reader with eof signaling. the eof channel is | 
					
						
							|  |  |  | // closed when the wrapped reader returns an error or when count bytes | 
					
						
							|  |  |  | // have been read. | 
					
						
							|  |  |  | type eofSignal struct { | 
					
						
							|  |  |  | 	wrapped io.Reader | 
					
						
							|  |  |  | 	count   uint32 // number of bytes left | 
					
						
							|  |  |  | 	eof     chan<- struct{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // note: when using eofSignal to detect whether a message payload | 
					
						
							|  |  |  | // has been read, Read might not be called for zero sized messages. | 
					
						
							|  |  |  | func (r *eofSignal) Read(buf []byte) (int, error) { | 
					
						
							|  |  |  | 	if r.count == 0 { | 
					
						
							|  |  |  | 		if r.eof != nil { | 
					
						
							|  |  |  | 			r.eof <- struct{}{} | 
					
						
							|  |  |  | 			r.eof = nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return 0, io.EOF | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	max := len(buf) | 
					
						
							|  |  |  | 	if int(r.count) < len(buf) { | 
					
						
							|  |  |  | 		max = int(r.count) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	n, err := r.wrapped.Read(buf[:max]) | 
					
						
							|  |  |  | 	r.count -= uint32(n) | 
					
						
							|  |  |  | 	if (err != nil || r.count == 0) && r.eof != nil { | 
					
						
							|  |  |  | 		r.eof <- struct{}{} // tell Peer that msg has been consumed | 
					
						
							|  |  |  | 		r.eof = nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return n, err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | // MsgPipe creates a message pipe. Reads on one end are matched | 
					
						
							|  |  |  | // with writes on the other. The pipe is full-duplex, both ends | 
					
						
							|  |  |  | // implement MsgReadWriter. | 
					
						
							|  |  |  | func MsgPipe() (*MsgPipeRW, *MsgPipeRW) { | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		c1, c2  = make(chan Msg), make(chan Msg) | 
					
						
							|  |  |  | 		closing = make(chan struct{}) | 
					
						
							|  |  |  | 		closed  = new(int32) | 
					
						
							|  |  |  | 		rw1     = &MsgPipeRW{c1, c2, closing, closed} | 
					
						
							|  |  |  | 		rw2     = &MsgPipeRW{c2, c1, closing, closed} | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	return rw1, rw2 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ErrPipeClosed is returned from pipe operations after the | 
					
						
							|  |  |  | // pipe has been closed. | 
					
						
							|  |  |  | var ErrPipeClosed = errors.New("p2p: read or write on closed message pipe") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // MsgPipeRW is an endpoint of a MsgReadWriter pipe. | 
					
						
							|  |  |  | type MsgPipeRW struct { | 
					
						
							|  |  |  | 	w       chan<- Msg | 
					
						
							|  |  |  | 	r       <-chan Msg | 
					
						
							|  |  |  | 	closing chan struct{} | 
					
						
							|  |  |  | 	closed  *int32 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteMsg sends a messsage on the pipe. | 
					
						
							|  |  |  | // It blocks until the receiver has consumed the message payload. | 
					
						
							|  |  |  | func (p *MsgPipeRW) WriteMsg(msg Msg) error { | 
					
						
							|  |  |  | 	if atomic.LoadInt32(p.closed) == 0 { | 
					
						
							|  |  |  | 		consumed := make(chan struct{}, 1) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		msg.Payload = &eofSignal{msg.Payload, msg.Size, consumed} | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 		select { | 
					
						
							|  |  |  | 		case p.w <- msg: | 
					
						
							|  |  |  | 			if msg.Size > 0 { | 
					
						
							|  |  |  | 				// wait for payload read or discard | 
					
						
							| 
									
										
										
										
											2015-03-19 15:16:06 +01:00
										 |  |  | 				select { | 
					
						
							|  |  |  | 				case <-consumed: | 
					
						
							|  |  |  | 				case <-p.closing: | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		case <-p.closing: | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ErrPipeClosed | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReadMsg returns a message sent on the other end of the pipe. | 
					
						
							|  |  |  | func (p *MsgPipeRW) ReadMsg() (Msg, error) { | 
					
						
							|  |  |  | 	if atomic.LoadInt32(p.closed) == 0 { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case msg := <-p.r: | 
					
						
							|  |  |  | 			return msg, nil | 
					
						
							|  |  |  | 		case <-p.closing: | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return Msg{}, ErrPipeClosed | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close unblocks any pending ReadMsg and WriteMsg calls on both ends | 
					
						
							| 
									
										
										
										
											2015-03-19 15:16:06 +01:00
										 |  |  | // of the pipe. They will return ErrPipeClosed. Close also | 
					
						
							|  |  |  | // interrupts any reads from a message payload. | 
					
						
							| 
									
										
										
										
											2014-12-12 11:39:07 +01:00
										 |  |  | func (p *MsgPipeRW) Close() error { | 
					
						
							|  |  |  | 	if atomic.AddInt32(p.closed, 1) != 1 { | 
					
						
							|  |  |  | 		// someone else is already closing | 
					
						
							|  |  |  | 		atomic.StoreInt32(p.closed, 1) // avoid overflow | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	close(p.closing) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-03-19 15:08:04 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ExpectMsg reads a message from r and verifies that its | 
					
						
							|  |  |  | // code and encoded RLP content match the provided values. | 
					
						
							|  |  |  | // If content is nil, the payload is discarded and not verified. | 
					
						
							|  |  |  | func ExpectMsg(r MsgReader, code uint64, content interface{}) error { | 
					
						
							|  |  |  | 	msg, err := r.ReadMsg() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if msg.Code != code { | 
					
						
							|  |  |  | 		return fmt.Errorf("message code mismatch: got %d, expected %d", msg.Code, code) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if content == nil { | 
					
						
							|  |  |  | 		return msg.Discard() | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		contentEnc, err := rlp.EncodeToBytes(content) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			panic("content encode error: " + err.Error()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if int(msg.Size) != len(contentEnc) { | 
					
						
							|  |  |  | 			return fmt.Errorf("message size mismatch: got %d, want %d", msg.Size, len(contentEnc)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		actualContent, err := ioutil.ReadAll(msg.Payload) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if !bytes.Equal(actualContent, contentEnc) { | 
					
						
							|  |  |  | 			return fmt.Errorf("message payload mismatch:\ngot:  %x\nwant: %x", actualContent, contentEnc) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-09-25 09:08:07 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // msgEventer wraps a MsgReadWriter and sends events whenever a message is sent | 
					
						
							|  |  |  | // or received | 
					
						
							|  |  |  | type msgEventer struct { | 
					
						
							|  |  |  | 	MsgReadWriter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	feed     *event.Feed | 
					
						
							|  |  |  | 	peerID   discover.NodeID | 
					
						
							|  |  |  | 	Protocol string | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newMsgEventer returns a msgEventer which sends message events to the given | 
					
						
							|  |  |  | // feed | 
					
						
							|  |  |  | func newMsgEventer(rw MsgReadWriter, feed *event.Feed, peerID discover.NodeID, proto string) *msgEventer { | 
					
						
							|  |  |  | 	return &msgEventer{ | 
					
						
							|  |  |  | 		MsgReadWriter: rw, | 
					
						
							|  |  |  | 		feed:          feed, | 
					
						
							|  |  |  | 		peerID:        peerID, | 
					
						
							|  |  |  | 		Protocol:      proto, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ReadMsg reads a message from the underlying MsgReadWriter and emits a | 
					
						
							|  |  |  | // "message received" event | 
					
						
							|  |  |  | func (self *msgEventer) ReadMsg() (Msg, error) { | 
					
						
							|  |  |  | 	msg, err := self.MsgReadWriter.ReadMsg() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return msg, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	self.feed.Send(&PeerEvent{ | 
					
						
							|  |  |  | 		Type:     PeerEventTypeMsgRecv, | 
					
						
							|  |  |  | 		Peer:     self.peerID, | 
					
						
							|  |  |  | 		Protocol: self.Protocol, | 
					
						
							|  |  |  | 		MsgCode:  &msg.Code, | 
					
						
							|  |  |  | 		MsgSize:  &msg.Size, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	return msg, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // WriteMsg writes a message to the underlying MsgReadWriter and emits a | 
					
						
							|  |  |  | // "message sent" event | 
					
						
							|  |  |  | func (self *msgEventer) WriteMsg(msg Msg) error { | 
					
						
							|  |  |  | 	err := self.MsgReadWriter.WriteMsg(msg) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	self.feed.Send(&PeerEvent{ | 
					
						
							|  |  |  | 		Type:     PeerEventTypeMsgSend, | 
					
						
							|  |  |  | 		Peer:     self.peerID, | 
					
						
							|  |  |  | 		Protocol: self.Protocol, | 
					
						
							|  |  |  | 		MsgCode:  &msg.Code, | 
					
						
							|  |  |  | 		MsgSize:  &msg.Size, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close closes the underlying MsgReadWriter if it implements the io.Closer | 
					
						
							|  |  |  | // interface | 
					
						
							|  |  |  | func (self *msgEventer) Close() error { | 
					
						
							|  |  |  | 	if v, ok := self.MsgReadWriter.(io.Closer); ok { | 
					
						
							|  |  |  | 		return v.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } |