9 "github.com/pkg/errors"
10 log "github.com/sirupsen/logrus"
11 crypto "github.com/tendermint/go-crypto"
12 wire "github.com/tendermint/go-wire"
13 cmn "github.com/tendermint/tmlibs/common"
15 cfg "github.com/bytom/config"
18 // Peer could be marked as persistent, in which case you can use
19 // Redial function to reconnect. Note that inbound peers can't be
20 // made persistent. They should be made persistent on the other end.
23 // peerConn contains the raw connection and its config.
24 type peerConn struct {
27 conn net.Conn // source connection
30 // Before using a peer, you will need to perform a handshake on connection.
34 // raw peerConn and the multiplex connection
36 mconn *MConnection // multiplex connection
40 Data *cmn.CMap // User data.
43 // PeerConfig is a Peer configuration.
44 type PeerConfig struct {
45 AuthEnc bool `mapstructure:"auth_enc"` // authenticated encryption
47 // times are in seconds
48 HandshakeTimeout time.Duration `mapstructure:"handshake_timeout"`
49 DialTimeout time.Duration `mapstructure:"dial_timeout"`
51 MConfig *MConnConfig `mapstructure:"connection"`
53 Fuzz bool `mapstructure:"fuzz"` // fuzz connection (for testing)
54 FuzzConfig *FuzzConnConfig `mapstructure:"fuzz_config"`
57 // DefaultPeerConfig returns the default config.
58 func DefaultPeerConfig(config *cfg.P2PConfig) *PeerConfig {
61 HandshakeTimeout: time.Duration(config.HandshakeTimeout), // * time.Second,
62 DialTimeout: time.Duration(config.DialTimeout), // * time.Second,
63 MConfig: DefaultMConnConfig(),
65 FuzzConfig: DefaultFuzzConnConfig(),
69 func newPeer(pc *peerConn, nodeInfo *NodeInfo, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{})) *Peer {
70 // Key and NodeInfo are set after Handshake
77 p.Key = nodeInfo.PubKey.KeyString()
78 p.mconn = createMConnection(pc.conn, p, reactorsByCh, chDescs, onPeerError, pc.config.MConfig)
80 p.BaseService = *cmn.NewBaseService(nil, "Peer", p)
84 func newOutboundPeer(addr *NetAddress, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{}), ourNodePrivKey crypto.PrivKeyEd25519, config *cfg.P2PConfig) (*peerConn, error) {
85 return newOutboundPeerConn(addr, reactorsByCh, chDescs, onPeerError, ourNodePrivKey, DefaultPeerConfig(config))
88 func newOutboundPeerConn(addr *NetAddress, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{}), ourNodePrivKey crypto.PrivKeyEd25519, config *PeerConfig) (*peerConn, error) {
89 conn, err := dial(addr, config)
91 return nil, errors.Wrap(err, "Error dial peer")
94 pc, err := newPeerConn(conn, true, reactorsByCh, chDescs, onPeerError, ourNodePrivKey, config)
103 func newInboundPeerConn(conn net.Conn, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{}), ourNodePrivKey crypto.PrivKeyEd25519, config *cfg.P2PConfig) (*peerConn, error) {
104 return newPeerConn(conn, false, reactorsByCh, chDescs, onPeerError, ourNodePrivKey, DefaultPeerConfig(config))
107 func newPeerConn(rawConn net.Conn, outbound bool, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{}), ourNodePrivKey crypto.PrivKeyEd25519, config *PeerConfig) (*peerConn, error) {
112 // so we have time to do peer handshakes and get set up
113 conn = FuzzConnAfterFromConfig(conn, 10*time.Second, config.FuzzConfig)
116 // Encrypt connection
118 conn.SetDeadline(time.Now().Add(config.HandshakeTimeout * time.Second))
121 conn, err = MakeSecretConnection(conn, ourNodePrivKey)
123 return nil, errors.Wrap(err, "Error creating peer")
127 // Only the information we already have
135 // CloseConn should be used when the peer was created, but never started.
136 func (pc *peerConn) CloseConn() {
140 // HandshakeTimeout performs a handshake between a given node and the peer.
142 func (pc *peerConn) HandshakeTimeout(ourNodeInfo *NodeInfo, timeout time.Duration) (*NodeInfo, error) {
143 // Set deadline for handshake so we don't block forever on conn.ReadFull
144 pc.conn.SetDeadline(time.Now().Add(timeout))
146 var peerNodeInfo = new(NodeInfo)
152 wire.WriteBinary(ourNodeInfo, pc.conn, &n, &err1)
156 wire.ReadBinary(peerNodeInfo, pc.conn, maxNodeInfoSize, &n, &err2)
157 log.WithField("peerNodeInfo", peerNodeInfo).Info("Peer handshake")
160 return peerNodeInfo, errors.Wrap(err1, "Error during handshake/write")
163 return peerNodeInfo, errors.Wrap(err2, "Error during handshake/read")
167 pc.conn.SetDeadline(time.Time{})
169 return peerNodeInfo, nil
172 // Addr returns peer's remote network address.
173 func (p *Peer) Addr() net.Addr {
174 return p.conn.RemoteAddr()
177 // PubKey returns peer's public key.
178 func (p *Peer) PubKey() crypto.PubKeyEd25519 {
179 if p.config.AuthEnc {
180 return p.conn.(*SecretConnection).RemotePubKey()
182 if p.NodeInfo == nil {
183 panic("Attempt to get peer's PubKey before calling Handshake")
188 // OnStart implements BaseService.
189 func (p *Peer) OnStart() error {
190 p.BaseService.OnStart()
191 _, err := p.mconn.Start()
195 // OnStop implements BaseService.
196 func (p *Peer) OnStop() {
197 p.BaseService.OnStop()
201 // Connection returns underlying MConnection.
202 func (p *Peer) Connection() *MConnection {
206 // IsOutbound returns true if the connection is outbound, false otherwise.
207 func (p *Peer) IsOutbound() bool {
211 // Send msg to the channel identified by chID byte. Returns false if the send
212 // queue is full after timeout, specified by MConnection.
213 func (p *Peer) Send(chID byte, msg interface{}) bool {
215 // see Switch#Broadcast, where we fetch the list of peers and loop over
216 // them - while we're looping, one peer may be removed and stopped.
219 return p.mconn.Send(chID, msg)
222 // TrySend msg to the channel identified by chID byte. Immediately returns
223 // false if the send queue is full.
224 func (p *Peer) TrySend(chID byte, msg interface{}) bool {
228 return p.mconn.TrySend(chID, msg)
231 // CanSend returns true if the send queue is not full, false otherwise.
232 func (p *Peer) CanSend(chID byte) bool {
236 return p.mconn.CanSend(chID)
239 // WriteTo writes the peer's public key to w.
240 func (p *Peer) WriteTo(w io.Writer) (n int64, err error) {
242 wire.WriteString(p.Key, w, &n_, &err)
247 // String representation.
248 func (p *Peer) String() string {
250 return fmt.Sprintf("Peer{%v %v out}", p.mconn, p.Key[:12])
253 return fmt.Sprintf("Peer{%v %v in}", p.mconn, p.Key[:12])
256 // Equals reports whenever 2 peers are actually represent the same node.
257 func (p *Peer) Equals(other *Peer) bool {
258 return p.Key == other.Key
261 // Get the data for a given key.
262 func (p *Peer) Get(key string) interface{} {
263 return p.Data.Get(key)
266 func dial(addr *NetAddress, config *PeerConfig) (net.Conn, error) {
267 conn, err := addr.DialTimeout(config.DialTimeout * time.Second)
274 func createMConnection(conn net.Conn, p *Peer, reactorsByCh map[byte]Reactor, chDescs []*ChannelDescriptor, onPeerError func(*Peer, interface{}), config *MConnConfig) *MConnection {
275 onReceive := func(chID byte, msgBytes []byte) {
276 reactor := reactorsByCh[chID]
278 cmn.PanicSanity(cmn.Fmt("Unknown channel %X", chID))
280 reactor.Receive(chID, p, msgBytes)
283 onError := func(r interface{}) {
287 return NewMConnectionWithConfig(conn, chDescs, onReceive, onError, config)