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.
|
// 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")
|
||||||
}
|
}
|
||||||
|
@ -182,11 +183,11 @@ func (m *Message) decodePayload(r io.Reader) error {
|
||||||
// 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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue