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),