unmarshal addressList

This commit is contained in:
anthdm 2018-01-28 11:12:05 +01:00
parent 68088d816c
commit 9c152bae79
6 changed files with 113 additions and 21 deletions

View file

@ -5,6 +5,7 @@ import (
"crypto/sha256" "crypto/sha256"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"io" "io"
"github.com/anthdm/neo-go/pkg/network/payload" "github.com/anthdm/neo-go/pkg/network/payload"
@ -137,10 +138,15 @@ func (m *Message) commandType() commandType {
func (m *Message) decode(r io.Reader) error { func (m *Message) decode(r io.Reader) error {
// 24 bytes for the fixed sized fields. // 24 bytes for the fixed sized fields.
buf := make([]byte, minMessageSize) buf := make([]byte, minMessageSize)
if _, err := r.Read(buf); err != nil { n, err := r.Read(buf)
if err != nil {
return err return err
} }
if n != minMessageSize {
return fmt.Errorf("Expected to read exactly %d bytes got %d", minMessageSize, n)
}
m.Magic = NetMode(binary.LittleEndian.Uint32(buf[0:4])) m.Magic = NetMode(binary.LittleEndian.Uint32(buf[0:4]))
m.Command = buf[4:16] m.Command = buf[4:16]
m.Length = binary.LittleEndian.Uint32(buf[16:20]) m.Length = binary.LittleEndian.Uint32(buf[16:20])
@ -156,10 +162,18 @@ func (m *Message) decode(r io.Reader) error {
func (m *Message) unmarshalPayload(r io.Reader) error { func (m *Message) unmarshalPayload(r io.Reader) error {
pbuf := make([]byte, m.Length) pbuf := make([]byte, m.Length)
if _, err := r.Read(pbuf); err != nil { n, err := r.Read(pbuf)
if err != nil {
return err return err
} }
fmt.Printf("incomming payload: %d bytes\n", len(pbuf))
fmt.Println(pbuf)
if uint32(n) != m.Length {
return fmt.Errorf("expected to have read exactly %d bytes got %d", m.Length, n)
}
// Compare the checksum of the payload. // Compare the checksum of the payload.
if !compareChecksum(m.Checksum, pbuf) { if !compareChecksum(m.Checksum, pbuf) {
return errors.New("checksum mismatch error") return errors.New("checksum mismatch error")
@ -177,6 +191,11 @@ func (m *Message) unmarshalPayload(r io.Reader) error {
if err := p.UnmarshalBinary(pbuf); err != nil { if err := p.UnmarshalBinary(pbuf); err != nil {
return err return err
} }
case cmdAddr:
p = &payload.AddressList{}
if err := p.UnmarshalBinary(pbuf); err != nil {
return err
}
} }
m.Payload = p m.Payload = p
@ -201,10 +220,24 @@ func (m *Message) encode(w io.Writer) error {
copy(buf[minMessageSize:minMessageSize+m.Length], payload) copy(buf[minMessageSize:minMessageSize+m.Length], payload)
} }
if _, err := w.Write(buf); err != nil { n, err := w.Write(buf)
if err != nil {
return err return err
} }
// safety check to if we have written enough bytes.
if m.Length > 0 {
expectWritten := minMessageSize + m.Length
if uint32(n) != expectWritten {
return fmt.Errorf("expected to written exactly %d did %d", expectWritten, n)
}
} else {
expectWritten := minMessageSize
if n != expectWritten {
return fmt.Errorf("expected to written exactly %d did %d", expectWritten, n)
}
}
return nil return nil
} }

View file

@ -1,37 +1,70 @@
package payload package payload
import ( import (
"io" "bytes"
"net" "encoding/binary"
"unsafe"
) )
// Endpoint host + port of a node.
type Endpoint struct {
IP [16]byte // TODO: make a uint128 type
Port uint16
}
// AddrWithTime payload // AddrWithTime payload
type AddrWithTime struct { type AddrWithTime struct {
Timestamp uint32 Timestamp uint32
Services uint64 Services uint64
Addr net.Addr Addr Endpoint
} }
// Size implements the payloader interface.
func (p *AddrWithTime) Size() uint32 { func (p *AddrWithTime) Size() uint32 {
return 4 + 8 + uint32(unsafe.Sizeof(p.Addr)) return 30
} }
func (p *AddrWithTime) Encode(r io.Reader) error { // 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.LittleEndian.Uint16(b[28:30])
return nil return nil
} }
func (p *AddrWithTime) Decode(w io.Writer) error { // MarshalBinary implements the Payloader interface.
func (p *AddrWithTime) MarshalBinary() ([]byte, error) {
return nil, nil
}
// AddressList contains a slice of AddrWithTime.
type AddressList struct {
Addrs []*AddrWithTime
}
// UnmarshalBinary implements the Payloader interface.
func (p *AddressList) UnmarshalBinary(b []byte) error {
var lenList uint8
binary.Read(bytes.NewReader(b[0:1]), binary.LittleEndian, &lenList)
offset := 1 // skip the uint8 length byte.
size := 30 // size of AddrWithTime
for i := 0; i < int(lenList); i++ {
address := &AddrWithTime{}
address.UnmarshalBinary(b[offset : offset+size])
p.Addrs = append(p.Addrs, address)
offset += size
}
return nil return nil
} }
// AddressList is a slice of AddrWithTime. // MarshalBinary implements the Payloader interface.
type AddressList []*AddrWithTime func (p *AddressList) MarshalBinary() ([]byte, error) {
return nil, nil
func (p AddressList) Encode(r io.Reader) error {
return nil
} }
func (p AddressList) Decode(w io.Writer) error { // Size implements the Payloader interface.
return nil func (p *AddressList) Size() uint32 {
return uint32(len(p.Addrs) * 30)
} }

View file

@ -3,6 +3,7 @@ package payload
import ( import (
"bytes" "bytes"
"encoding/binary" "encoding/binary"
"fmt"
. "github.com/anthdm/neo-go/pkg/util" . "github.com/anthdm/neo-go/pkg/util"
) )
@ -47,6 +48,8 @@ func (p *Inventory) UnmarshalBinary(b []byte) error {
// TODO: what byte is [1:2] ? // TODO: what byte is [1:2] ?
// We have 1 byte for the type which is uint8 and 32 for the hash. // We have 1 byte for the type which is uint8 and 32 for the hash.
// There is 1 byte left over. // There is 1 byte left over.
fmt.Println(b[0:1])
fmt.Println(b[1:2])
binary.Read(bytes.NewReader(b), binary.LittleEndian, &p.Type) binary.Read(bytes.NewReader(b), binary.LittleEndian, &p.Type)
p.Hash.UnmarshalBinary(b[2:len(b)]) p.Hash.UnmarshalBinary(b[2:len(b)])
return nil return nil

View file

@ -5,8 +5,7 @@ import (
) )
const ( const (
lenUA = 12 minVersionSize = 27
minVersionSize = 27 + lenUA
) )
// Version payload. // Version payload.
@ -21,7 +20,7 @@ type Version struct {
Port uint16 Port uint16
// it's used to distinguish the node from public IP // it's used to distinguish the node from public IP
Nonce uint32 Nonce uint32
// client id currently 12 bytes \v/NEO:2.6.0/ // client id
UserAgent []byte UserAgent []byte
// Height of the block chain // Height of the block chain
StartHeight uint32 StartHeight uint32
@ -45,6 +44,12 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version {
// UnmarshalBinary implements the Payloader interface. // UnmarshalBinary implements the Payloader interface.
func (p *Version) UnmarshalBinary(b []byte) error { func (p *Version) UnmarshalBinary(b []byte) error {
// Length of the user agent should be calculated dynamicaly.
// There is no information about the size or format of this.
// the only thing we know is by looking at the #c source code.
// /NEO:{0}/ => /NEO:2.6.0/
lenUA := len(b) - minVersionSize
p.Version = binary.LittleEndian.Uint32(b[0:4]) p.Version = binary.LittleEndian.Uint32(b[0:4])
p.Services = binary.LittleEndian.Uint64(b[4:12]) p.Services = binary.LittleEndian.Uint64(b[4:12])
p.Timestamp = binary.LittleEndian.Uint32(b[12:16]) p.Timestamp = binary.LittleEndian.Uint32(b[12:16])
@ -87,6 +92,7 @@ func (p *Version) MarshalBinary() ([]byte, error) {
return b, nil return b, nil
} }
// Size implements the payloader interface.
func (p *Version) Size() uint32 { func (p *Version) Size() uint32 {
return uint32(minVersionSize + len(p.UserAgent)) return uint32(minVersionSize + len(p.UserAgent))
} }

View file

@ -7,6 +7,7 @@ import (
"net" "net"
"os" "os"
"strconv" "strconv"
"time"
"github.com/anthdm/neo-go/pkg/network/payload" "github.com/anthdm/neo-go/pkg/network/payload"
"github.com/anthdm/neo-go/pkg/util" "github.com/anthdm/neo-go/pkg/util"
@ -182,6 +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)
case cmdGetHeaders: case cmdGetHeaders:
case cmdHeaders: case cmdHeaders:
case cmdGetBlocks: case cmdGetBlocks:
@ -220,6 +222,12 @@ func (s *Server) handleVersionCmd(v *payload.Version, peer *Peer) error {
verackMsg := newMessage(s.net, cmdVerack, nil) verackMsg := newMessage(s.net, cmdVerack, nil)
peer.send <- verackMsg peer.send <- verackMsg
go s.startProtocol(peer)
return nil
}
func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error {
return nil return nil
} }
@ -240,6 +248,15 @@ func (s *Server) handleGetAddrCmd(msg *Message, peer *Peer) error {
return nil return nil
} }
func (s *Server) startProtocol(peer *Peer) {
for {
getaddrMsg := newMessage(s.net, cmdGetAddr, nil)
peer.send <- getaddrMsg
time.Sleep(10 * time.Second)
}
}
func logo() string { func logo() string {
return ` return `
_ ____________ __________ _ ____________ __________

View file

@ -52,8 +52,8 @@ func handleConnection(s *Server, conn net.Conn, initiated bool) {
// Read from the connection and decode it into an RPCMessage and // Read from the connection and decode it into an RPCMessage and
// tell the server there is message available for proccesing. // tell the server there is message available for proccesing.
for {
msg := &Message{} msg := &Message{}
for {
if err := msg.decode(conn); err != nil { if err := msg.decode(conn); err != nil {
// remote connection probably closed. // remote connection probably closed.
if err == io.EOF { if err == io.EOF {