broke out contact into separate file
This commit is contained in:
parent
7f6d7ac960
commit
107757060e
4 changed files with 155 additions and 133 deletions
124
dht/contact.go
Normal file
124
dht/contact.go
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
package dht
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"net"
|
||||||
|
|
||||||
|
"github.com/lbryio/lbry.go/errors"
|
||||||
|
"github.com/lbryio/reflector.go/dht/bits"
|
||||||
|
|
||||||
|
"github.com/lyoshenka/bencode"
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: if routing table is ever empty (aka the node is isolated), it should re-bootstrap
|
||||||
|
|
||||||
|
// TODO: use a tree with bucket splitting instead of a fixed bucket list. include jack's optimization (see link in commit mesg)
|
||||||
|
// https://github.com/lbryio/lbry/pull/1211/commits/341b27b6d21ac027671d42458826d02735aaae41
|
||||||
|
|
||||||
|
// Contact is a type representation of another node that a specific node is in communication with.
|
||||||
|
type Contact struct {
|
||||||
|
ID bits.Bitmap
|
||||||
|
IP net.IP
|
||||||
|
Port int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equals returns T/F if two contacts are the same.
|
||||||
|
func (c Contact) Equals(other Contact, checkID bool) bool {
|
||||||
|
return c.IP.Equal(other.IP) && c.Port == other.Port && (!checkID || c.ID == other.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr returns the UPD Address of the contact.
|
||||||
|
func (c Contact) Addr() *net.UDPAddr {
|
||||||
|
return &net.UDPAddr{IP: c.IP, Port: c.Port}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String returns the concatenated short hex encoded string of its ID + @ + string represention of its UPD Address.
|
||||||
|
func (c Contact) String() string {
|
||||||
|
return c.ID.HexShort() + "@" + c.Addr().String()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalCompact returns the compact byte slice representation of a contact.
|
||||||
|
func (c Contact) MarshalCompact() ([]byte, error) {
|
||||||
|
if c.IP.To4() == nil {
|
||||||
|
return nil, errors.Err("ip not set")
|
||||||
|
}
|
||||||
|
if c.Port < 0 || c.Port > 65535 {
|
||||||
|
return nil, errors.Err("invalid port")
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
buf.Write(c.IP.To4())
|
||||||
|
buf.WriteByte(byte(c.Port >> 8))
|
||||||
|
buf.WriteByte(byte(c.Port))
|
||||||
|
buf.Write(c.ID[:])
|
||||||
|
|
||||||
|
if buf.Len() != compactNodeInfoLength {
|
||||||
|
return nil, errors.Err("i dont know how this happened")
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.Bytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalCompact unmarshals the compact byte slice representation of a contact.
|
||||||
|
func (c *Contact) UnmarshalCompact(b []byte) error {
|
||||||
|
if len(b) != compactNodeInfoLength {
|
||||||
|
return errors.Err("invalid compact length")
|
||||||
|
}
|
||||||
|
c.IP = net.IPv4(b[0], b[1], b[2], b[3]).To4()
|
||||||
|
c.Port = int(uint16(b[5]) | uint16(b[4])<<8)
|
||||||
|
c.ID = bits.FromBytesP(b[6:])
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalBencode returns the serialized byte slice representation of a contact.
|
||||||
|
func (c Contact) MarshalBencode() ([]byte, error) {
|
||||||
|
return bencode.EncodeBytes([]interface{}{c.ID, c.IP.String(), c.Port})
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalBencode unmarshals the serialized byte slice into the appropriate fields of the contact.
|
||||||
|
func (c *Contact) UnmarshalBencode(b []byte) error {
|
||||||
|
var raw []bencode.RawMessage
|
||||||
|
err := bencode.DecodeBytes(b, &raw)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(raw) != 3 {
|
||||||
|
return errors.Err("contact must have 3 elements; got %d", len(raw))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bencode.DecodeBytes(raw[0], &c.ID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var ipStr string
|
||||||
|
err = bencode.DecodeBytes(raw[1], &ipStr)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
c.IP = net.ParseIP(ipStr).To4()
|
||||||
|
if c.IP == nil {
|
||||||
|
return errors.Err("invalid IP")
|
||||||
|
}
|
||||||
|
|
||||||
|
err = bencode.DecodeBytes(raw[2], &c.Port)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type sortedContact struct {
|
||||||
|
contact Contact
|
||||||
|
xorDistanceToTarget bits.Bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
type byXorDistance []sortedContact
|
||||||
|
|
||||||
|
func (a byXorDistance) Len() int { return len(a) }
|
||||||
|
func (a byXorDistance) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||||
|
func (a byXorDistance) Less(i, j int) bool {
|
||||||
|
return a[i].xorDistanceToTarget.Cmp(a[j].xorDistanceToTarget) < 0
|
||||||
|
}
|
31
dht/contact_test.go
Normal file
31
dht/contact_test.go
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
package dht
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lbryio/reflector.go/dht/bits"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestCompactEncoding(t *testing.T) {
|
||||||
|
c := Contact{
|
||||||
|
ID: bits.FromHexP("1c8aff71b99462464d9eeac639595ab99664be3482cb91a29d87467515c7d9158fe72aa1f1582dab07d8f8b5db277f41"),
|
||||||
|
IP: net.ParseIP("1.2.3.4"),
|
||||||
|
Port: int(55<<8 + 66),
|
||||||
|
}
|
||||||
|
|
||||||
|
var compact []byte
|
||||||
|
compact, err := c.MarshalCompact()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(compact) != compactNodeInfoLength {
|
||||||
|
t.Fatalf("got length of %d; expected %d", len(compact), compactNodeInfoLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(compact, append([]byte{1, 2, 3, 4, 55, 66}, c.ID[:]...)) {
|
||||||
|
t.Errorf("compact bytes not encoded correctly")
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
package dht
|
package dht
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
@ -15,7 +14,6 @@ import (
|
||||||
"github.com/lbryio/lbry.go/stopOnce"
|
"github.com/lbryio/lbry.go/stopOnce"
|
||||||
"github.com/lbryio/reflector.go/dht/bits"
|
"github.com/lbryio/reflector.go/dht/bits"
|
||||||
|
|
||||||
"github.com/lyoshenka/bencode"
|
|
||||||
log "github.com/sirupsen/logrus"
|
log "github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -24,114 +22,6 @@ import (
|
||||||
// TODO: use a tree with bucket splitting instead of a fixed bucket list. include jack's optimization (see link in commit mesg)
|
// TODO: use a tree with bucket splitting instead of a fixed bucket list. include jack's optimization (see link in commit mesg)
|
||||||
// https://github.com/lbryio/lbry/pull/1211/commits/341b27b6d21ac027671d42458826d02735aaae41
|
// https://github.com/lbryio/lbry/pull/1211/commits/341b27b6d21ac027671d42458826d02735aaae41
|
||||||
|
|
||||||
// Contact is a type representation of another node that a specific node is in communication with.
|
|
||||||
type Contact struct {
|
|
||||||
ID bits.Bitmap
|
|
||||||
IP net.IP
|
|
||||||
Port int
|
|
||||||
}
|
|
||||||
|
|
||||||
// Equals returns T/F if two contacts are the same.
|
|
||||||
func (c Contact) Equals(other Contact, checkID bool) bool {
|
|
||||||
return c.IP.Equal(other.IP) && c.Port == other.Port && (!checkID || c.ID == other.ID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Addr returns the UPD Address of the contact.
|
|
||||||
func (c Contact) Addr() *net.UDPAddr {
|
|
||||||
return &net.UDPAddr{IP: c.IP, Port: c.Port}
|
|
||||||
}
|
|
||||||
|
|
||||||
// String returns the concatenated short hex encoded string of its ID + @ + string represention of its UPD Address.
|
|
||||||
func (c Contact) String() string {
|
|
||||||
return c.ID.HexShort() + "@" + c.Addr().String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalCompact returns the compact byte slice representation of a contact.
|
|
||||||
func (c Contact) MarshalCompact() ([]byte, error) {
|
|
||||||
if c.IP.To4() == nil {
|
|
||||||
return nil, errors.Err("ip not set")
|
|
||||||
}
|
|
||||||
if c.Port < 0 || c.Port > 65535 {
|
|
||||||
return nil, errors.Err("invalid port")
|
|
||||||
}
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
buf.Write(c.IP.To4())
|
|
||||||
buf.WriteByte(byte(c.Port >> 8))
|
|
||||||
buf.WriteByte(byte(c.Port))
|
|
||||||
buf.Write(c.ID[:])
|
|
||||||
|
|
||||||
if buf.Len() != compactNodeInfoLength {
|
|
||||||
return nil, errors.Err("i dont know how this happened")
|
|
||||||
}
|
|
||||||
|
|
||||||
return buf.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalCompact unmarshals the compact byte slice representation of a contact.
|
|
||||||
func (c *Contact) UnmarshalCompact(b []byte) error {
|
|
||||||
if len(b) != compactNodeInfoLength {
|
|
||||||
return errors.Err("invalid compact length")
|
|
||||||
}
|
|
||||||
c.IP = net.IPv4(b[0], b[1], b[2], b[3]).To4()
|
|
||||||
c.Port = int(uint16(b[5]) | uint16(b[4])<<8)
|
|
||||||
c.ID = bits.FromBytesP(b[6:])
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalBencode returns the serialized byte slice representation of a contact.
|
|
||||||
func (c Contact) MarshalBencode() ([]byte, error) {
|
|
||||||
return bencode.EncodeBytes([]interface{}{c.ID, c.IP.String(), c.Port})
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnmarshalBencode unmarshals the serialized byte slice into the appropriate fields of the contact.
|
|
||||||
func (c *Contact) UnmarshalBencode(b []byte) error {
|
|
||||||
var raw []bencode.RawMessage
|
|
||||||
err := bencode.DecodeBytes(b, &raw)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(raw) != 3 {
|
|
||||||
return errors.Err("contact must have 3 elements; got %d", len(raw))
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bencode.DecodeBytes(raw[0], &c.ID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var ipStr string
|
|
||||||
err = bencode.DecodeBytes(raw[1], &ipStr)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
c.IP = net.ParseIP(ipStr).To4()
|
|
||||||
if c.IP == nil {
|
|
||||||
return errors.Err("invalid IP")
|
|
||||||
}
|
|
||||||
|
|
||||||
err = bencode.DecodeBytes(raw[2], &c.Port)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type sortedContact struct {
|
|
||||||
contact Contact
|
|
||||||
xorDistanceToTarget bits.Bitmap
|
|
||||||
}
|
|
||||||
|
|
||||||
type byXorDistance []sortedContact
|
|
||||||
|
|
||||||
func (a byXorDistance) Len() int { return len(a) }
|
|
||||||
func (a byXorDistance) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
||||||
func (a byXorDistance) Less(i, j int) bool {
|
|
||||||
return a[i].xorDistanceToTarget.Less(a[j].xorDistanceToTarget)
|
|
||||||
}
|
|
||||||
|
|
||||||
// peer is a contact with extra freshness information
|
// peer is a contact with extra freshness information
|
||||||
type peer struct {
|
type peer struct {
|
||||||
Contact Contact
|
Contact Contact
|
||||||
|
|
|
@ -3,7 +3,6 @@ package dht
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net"
|
"net"
|
||||||
"reflect"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -67,28 +66,6 @@ func TestRoutingTable_GetClosest(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCompactEncoding(t *testing.T) {
|
|
||||||
c := Contact{
|
|
||||||
ID: bits.FromHexP("1c8aff71b99462464d9eeac639595ab99664be3482cb91a29d87467515c7d9158fe72aa1f1582dab07d8f8b5db277f41"),
|
|
||||||
IP: net.ParseIP("1.2.3.4"),
|
|
||||||
Port: int(55<<8 + 66),
|
|
||||||
}
|
|
||||||
|
|
||||||
var compact []byte
|
|
||||||
compact, err := c.MarshalCompact()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(compact) != compactNodeInfoLength {
|
|
||||||
t.Fatalf("got length of %d; expected %d", len(compact), compactNodeInfoLength)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !reflect.DeepEqual(compact, append([]byte{1, 2, 3, 4, 55, 66}, c.ID[:]...)) {
|
|
||||||
t.Errorf("compact bytes not encoded correctly")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRoutingTable_Refresh(t *testing.T) {
|
func TestRoutingTable_Refresh(t *testing.T) {
|
||||||
t.Skip("TODO: test routing table refreshing")
|
t.Skip("TODO: test routing table refreshing")
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue