handle address list message.

This commit is contained in:
anthdm 2018-01-28 16:18:48 +01:00
parent 8bbe1435fb
commit 5799cdb3ea
4 changed files with 139 additions and 39 deletions

View file

@ -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

View file

@ -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.

View file

@ -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)
}
}

View file

@ -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