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.
This commit is contained in:
Owain G. Ainsworth 2013-10-21 18:45:30 +01:00
parent d647eea2b7
commit b1f14732b1
3 changed files with 99 additions and 4 deletions

View file

@ -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

View file

@ -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()

View file

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