diff --git a/dht/config.go b/dht/config.go index cb305e9..2845257 100644 --- a/dht/config.go +++ b/dht/config.go @@ -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: 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 nodeIDLength = bits.NumBytes // bytes. this is the constant B in the spec messageIDLength = 20 // bytes. diff --git a/dht/contact.go b/dht/contact.go index 79434e4..cd01179 100644 --- a/dht/contact.go +++ b/dht/contact.go @@ -2,6 +2,7 @@ package dht import ( "bytes" + "encoding/json" "net" "sort" "strconv" @@ -41,6 +42,20 @@ func (c Contact) String() string { 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 // 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) { diff --git a/dht/message.go b/dht/message.go index bdd3dc2..26394e8 100644 --- a/dht/message.go +++ b/dht/message.go @@ -40,6 +40,7 @@ const ( headerPayloadField = "3" headerArgsField = "4" contactsField = "contacts" + pageField = "p" tokenField = "token" protocolVersionField = "protocolVersion" ) @@ -270,6 +271,7 @@ type Response struct { FindValueKey string Token string ProtocolVersion int + Page uint8 } func (r Response) argsDebug() string { @@ -390,27 +392,34 @@ func (r *Response) UnmarshalBencode(b []byte) error { if contacts, ok := rawData[contactsField]; ok { err = bencode.DecodeBytes(contacts, &r.Contacts) + delete(rawData, contactsField) // so it doesnt mess up findValue key finding below if err != nil { return err } - } else { - for k, v := range rawData { - r.FindValueKey = k - var compactContacts [][]byte - err = bencode.DecodeBytes(v, &compactContacts) + } + if page, ok := rawData[pageField]; ok { + err = bencode.DecodeBytes(page, &r.Page) + delete(rawData, pageField) // so it doesnt mess up findValue key finding below + 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 { return err } - for _, compact := range compactContacts { - var c Contact - err = c.UnmarshalCompact(compact) - if err != nil { - return err - } - r.Contacts = append(r.Contacts, c) - } - break + r.Contacts = append(r.Contacts, c) } + break } return nil diff --git a/dht/rpc.go b/dht/rpc.go index 0fc66c7..6342f8e 100644 --- a/dht/rpc.go +++ b/dht/rpc.go @@ -102,6 +102,7 @@ type RpcIterativeFindValueArgs struct { type RpcIterativeFindValueResult struct { Contacts []Contact FoundValue bool + Values []Contact } 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 { 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 { return err } result.Contacts = foundContacts result.FoundValue = found + if found { + for _, contact := range foundContacts { + if contact.PeerPort > 0 { + result.Values = append(result.Values, contact) + } + } + } return nil } diff --git a/extras/util/strings.go b/extras/util/strings.go index 9000b29..091a58e 100644 --- a/extras/util/strings.go +++ b/extras/util/strings.go @@ -21,6 +21,7 @@ func NormalizeName(s string) string { c := cases.Fold() return c.String(norm.NFD.String(s)) } + // ReverseBytesInPlace reverse the bytes. thanks, Satoshi 😒 func ReverseBytesInPlace(s []byte) { for i, j := 0, len(s)-1; i < j; i, j = i+1, j-1 {