From 9c152bae7933cd9ad07940f7ae71e6bee29e17dc Mon Sep 17 00:00:00 2001 From: anthdm Date: Sun, 28 Jan 2018 11:12:05 +0100 Subject: [PATCH] unmarshal addressList --- pkg/network/message.go | 39 ++++++++++++++++++-- pkg/network/payload/addr.go | 61 ++++++++++++++++++++++++-------- pkg/network/payload/inventory.go | 3 ++ pkg/network/payload/version.go | 12 +++++-- pkg/network/server.go | 17 +++++++++ pkg/network/tcp.go | 2 +- 6 files changed, 113 insertions(+), 21 deletions(-) diff --git a/pkg/network/message.go b/pkg/network/message.go index 1b214a5e9..250508dc4 100644 --- a/pkg/network/message.go +++ b/pkg/network/message.go @@ -5,6 +5,7 @@ import ( "crypto/sha256" "encoding/binary" "errors" + "fmt" "io" "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 { // 24 bytes for the fixed sized fields. buf := make([]byte, minMessageSize) - if _, err := r.Read(buf); err != nil { + n, err := r.Read(buf) + if err != nil { 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.Command = buf[4:16] 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 { pbuf := make([]byte, m.Length) - if _, err := r.Read(pbuf); err != nil { + n, err := r.Read(pbuf) + if err != nil { 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. if !compareChecksum(m.Checksum, pbuf) { 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 { return err } + case cmdAddr: + p = &payload.AddressList{} + if err := p.UnmarshalBinary(pbuf); err != nil { + return err + } } m.Payload = p @@ -201,10 +220,24 @@ func (m *Message) encode(w io.Writer) error { copy(buf[minMessageSize:minMessageSize+m.Length], payload) } - if _, err := w.Write(buf); err != nil { + n, err := w.Write(buf) + if err != nil { 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 } diff --git a/pkg/network/payload/addr.go b/pkg/network/payload/addr.go index ca016c95c..b3cee7745 100644 --- a/pkg/network/payload/addr.go +++ b/pkg/network/payload/addr.go @@ -1,37 +1,70 @@ package payload import ( - "io" - "net" - "unsafe" + "bytes" + "encoding/binary" ) +// Endpoint host + port of a node. +type Endpoint struct { + IP [16]byte // TODO: make a uint128 type + Port uint16 +} + // AddrWithTime payload type AddrWithTime struct { Timestamp uint32 Services uint64 - Addr net.Addr + Addr Endpoint } +// Size implements the payloader interface. 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 } -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 } -// AddressList is a slice of AddrWithTime. -type AddressList []*AddrWithTime - -func (p AddressList) Encode(r io.Reader) error { - return nil +// MarshalBinary implements the Payloader interface. +func (p *AddressList) MarshalBinary() ([]byte, error) { + return nil, nil } -func (p AddressList) Decode(w io.Writer) error { - return nil +// Size implements the Payloader interface. +func (p *AddressList) Size() uint32 { + return uint32(len(p.Addrs) * 30) } diff --git a/pkg/network/payload/inventory.go b/pkg/network/payload/inventory.go index ca508b4bb..1ad887e15 100644 --- a/pkg/network/payload/inventory.go +++ b/pkg/network/payload/inventory.go @@ -3,6 +3,7 @@ package payload import ( "bytes" "encoding/binary" + "fmt" . "github.com/anthdm/neo-go/pkg/util" ) @@ -47,6 +48,8 @@ func (p *Inventory) UnmarshalBinary(b []byte) error { // TODO: what byte is [1:2] ? // We have 1 byte for the type which is uint8 and 32 for the hash. // 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) p.Hash.UnmarshalBinary(b[2:len(b)]) return nil diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index f0e7a79c0..34828a9d9 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -5,8 +5,7 @@ import ( ) const ( - lenUA = 12 - minVersionSize = 27 + lenUA + minVersionSize = 27 ) // Version payload. @@ -21,7 +20,7 @@ type Version struct { Port uint16 // it's used to distinguish the node from public IP Nonce uint32 - // client id currently 12 bytes \v/NEO:2.6.0/ + // client id UserAgent []byte // Height of the block chain StartHeight uint32 @@ -45,6 +44,12 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version { // UnmarshalBinary implements the Payloader interface. 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.Services = binary.LittleEndian.Uint64(b[4:12]) p.Timestamp = binary.LittleEndian.Uint32(b[12:16]) @@ -87,6 +92,7 @@ func (p *Version) MarshalBinary() ([]byte, error) { return b, nil } +// Size implements the payloader interface. func (p *Version) Size() uint32 { return uint32(minVersionSize + len(p.UserAgent)) } diff --git a/pkg/network/server.go b/pkg/network/server.go index 13bd593ce..5eebfd26f 100644 --- a/pkg/network/server.go +++ b/pkg/network/server.go @@ -7,6 +7,7 @@ import ( "net" "os" "strconv" + "time" "github.com/anthdm/neo-go/pkg/network/payload" "github.com/anthdm/neo-go/pkg/util" @@ -182,6 +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) case cmdGetHeaders: case cmdHeaders: case cmdGetBlocks: @@ -220,6 +222,12 @@ func (s *Server) handleVersionCmd(v *payload.Version, peer *Peer) error { verackMsg := newMessage(s.net, cmdVerack, nil) peer.send <- verackMsg + go s.startProtocol(peer) + + return nil +} + +func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer *Peer) error { return nil } @@ -240,6 +248,15 @@ func (s *Server) handleGetAddrCmd(msg *Message, peer *Peer) error { 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 { return ` _ ____________ __________ diff --git a/pkg/network/tcp.go b/pkg/network/tcp.go index 408be9b06..c530c3cff 100644 --- a/pkg/network/tcp.go +++ b/pkg/network/tcp.go @@ -52,8 +52,8 @@ func handleConnection(s *Server, conn net.Conn, initiated bool) { // Read from the connection and decode it into an RPCMessage and // tell the server there is message available for proccesing. + msg := &Message{} for { - msg := &Message{} if err := msg.decode(conn); err != nil { // remote connection probably closed. if err == io.EOF {