You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

137 lines
2.9 KiB

package p2p
import (
"fmt"
"io"
"net"
"sync/atomic"
"github.com/tendermint/tendermint/binary"
. "github.com/tendermint/tendermint/common"
"github.com/tendermint/tendermint/types"
)
type Peer struct {
outbound bool
mconn *MConnection
running uint32
*types.NodeInfo
Key string
Data *CMap // User data.
}
// NOTE: blocking
// Before creating a peer with newPeer(), perform a handshake on connection.
func peerHandshake(conn net.Conn, ourNodeInfo *types.NodeInfo) (*types.NodeInfo, error) {
var peerNodeInfo = new(types.NodeInfo)
var err1 error
var err2 error
Parallel(
func() {
var n int64
binary.WriteBinary(ourNodeInfo, conn, &n, &err1)
},
func() {
var n int64
binary.ReadBinary(peerNodeInfo, conn, &n, &err2)
log.Info("Peer handshake", "peerNodeInfo", peerNodeInfo)
})
if err1 != nil {
return nil, err1
}
if err2 != nil {
return nil, err2
}
return peerNodeInfo, nil
}
// NOTE: call peerHandshake on conn before calling newPeer().
func newPeer(conn net.Conn, peerNodeInfo *types.NodeInfo, outbound bool, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{})) *Peer {
var p *Peer
onReceive := func(chId byte, msgBytes []byte) {
reactor := reactorsByCh[chId]
if reactor == nil {
panic(Fmt("Unknown channel %X", chId))
}
reactor.Receive(chId, p, msgBytes)
}
onError := func(r interface{}) {
p.stop()
onPeerError(p, r)
}
mconn := NewMConnection(conn, chDescs, onReceive, onError)
p = &Peer{
outbound: outbound,
mconn: mconn,
running: 0,
NodeInfo: peerNodeInfo,
Key: peerNodeInfo.PubKey.KeyString(),
Data: NewCMap(),
}
return p
}
func (p *Peer) start() {
if atomic.CompareAndSwapUint32(&p.running, 0, 1) {
log.Debug("Starting Peer", "peer", p)
p.mconn.Start()
}
}
func (p *Peer) stop() {
if atomic.CompareAndSwapUint32(&p.running, 1, 0) {
log.Debug("Stopping Peer", "peer", p)
p.mconn.Stop()
}
}
func (p *Peer) IsRunning() bool {
return atomic.LoadUint32(&p.running) == 1
}
func (p *Peer) Connection() *MConnection {
return p.mconn
}
func (p *Peer) IsOutbound() bool {
return p.outbound
}
func (p *Peer) Send(chId byte, msg interface{}) bool {
if atomic.LoadUint32(&p.running) == 0 {
return false
}
return p.mconn.Send(chId, msg)
}
func (p *Peer) TrySend(chId byte, msg interface{}) bool {
if atomic.LoadUint32(&p.running) == 0 {
return false
}
return p.mconn.TrySend(chId, msg)
}
func (p *Peer) CanSend(chId byte) bool {
if atomic.LoadUint32(&p.running) == 0 {
return false
}
return p.mconn.CanSend(chId)
}
func (p *Peer) WriteTo(w io.Writer) (n int64, err error) {
binary.WriteString(p.Key, w, &n, &err)
return
}
func (p *Peer) String() string {
if p.outbound {
return fmt.Sprintf("Peer{->%v}", p.mconn)
} else {
return fmt.Sprintf("Peer{%v->}", p.mconn)
}
}
func (p *Peer) Equals(other *Peer) bool {
return p.Key == other.Key
}