Fix dht find value and updates from latest protocol changes #90

Merged
shyba merged 5 commits from fix_dht into master 2021-10-05 15:03:23 +02:00
5 changed files with 49 additions and 16 deletions

View file

@ -17,7 +17,7 @@ const (
// TODO: all these constants should be defaults, and should be used to set values in the standard Config. then the code should use values in the config // TODO: all these constants should be defaults, and should be used to set values in the standard Config. then the code should use values in the config
// TODO: alternatively, have a global Config for constants. at least that way tests can modify the values // TODO: alternatively, have a global Config for constants. at least that way tests can modify the values
alpha = 3 // this is the constant alpha in the spec alpha = 5 // this is the constant alpha in the spec
bucketSize = 8 // this is the constant k in the spec bucketSize = 8 // this is the constant k in the spec
nodeIDLength = bits.NumBytes // bytes. this is the constant B in the spec nodeIDLength = bits.NumBytes // bytes. this is the constant B in the spec
messageIDLength = 20 // bytes. messageIDLength = 20 // bytes.

View file

@ -2,6 +2,7 @@ package dht
import ( import (
"bytes" "bytes"
"encoding/json"
"net" "net"
"sort" "sort"
"strconv" "strconv"
@ -41,6 +42,20 @@ func (c Contact) String() string {
return str return str
} }
func (c Contact) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
ID string
IP string
Port int
PeerPort int
}{
ID: c.ID.Hex(),
IP: c.IP.String(),
Port: c.Port,
PeerPort: c.PeerPort,
})
}
// MarshalCompact returns a compact byteslice representation of the contact // MarshalCompact returns a compact byteslice representation of the contact
// NOTE: The compact representation always uses the tcp PeerPort, not the udp Port. This is dumb, but that's how the python daemon does it // NOTE: The compact representation always uses the tcp PeerPort, not the udp Port. This is dumb, but that's how the python daemon does it
func (c Contact) MarshalCompact() ([]byte, error) { func (c Contact) MarshalCompact() ([]byte, error) {

View file

@ -40,6 +40,7 @@ const (
headerPayloadField = "3" headerPayloadField = "3"
headerArgsField = "4" headerArgsField = "4"
contactsField = "contacts" contactsField = "contacts"
pageField = "p"
tokenField = "token" tokenField = "token"
protocolVersionField = "protocolVersion" protocolVersionField = "protocolVersion"
) )
@ -270,6 +271,7 @@ type Response struct {
FindValueKey string FindValueKey string
Token string Token string
ProtocolVersion int ProtocolVersion int
Page uint8
} }
func (r Response) argsDebug() string { func (r Response) argsDebug() string {
@ -390,27 +392,34 @@ func (r *Response) UnmarshalBencode(b []byte) error {
if contacts, ok := rawData[contactsField]; ok { if contacts, ok := rawData[contactsField]; ok {
err = bencode.DecodeBytes(contacts, &r.Contacts) err = bencode.DecodeBytes(contacts, &r.Contacts)
delete(rawData, contactsField) // so it doesnt mess up findValue key finding below
if err != nil { if err != nil {
return err return err
} }
} else { }
for k, v := range rawData { if page, ok := rawData[pageField]; ok {
r.FindValueKey = k err = bencode.DecodeBytes(page, &r.Page)
var compactContacts [][]byte delete(rawData, pageField) // so it doesnt mess up findValue key finding below
err = bencode.DecodeBytes(v, &compactContacts) if err != nil {
return err
}
}
for k, v := range rawData {
r.FindValueKey = k
var compactContacts [][]byte
err = bencode.DecodeBytes(v, &compactContacts)
if err != nil {
return err
}
for _, compact := range compactContacts {
var c Contact
err = c.UnmarshalCompact(compact)
if err != nil { if err != nil {
return err return err
} }
for _, compact := range compactContacts { r.Contacts = append(r.Contacts, c)
var c Contact
err = c.UnmarshalCompact(compact)
if err != nil {
return err
}
r.Contacts = append(r.Contacts, c)
}
break
} }
break
} }
return nil return nil

View file

@ -102,6 +102,7 @@ type RpcIterativeFindValueArgs struct {
type RpcIterativeFindValueResult struct { type RpcIterativeFindValueResult struct {
Contacts []Contact Contacts []Contact
FoundValue bool FoundValue bool
Values []Contact
} }
func (rpc *rpcReceiver) IterativeFindValue(r *http.Request, args *RpcIterativeFindValueArgs, result *RpcIterativeFindValueResult) error { func (rpc *rpcReceiver) IterativeFindValue(r *http.Request, args *RpcIterativeFindValueArgs, result *RpcIterativeFindValueResult) error {
@ -109,12 +110,19 @@ func (rpc *rpcReceiver) IterativeFindValue(r *http.Request, args *RpcIterativeFi
if err != nil { if err != nil {
return err return err
} }
foundContacts, found, err := FindContacts(rpc.dht.node, key, false, nil) foundContacts, found, err := FindContacts(rpc.dht.node, key, true, nil)
if err != nil { if err != nil {
return err return err
} }
result.Contacts = foundContacts result.Contacts = foundContacts
result.FoundValue = found result.FoundValue = found
if found {
for _, contact := range foundContacts {
if contact.PeerPort > 0 {
result.Values = append(result.Values, contact)
}
}
}
return nil return nil
} }

View file

@ -21,6 +21,7 @@ func NormalizeName(s string) string {
c := cases.Fold() c := cases.Fold()
return c.String(norm.NFD.String(s)) return c.String(norm.NFD.String(s))
} }
// ReverseBytesInPlace reverse the bytes. thanks, Satoshi 😒 // ReverseBytesInPlace reverse the bytes. thanks, Satoshi 😒
func ReverseBytesInPlace(s []byte) { func ReverseBytesInPlace(s []byte) {
for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {