| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | package p2p | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							| 
									
										
										
										
											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-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" | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							| 
									
										
										
										
											2015-02-11 17:19:31 +01:00
										 |  |  | 	defaultDialTimeout   = 10 * time.Second | 
					
						
							|  |  |  | 	refreshPeersInterval = 30 * time.Second | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// total timeout for encryption handshake and protocol | 
					
						
							|  |  |  | 	// handshake in both directions. | 
					
						
							|  |  |  | 	handshakeTimeout = 5 * time.Second | 
					
						
							|  |  |  | 	// maximum time allowed for reading a complete message. | 
					
						
							|  |  |  | 	// this is effectively the amount of time a connection can be idle. | 
					
						
							|  |  |  | 	frameReadTimeout = 1 * time.Minute | 
					
						
							|  |  |  | 	// maximum amount of time allowed for writing a complete message. | 
					
						
							|  |  |  | 	frameWriteTimeout = 5 * time.Second | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | var srvlog = logger.NewLogger("P2P Server") | 
					
						
							| 
									
										
										
										
											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-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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-02-19 01:52:03 +01:00
										 |  |  | 	setupFunc | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	newPeerHook | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	ourHandshake *protoHandshake | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	lock     sync.RWMutex | 
					
						
							|  |  |  | 	running  bool | 
					
						
							|  |  |  | 	listener net.Listener | 
					
						
							|  |  |  | 	peers    map[discover.NodeID]*Peer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ntab *discover.Table | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	quit        chan struct{} | 
					
						
							|  |  |  | 	loopWG      sync.WaitGroup // {dial,listen,nat}Loop | 
					
						
							|  |  |  | 	peerWG      sync.WaitGroup // active peer goroutines | 
					
						
							|  |  |  | 	peerConnect chan *discover.Node | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | type setupFunc func(net.Conn, *ecdsa.PrivateKey, *protoHandshake, *discover.Node) (*conn, error) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | type newPeerHook func(*Peer) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Peers returns all connected peers. | 
					
						
							|  |  |  | func (srv *Server) Peers() (peers []*Peer) { | 
					
						
							|  |  |  | 	srv.lock.RLock() | 
					
						
							|  |  |  | 	defer srv.lock.RUnlock() | 
					
						
							|  |  |  | 	for _, peer := range srv.peers { | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 		if peer != nil { | 
					
						
							|  |  |  | 			peers = append(peers, peer) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // PeerCount returns the number of connected peers. | 
					
						
							|  |  |  | func (srv *Server) PeerCount() int { | 
					
						
							|  |  |  | 	srv.lock.RLock() | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	n := len(srv.peers) | 
					
						
							|  |  |  | 	srv.lock.RUnlock() | 
					
						
							|  |  |  | 	return n | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | // SuggestPeer creates a connection to the given Node if it | 
					
						
							|  |  |  | // is not already connected. | 
					
						
							| 
									
										
										
										
											2015-02-07 00:15:04 +01:00
										 |  |  | func (srv *Server) SuggestPeer(n *discover.Node) { | 
					
						
							|  |  |  | 	srv.peerConnect <- n | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Broadcast sends an RLP-encoded message to all connected peers. | 
					
						
							|  |  |  | // This method is deprecated and will be removed later. | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | func (srv *Server) Broadcast(protocol string, code uint64, data interface{}) error { | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 	var payload []byte | 
					
						
							|  |  |  | 	if data != nil { | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 		var err error | 
					
						
							|  |  |  | 		payload, err = rlp.EncodeToBytes(data) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	srv.lock.RLock() | 
					
						
							|  |  |  | 	defer srv.lock.RUnlock() | 
					
						
							|  |  |  | 	for _, peer := range srv.peers { | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 		if peer != nil { | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 			var msg = Msg{Code: code} | 
					
						
							|  |  |  | 			if data != nil { | 
					
						
							|  |  |  | 				msg.Payload = bytes.NewReader(payload) | 
					
						
							|  |  |  | 				msg.Size = uint32(len(payload)) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			peer.writeProtoMsg(protocol, msg) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-19 15:11:02 +01:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // Start starts running the server. | 
					
						
							|  |  |  | // Servers can be re-used and started again after stopping. | 
					
						
							|  |  |  | func (srv *Server) Start() (err error) { | 
					
						
							|  |  |  | 	srv.lock.Lock() | 
					
						
							|  |  |  | 	defer srv.lock.Unlock() | 
					
						
							|  |  |  | 	if srv.running { | 
					
						
							|  |  |  | 		return errors.New("server already running") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	srvlog.Infoln("Starting Server") | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	if srv.MaxPeers <= 0 { | 
					
						
							|  |  |  | 		return fmt.Errorf("Server.MaxPeers must be > 0") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	srv.quit = make(chan struct{}) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srv.peers = make(map[discover.NodeID]*Peer) | 
					
						
							|  |  |  | 	srv.peerConnect = make(chan *discover.Node) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	if srv.setupFunc == nil { | 
					
						
							|  |  |  | 		srv.setupFunc = setupConn | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 17:08:18 +01:00
										 |  |  | 	// node table | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	ntab, err := discover.ListenUDP(srv.PrivateKey, srv.ListenAddr, srv.NAT) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	srv.ntab = ntab | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 17:08:18 +01:00
										 |  |  | 	// handshake | 
					
						
							| 
									
										
										
										
											2015-03-15 13:38:41 +07:00
										 |  |  | 	srv.ourHandshake = &protoHandshake{Version: baseProtocolVersion, Name: srv.Name, ID: ntab.Self().ID} | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if srv.Dialer == nil { | 
					
						
							|  |  |  | 		srv.Dialer = &net.Dialer{Timeout: defaultDialTimeout} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	if !srv.NoDial { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		srv.loopWG.Add(1) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 		go srv.dialLoop() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if srv.NoDial && srv.ListenAddr == "" { | 
					
						
							|  |  |  | 		srvlog.Warnln("I will be kind-of useless, neither dialing nor listening.") | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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 { | 
					
						
							|  |  |  | 	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-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 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 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() | 
					
						
							|  |  |  | 	if !srv.running { | 
					
						
							|  |  |  | 		srv.lock.Unlock() | 
					
						
							|  |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	srv.running = false | 
					
						
							|  |  |  | 	srv.lock.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srvlog.Infoln("Stopping Server") | 
					
						
							|  |  |  | 	srv.ntab.Close() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	if srv.listener != nil { | 
					
						
							|  |  |  | 		// this unblocks listener Accept | 
					
						
							|  |  |  | 		srv.listener.Close() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	close(srv.quit) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srv.loopWG.Wait() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	// No new peers can be added at this point because dialLoop and | 
					
						
							|  |  |  | 	// listenLoop are down. It is safe to call peerWG.Wait because | 
					
						
							|  |  |  | 	// peerWG.Add is not called outside of those loops. | 
					
						
							|  |  |  | 	for _, peer := range srv.peers { | 
					
						
							|  |  |  | 		peer.Disconnect(DiscQuitting) | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srv.peerWG.Wait() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | // main loop for adding connections via listening | 
					
						
							|  |  |  | func (srv *Server) listenLoop() { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	defer srv.loopWG.Done() | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	srvlog.Infoln("Listening on", srv.listener.Addr()) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	for { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		conn, err := srv.listener.Accept() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 			return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		srvlog.Debugf("Accepted conn %v\n", conn.RemoteAddr()) | 
					
						
							|  |  |  | 		srv.peerWG.Add(1) | 
					
						
							|  |  |  | 		go srv.startPeer(conn, nil) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | func (srv *Server) dialLoop() { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	defer srv.loopWG.Done() | 
					
						
							|  |  |  | 	refresh := time.NewTicker(refreshPeersInterval) | 
					
						
							|  |  |  | 	defer refresh.Stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	srv.ntab.Bootstrap(srv.BootstrapNodes) | 
					
						
							|  |  |  | 	go srv.findPeers() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	dialed := make(chan *discover.Node) | 
					
						
							|  |  |  | 	dialing := make(map[discover.NodeID]bool) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: limit number of active dials | 
					
						
							|  |  |  | 	// TODO: ensure only one findPeers goroutine is running | 
					
						
							|  |  |  | 	// TODO: pause findPeers when we're at capacity | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		case <-refresh.C: | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 			go srv.findPeers() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case dest := <-srv.peerConnect: | 
					
						
							| 
									
										
										
										
											2015-02-13 14:50:14 +01:00
										 |  |  | 			// avoid dialing nodes that are already connected. | 
					
						
							|  |  |  | 			// there is another check for this in addPeer, | 
					
						
							|  |  |  | 			// which runs after the handshake. | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 			srv.lock.Lock() | 
					
						
							|  |  |  | 			_, isconnected := srv.peers[dest.ID] | 
					
						
							|  |  |  | 			srv.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2015-03-15 13:38:41 +07:00
										 |  |  | 			if isconnected || dialing[dest.ID] || dest.ID == srv.Self().ID { | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 				continue | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			dialing[dest.ID] = true | 
					
						
							|  |  |  | 			srv.peerWG.Add(1) | 
					
						
							|  |  |  | 			go func() { | 
					
						
							|  |  |  | 				srv.dialNode(dest) | 
					
						
							|  |  |  | 				// at this point, the peer has been added | 
					
						
							|  |  |  | 				// or discarded. either way, we're not dialing it anymore. | 
					
						
							|  |  |  | 				dialed <- dest | 
					
						
							|  |  |  | 			}() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case dest := <-dialed: | 
					
						
							|  |  |  | 			delete(dialing, dest.ID) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		case <-srv.quit: | 
					
						
							|  |  |  | 			// TODO: maybe wait for active dials | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (srv *Server) dialNode(dest *discover.Node) { | 
					
						
							| 
									
										
										
										
											2015-02-06 14:40:53 +01:00
										 |  |  | 	addr := &net.TCPAddr{IP: dest.IP, Port: dest.TCPPort} | 
					
						
							|  |  |  | 	srvlog.Debugf("Dialing %v\n", dest) | 
					
						
							|  |  |  | 	conn, err := srv.Dialer.Dial("tcp", addr.String()) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-01-19 11:21:46 +01:00
										 |  |  | 		srvlog.DebugDetailf("dial error: %v", err) | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srv.startPeer(conn, dest) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-15 13:38:41 +07:00
										 |  |  | func (srv *Server) Self() *discover.Node { | 
					
						
							|  |  |  | 	return srv.ntab.Self() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (srv *Server) findPeers() { | 
					
						
							| 
									
										
										
										
											2015-03-15 13:38:41 +07:00
										 |  |  | 	far := srv.Self().ID | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	for i := range far { | 
					
						
							|  |  |  | 		far[i] = ^far[i] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-15 13:38:41 +07:00
										 |  |  | 	closeToSelf := srv.ntab.Lookup(srv.Self().ID) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	farFromSelf := srv.ntab.Lookup(far) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for i := 0; i < len(closeToSelf) || i < len(farFromSelf); i++ { | 
					
						
							|  |  |  | 		if i < len(closeToSelf) { | 
					
						
							|  |  |  | 			srv.peerConnect <- closeToSelf[i] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if i < len(farFromSelf) { | 
					
						
							|  |  |  | 			srv.peerConnect <- farFromSelf[i] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | func (srv *Server) startPeer(fd net.Conn, dest *discover.Node) { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:49:49 +01:00
										 |  |  | 	// TODO: handle/store session token | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 	fd.SetDeadline(time.Now().Add(handshakeTimeout)) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	conn, err := srv.setupFunc(fd, srv.PrivateKey, srv.ourHandshake, dest) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 		fd.Close() | 
					
						
							|  |  |  | 		srvlog.Debugf("Handshake with %v failed: %v", fd.RemoteAddr(), err) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-03-04 16:27:37 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	conn.MsgReadWriter = &netWrapper{ | 
					
						
							|  |  |  | 		wrapped: conn.MsgReadWriter, | 
					
						
							|  |  |  | 		conn:    fd, rtimeout: frameReadTimeout, wtimeout: frameWriteTimeout, | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 	p := newPeer(fd, conn, srv.Protocols) | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	if ok, reason := srv.addPeer(conn.ID, p); !ok { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:47:05 +01:00
										 |  |  | 		srvlog.DebugDetailf("Not adding %v (%v)\n", p, reason) | 
					
						
							|  |  |  | 		p.politeDisconnect(reason) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:47:05 +01:00
										 |  |  | 	srvlog.Debugf("Added %v\n", p) | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 	srvjslog.LogJson(&logger.P2PConnected{ | 
					
						
							|  |  |  | 		RemoteId:            fmt.Sprintf("%x", conn.ID[:]), | 
					
						
							| 
									
										
										
										
											2015-02-27 03:06:55 +00:00
										 |  |  | 		RemoteAddress:       fd.RemoteAddr().String(), | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 		RemoteVersionString: conn.Name, | 
					
						
							|  |  |  | 		NumConnections:      srv.PeerCount(), | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01: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-02-05 03:07:58 +01:00
										 |  |  | 	srv.removePeer(p) | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:47:05 +01:00
										 |  |  | 	srvlog.Debugf("Removed %v (%v)\n", p, discreason) | 
					
						
							| 
									
										
										
										
											2015-02-19 17:09:33 +01:00
										 |  |  | 	srvjslog.LogJson(&logger.P2PDisconnected{ | 
					
						
							|  |  |  | 		RemoteId:       fmt.Sprintf("%x", conn.ID[:]), | 
					
						
							|  |  |  | 		NumConnections: srv.PeerCount(), | 
					
						
							|  |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (srv *Server) addPeer(id discover.NodeID, p *Peer) (bool, DiscReason) { | 
					
						
							| 
									
										
										
										
											2014-11-21 21:48:49 +01:00
										 |  |  | 	srv.lock.Lock() | 
					
						
							|  |  |  | 	defer srv.lock.Unlock() | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case !srv.running: | 
					
						
							|  |  |  | 		return false, DiscQuitting | 
					
						
							|  |  |  | 	case len(srv.peers) >= srv.MaxPeers: | 
					
						
							|  |  |  | 		return false, DiscTooManyPeers | 
					
						
							|  |  |  | 	case srv.peers[id] != nil: | 
					
						
							|  |  |  | 		return false, DiscAlreadyConnected | 
					
						
							| 
									
										
										
										
											2015-03-15 13:38:41 +07:00
										 |  |  | 	case id == srv.Self().ID: | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 		return false, DiscSelf | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	srv.peers[id] = p | 
					
						
							|  |  |  | 	return true, 0 | 
					
						
							| 
									
										
										
										
											2014-10-23 16:57:54 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | func (srv *Server) removePeer(p *Peer) { | 
					
						
							|  |  |  | 	srv.lock.Lock() | 
					
						
							| 
									
										
										
										
											2015-02-19 01:52:03 +01:00
										 |  |  | 	delete(srv.peers, p.ID()) | 
					
						
							| 
									
										
										
										
											2015-02-05 03:07:58 +01:00
										 |  |  | 	srv.lock.Unlock() | 
					
						
							|  |  |  | 	srv.peerWG.Done() | 
					
						
							| 
									
										
										
										
											2014-11-04 13:21:44 +01:00
										 |  |  | } |