| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | package p2p | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-02-07 00:13:22 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	"io" | 
					
						
							|  |  |  | 	"io/ioutil" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	"net" | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	"sort" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/discover" | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-02-13 15:08:40 +01:00
										 |  |  | 	baseProtocolVersion    = 3 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	baseProtocolLength     = uint64(16) | 
					
						
							|  |  |  | 	baseProtocolMaxMsgSize = 10 * 1024 * 1024 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:44:00 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 16:53:52 +01:00
										 |  |  | 	pingInterval          = 15 * time.Second | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 	disconnectGracePeriod = 2 * time.Second | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	// devp2p message codes | 
					
						
							|  |  |  | 	handshakeMsg = 0x00 | 
					
						
							|  |  |  | 	discMsg      = 0x01 | 
					
						
							|  |  |  | 	pingMsg      = 0x02 | 
					
						
							|  |  |  | 	pongMsg      = 0x03 | 
					
						
							|  |  |  | 	getPeersMsg  = 0x04 | 
					
						
							|  |  |  | 	peersMsg     = 0x05 | 
					
						
							|  |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // Peer represents a connected remote node. | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | type Peer struct { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	// Peers have all the log methods. | 
					
						
							|  |  |  | 	// Use them to display messages related to the peer. | 
					
						
							|  |  |  | 	*logger.Logger | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	conn    net.Conn | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	rw      *conn | 
					
						
							|  |  |  | 	running map[string]*protoRW | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	protoWG  sync.WaitGroup | 
					
						
							|  |  |  | 	protoErr chan error | 
					
						
							|  |  |  | 	closed   chan struct{} | 
					
						
							|  |  |  | 	disc     chan DiscReason | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewPeer returns a peer for testing purposes. | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func NewPeer(id discover.NodeID, name string, caps []Cap) *Peer { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	pipe, _ := net.Pipe() | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	msgpipe, _ := MsgPipe() | 
					
						
							|  |  |  | 	conn := &conn{msgpipe, &protoHandshake{ID: id, Name: name, Caps: caps}} | 
					
						
							|  |  |  | 	peer := newPeer(pipe, conn, nil) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	close(peer.closed) // ensures Disconnect doesn't block | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	return peer | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // ID returns the node's public key. | 
					
						
							|  |  |  | func (p *Peer) ID() discover.NodeID { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	return p.rw.ID | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // Name returns the node name that the remote node advertised. | 
					
						
							|  |  |  | func (p *Peer) Name() string { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	return p.rw.Name | 
					
						
							| 
									
										
										
										
											2015-01-18 07:59:54 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Caps returns the capabilities (supported subprotocols) of the remote peer. | 
					
						
							|  |  |  | func (p *Peer) Caps() []Cap { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	// TODO: maybe return copy | 
					
						
							|  |  |  | 	return p.rw.Caps | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RemoteAddr returns the remote address of the network connection. | 
					
						
							|  |  |  | func (p *Peer) RemoteAddr() net.Addr { | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	return p.conn.RemoteAddr() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // LocalAddr returns the local address of the network connection. | 
					
						
							|  |  |  | func (p *Peer) LocalAddr() net.Addr { | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	return p.conn.LocalAddr() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Disconnect terminates the peer connection with the given reason. | 
					
						
							|  |  |  | // It returns immediately and does not wait until the connection is closed. | 
					
						
							|  |  |  | func (p *Peer) Disconnect(reason DiscReason) { | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case p.disc <- reason: | 
					
						
							|  |  |  | 	case <-p.closed: | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // String implements fmt.Stringer. | 
					
						
							|  |  |  | func (p *Peer) String() string { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	return fmt.Sprintf("Peer %.8x %v", p.rw.ID[:], p.RemoteAddr()) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | func newPeer(fd net.Conn, conn *conn, protocols []Protocol) *Peer { | 
					
						
							|  |  |  | 	logtag := fmt.Sprintf("Peer %.8x %v", conn.ID[:], fd.RemoteAddr()) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	p := &Peer{ | 
					
						
							|  |  |  | 		Logger:   logger.NewLogger(logtag), | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 		conn:     fd, | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 		rw:       conn, | 
					
						
							|  |  |  | 		running:  matchProtocols(protocols, conn.Caps, conn), | 
					
						
							|  |  |  | 		disc:     make(chan DiscReason), | 
					
						
							|  |  |  | 		protoErr: make(chan error), | 
					
						
							|  |  |  | 		closed:   make(chan struct{}), | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	return p | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (p *Peer) run() DiscReason { | 
					
						
							|  |  |  | 	var readErr = make(chan error, 1) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	defer p.closeProtocols() | 
					
						
							|  |  |  | 	defer close(p.closed) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	p.startProtocols() | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	go func() { readErr <- p.readLoop() }() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 16:53:52 +01:00
										 |  |  | 	ping := time.NewTicker(pingInterval) | 
					
						
							|  |  |  | 	defer ping.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-07 00:13:22 +01:00
										 |  |  | 	// Wait for an error or disconnect. | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	var reason DiscReason | 
					
						
							| 
									
										
										
										
											2015-02-19 16:53:52 +01:00
										 |  |  | loop: | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-ping.C: | 
					
						
							|  |  |  | 			go func() { | 
					
						
							|  |  |  | 				if err := EncodeMsg(p.rw, pingMsg, nil); err != nil { | 
					
						
							|  |  |  | 					p.protoErr <- err | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}() | 
					
						
							|  |  |  | 		case err := <-readErr: | 
					
						
							|  |  |  | 			// We rely on protocols to abort if there is a write error. It | 
					
						
							|  |  |  | 			// might be more robust to handle them here as well. | 
					
						
							|  |  |  | 			p.DebugDetailf("Read error: %v\n", err) | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 			p.conn.Close() | 
					
						
							| 
									
										
										
										
											2015-02-19 16:53:52 +01:00
										 |  |  | 			return DiscNetworkError | 
					
						
							|  |  |  | 		case err := <-p.protoErr: | 
					
						
							|  |  |  | 			reason = discReasonForError(err) | 
					
						
							|  |  |  | 			break loop | 
					
						
							|  |  |  | 		case reason = <-p.disc: | 
					
						
							|  |  |  | 			break loop | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-07 00:13:22 +01:00
										 |  |  | 	p.politeDisconnect(reason) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Wait for readLoop. It will end because conn is now closed. | 
					
						
							|  |  |  | 	<-readErr | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	p.Debugf("Disconnected: %v\n", reason) | 
					
						
							|  |  |  | 	return reason | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (p *Peer) politeDisconnect(reason DiscReason) { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	done := make(chan struct{}) | 
					
						
							|  |  |  | 	go func() { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		EncodeMsg(p.rw, discMsg, uint(reason)) | 
					
						
							| 
									
										
										
										
											2015-02-07 00:13:22 +01:00
										 |  |  | 		// Wait for the other side to close the connection. | 
					
						
							|  |  |  | 		// Discard any data that they send until then. | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 		io.Copy(ioutil.Discard, p.conn) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 		close(done) | 
					
						
							|  |  |  | 	}() | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case <-done: | 
					
						
							|  |  |  | 	case <-time.After(disconnectGracePeriod): | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	p.conn.Close() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (p *Peer) readLoop() error { | 
					
						
							|  |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 		p.conn.SetDeadline(time.Now().Add(frameReadTimeout)) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		msg, err := p.rw.ReadMsg() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err = p.handle(msg); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (p *Peer) handle(msg Msg) error { | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case msg.Code == pingMsg: | 
					
						
							|  |  |  | 		msg.Discard() | 
					
						
							|  |  |  | 		go EncodeMsg(p.rw, pongMsg) | 
					
						
							|  |  |  | 	case msg.Code == discMsg: | 
					
						
							| 
									
										
										
										
											2015-03-04 12:03:43 +01:00
										 |  |  | 		var reason [1]DiscReason | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		// no need to discard or for error checking, we'll close the | 
					
						
							|  |  |  | 		// connection after this. | 
					
						
							|  |  |  | 		rlp.Decode(msg.Payload, &reason) | 
					
						
							|  |  |  | 		p.Disconnect(DiscRequested) | 
					
						
							| 
									
										
										
										
											2015-03-04 12:03:43 +01:00
										 |  |  | 		return discRequestedError(reason[0]) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	case msg.Code < baseProtocolLength: | 
					
						
							|  |  |  | 		// ignore other base protocol messages | 
					
						
							|  |  |  | 		return msg.Discard() | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// it's a subprotocol message | 
					
						
							|  |  |  | 		proto, err := p.getProto(msg.Code) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 			return fmt.Errorf("msg code out of range: %v", msg.Code) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		proto.in <- msg | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | // matchProtocols creates structures for matching named subprotocols. | 
					
						
							|  |  |  | func matchProtocols(protocols []Protocol, caps []Cap, rw MsgReadWriter) map[string]*protoRW { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	sort.Sort(capsByName(caps)) | 
					
						
							|  |  |  | 	offset := baseProtocolLength | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	result := make(map[string]*protoRW) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | outer: | 
					
						
							|  |  |  | 	for _, cap := range caps { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 		for _, proto := range protocols { | 
					
						
							|  |  |  | 			if proto.Name == cap.Name && proto.Version == cap.Version && result[cap.Name] == nil { | 
					
						
							|  |  |  | 				result[cap.Name] = &protoRW{Protocol: proto, offset: offset, in: make(chan Msg), w: rw} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 				offset += proto.Length | 
					
						
							|  |  |  | 				continue outer | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	return result | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | func (p *Peer) startProtocols() { | 
					
						
							|  |  |  | 	for _, proto := range p.running { | 
					
						
							|  |  |  | 		proto := proto | 
					
						
							|  |  |  | 		p.DebugDetailf("Starting protocol %s/%d\n", proto.Name, proto.Version) | 
					
						
							|  |  |  | 		p.protoWG.Add(1) | 
					
						
							|  |  |  | 		go func() { | 
					
						
							|  |  |  | 			err := proto.Run(p, proto) | 
					
						
							|  |  |  | 			if err == nil { | 
					
						
							|  |  |  | 				p.DebugDetailf("Protocol %s/%d returned\n", proto.Name, proto.Version) | 
					
						
							|  |  |  | 				err = errors.New("protocol returned") | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				p.DebugDetailf("Protocol %s/%d error: %v\n", proto.Name, proto.Version, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			select { | 
					
						
							|  |  |  | 			case p.protoErr <- err: | 
					
						
							|  |  |  | 			case <-p.closed: | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			p.protoWG.Done() | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // getProto finds the protocol responsible for handling | 
					
						
							|  |  |  | // the given message code. | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | func (p *Peer) getProto(code uint64) (*protoRW, error) { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	for _, proto := range p.running { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 		if code >= proto.offset && code < proto.offset+proto.Length { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			return proto, nil | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil, newPeerError(errInvalidMsgCode, "%d", code) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (p *Peer) closeProtocols() { | 
					
						
							|  |  |  | 	for _, p := range p.running { | 
					
						
							|  |  |  | 		close(p.in) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	p.protoWG.Wait() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // writeProtoMsg sends the given message on behalf of the given named protocol. | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // this exists because of Server.Broadcast. | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | func (p *Peer) writeProtoMsg(protoName string, msg Msg) error { | 
					
						
							|  |  |  | 	proto, ok := p.running[protoName] | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return fmt.Errorf("protocol %s not handled by peer", protoName) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	if msg.Code >= proto.Length { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 		return newPeerError(errInvalidMsgCode, "code %x is out of range for protocol %q", msg.Code, protoName) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	msg.Code += proto.offset | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	return p.rw.WriteMsg(msg) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | type protoRW struct { | 
					
						
							|  |  |  | 	Protocol | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	in     chan Msg | 
					
						
							|  |  |  | 	offset uint64 | 
					
						
							|  |  |  | 	w      MsgWriter | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | func (rw *protoRW) WriteMsg(msg Msg) error { | 
					
						
							|  |  |  | 	if msg.Code >= rw.Length { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 		return newPeerError(errInvalidMsgCode, "not handled") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	msg.Code += rw.offset | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	return rw.w.WriteMsg(msg) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | func (rw *protoRW) ReadMsg() (Msg, error) { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	msg, ok := <-rw.in | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							|  |  |  | 		return msg, io.EOF | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	msg.Code -= rw.offset | 
					
						
							|  |  |  | 	return msg, nil | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } |