|
@ -10,28 +10,34 @@ import ( |
|
|
"github.com/tendermint/tendermint/merkle" |
|
|
"github.com/tendermint/tendermint/merkle" |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
/* Client |
|
|
|
|
|
|
|
|
// BUG(jae) handle peer disconnects
|
|
|
|
|
|
|
|
|
A client is half of a p2p system. |
|
|
|
|
|
It can reach out to the network and establish connections with servers. |
|
|
|
|
|
A client doesn't listen for incoming connections -- that's done by the server. |
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
A client is half of a p2p system. |
|
|
|
|
|
It can reach out to the network and establish connections with other peers. |
|
|
|
|
|
A client doesn't listen for incoming connections -- that's done by the server. |
|
|
|
|
|
|
|
|
makePeerFn is a factory method for generating new peers from new *Connections. |
|
|
|
|
|
makePeerFn(nil) must return a prototypical peer that represents the self "peer". |
|
|
|
|
|
|
|
|
All communication amongst peers are multiplexed by "channels". |
|
|
|
|
|
(Not the same as Go "channels") |
|
|
|
|
|
|
|
|
XXX what about peer disconnects? |
|
|
|
|
|
|
|
|
To send a message, encapsulate it into a "Packet" and send it to each peer. |
|
|
|
|
|
You can find all connected and active peers by iterating over ".Peers()". |
|
|
|
|
|
".Broadcast()" is provided for convenience, but by iterating over |
|
|
|
|
|
the peers manually the caller can decide which subset receives a message. |
|
|
|
|
|
|
|
|
|
|
|
Incoming messages are received by calling ".Receive()". |
|
|
*/ |
|
|
*/ |
|
|
type Client struct { |
|
|
type Client struct { |
|
|
addrBook *AddrBook |
|
|
addrBook *AddrBook |
|
|
targetNumPeers int |
|
|
targetNumPeers int |
|
|
makePeerFn func(*Connection) *Peer |
|
|
makePeerFn func(*Connection) *Peer |
|
|
self *Peer |
|
|
self *Peer |
|
|
recvQueues map[String]chan *InboundPacket |
|
|
|
|
|
|
|
|
|
|
|
mtx sync.Mutex |
|
|
|
|
|
peers merkle.Tree // addr -> *Peer
|
|
|
|
|
|
quit chan struct{} |
|
|
|
|
|
stopped uint32 |
|
|
|
|
|
|
|
|
pktRecvQueues map[String]chan *InboundPacket |
|
|
|
|
|
peersMtx sync.Mutex |
|
|
|
|
|
peers merkle.Tree // addr -> *Peer
|
|
|
|
|
|
quit chan struct{} |
|
|
|
|
|
erroredPeers chan peerError |
|
|
|
|
|
stopped uint32 |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
var ( |
|
|
var ( |
|
@ -39,15 +45,17 @@ var ( |
|
|
CLIENT_DUPLICATE_PEER_ERROR = errors.New("Duplicate peer") |
|
|
CLIENT_DUPLICATE_PEER_ERROR = errors.New("Duplicate peer") |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
// "makePeerFn" is a factory method for generating new peers from new *Connections.
|
|
|
|
|
|
// "makePeerFn(nil)" must return a prototypical peer that represents the self "peer".
|
|
|
func NewClient(makePeerFn func(*Connection) *Peer) *Client { |
|
|
func NewClient(makePeerFn func(*Connection) *Peer) *Client { |
|
|
self := makePeerFn(nil) |
|
|
self := makePeerFn(nil) |
|
|
if self == nil { |
|
|
if self == nil { |
|
|
Panicf("makePeerFn(nil) must return a prototypical peer for self") |
|
|
Panicf("makePeerFn(nil) must return a prototypical peer for self") |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
recvQueues := make(map[String]chan *InboundPacket) |
|
|
|
|
|
|
|
|
pktRecvQueues := make(map[String]chan *InboundPacket) |
|
|
for chName, _ := range self.channels { |
|
|
for chName, _ := range self.channels { |
|
|
recvQueues[chName] = make(chan *InboundPacket) |
|
|
|
|
|
|
|
|
pktRecvQueues[chName] = make(chan *InboundPacket) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
c := &Client{ |
|
|
c := &Client{ |
|
@ -55,30 +63,39 @@ func NewClient(makePeerFn func(*Connection) *Peer) *Client { |
|
|
targetNumPeers: 0, // TODO
|
|
|
targetNumPeers: 0, // TODO
|
|
|
makePeerFn: makePeerFn, |
|
|
makePeerFn: makePeerFn, |
|
|
self: self, |
|
|
self: self, |
|
|
recvQueues: recvQueues, |
|
|
|
|
|
|
|
|
|
|
|
peers: merkle.NewIAVLTree(nil), |
|
|
|
|
|
quit: make(chan struct{}), |
|
|
|
|
|
stopped: 0, |
|
|
|
|
|
|
|
|
pktRecvQueues: pktRecvQueues, |
|
|
|
|
|
peers: merkle.NewIAVLTree(nil), |
|
|
|
|
|
quit: make(chan struct{}), |
|
|
|
|
|
erroredPeers: make(chan peerError), |
|
|
|
|
|
stopped: 0, |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// automatically start
|
|
|
|
|
|
c.start() |
|
|
|
|
|
|
|
|
return c |
|
|
return c |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) start() { |
|
|
|
|
|
// Handle peer disconnects & errors
|
|
|
|
|
|
go c.peerErrorHandler() |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
func (c *Client) Stop() { |
|
|
func (c *Client) Stop() { |
|
|
log.Infof("Stopping client") |
|
|
log.Infof("Stopping client") |
|
|
// lock
|
|
|
// lock
|
|
|
c.mtx.Lock() |
|
|
|
|
|
|
|
|
c.peersMtx.Lock() |
|
|
if atomic.CompareAndSwapUint32(&c.stopped, 0, 1) { |
|
|
if atomic.CompareAndSwapUint32(&c.stopped, 0, 1) { |
|
|
close(c.quit) |
|
|
close(c.quit) |
|
|
// stop each peer.
|
|
|
// stop each peer.
|
|
|
for peerValue := range c.peers.Values() { |
|
|
for peerValue := range c.peers.Values() { |
|
|
peer := peerValue.(*Peer) |
|
|
peer := peerValue.(*Peer) |
|
|
peer.Stop() |
|
|
|
|
|
|
|
|
peer.stop() |
|
|
} |
|
|
} |
|
|
// empty tree.
|
|
|
// empty tree.
|
|
|
c.peers = merkle.NewIAVLTree(nil) |
|
|
c.peers = merkle.NewIAVLTree(nil) |
|
|
} |
|
|
} |
|
|
c.mtx.Unlock() |
|
|
|
|
|
|
|
|
c.peersMtx.Unlock() |
|
|
// unlock
|
|
|
// unlock
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -95,7 +112,7 @@ func (c *Client) AddPeerWithConnection(conn *Connection, outgoing bool) (*Peer, |
|
|
return nil, err |
|
|
return nil, err |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
go peer.Start(c.recvQueues) |
|
|
|
|
|
|
|
|
go peer.start(c.pktRecvQueues, c.erroredPeers) |
|
|
|
|
|
|
|
|
return peer, nil |
|
|
return peer, nil |
|
|
} |
|
|
} |
|
@ -120,16 +137,18 @@ func (c *Client) Broadcast(pkt Packet) (numSuccess, numFailure int) { |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
// blocks until a message is popped.
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
Receive blocks on a channel until a message is found. |
|
|
|
|
|
*/ |
|
|
func (c *Client) Receive(chName String) *InboundPacket { |
|
|
func (c *Client) Receive(chName String) *InboundPacket { |
|
|
if atomic.LoadUint32(&c.stopped) == 1 { |
|
|
if atomic.LoadUint32(&c.stopped) == 1 { |
|
|
return nil |
|
|
return nil |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
log.Tracef("Receive on [%v]", chName) |
|
|
log.Tracef("Receive on [%v]", chName) |
|
|
q := c.recvQueues[chName] |
|
|
|
|
|
|
|
|
q := c.pktRecvQueues[chName] |
|
|
if q == nil { |
|
|
if q == nil { |
|
|
Panicf("Expected recvQueues[%f], found none", chName) |
|
|
|
|
|
|
|
|
Panicf("Expected pktRecvQueues[%f], found none", chName) |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
select { |
|
|
select { |
|
@ -142,22 +161,22 @@ func (c *Client) Receive(chName String) *InboundPacket { |
|
|
|
|
|
|
|
|
func (c *Client) Peers() merkle.Tree { |
|
|
func (c *Client) Peers() merkle.Tree { |
|
|
// lock & defer
|
|
|
// lock & defer
|
|
|
c.mtx.Lock() |
|
|
|
|
|
defer c.mtx.Unlock() |
|
|
|
|
|
|
|
|
c.peersMtx.Lock() |
|
|
|
|
|
defer c.peersMtx.Unlock() |
|
|
return c.peers.Copy() |
|
|
return c.peers.Copy() |
|
|
// unlock deferred
|
|
|
// unlock deferred
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
func (c *Client) StopPeer(peer *Peer) { |
|
|
func (c *Client) StopPeer(peer *Peer) { |
|
|
// lock
|
|
|
// lock
|
|
|
c.mtx.Lock() |
|
|
|
|
|
|
|
|
c.peersMtx.Lock() |
|
|
peerValue, _ := c.peers.Remove(peer.RemoteAddress()) |
|
|
peerValue, _ := c.peers.Remove(peer.RemoteAddress()) |
|
|
c.mtx.Unlock() |
|
|
|
|
|
|
|
|
c.peersMtx.Unlock() |
|
|
// unlock
|
|
|
// unlock
|
|
|
|
|
|
|
|
|
peer_ := peerValue.(*Peer) |
|
|
peer_ := peerValue.(*Peer) |
|
|
if peer_ != nil { |
|
|
if peer_ != nil { |
|
|
peer_.Stop() |
|
|
|
|
|
|
|
|
peer_.stop() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
@ -165,8 +184,8 @@ func (c *Client) addPeer(peer *Peer) error { |
|
|
addr := peer.RemoteAddress() |
|
|
addr := peer.RemoteAddress() |
|
|
|
|
|
|
|
|
// lock & defer
|
|
|
// lock & defer
|
|
|
c.mtx.Lock() |
|
|
|
|
|
defer c.mtx.Unlock() |
|
|
|
|
|
|
|
|
c.peersMtx.Lock() |
|
|
|
|
|
defer c.peersMtx.Unlock() |
|
|
if c.stopped == 1 { |
|
|
if c.stopped == 1 { |
|
|
return CLIENT_STOPPED_ERROR |
|
|
return CLIENT_STOPPED_ERROR |
|
|
} |
|
|
} |
|
@ -181,3 +200,16 @@ func (c *Client) addPeer(peer *Peer) error { |
|
|
} |
|
|
} |
|
|
// unlock deferred
|
|
|
// unlock deferred
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
func (c *Client) peerErrorHandler() { |
|
|
|
|
|
for { |
|
|
|
|
|
select { |
|
|
|
|
|
case <-c.quit: |
|
|
|
|
|
return |
|
|
|
|
|
case errPeer := <-c.erroredPeers: |
|
|
|
|
|
// TODO do something
|
|
|
|
|
|
c.StopPeer(errPeer.peer) |
|
|
|
|
|
return |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |