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. // Compare the checksum of the payload.
fmt.Println(len(pbuf))
if !compareChecksum(m.Checksum, pbuf) { if !compareChecksum(m.Checksum, pbuf) {
return errors.New("checksum mismatch error") 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 { if err := p.DecodeBinary(rr); err != nil {
return err return err
} }
// case cmdInv: // case cmdInv:
// p = &payload.Inventory{} // p = &payload.Inventory{}
// if err := p.UnmarshalBinary(pbuf); err != nil { // if err := p.UnmarshalBinary(pbuf); err != nil {
// return err // return err
// } // }
// case cmdAddr: case cmdAddr:
// p = &payload.AddressList{} p = &payload.AddressList{}
// if err := p.UnmarshalBinary(pbuf); err != nil { if err := p.DecodeBinary(rr); err != nil {
// return err return err
// } }
} }
m.Payload = p m.Payload = p

View file

@ -1,9 +1,11 @@
package payload package payload
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"io"
"strconv"
"strings"
) )
// Endpoint host + port of a node, compatible with net.Addr. // Endpoint host + port of a node, compatible with net.Addr.
@ -12,6 +14,33 @@ type Endpoint struct {
Port uint16 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. // Network implements the net.Addr interface.
func (e Endpoint) Network() string { return "tcp" } func (e Endpoint) Network() string { return "tcp" }
@ -32,50 +61,72 @@ type AddrWithTime struct {
Addr Endpoint 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 { func (p *AddrWithTime) Size() uint32 {
return 30 return 30
} }
// UnmarshalBinary implements the Payloader interface. // DecodeBinary implements the Payload interface.
func (p *AddrWithTime) UnmarshalBinary(b []byte) error { func (p *AddrWithTime) DecodeBinary(r io.Reader) error {
p.Timestamp = binary.LittleEndian.Uint32(b[0:4]) err := binary.Read(r, binary.LittleEndian, &p.Timestamp)
p.Services = binary.LittleEndian.Uint64(b[4:12]) err = binary.Read(r, binary.LittleEndian, &p.Services)
binary.Read(bytes.NewReader(b[12:28]), binary.BigEndian, &p.Addr.IP) err = binary.Read(r, binary.BigEndian, &p.Addr.IP)
p.Addr.Port = binary.BigEndian.Uint16(b[28:30]) err = binary.Read(r, binary.BigEndian, &p.Addr.Port)
return nil
return err
} }
// MarshalBinary implements the Payloader interface. // EncodeBinary implements the Payload interface.
func (p *AddrWithTime) MarshalBinary() ([]byte, error) { func (p *AddrWithTime) EncodeBinary(w io.Writer) error {
return nil, nil 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 { type AddressList struct {
Addrs []*AddrWithTime Addrs []*AddrWithTime
} }
// UnmarshalBinary implements the Payloader interface. // DecodeBinary implements the Payload interface.
func (p *AddressList) UnmarshalBinary(b []byte) error { func (p *AddressList) DecodeBinary(r io.Reader) error {
var lenList uint8 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. for i := 0; i < int(4); i++ {
size := 30 // size of AddrWithTime
for i := 0; i < int(lenList); i++ {
address := &AddrWithTime{} address := &AddrWithTime{}
address.UnmarshalBinary(b[offset : offset+size]) if err := address.DecodeBinary(r); err != nil {
return err
}
p.Addrs = append(p.Addrs, address) p.Addrs = append(p.Addrs, address)
offset += size
} }
return nil return nil
} }
// MarshalBinary implements the Payloader interface. // EncodeBinary implements the Payload interface.
func (p *AddressList) MarshalBinary() ([]byte, error) { func (p *AddressList) EncodeBinary(w io.Writer) error {
return nil, nil // 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. // Size implements the Payloader interface.

View file

@ -1,8 +1,54 @@
package payload package payload
import ( import (
"bytes"
"fmt"
"reflect"
"testing" "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: case cmdGetAddr:
// return s.handleGetAddrCmd(msg, peer) // return s.handleGetAddrCmd(msg, peer)
case cmdAddr: case cmdAddr:
// return s.handleAddrCmd(msg.Payload.(*payload.AddressList), peer) return s.handleAddrCmd(msg.Payload.(*payload.AddressList), peer)
case cmdGetHeaders: case cmdGetHeaders:
case cmdHeaders: case cmdHeaders:
case cmdGetBlocks: 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. // 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 { func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error {
for _, addr := range addrList.Addrs { for _, addr := range addrList.Addrs {
if !s.addrAlreadyConnected(addr.Addr) { fmt.Println(addr)
go connectToRemoteNode(s, addr.Addr.String()) // if !s.addrAlreadyConnected(addr.Addr) {
} // go connectToRemoteNode(s, addr.Addr.String())
// }
} }
return nil return nil
} }
@ -269,6 +270,7 @@ func (s *Server) handleGetAddrCmd(msg *Message, peer *Peer) error {
} }
func (s *Server) startProtocol(peer *Peer) { func (s *Server) startProtocol(peer *Peer) {
// TODO: check if this peer is still connected.
for { for {
getaddrMsg := newMessage(s.net, cmdGetAddr, nil) getaddrMsg := newMessage(s.net, cmdGetAddr, nil)
peer.send <- getaddrMsg peer.send <- getaddrMsg