handle address list message.
This commit is contained in:
parent
8bbe1435fb
commit
5799cdb3ea
4 changed files with 139 additions and 39 deletions
|
@ -165,6 +165,7 @@ func (m *Message) decodePayload(r io.Reader) error {
|
|||
}
|
||||
|
||||
// Compare the checksum of the payload.
|
||||
fmt.Println(len(pbuf))
|
||||
if !compareChecksum(m.Checksum, pbuf) {
|
||||
return errors.New("checksum mismatch error")
|
||||
}
|
||||
|
@ -177,16 +178,16 @@ func (m *Message) decodePayload(r io.Reader) error {
|
|||
if err := p.DecodeBinary(rr); err != nil {
|
||||
return err
|
||||
}
|
||||
// case cmdInv:
|
||||
// p = &payload.Inventory{}
|
||||
// if err := p.UnmarshalBinary(pbuf); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// case cmdAddr:
|
||||
// p = &payload.AddressList{}
|
||||
// if err := p.UnmarshalBinary(pbuf); err != nil {
|
||||
// return err
|
||||
// }
|
||||
// case cmdInv:
|
||||
// p = &payload.Inventory{}
|
||||
// if err := p.UnmarshalBinary(pbuf); err != nil {
|
||||
// return err
|
||||
// }
|
||||
case cmdAddr:
|
||||
p = &payload.AddressList{}
|
||||
if err := p.DecodeBinary(rr); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
m.Payload = p
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package payload
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Endpoint host + port of a node, compatible with net.Addr.
|
||||
|
@ -12,6 +14,33 @@ type Endpoint struct {
|
|||
Port uint16
|
||||
}
|
||||
|
||||
// EndpointFromString returns an Endpoint from the given string.
|
||||
// For now this only handles the most simple hostport form.
|
||||
// e.g. 127.0.0.1:3000
|
||||
// This should be enough to work with for now.
|
||||
func EndpointFromString(s string) (Endpoint, error) {
|
||||
hostPort := strings.Split(s, ":")
|
||||
if len(hostPort) != 2 {
|
||||
return Endpoint{}, fmt.Errorf("invalid address string: %s", s)
|
||||
}
|
||||
host := hostPort[0]
|
||||
port := hostPort[1]
|
||||
|
||||
ch := strings.Split(host, ".")
|
||||
|
||||
buf := [16]byte{}
|
||||
var n int
|
||||
for i := 0; i < len(ch); i++ {
|
||||
n = 12 + i
|
||||
nn, _ := strconv.Atoi(ch[i])
|
||||
buf[n] = byte(nn)
|
||||
}
|
||||
|
||||
p, _ := strconv.Atoi(port)
|
||||
|
||||
return Endpoint{buf, uint16(p)}, nil
|
||||
}
|
||||
|
||||
// Network implements the net.Addr interface.
|
||||
func (e Endpoint) Network() string { return "tcp" }
|
||||
|
||||
|
@ -32,50 +61,72 @@ type AddrWithTime struct {
|
|||
Addr Endpoint
|
||||
}
|
||||
|
||||
// Size implements the payloader interface.
|
||||
func NewAddrWithTime(addr Endpoint) *AddrWithTime {
|
||||
return &AddrWithTime{
|
||||
Timestamp: 1337,
|
||||
Services: 1,
|
||||
Addr: addr,
|
||||
}
|
||||
}
|
||||
|
||||
// Size implements the payload interface.
|
||||
func (p *AddrWithTime) Size() uint32 {
|
||||
return 30
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the Payloader interface.
|
||||
func (p *AddrWithTime) UnmarshalBinary(b []byte) error {
|
||||
p.Timestamp = binary.LittleEndian.Uint32(b[0:4])
|
||||
p.Services = binary.LittleEndian.Uint64(b[4:12])
|
||||
binary.Read(bytes.NewReader(b[12:28]), binary.BigEndian, &p.Addr.IP)
|
||||
p.Addr.Port = binary.BigEndian.Uint16(b[28:30])
|
||||
return nil
|
||||
// DecodeBinary implements the Payload interface.
|
||||
func (p *AddrWithTime) DecodeBinary(r io.Reader) error {
|
||||
err := binary.Read(r, binary.LittleEndian, &p.Timestamp)
|
||||
err = binary.Read(r, binary.LittleEndian, &p.Services)
|
||||
err = binary.Read(r, binary.BigEndian, &p.Addr.IP)
|
||||
err = binary.Read(r, binary.BigEndian, &p.Addr.Port)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// MarshalBinary implements the Payloader interface.
|
||||
func (p *AddrWithTime) MarshalBinary() ([]byte, error) {
|
||||
return nil, nil
|
||||
// EncodeBinary implements the Payload interface.
|
||||
func (p *AddrWithTime) EncodeBinary(w io.Writer) error {
|
||||
err := binary.Write(w, binary.LittleEndian, p.Timestamp)
|
||||
err = binary.Write(w, binary.LittleEndian, p.Services)
|
||||
err = binary.Write(w, binary.BigEndian, p.Addr.IP)
|
||||
err = binary.Write(w, binary.BigEndian, p.Addr.Port)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// AddressList contains a slice of AddrWithTime.
|
||||
// AddressList holds a slice of AddrWithTime.
|
||||
type AddressList struct {
|
||||
Addrs []*AddrWithTime
|
||||
}
|
||||
|
||||
// UnmarshalBinary implements the Payloader interface.
|
||||
func (p *AddressList) UnmarshalBinary(b []byte) error {
|
||||
// DecodeBinary implements the Payload interface.
|
||||
func (p *AddressList) DecodeBinary(r io.Reader) error {
|
||||
var lenList uint8
|
||||
binary.Read(bytes.NewReader(b[0:1]), binary.LittleEndian, &lenList)
|
||||
binary.Read(r, binary.LittleEndian, &lenList)
|
||||
|
||||
offset := 1 // skip the uint8 length byte.
|
||||
size := 30 // size of AddrWithTime
|
||||
for i := 0; i < int(lenList); i++ {
|
||||
for i := 0; i < int(4); i++ {
|
||||
address := &AddrWithTime{}
|
||||
address.UnmarshalBinary(b[offset : offset+size])
|
||||
if err := address.DecodeBinary(r); err != nil {
|
||||
return err
|
||||
}
|
||||
p.Addrs = append(p.Addrs, address)
|
||||
offset += size
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// MarshalBinary implements the Payloader interface.
|
||||
func (p *AddressList) MarshalBinary() ([]byte, error) {
|
||||
return nil, nil
|
||||
// EncodeBinary implements the Payload interface.
|
||||
func (p *AddressList) EncodeBinary(w io.Writer) error {
|
||||
// Write the length of the slice
|
||||
binary.Write(w, binary.LittleEndian, uint8(len(p.Addrs)))
|
||||
|
||||
for _, addr := range p.Addrs {
|
||||
if err := addr.EncodeBinary(w); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Size implements the Payloader interface.
|
||||
|
|
|
@ -1,8 +1,54 @@
|
|||
package payload
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewAddrWithTime(t *testing.T) {
|
||||
func TestEncodeDecodeAddr(t *testing.T) {
|
||||
e, err := EndpointFromString("127.0.0.1:2000")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addr := NewAddrWithTime(e)
|
||||
buf := new(bytes.Buffer)
|
||||
if err := addr.EncodeBinary(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addrDecode := &AddrWithTime{}
|
||||
if err := addrDecode.DecodeBinary(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(addr, addrDecode) {
|
||||
t.Fatalf("expected both addr payloads to be equal: %v and %v", addr, addrDecode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeDecodeAddressList(t *testing.T) {
|
||||
var lenList uint8 = 4
|
||||
addrs := make([]*AddrWithTime, lenList)
|
||||
for i := 0; i < int(lenList); i++ {
|
||||
e, _ := EndpointFromString(fmt.Sprintf("127.0.0.1:200%d", i))
|
||||
addrs[i] = NewAddrWithTime(e)
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
addrList := &AddressList{addrs}
|
||||
if err := addrList.EncodeBinary(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addrListDecode := &AddressList{}
|
||||
if err := addrListDecode.DecodeBinary(buf); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(addrList, addrListDecode) {
|
||||
t.Fatalf("expected both address list payloads to be equal: %v and %v", addrList, addrListDecode)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -183,7 +183,7 @@ func (s *Server) processMessage(msg *Message, peer *Peer) error {
|
|||
case cmdGetAddr:
|
||||
// return s.handleGetAddrCmd(msg, peer)
|
||||
case cmdAddr:
|
||||
// return s.handleAddrCmd(msg.Payload.(*payload.AddressList), peer)
|
||||
return s.handleAddrCmd(msg.Payload.(*payload.AddressList), peer)
|
||||
case cmdGetHeaders:
|
||||
case cmdHeaders:
|
||||
case cmdGetBlocks:
|
||||
|
@ -231,9 +231,10 @@ func (s *Server) handleVersionCmd(v *payload.Version, peer *Peer) error {
|
|||
// When the remote node reveals its known peers we try to connect to all of them.
|
||||
func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error {
|
||||
for _, addr := range addrList.Addrs {
|
||||
if !s.addrAlreadyConnected(addr.Addr) {
|
||||
go connectToRemoteNode(s, addr.Addr.String())
|
||||
}
|
||||
fmt.Println(addr)
|
||||
// if !s.addrAlreadyConnected(addr.Addr) {
|
||||
// go connectToRemoteNode(s, addr.Addr.String())
|
||||
// }
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -269,6 +270,7 @@ func (s *Server) handleGetAddrCmd(msg *Message, peer *Peer) error {
|
|||
}
|
||||
|
||||
func (s *Server) startProtocol(peer *Peer) {
|
||||
// TODO: check if this peer is still connected.
|
||||
for {
|
||||
getaddrMsg := newMessage(s.net, cmdGetAddr, nil)
|
||||
peer.send <- getaddrMsg
|
||||
|
|
Loading…
Reference in a new issue