2014-06-18 20:48:32 -07:00
|
|
|
package peer
|
|
|
|
|
|
|
|
import (
|
2014-06-25 21:37:20 -07:00
|
|
|
. "github.com/tendermint/tendermint/common"
|
2014-06-18 20:48:32 -07:00
|
|
|
"github.com/tendermint/tendermint/merkle"
|
2014-06-25 21:37:20 -07:00
|
|
|
"sync/atomic"
|
2014-06-18 20:48:32 -07:00
|
|
|
"sync"
|
2014-06-24 17:28:40 -07:00
|
|
|
"errors"
|
2014-06-18 20:48:32 -07:00
|
|
|
)
|
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
/* Client
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
2014-06-29 00:35:16 -07:00
|
|
|
makePeerFn is a factory method for generating new peers from new *Connections.
|
|
|
|
makePeerFn(nil) must return a prototypical peer that represents the self "peer".
|
2014-06-24 17:28:40 -07:00
|
|
|
|
|
|
|
XXX what about peer disconnects?
|
|
|
|
*/
|
2014-06-18 20:48:32 -07:00
|
|
|
type Client struct {
|
2014-06-28 13:09:04 -07:00
|
|
|
addrBook *AddrBook
|
2014-06-18 20:48:32 -07:00
|
|
|
targetNumPeers int
|
2014-06-29 00:35:16 -07:00
|
|
|
makePeerFn func(*Connection) *Peer
|
2014-06-24 17:28:40 -07:00
|
|
|
self *Peer
|
2014-06-29 10:48:52 -07:00
|
|
|
inQueues map[string]chan *InboundMsg
|
2014-06-18 20:48:32 -07:00
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
mtx sync.Mutex
|
2014-06-18 20:48:32 -07:00
|
|
|
peers merkle.Tree // addr -> *Peer
|
2014-06-24 17:28:40 -07:00
|
|
|
quit chan struct{}
|
|
|
|
stopped uint32
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
var (
|
|
|
|
CLIENT_STOPPED_ERROR = errors.New("Client already stopped")
|
|
|
|
CLIENT_DUPLICATE_PEER_ERROR = errors.New("Duplicate peer")
|
|
|
|
)
|
|
|
|
|
2014-06-29 00:35:16 -07:00
|
|
|
func NewClient(makePeerFn func(*Connection) *Peer) *Client {
|
|
|
|
self := makePeerFn(nil)
|
2014-06-24 17:28:40 -07:00
|
|
|
if self == nil {
|
2014-06-29 00:35:16 -07:00
|
|
|
Panicf("makePeerFn(nil) must return a prototypical peer for self")
|
2014-06-24 17:28:40 -07:00
|
|
|
}
|
|
|
|
|
2014-06-29 10:48:52 -07:00
|
|
|
inQueues := make(map[string]chan *InboundMsg)
|
2014-06-28 13:09:04 -07:00
|
|
|
for chName, _ := range self.channels {
|
2014-06-24 17:28:40 -07:00
|
|
|
inQueues[chName] = make(chan *InboundMsg)
|
|
|
|
}
|
|
|
|
|
2014-06-18 20:48:32 -07:00
|
|
|
c := &Client{
|
2014-06-28 13:09:04 -07:00
|
|
|
addrBook: nil, // TODO
|
|
|
|
targetNumPeers: 0, // TODO
|
2014-06-29 00:35:16 -07:00
|
|
|
makePeerFn: makePeerFn,
|
2014-06-28 13:09:04 -07:00
|
|
|
self: self,
|
|
|
|
inQueues: inQueues,
|
|
|
|
|
|
|
|
peers: merkle.NewIAVLTree(nil),
|
|
|
|
quit: make(chan struct{}),
|
|
|
|
stopped: 0,
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
|
|
|
return c
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *Client) Stop() {
|
2014-06-29 00:35:16 -07:00
|
|
|
log.Infof("Stopping client")
|
2014-06-24 17:28:40 -07:00
|
|
|
// lock
|
|
|
|
c.mtx.Lock()
|
|
|
|
if atomic.CompareAndSwapUint32(&c.stopped, 0, 1) {
|
|
|
|
close(c.quit)
|
|
|
|
// stop each peer.
|
|
|
|
for peerValue := range c.peers.Values() {
|
|
|
|
peer := peerValue.(*Peer)
|
|
|
|
peer.Stop()
|
|
|
|
}
|
|
|
|
// empty tree.
|
|
|
|
c.peers = merkle.NewIAVLTree(nil)
|
|
|
|
}
|
|
|
|
c.mtx.Unlock()
|
|
|
|
// unlock
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
func (c *Client) AddPeerWithConnection(conn *Connection, outgoing bool) (*Peer, error) {
|
|
|
|
if atomic.LoadUint32(&c.stopped) == 1 { return nil, CLIENT_STOPPED_ERROR }
|
2014-06-18 20:48:32 -07:00
|
|
|
|
2014-06-29 00:35:16 -07:00
|
|
|
log.Infof("Adding peer with connection: %v, outgoing: %v", conn, outgoing)
|
|
|
|
peer := c.makePeerFn(conn)
|
2014-06-24 17:28:40 -07:00
|
|
|
peer.outgoing = outgoing
|
|
|
|
err := c.addPeer(peer)
|
2014-06-18 20:48:32 -07:00
|
|
|
if err != nil { return nil, err }
|
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
go peer.Start(c.inQueues)
|
2014-06-18 20:48:32 -07:00
|
|
|
|
|
|
|
return peer, nil
|
|
|
|
}
|
|
|
|
|
2014-06-29 10:48:52 -07:00
|
|
|
func (c *Client) Broadcast(chName string, msg Msg) {
|
2014-06-24 17:28:40 -07:00
|
|
|
if atomic.LoadUint32(&c.stopped) == 1 { return }
|
|
|
|
|
2014-06-29 10:48:52 -07:00
|
|
|
log.Tracef("Broadcast on [%v] msg: %v", chName, msg)
|
2014-06-29 00:35:16 -07:00
|
|
|
for v := range c.Peers().Values() {
|
2014-06-24 17:28:40 -07:00
|
|
|
peer := v.(*Peer)
|
|
|
|
success := peer.TryQueueOut(chName , msg)
|
2014-06-29 10:48:52 -07:00
|
|
|
log.Tracef("Broadcast for peer %v success: %v", peer, success)
|
2014-06-24 17:28:40 -07:00
|
|
|
if !success {
|
|
|
|
// TODO: notify the peer
|
|
|
|
}
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
2014-06-29 10:48:52 -07:00
|
|
|
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
|
|
|
|
2014-06-29 10:48:52 -07:00
|
|
|
// blocks until a message is popped.
|
|
|
|
func (c *Client) PopMessage(chName string) *InboundMsg {
|
2014-06-24 17:28:40 -07:00
|
|
|
if atomic.LoadUint32(&c.stopped) == 1 { return nil }
|
|
|
|
|
2014-06-29 10:48:52 -07:00
|
|
|
log.Tracef("PopMessage on [%v]", chName)
|
2014-06-24 17:28:40 -07:00
|
|
|
q := c.inQueues[chName]
|
|
|
|
if q == nil { Panicf("Expected inQueues[%f], found none", chName) }
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
2014-06-25 21:37:20 -07:00
|
|
|
case <-c.quit:
|
2014-06-24 17:28:40 -07:00
|
|
|
return nil
|
2014-06-25 21:37:20 -07:00
|
|
|
case inMsg := <-q:
|
|
|
|
return inMsg
|
2014-06-24 17:28:40 -07:00
|
|
|
}
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-29 00:35:16 -07:00
|
|
|
func (c *Client) Peers() merkle.Tree {
|
|
|
|
// lock & defer
|
|
|
|
c.mtx.Lock(); defer c.mtx.Unlock()
|
|
|
|
return c.peers.Copy()
|
|
|
|
// unlock deferred
|
|
|
|
}
|
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
func (c *Client) StopPeer(peer *Peer) {
|
|
|
|
// lock
|
|
|
|
c.mtx.Lock()
|
2014-06-25 21:37:20 -07:00
|
|
|
peerValue, _ := c.peers.Remove(peer.RemoteAddress())
|
2014-06-24 17:28:40 -07:00
|
|
|
c.mtx.Unlock()
|
|
|
|
// unlock
|
2014-06-18 20:48:32 -07:00
|
|
|
|
2014-06-25 21:37:20 -07:00
|
|
|
peer_ := peerValue.(*Peer)
|
|
|
|
if peer_ != nil {
|
|
|
|
peer_.Stop()
|
2014-06-24 17:28:40 -07:00
|
|
|
}
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
func (c *Client) addPeer(peer *Peer) error {
|
|
|
|
addr := peer.RemoteAddress()
|
2014-06-18 20:48:32 -07:00
|
|
|
|
2014-06-24 17:28:40 -07:00
|
|
|
// lock & defer
|
|
|
|
c.mtx.Lock(); defer c.mtx.Unlock()
|
|
|
|
if c.stopped == 1 { return CLIENT_STOPPED_ERROR }
|
|
|
|
if !c.peers.Has(addr) {
|
2014-06-29 00:35:16 -07:00
|
|
|
log.Tracef("Actually putting addr: %v, peer: %v", addr, peer)
|
2014-06-24 17:28:40 -07:00
|
|
|
c.peers.Put(addr, peer)
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
// ignore duplicate peer for addr.
|
|
|
|
log.Infof("Ignoring duplicate peer for addr %v", addr)
|
|
|
|
return CLIENT_DUPLICATE_PEER_ERROR
|
|
|
|
}
|
|
|
|
// unlock deferred
|
2014-06-18 20:48:32 -07:00
|
|
|
}
|