| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | package p2p | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	"crypto/ecdsa" | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"net" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger" | 
					
						
							| 
									
										
										
										
											2015-04-07 14:57:04 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/logger/glog" | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/discover" | 
					
						
							| 
									
										
										
										
											2015-02-11 17:19:31 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/p2p/nat" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-05-14 01:43:30 +02:00
										 |  |  | 	defaultDialTimeout      = 15 * time.Second | 
					
						
							| 
									
										
										
										
											2015-04-30 19:34:33 +03:00
										 |  |  | 	refreshPeersInterval    = 30 * time.Second | 
					
						
							|  |  |  | 	staticPeerCheckInterval = 15 * time.Second | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-04 17:35:49 +03:00
										 |  |  | 	// Maximum number of concurrently handshaking inbound connections. | 
					
						
							| 
									
										
										
										
											2015-05-14 01:43:30 +02:00
										 |  |  | 	maxAcceptConns = 50 | 
					
						
							| 
									
										
										
										
											2015-04-10 17:24:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-30 15:06:05 +03:00
										 |  |  | 	// Maximum number of concurrently dialing outbound connections. | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	maxActiveDialTasks = 16 | 
					
						
							| 
									
										
										
										
											2015-04-30 15:06:05 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-22 15:38:17 +02:00
										 |  |  | 	// Maximum time allowed for reading a complete message. | 
					
						
							|  |  |  | 	// This is effectively the amount of time a connection can be idle. | 
					
						
							|  |  |  | 	frameReadTimeout = 30 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Maximum amount of time allowed for writing a complete message. | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 	frameWriteTimeout = 5 * time.Second | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | var errServerStopped = errors.New("server stopped") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | var srvjslog = logger.NewJsonLogger() | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Server manages all peer connections. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The fields of Server are used as configuration parameters. | 
					
						
							|  |  |  | // You should set them before starting the Server. Fields may not be | 
					
						
							|  |  |  | // modified while the server is running. | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | type Server struct { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	// This field must be set to a valid secp256k1 private key. | 
					
						
							|  |  |  | 	PrivateKey *ecdsa.PrivateKey | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// MaxPeers is the maximum number of peers that can be | 
					
						
							|  |  |  | 	// connected. It must be greater than zero. | 
					
						
							|  |  |  | 	MaxPeers int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-04 17:35:49 +03:00
										 |  |  | 	// MaxPendingPeers is the maximum number of peers that can be pending in the | 
					
						
							|  |  |  | 	// handshake phase, counted separately for inbound and outbound connections. | 
					
						
							|  |  |  | 	// Zero defaults to preset values. | 
					
						
							|  |  |  | 	MaxPendingPeers int | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 	// Discovery specifies whether the peer discovery mechanism should be started | 
					
						
							|  |  |  | 	// or not. Disabling is usually useful for protocol debugging (manual topology). | 
					
						
							|  |  |  | 	Discovery bool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	// Name sets the node name of this server. | 
					
						
							| 
									
										
										
										
											2015-03-16 11:27:38 +01:00
										 |  |  | 	// Use common.MakeName to create a name that follows existing conventions. | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	Name string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Bootstrap nodes are used to establish connectivity | 
					
						
							|  |  |  | 	// with the rest of the network. | 
					
						
							| 
									
										
										
										
											2015-02-07 00:38:36 +01:00
										 |  |  | 	BootstrapNodes []*discover.Node | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-30 19:32:48 +03:00
										 |  |  | 	// Static nodes are used as pre-configured connections which are always | 
					
						
							|  |  |  | 	// maintained and re-connected on disconnects. | 
					
						
							|  |  |  | 	StaticNodes []*discover.Node | 
					
						
							| 
									
										
										
										
											2015-04-29 18:04:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-04 13:59:51 +03:00
										 |  |  | 	// Trusted nodes are used as pre-configured connections which are always | 
					
						
							|  |  |  | 	// allowed to connect, even above the peer limit. | 
					
						
							|  |  |  | 	TrustedNodes []*discover.Node | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-24 18:04:41 +03:00
										 |  |  | 	// NodeDatabase is the path to the database containing the previously seen | 
					
						
							|  |  |  | 	// live nodes in the network. | 
					
						
							|  |  |  | 	NodeDatabase string | 
					
						
							| 
									
										
										
										
											2015-04-23 18:47:24 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	// Protocols should contain the protocols supported | 
					
						
							|  |  |  | 	// by the server. Matching protocols are launched for | 
					
						
							|  |  |  | 	// each peer. | 
					
						
							|  |  |  | 	Protocols []Protocol | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If ListenAddr is set to a non-nil address, the server | 
					
						
							|  |  |  | 	// will listen for incoming connections. | 
					
						
							|  |  |  | 	// | 
					
						
							|  |  |  | 	// If the port is zero, the operating system will pick a port. The | 
					
						
							|  |  |  | 	// ListenAddr field will be updated with the actual address when | 
					
						
							|  |  |  | 	// the server is started. | 
					
						
							|  |  |  | 	ListenAddr string | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If set to a non-nil value, the given NAT port mapper | 
					
						
							|  |  |  | 	// is used to make the listening port available to the | 
					
						
							|  |  |  | 	// Internet. | 
					
						
							| 
									
										
										
										
											2015-02-11 17:19:31 +01:00
										 |  |  | 	NAT nat.Interface | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If Dialer is set to a non-nil value, the given Dialer | 
					
						
							|  |  |  | 	// is used to dial outbound peer connections. | 
					
						
							|  |  |  | 	Dialer *net.Dialer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If NoDial is true, the server will not dial any peers. | 
					
						
							|  |  |  | 	NoDial bool | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	// Hooks for testing. These are useful because we can inhibit | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	// the whole protocol stack. | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	newTransport func(net.Conn) transport | 
					
						
							|  |  |  | 	newPeerHook  func(*Peer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lock    sync.Mutex // protects running | 
					
						
							|  |  |  | 	running bool | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	ntab         discoverTable | 
					
						
							|  |  |  | 	listener     net.Listener | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	ourHandshake *protoHandshake | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// These are for Peers, PeerCount (and nothing else). | 
					
						
							|  |  |  | 	peerOp     chan peerOpFunc | 
					
						
							|  |  |  | 	peerOpDone chan struct{} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	quit          chan struct{} | 
					
						
							|  |  |  | 	addstatic     chan *discover.Node | 
					
						
							|  |  |  | 	posthandshake chan *conn | 
					
						
							|  |  |  | 	addpeer       chan *conn | 
					
						
							|  |  |  | 	delpeer       chan *Peer | 
					
						
							|  |  |  | 	loopWG        sync.WaitGroup // loop, listenLoop | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type peerOpFunc func(map[discover.NodeID]*Peer) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type connFlag int | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	dynDialedConn connFlag = 1 << iota | 
					
						
							|  |  |  | 	staticDialedConn | 
					
						
							|  |  |  | 	inboundConn | 
					
						
							|  |  |  | 	trustedConn | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // conn wraps a network connection with information gathered | 
					
						
							|  |  |  | // during the two handshakes. | 
					
						
							|  |  |  | type conn struct { | 
					
						
							|  |  |  | 	fd net.Conn | 
					
						
							|  |  |  | 	transport | 
					
						
							|  |  |  | 	flags connFlag | 
					
						
							|  |  |  | 	cont  chan error      // The run loop uses cont to signal errors to setupConn. | 
					
						
							|  |  |  | 	id    discover.NodeID // valid after the encryption handshake | 
					
						
							|  |  |  | 	caps  []Cap           // valid after the protocol handshake | 
					
						
							|  |  |  | 	name  string          // valid after the protocol handshake | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | type transport interface { | 
					
						
							|  |  |  | 	// The two handshakes. | 
					
						
							|  |  |  | 	doEncHandshake(prv *ecdsa.PrivateKey, dialDest *discover.Node) (discover.NodeID, error) | 
					
						
							|  |  |  | 	doProtoHandshake(our *protoHandshake) (*protoHandshake, error) | 
					
						
							|  |  |  | 	// The MsgReadWriter can only be used after the encryption | 
					
						
							|  |  |  | 	// handshake has completed. The code uses conn.id to track this | 
					
						
							|  |  |  | 	// by setting it to a non-nil value after the encryption handshake. | 
					
						
							|  |  |  | 	MsgReadWriter | 
					
						
							|  |  |  | 	// transports must provide Close because we use MsgPipe in some of | 
					
						
							|  |  |  | 	// the tests. Closing the actual network connection doesn't do | 
					
						
							|  |  |  | 	// anything in those tests because NsgPipe doesn't use it. | 
					
						
							|  |  |  | 	close(err error) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | func (c *conn) String() string { | 
					
						
							|  |  |  | 	s := c.flags.String() + " conn" | 
					
						
							|  |  |  | 	if (c.id != discover.NodeID{}) { | 
					
						
							|  |  |  | 		s += fmt.Sprintf(" %x", c.id[:8]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s += " " + c.fd.RemoteAddr().String() | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (f connFlag) String() string { | 
					
						
							|  |  |  | 	s := "" | 
					
						
							|  |  |  | 	if f&trustedConn != 0 { | 
					
						
							|  |  |  | 		s += " trusted" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if f&dynDialedConn != 0 { | 
					
						
							|  |  |  | 		s += " dyn dial" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if f&staticDialedConn != 0 { | 
					
						
							|  |  |  | 		s += " static dial" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if f&inboundConn != 0 { | 
					
						
							|  |  |  | 		s += " inbound" | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if s != "" { | 
					
						
							|  |  |  | 		s = s[1:] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return s | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (c *conn) is(f connFlag) bool { | 
					
						
							|  |  |  | 	return c.flags&f != 0 | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Peers returns all connected peers. | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | func (srv *Server) Peers() []*Peer { | 
					
						
							|  |  |  | 	var ps []*Peer | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	// Note: We'd love to put this function into a variable but | 
					
						
							|  |  |  | 	// that seems to cause a weird compiler error in some | 
					
						
							|  |  |  | 	// environments. | 
					
						
							|  |  |  | 	case srv.peerOp <- func(peers map[discover.NodeID]*Peer) { | 
					
						
							|  |  |  | 		for _, p := range peers { | 
					
						
							|  |  |  | 			ps = append(ps, p) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	}: | 
					
						
							|  |  |  | 		<-srv.peerOpDone | 
					
						
							|  |  |  | 	case <-srv.quit: | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	return ps | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // PeerCount returns the number of connected peers. | 
					
						
							|  |  |  | func (srv *Server) PeerCount() int { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	var count int | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case srv.peerOp <- func(ps map[discover.NodeID]*Peer) { count = len(ps) }: | 
					
						
							|  |  |  | 		<-srv.peerOpDone | 
					
						
							|  |  |  | 	case <-srv.quit: | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return count | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-30 16:15:29 +03:00
										 |  |  | // AddPeer connects to the given node and maintains the connection until the | 
					
						
							|  |  |  | // server is shut down. If the connection fails for any reason, the server will | 
					
						
							|  |  |  | // attempt to reconnect the peer. | 
					
						
							|  |  |  | func (srv *Server) AddPeer(node *discover.Node) { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case srv.addstatic <- node: | 
					
						
							|  |  |  | 	case <-srv.quit: | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Self returns the local node's endpoint information. | 
					
						
							|  |  |  | func (srv *Server) Self() *discover.Node { | 
					
						
							| 
									
										
										
										
											2015-04-30 12:41:27 +03:00
										 |  |  | 	srv.lock.Lock() | 
					
						
							|  |  |  | 	defer srv.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2015-05-26 19:16:05 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// If the server's not running, return an empty node | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	if !srv.running { | 
					
						
							|  |  |  | 		return &discover.Node{IP: net.ParseIP("0.0.0.0")} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-26 19:16:05 +03:00
										 |  |  | 	// If the node is running but discovery is off, manually assemble the node infos | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 	if srv.ntab == nil { | 
					
						
							| 
									
										
										
										
											2015-05-26 19:16:05 +03:00
										 |  |  | 		// Inbound connections disabled, use zero address | 
					
						
							|  |  |  | 		if srv.listener == nil { | 
					
						
							|  |  |  | 			return &discover.Node{IP: net.ParseIP("0.0.0.0"), ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// Otherwise inject the listener address too | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 		addr := srv.listener.Addr().(*net.TCPAddr) | 
					
						
							|  |  |  | 		return &discover.Node{ | 
					
						
							|  |  |  | 			ID:  discover.PubkeyID(&srv.PrivateKey.PublicKey), | 
					
						
							|  |  |  | 			IP:  addr.IP, | 
					
						
							|  |  |  | 			TCP: uint16(addr.Port), | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-26 19:16:05 +03:00
										 |  |  | 	// Otherwise return the live node infos | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	return srv.ntab.Self() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-04-30 12:41:27 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | // Stop terminates the server and all active peer connections. | 
					
						
							|  |  |  | // It blocks until all active connections have been closed. | 
					
						
							|  |  |  | func (srv *Server) Stop() { | 
					
						
							|  |  |  | 	srv.lock.Lock() | 
					
						
							|  |  |  | 	defer srv.lock.Unlock() | 
					
						
							|  |  |  | 	if !srv.running { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	srv.running = false | 
					
						
							|  |  |  | 	if srv.listener != nil { | 
					
						
							|  |  |  | 		// this unblocks listener Accept | 
					
						
							|  |  |  | 		srv.listener.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	close(srv.quit) | 
					
						
							|  |  |  | 	srv.loopWG.Wait() | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Start starts running the server. | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | // Servers can not be re-used after stopping. | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | func (srv *Server) Start() (err error) { | 
					
						
							|  |  |  | 	srv.lock.Lock() | 
					
						
							|  |  |  | 	defer srv.lock.Unlock() | 
					
						
							|  |  |  | 	if srv.running { | 
					
						
							|  |  |  | 		return errors.New("server already running") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	srv.running = true | 
					
						
							| 
									
										
										
										
											2015-04-07 14:57:04 +02:00
										 |  |  | 	glog.V(logger.Info).Infoln("Starting Server") | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 17:08:18 +01:00
										 |  |  | 	// static fields | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if srv.PrivateKey == nil { | 
					
						
							|  |  |  | 		return fmt.Errorf("Server.PrivateKey must be set to a non-nil key") | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	if srv.newTransport == nil { | 
					
						
							|  |  |  | 		srv.newTransport = newRLPX | 
					
						
							| 
									
										
										
										
											2015-04-29 18:04:08 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	if srv.Dialer == nil { | 
					
						
							|  |  |  | 		srv.Dialer = &net.Dialer{Timeout: defaultDialTimeout} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	srv.quit = make(chan struct{}) | 
					
						
							|  |  |  | 	srv.addpeer = make(chan *conn) | 
					
						
							|  |  |  | 	srv.delpeer = make(chan *Peer) | 
					
						
							|  |  |  | 	srv.posthandshake = make(chan *conn) | 
					
						
							|  |  |  | 	srv.addstatic = make(chan *discover.Node) | 
					
						
							|  |  |  | 	srv.peerOp = make(chan peerOpFunc) | 
					
						
							|  |  |  | 	srv.peerOpDone = make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 17:08:18 +01:00
										 |  |  | 	// node table | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 	if srv.Discovery { | 
					
						
							|  |  |  | 		ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT, srv.NodeDatabase) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		srv.ntab = ntab | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	dynPeers := srv.MaxPeers / 2 | 
					
						
							|  |  |  | 	if !srv.Discovery { | 
					
						
							|  |  |  | 		dynPeers = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	dialer := newDialState(srv.StaticNodes, srv.ntab, dynPeers) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 17:08:18 +01:00
										 |  |  | 	// handshake | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 	srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: discover.PubkeyID(&srv.PrivateKey.PublicKey)} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	for _, p := range srv.Protocols { | 
					
						
							|  |  |  | 		srv.ourHandshake.Caps = append(srv.ourHandshake.Caps, p.cap()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-19 17:08:18 +01:00
										 |  |  | 	// listen/dial | 
					
						
							|  |  |  | 	if srv.ListenAddr != "" { | 
					
						
							|  |  |  | 		if err := srv.startListening(); err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	if srv.NoDial && srv.ListenAddr == "" { | 
					
						
							| 
									
										
										
										
											2015-04-07 14:57:04 +02:00
										 |  |  | 		glog.V(logger.Warn).Infoln("I will be kind-of useless, neither dialing nor listening.") | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	srv.loopWG.Add(1) | 
					
						
							|  |  |  | 	go srv.run(dialer) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	srv.running = true | 
					
						
							|  |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | func (srv *Server) startListening() error { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Launch the TCP listener. | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	listener, err := net.Listen("tcp", srv.ListenAddr) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-11 17:19:31 +01:00
										 |  |  | 	laddr := listener.Addr().(*net.TCPAddr) | 
					
						
							|  |  |  | 	srv.ListenAddr = laddr.String() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	srv.listener = listener | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srv.loopWG.Add(1) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	go srv.listenLoop() | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Map the TCP listening port if NAT is configured. | 
					
						
							| 
									
										
										
										
											2015-02-11 17:19:31 +01:00
										 |  |  | 	if !laddr.IP.IsLoopback() && srv.NAT != nil { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		srv.loopWG.Add(1) | 
					
						
							| 
									
										
										
										
											2015-02-11 17:19:31 +01:00
										 |  |  | 		go func() { | 
					
						
							|  |  |  | 			nat.Map(srv.NAT, srv.quit, "tcp", laddr.Port, laddr.Port, "ethereum p2p") | 
					
						
							|  |  |  | 			srv.loopWG.Done() | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | type dialer interface { | 
					
						
							|  |  |  | 	newTasks(running int, peers map[discover.NodeID]*Peer, now time.Time) []task | 
					
						
							|  |  |  | 	taskDone(task, time.Time) | 
					
						
							|  |  |  | 	addStatic(*discover.Node) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (srv *Server) run(dialstate dialer) { | 
					
						
							|  |  |  | 	defer srv.loopWG.Done() | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		peers   = make(map[discover.NodeID]*Peer) | 
					
						
							|  |  |  | 		trusted = make(map[discover.NodeID]bool, len(srv.TrustedNodes)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		tasks        []task | 
					
						
							|  |  |  | 		pendingTasks []task | 
					
						
							|  |  |  | 		taskdone     = make(chan task, maxActiveDialTasks) | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// Put trusted nodes into a map to speed up checks. | 
					
						
							|  |  |  | 	// Trusted peers are loaded on startup and cannot be | 
					
						
							|  |  |  | 	// modified while the server is running. | 
					
						
							|  |  |  | 	for _, n := range srv.TrustedNodes { | 
					
						
							|  |  |  | 		trusted[n.ID] = true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Some task list helpers. | 
					
						
							|  |  |  | 	delTask := func(t task) { | 
					
						
							|  |  |  | 		for i := range tasks { | 
					
						
							|  |  |  | 			if tasks[i] == t { | 
					
						
							|  |  |  | 				tasks = append(tasks[:i], tasks[i+1:]...) | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	scheduleTasks := func(new []task) { | 
					
						
							|  |  |  | 		pt := append(pendingTasks, new...) | 
					
						
							|  |  |  | 		start := maxActiveDialTasks - len(tasks) | 
					
						
							|  |  |  | 		if len(pt) < start { | 
					
						
							|  |  |  | 			start = len(pt) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if start > 0 { | 
					
						
							|  |  |  | 			tasks = append(tasks, pt[:start]...) | 
					
						
							|  |  |  | 			for _, t := range pt[:start] { | 
					
						
							|  |  |  | 				t := t | 
					
						
							|  |  |  | 				glog.V(logger.Detail).Infoln("new task:", t) | 
					
						
							|  |  |  | 				go func() { t.Do(srv); taskdone <- t }() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			copy(pt, pt[start:]) | 
					
						
							|  |  |  | 			pendingTasks = pt[:len(pt)-start] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | running: | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		// Query the dialer for new tasks and launch them. | 
					
						
							|  |  |  | 		now := time.Now() | 
					
						
							|  |  |  | 		nt := dialstate.newTasks(len(pendingTasks)+len(tasks), peers, now) | 
					
						
							|  |  |  | 		scheduleTasks(nt) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 		select { | 
					
						
							|  |  |  | 		case <-srv.quit: | 
					
						
							|  |  |  | 			// The server was stopped. Run the cleanup logic. | 
					
						
							|  |  |  | 			glog.V(logger.Detail).Infoln("<-quit: spinning down") | 
					
						
							|  |  |  | 			break running | 
					
						
							|  |  |  | 		case n := <-srv.addstatic: | 
					
						
							|  |  |  | 			// This channel is used by AddPeer to add to the | 
					
						
							|  |  |  | 			// ephemeral static peer list. Add it to the dialer, | 
					
						
							|  |  |  | 			// it will keep the node connected. | 
					
						
							|  |  |  | 			glog.V(logger.Detail).Infoln("<-addstatic:", n) | 
					
						
							|  |  |  | 			dialstate.addStatic(n) | 
					
						
							|  |  |  | 		case op := <-srv.peerOp: | 
					
						
							|  |  |  | 			// This channel is used by Peers and PeerCount. | 
					
						
							|  |  |  | 			op(peers) | 
					
						
							|  |  |  | 			srv.peerOpDone <- struct{}{} | 
					
						
							|  |  |  | 		case t := <-taskdone: | 
					
						
							|  |  |  | 			// A task got done. Tell dialstate about it so it | 
					
						
							|  |  |  | 			// can update its state and remove it from the active | 
					
						
							|  |  |  | 			// tasks list. | 
					
						
							|  |  |  | 			glog.V(logger.Detail).Infoln("<-taskdone:", t) | 
					
						
							|  |  |  | 			dialstate.taskDone(t, now) | 
					
						
							|  |  |  | 			delTask(t) | 
					
						
							|  |  |  | 		case c := <-srv.posthandshake: | 
					
						
							|  |  |  | 			// A connection has passed the encryption handshake so | 
					
						
							|  |  |  | 			// the remote identity is known (but hasn't been verified yet). | 
					
						
							|  |  |  | 			if trusted[c.id] { | 
					
						
							|  |  |  | 				// Ensure that the trusted flag is set before checking against MaxPeers. | 
					
						
							|  |  |  | 				c.flags |= trustedConn | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			glog.V(logger.Detail).Infoln("<-posthandshake:", c) | 
					
						
							|  |  |  | 			// TODO: track in-progress inbound node IDs (pre-Peer) to avoid dialing them. | 
					
						
							|  |  |  | 			c.cont <- srv.encHandshakeChecks(peers, c) | 
					
						
							|  |  |  | 		case c := <-srv.addpeer: | 
					
						
							|  |  |  | 			// At this point the connection is past the protocol handshake. | 
					
						
							|  |  |  | 			// Its capabilities are known and the remote identity is verified. | 
					
						
							|  |  |  | 			glog.V(logger.Detail).Infoln("<-addpeer:", c) | 
					
						
							|  |  |  | 			err := srv.protoHandshakeChecks(peers, c) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				glog.V(logger.Detail).Infof("Not adding %v as peer: %v", c, err) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// The handshakes are done and it passed all checks. | 
					
						
							|  |  |  | 				p := newPeer(c, srv.Protocols) | 
					
						
							|  |  |  | 				peers[c.id] = p | 
					
						
							|  |  |  | 				go srv.runPeer(p) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// The dialer logic relies on the assumption that | 
					
						
							|  |  |  | 			// dial tasks complete after the peer has been added or | 
					
						
							|  |  |  | 			// discarded. Unblock the task last. | 
					
						
							|  |  |  | 			c.cont <- err | 
					
						
							|  |  |  | 		case p := <-srv.delpeer: | 
					
						
							|  |  |  | 			// A peer disconnected. | 
					
						
							|  |  |  | 			glog.V(logger.Detail).Infoln("<-delpeer:", p) | 
					
						
							|  |  |  | 			delete(peers, p.ID()) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Terminate discovery. If there is a running lookup it will terminate soon. | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 	if srv.ntab != nil { | 
					
						
							|  |  |  | 		srv.ntab.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Disconnect all peers. | 
					
						
							|  |  |  | 	for _, p := range peers { | 
					
						
							|  |  |  | 		p.Disconnect(DiscQuitting) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Wait for peers to shut down. Pending connections and tasks are | 
					
						
							|  |  |  | 	// not handled here and will terminate soon-ish because srv.quit | 
					
						
							|  |  |  | 	// is closed. | 
					
						
							|  |  |  | 	glog.V(logger.Detail).Infof("ignoring %d pending tasks at spindown", len(tasks)) | 
					
						
							|  |  |  | 	for len(peers) > 0 { | 
					
						
							|  |  |  | 		p := <-srv.delpeer | 
					
						
							|  |  |  | 		glog.V(logger.Detail).Infoln("<-delpeer (spindown):", p) | 
					
						
							|  |  |  | 		delete(peers, p.ID()) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | func (srv *Server) protoHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) error { | 
					
						
							|  |  |  | 	// Drop connections with no matching protocols. | 
					
						
							|  |  |  | 	if len(srv.Protocols) > 0 && countMatchingProtocols(srv.Protocols, c.caps) == 0 { | 
					
						
							|  |  |  | 		return DiscUselessPeer | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Repeat the encryption handshake checks because the | 
					
						
							|  |  |  | 	// peer set might have changed between the handshakes. | 
					
						
							|  |  |  | 	return srv.encHandshakeChecks(peers, c) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | func (srv *Server) encHandshakeChecks(peers map[discover.NodeID]*Peer, c *conn) error { | 
					
						
							|  |  |  | 	switch { | 
					
						
							|  |  |  | 	case !c.is(trustedConn|staticDialedConn) && len(peers) >= srv.MaxPeers: | 
					
						
							|  |  |  | 		return DiscTooManyPeers | 
					
						
							|  |  |  | 	case peers[c.id] != nil: | 
					
						
							|  |  |  | 		return DiscAlreadyConnected | 
					
						
							| 
									
										
										
										
											2015-05-26 19:07:24 +03:00
										 |  |  | 	case c.id == srv.Self().ID: | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 		return DiscSelf | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2015-04-22 10:59:15 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-10 13:25:35 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | // listenLoop runs in its own goroutine and accepts | 
					
						
							|  |  |  | // inbound connections. | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | func (srv *Server) listenLoop() { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	defer srv.loopWG.Done() | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	glog.V(logger.Info).Infoln("Listening on", srv.listener.Addr()) | 
					
						
							| 
									
										
										
										
											2015-04-10 17:24:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// This channel acts as a semaphore limiting | 
					
						
							|  |  |  | 	// active inbound connections that are lingering pre-handshake. | 
					
						
							|  |  |  | 	// If all slots are taken, no further connections are accepted. | 
					
						
							| 
									
										
										
										
											2015-05-04 17:35:49 +03:00
										 |  |  | 	tokens := maxAcceptConns | 
					
						
							|  |  |  | 	if srv.MaxPendingPeers > 0 { | 
					
						
							|  |  |  | 		tokens = srv.MaxPendingPeers | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	slots := make(chan struct{}, tokens) | 
					
						
							|  |  |  | 	for i := 0; i < tokens; i++ { | 
					
						
							| 
									
										
										
										
											2015-04-10 17:24:41 +02:00
										 |  |  | 		slots <- struct{}{} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2015-04-10 17:24:41 +02:00
										 |  |  | 		<-slots | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 		fd, err := srv.listener.Accept() | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 		glog.V(logger.Debug).Infof("Accepted conn %v\n", fd.RemoteAddr()) | 
					
						
							| 
									
										
										
										
											2015-04-10 17:24:41 +02:00
										 |  |  | 		go func() { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 			srv.setupConn(fd, inboundConn, nil) | 
					
						
							| 
									
										
										
										
											2015-04-10 17:24:41 +02:00
										 |  |  | 			slots <- struct{}{} | 
					
						
							|  |  |  | 		}() | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | // setupConn runs the handshakes and attempts to add the connection | 
					
						
							|  |  |  | // as a peer. It returns when the connection has been added as a peer | 
					
						
							|  |  |  | // or the handshakes have failed. | 
					
						
							|  |  |  | func (srv *Server) setupConn(fd net.Conn, flags connFlag, dialDest *discover.Node) { | 
					
						
							|  |  |  | 	// Prevent leftover pending conns from entering the handshake. | 
					
						
							|  |  |  | 	srv.lock.Lock() | 
					
						
							|  |  |  | 	running := srv.running | 
					
						
							|  |  |  | 	srv.lock.Unlock() | 
					
						
							|  |  |  | 	c := &conn{fd: fd, transport: srv.newTransport(fd), flags: flags, cont: make(chan error)} | 
					
						
							|  |  |  | 	if !running { | 
					
						
							|  |  |  | 		c.close(errServerStopped) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-04-30 15:06:05 +03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Run the encryption handshake. | 
					
						
							|  |  |  | 	var err error | 
					
						
							|  |  |  | 	if c.id, err = c.doEncHandshake(srv.PrivateKey, dialDest); err != nil { | 
					
						
							|  |  |  | 		glog.V(logger.Debug).Infof("%v faild enc handshake: %v", c, err) | 
					
						
							|  |  |  | 		c.close(err) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-04-03 03:56:17 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// For dialed connections, check that the remote public key matches. | 
					
						
							|  |  |  | 	if dialDest != nil && c.id != dialDest.ID { | 
					
						
							|  |  |  | 		c.close(DiscUnexpectedIdentity) | 
					
						
							|  |  |  | 		glog.V(logger.Debug).Infof("%v dialed identity mismatch, want %x", c, dialDest.ID[:8]) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	if err := srv.checkpoint(c, srv.posthandshake); err != nil { | 
					
						
							|  |  |  | 		glog.V(logger.Debug).Infof("%v failed checkpoint posthandshake: %v", c, err) | 
					
						
							|  |  |  | 		c.close(err) | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Run the protocol handshake | 
					
						
							|  |  |  | 	phs, err := c.doProtoHandshake(srv.ourHandshake) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 		glog.V(logger.Debug).Infof("%v failed proto handshake: %v", c, err) | 
					
						
							|  |  |  | 		c.close(err) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	if phs.ID != c.id { | 
					
						
							|  |  |  | 		glog.V(logger.Debug).Infof("%v wrong proto handshake identity: %x", c, phs.ID[:8]) | 
					
						
							|  |  |  | 		c.close(DiscUnexpectedIdentity) | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	c.caps, c.name = phs.Caps, phs.Name | 
					
						
							|  |  |  | 	if err := srv.checkpoint(c, srv.addpeer); err != nil { | 
					
						
							|  |  |  | 		glog.V(logger.Debug).Infof("%v failed checkpoint addpeer: %v", c, err) | 
					
						
							|  |  |  | 		c.close(err) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// If the checks completed successfully, runPeer has now been | 
					
						
							|  |  |  | 	// launched by run. | 
					
						
							| 
									
										
										
										
											2015-04-03 03:56:17 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | // checkpoint sends the conn to run, which performs the | 
					
						
							|  |  |  | // post-handshake checks for the stage (posthandshake, addpeer). | 
					
						
							|  |  |  | func (srv *Server) checkpoint(c *conn, stage chan<- *conn) error { | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case stage <- c: | 
					
						
							|  |  |  | 	case <-srv.quit: | 
					
						
							|  |  |  | 		return errServerStopped | 
					
						
							| 
									
										
										
										
											2015-05-08 15:54:35 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	select { | 
					
						
							|  |  |  | 	case err := <-c.cont: | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	case <-srv.quit: | 
					
						
							|  |  |  | 		return errServerStopped | 
					
						
							| 
									
										
										
										
											2015-05-08 15:54:35 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | // runPeer runs in its own goroutine for each peer. | 
					
						
							|  |  |  | // it waits until the Peer logic returns and removes | 
					
						
							|  |  |  | // the peer. | 
					
						
							| 
									
										
										
										
											2015-04-03 03:56:17 +02:00
										 |  |  | func (srv *Server) runPeer(p *Peer) { | 
					
						
							| 
									
										
										
										
											2015-04-07 14:57:04 +02:00
										 |  |  | 	glog.V(logger.Debug).Infof("Added %v\n", p) | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 	srvjslog.LogJson(&logger.P2PConnected{ | 
					
						
							| 
									
										
										
										
											2015-04-03 03:56:17 +02:00
										 |  |  | 		RemoteId:            p.ID().String(), | 
					
						
							|  |  |  | 		RemoteAddress:       p.RemoteAddr().String(), | 
					
						
							|  |  |  | 		RemoteVersionString: p.Name(), | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 		NumConnections:      srv.PeerCount(), | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-07 00:13:22 +01:00
										 |  |  | 	if srv.newPeerHook != nil { | 
					
						
							|  |  |  | 		srv.newPeerHook(p) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-13 14:47:05 +01:00
										 |  |  | 	discreason := p.run() | 
					
						
							| 
									
										
										
										
											2015-05-16 00:38:28 +02:00
										 |  |  | 	// Note: run waits for existing peers to be sent on srv.delpeer | 
					
						
							|  |  |  | 	// before returning, so this send should not select on srv.quit. | 
					
						
							|  |  |  | 	srv.delpeer <- p | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-07 14:57:04 +02:00
										 |  |  | 	glog.V(logger.Debug).Infof("Removed %v (%v)\n", p, discreason) | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 	srvjslog.LogJson(&logger.P2PDisconnected{ | 
					
						
							| 
									
										
										
										
											2015-04-03 03:56:17 +02:00
										 |  |  | 		RemoteId:       p.ID().String(), | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 		NumConnections: srv.PeerCount(), | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } |