btc-crawl/peer.go

107 lines
2.4 KiB
Go
Raw Normal View History

2014-04-22 18:28:10 -05:00
package main
import (
"fmt"
"net"
2014-05-15 19:04:09 -05:00
"time"
2014-04-25 17:13:45 -05:00
"github.com/conformal/btcwire"
2014-04-22 18:28:10 -05:00
)
type Peer struct {
2014-04-25 18:24:27 -05:00
client *Client
conn net.Conn
nonce uint64 // Nonce we're sending to the peer
pver uint32 // Negotiated ProtocolVersion
Address string
UserAgent string
ProtocolVersion int32
2014-05-15 19:04:09 -05:00
ConnectTimeout time.Duration // For the connect phase (can be overridden)
2014-04-22 18:28:10 -05:00
}
func NewPeer(client *Client, address string) *Peer {
p := Peer{
2014-05-15 19:04:09 -05:00
client: client,
pver: client.pver,
Address: address,
ConnectTimeout: time.Duration(20 * time.Second),
2014-04-22 18:28:10 -05:00
}
return &p
}
func (p *Peer) Connect() error {
if p.conn != nil {
return fmt.Errorf("Peer already connected, can't connect again.")
}
2014-05-15 19:04:09 -05:00
conn, err := net.DialTimeout("tcp", p.Address, p.ConnectTimeout)
2014-04-22 18:28:10 -05:00
if err != nil {
return err
}
p.conn = conn
return nil
}
func (p *Peer) Disconnect() {
p.conn.Close()
2014-04-25 18:24:27 -05:00
logger.Debugf("[%s] Closed.", p.Address)
2014-04-22 18:28:10 -05:00
}
func (p *Peer) Handshake() error {
if p.conn == nil {
return fmt.Errorf("Peer is not connected, can't handshake.")
}
2014-04-25 18:24:27 -05:00
logger.Debugf("[%s] Starting handshake.", p.Address)
2014-04-22 18:28:10 -05:00
nonce, err := btcwire.RandomUint64()
if err != nil {
return err
}
p.nonce = nonce
2014-05-20 17:37:36 -05:00
msgVersion, err := btcwire.NewMsgVersionFromConn(p.conn, p.nonce, 0)
msgVersion.UserAgent = p.client.userAgent
2014-04-22 18:28:10 -05:00
msgVersion.DisableRelayTx = true
2014-04-25 18:24:27 -05:00
if err := p.WriteMessage(msgVersion); err != nil {
2014-04-22 18:28:10 -05:00
return err
}
// Read the response version.
2014-04-25 18:24:27 -05:00
msg, _, err := p.ReadMessage()
2014-04-22 18:28:10 -05:00
if err != nil {
return err
}
vmsg, ok := msg.(*btcwire.MsgVersion)
if !ok {
return fmt.Errorf("Did not receive version message: %T", vmsg)
}
2014-04-25 18:24:27 -05:00
p.ProtocolVersion = vmsg.ProtocolVersion
p.UserAgent = vmsg.UserAgent
2014-04-22 18:28:10 -05:00
// Negotiate protocol version.
2014-04-25 18:24:27 -05:00
if uint32(vmsg.ProtocolVersion) < p.pver {
p.pver = uint32(vmsg.ProtocolVersion)
2014-04-22 18:28:10 -05:00
}
2014-04-25 18:24:27 -05:00
logger.Debugf("[%s] -> Version: %s", p.Address, vmsg.UserAgent)
2014-04-22 18:28:10 -05:00
// Normally we'd check if vmsg.Nonce == p.nonce but the crawler does not
// accept external connections so we skip it.
// Send verack.
2014-04-25 18:24:27 -05:00
if err := p.WriteMessage(btcwire.NewMsgVerAck()); err != nil {
2014-04-22 18:28:10 -05:00
return err
}
return nil
}
2014-04-25 17:13:45 -05:00
func (p *Peer) WriteMessage(msg btcwire.Message) error {
2014-04-25 18:24:27 -05:00
return btcwire.WriteMessage(p.conn, msg, p.pver, p.client.btcnet)
2014-04-25 17:13:45 -05:00
}
func (p *Peer) ReadMessage() (btcwire.Message, []byte, error) {
2014-04-25 18:24:27 -05:00
return btcwire.ReadMessage(p.conn, p.pver, p.client.btcnet)
2014-04-25 17:13:45 -05:00
}