mirror of
https://github.com/nspcc-dev/neo-go.git
synced 2025-02-18 11:15:36 +00:00
135 lines
3.1 KiB
Go
135 lines
3.1 KiB
Go
package payload
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"io"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
// Endpoint host + port of a node, compatible with net.Addr.
|
|
type Endpoint struct {
|
|
IP [16]byte // TODO: make a uint128 type
|
|
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" }
|
|
|
|
// String implements the net.Addr interface.
|
|
func (e Endpoint) String() string {
|
|
b := make([]uint8, 4)
|
|
for i := 0; i < 4; i++ {
|
|
b[i] = byte(e.IP[len(e.IP)-4+i])
|
|
}
|
|
return fmt.Sprintf("%d.%d.%d.%d:%d", b[0], b[1], b[2], b[3], e.Port)
|
|
}
|
|
|
|
// AddrWithTime payload
|
|
type AddrWithTime struct {
|
|
// Timestamp the node connected to the network.
|
|
Timestamp uint32
|
|
Services uint64
|
|
Addr Endpoint
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
// 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 holds a slice of AddrWithTime.
|
|
type AddressList struct {
|
|
Addrs []*AddrWithTime
|
|
}
|
|
|
|
// DecodeBinary implements the Payload interface.
|
|
func (p *AddressList) DecodeBinary(r io.Reader) error {
|
|
var lenList uint8
|
|
binary.Read(r, binary.LittleEndian, &lenList)
|
|
|
|
for i := 0; i < int(4); i++ {
|
|
address := &AddrWithTime{}
|
|
if err := address.DecodeBinary(r); err != nil {
|
|
return err
|
|
}
|
|
p.Addrs = append(p.Addrs, address)
|
|
}
|
|
|
|
return 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.
|
|
func (p *AddressList) Size() uint32 {
|
|
return uint32(len(p.Addrs) * 30)
|
|
}
|