From b1f14732b17f43f1524858714efb6f00ac6469c0 Mon Sep 17 00:00:00 2001 From: "Owain G. Ainsworth" Date: Mon, 21 Oct 2013 18:45:30 +0100 Subject: [PATCH] Implement getpeerinfo and getconnectedcount We have a channel for queries and commands in server, where we pass in args and the channel to reply from, let rpcserver use these interfaces to provide the requistie information. So far not all of the informaation is 100% correct, the syncpeer information needs to be fetched from blockmanager, the subversion isn't recorded and the number of bytes sent and recieved needs to be obtained from btcwire. The rest should be correct. --- peer.go | 4 +-- rpcserver.go | 9 ++++-- server.go | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 4 deletions(-) diff --git a/peer.go b/peer.go index 2007860c1..a68718d87 100644 --- a/peer.go +++ b/peer.go @@ -113,8 +113,8 @@ type peer struct { addr string na *btcwire.NetAddress timeConnected time.Time - lastSend time.Time - lastRecv time.Time + lastSend time.Time + lastRecv time.Time inbound bool connected int32 disconnect int32 // only to be used atomically diff --git a/rpcserver.go b/rpcserver.go index 1a7df9159..9204000bc 100644 --- a/rpcserver.go +++ b/rpcserver.go @@ -320,6 +320,7 @@ var handlers = map[string]commandHandler{ "getdifficulty": handleGetDifficulty, "getgenerate": handleGetGenerate, "gethashespersec": handleGetHashesPerSec, + "getpeerinfo": handleGetPeerInfo, "getrawmempool": handleGetRawMempool, "getrawtransaction": handleGetRawTransaction, "sendrawtransaction": handleSendRawTransaction, @@ -434,8 +435,7 @@ func handleGetBlockHash(s *rpcServer, cmd btcjson.Cmd, walletNotification chan [ // handleGetConnectionCount implements the getconnectioncount command. func handleGetConnectionCount(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) { - // TODO fillmein. - return 0, nil + return s.server.ConnectedCount(), nil } // handleGetDifficulty implements the getdifficulty command. @@ -467,6 +467,11 @@ func handleGetHashesPerSec(s *rpcServer, cmd btcjson.Cmd, walletNotification cha return 0, nil } +// handleGetPeerInfo implements the getpeerinfo command. +func handleGetPeerInfo(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) { + return s.server.PeerInfo(), nil +} + // handleGetRawMempool implements the getrawmempool command. func handleGetRawMempool(s *rpcServer, cmd btcjson.Cmd, walletNotification chan []byte) (interface{}, error) { hashes := s.server.txMemPool.TxShas() diff --git a/server.go b/server.go index d7cdb3610..83aad7e3a 100644 --- a/server.go +++ b/server.go @@ -60,6 +60,7 @@ type server struct { donePeers chan *peer banPeers chan *peer wakeup chan bool + query chan interface{} relayInv chan *btcwire.InvVect broadcast chan broadcastMsg wg sync.WaitGroup @@ -198,6 +199,75 @@ func (s *server) handleBroadcastMsg(peers *list.List, bmsg *broadcastMsg) { } } +type PeerInfo struct { + Addr string + Services btcwire.ServiceFlag + LastSend time.Time + LastRecv time.Time + BytesSent int + BytesRecv int + ConnTime time.Time + Version uint32 + SubVer string + Inbound bool + StartingHeight int32 + BanScore int + SyncNode bool +} + +type getConnCountMsg struct { + reply chan int +} + +type getPeerInfoMsg struct { + reply chan []*PeerInfo +} + + +func (s *server) handleQuery(querymsg interface{}, peers *list.List, bannedPeers map[string]time.Time) { + switch msg := querymsg.(type) { + case getConnCountMsg: + nconnected := 0 + for e := peers.Front(); e != nil; e = e.Next() { + peer := e.Value.(*peer) + if peer.Connected() { + nconnected++ + } + } + + msg.reply <- nconnected + case getPeerInfoMsg: + infos := make([]*PeerInfo, 0, peers.Len()) + for e := peers.Front(); e != nil; e = e.Next() { + peer := e.Value.(*peer) + if !peer.Connected() { + continue + } + // A lot of this will make the race detector go mad, + // however it is statistics for purely informational purposes + // and we don't really care if they are raced to get the new + // version. + info := &PeerInfo{ + Addr: peer.addr, + Services: peer.services, + LastSend: peer.lastSend, + LastRecv: peer.lastRecv, + BytesSent: 0, // TODO(oga) we need this from wire. + BytesRecv: 0, // TODO(oga) we need this from wire. + ConnTime: peer.timeConnected, + Version: peer.protocolVersion, + SubVer: "unknown", + Inbound: peer.inbound, + StartingHeight: peer.lastBlock, + BanScore: 0, + SyncNode: false, // TODO(oga) for now. bm knows this. + } + infos = append(infos, info) + } + msg.reply <- infos + } +} + // listenHandler is the main listener which accepts incoming connections for the // server. It must be run as a goroutine. func (s *server) listenHandler(listener net.Listener) { @@ -332,6 +402,9 @@ out: case <-s.wakeup: // this page left intentionally blank + case qmsg := <-s.query: + s.handleQuery(qmsg, peers, bannedPeers) + // Shutdown the peer handler. case <-s.quit: // Shutdown peers. @@ -456,6 +529,22 @@ func (s *server) BroadcastMessage(msg btcwire.Message, exclPeers ...*peer) { s.broadcast <- bmsg } +func (s *server) ConnectedCount() int { + replyChan := make(chan int) + + s.query <- getConnCountMsg{reply: replyChan} + + return <-replyChan +} + +func (s *server) PeerInfo() []*PeerInfo { + replyChan := make(chan []*PeerInfo) + + s.query <- getPeerInfoMsg{reply: replyChan} + + return <-replyChan +} + // Start begins accepting connections from peers. func (s *server) Start() { // Already started? @@ -594,6 +683,7 @@ func newServer(addr string, db btcdb.Db, btcnet btcwire.BitcoinNet) (*server, er donePeers: make(chan *peer, cfg.MaxPeers), banPeers: make(chan *peer, cfg.MaxPeers), wakeup: make(chan bool), + query: make(chan interface{}), relayInv: make(chan *btcwire.InvVect, cfg.MaxPeers), broadcast: make(chan broadcastMsg, cfg.MaxPeers), quit: make(chan bool),