5
0
mirror of https://github.com/cwinfo/yggdrasil-go.git synced 2024-11-26 16:31:41 +00:00

Make some API changes (currently broken)

This commit is contained in:
Neil Alexander 2019-08-05 00:30:12 +01:00
parent a2966291b9
commit 37533f157d
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
4 changed files with 84 additions and 81 deletions

View File

@ -17,6 +17,7 @@ import (
"github.com/yggdrasil-network/yggdrasil-go/src/address" "github.com/yggdrasil-network/yggdrasil-go/src/address"
"github.com/yggdrasil-network/yggdrasil-go/src/config" "github.com/yggdrasil-network/yggdrasil-go/src/config"
"github.com/yggdrasil-network/yggdrasil-go/src/crypto" "github.com/yggdrasil-network/yggdrasil-go/src/crypto"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
"github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil" "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
) )
@ -243,31 +244,46 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
} }
}) })
a.AddHandler("dhtPing", []string{"box_pub_key", "coords", "[target]"}, func(in Info) (Info, error) { a.AddHandler("dhtPing", []string{"box_pub_key", "coords", "[target]"}, func(in Info) (Info, error) {
var reserr error
var result yggdrasil.DHTRes
if in["target"] == nil { if in["target"] == nil {
in["target"] = "none" in["target"] = "none"
} }
result, err := a.core.DHTPing(in["box_pub_key"].(string), in["coords"].(string), in["target"].(string)) coords := util.DecodeCoordString(in["coords"].(string))
if err == nil { var boxPubKey crypto.BoxPubKey
infos := make(map[string]map[string]string, len(result.Infos)) if b, err := hex.DecodeString(in["box_pub_key"].(string)); err == nil {
for _, dinfo := range result.Infos { copy(boxPubKey[:], b[:])
info := map[string]string{ if n, err := hex.DecodeString(in["target"].(string)); err == nil {
"box_pub_key": hex.EncodeToString(dinfo.PublicKey[:]), var targetNodeID crypto.NodeID
"coords": fmt.Sprintf("%v", dinfo.Coords), copy(targetNodeID[:], n[:])
} result, reserr = a.core.DHTPing(boxPubKey, coords, &targetNodeID)
addr := net.IP(address.AddrForNodeID(crypto.GetNodeID(&dinfo.PublicKey))[:]).String() } else {
infos[addr] = info result, reserr = a.core.DHTPing(boxPubKey, coords, nil)
} }
return Info{"nodes": infos}, nil
} else { } else {
return Info{}, err return Info{}, err
} }
if reserr != nil {
return Info{}, reserr
}
infos := make(map[string]map[string]string, len(result.Infos))
for _, dinfo := range result.Infos {
info := map[string]string{
"box_pub_key": hex.EncodeToString(dinfo.PublicKey[:]),
"coords": fmt.Sprintf("%v", dinfo.Coords),
}
addr := net.IP(address.AddrForNodeID(crypto.GetNodeID(&dinfo.PublicKey))[:]).String()
infos[addr] = info
}
return Info{"nodes": infos}, nil
}) })
a.AddHandler("getNodeInfo", []string{"[box_pub_key]", "[coords]", "[nocache]"}, func(in Info) (Info, error) { a.AddHandler("getNodeInfo", []string{"[box_pub_key]", "[coords]", "[nocache]"}, func(in Info) (Info, error) {
var nocache bool var nocache bool
if in["nocache"] != nil { if in["nocache"] != nil {
nocache = in["nocache"].(string) == "true" nocache = in["nocache"].(string) == "true"
} }
var box_pub_key, coords string var box_pub_key string
var coords []uint64
if in["box_pub_key"] == nil && in["coords"] == nil { if in["box_pub_key"] == nil && in["coords"] == nil {
nodeinfo := a.core.MyNodeInfo() nodeinfo := a.core.MyNodeInfo()
var jsoninfo interface{} var jsoninfo interface{}
@ -280,7 +296,7 @@ func (a *AdminSocket) Init(c *yggdrasil.Core, state *config.NodeState, log *log.
return Info{}, errors.New("Expecting both box_pub_key and coords") return Info{}, errors.New("Expecting both box_pub_key and coords")
} else { } else {
box_pub_key = in["box_pub_key"].(string) box_pub_key = in["box_pub_key"].(string)
coords = in["coords"].(string) coords = util.DecodeCoordString(in["coords"].(string))
} }
result, err := a.core.GetNodeInfo(box_pub_key, coords, nocache) result, err := a.core.GetNodeInfo(box_pub_key, coords, nocache)
if err == nil { if err == nil {

View File

@ -2,9 +2,13 @@ package util
// These are misc. utility functions that didn't really fit anywhere else // These are misc. utility functions that didn't really fit anywhere else
import "runtime" import (
import "sync" "runtime"
import "time" "strconv"
"strings"
"sync"
"time"
)
// A wrapper around runtime.Gosched() so it doesn't need to be imported elsewhere. // A wrapper around runtime.Gosched() so it doesn't need to be imported elsewhere.
func Yield() { func Yield() {
@ -91,3 +95,16 @@ func Difference(a, b []string) []string {
} }
return ab return ab
} }
// DecodeCoordString decodes a string representing coordinates in [1 2 3] format
// and returns a []byte.
func DecodeCoordString(in string) (out []uint64) {
s := strings.Trim(in, "[]")
t := strings.Split(s, " ")
for _, a := range t {
if u, err := strconv.ParseUint(a, 0, 64); err == nil {
out = append(out, u)
}
}
return out
}

View File

@ -6,8 +6,6 @@ import (
"fmt" "fmt"
"net" "net"
"sort" "sort"
"strconv"
"strings"
"sync/atomic" "sync/atomic"
"time" "time"
@ -46,14 +44,14 @@ type SwitchPeer struct {
// DHT searches. // DHT searches.
type DHTEntry struct { type DHTEntry struct {
PublicKey crypto.BoxPubKey PublicKey crypto.BoxPubKey
Coords []byte Coords []uint64
LastSeen time.Duration LastSeen time.Duration
} }
// DHTRes represents a DHT response, as returned by DHTPing. // DHTRes represents a DHT response, as returned by DHTPing.
type DHTRes struct { type DHTRes struct {
PublicKey crypto.BoxPubKey // key of the sender PublicKey crypto.BoxPubKey // key of the sender
Coords []byte // coords of the sender Coords []uint64 // coords of the sender
Dest crypto.NodeID // the destination node ID Dest crypto.NodeID // the destination node ID
Infos []DHTEntry // response Infos []DHTEntry // response
} }
@ -166,7 +164,7 @@ func (c *Core) GetDHT() []DHTEntry {
}) })
for _, v := range dhtentry { for _, v := range dhtentry {
info := DHTEntry{ info := DHTEntry{
Coords: append([]byte{}, v.coords...), Coords: append([]uint64{}, coordsBytestoUint64s(v.coords)...),
LastSeen: now.Sub(v.recv), LastSeen: now.Sub(v.recv),
} }
copy(info.PublicKey[:], v.key[:]) copy(info.PublicKey[:], v.key[:])
@ -346,30 +344,7 @@ func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) {
// key and coordinates specified. The third parameter specifies whether a cached // key and coordinates specified. The third parameter specifies whether a cached
// result is acceptable - this results in less traffic being generated than is // result is acceptable - this results in less traffic being generated than is
// necessary when, e.g. crawling the network. // necessary when, e.g. crawling the network.
func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInfoPayload, error) { func (c *Core) GetNodeInfo(key crypto.BoxPubKey, coords []byte, nocache bool) (NodeInfoPayload, error) {
var key crypto.BoxPubKey
if keyBytes, err := hex.DecodeString(keyString); err != nil {
return NodeInfoPayload{}, err
} else {
copy(key[:], keyBytes)
}
if !nocache {
if response, err := c.router.nodeinfo.getCachedNodeInfo(key); err == nil {
return response, nil
}
}
var coords []byte
for _, cstr := range strings.Split(strings.Trim(coordString, "[]"), " ") {
if cstr == "" {
// Special case, happens if trimmed is the empty string, e.g. this is the root
continue
}
if u64, err := strconv.ParseUint(cstr, 10, 8); err != nil {
return NodeInfoPayload{}, err
} else {
coords = append(coords, uint8(u64))
}
}
response := make(chan *NodeInfoPayload, 1) response := make(chan *NodeInfoPayload, 1)
sendNodeInfoRequest := func() { sendNodeInfoRequest := func() {
c.router.nodeinfo.addCallback(key, func(nodeinfo *NodeInfoPayload) { c.router.nodeinfo.addCallback(key, func(nodeinfo *NodeInfoPayload) {
@ -389,7 +364,7 @@ func (c *Core) GetNodeInfo(keyString, coordString string, nocache bool) (NodeInf
for res := range response { for res := range response {
return *res, nil return *res, nil
} }
return NodeInfoPayload{}, fmt.Errorf("getNodeInfo timeout: %s", keyString) return NodeInfoPayload{}, fmt.Errorf("getNodeInfo timeout: %s", hex.EncodeToString(key[:]))
} }
// SetSessionGatekeeper allows you to configure a handler function for deciding // SetSessionGatekeeper allows you to configure a handler function for deciding
@ -477,64 +452,38 @@ func (c *Core) RemoveAllowedEncryptionPublicKey(bstr string) (err error) {
// DHTPing sends a DHT ping to the node with the provided key and coords, // DHTPing sends a DHT ping to the node with the provided key and coords,
// optionally looking up the specified target NodeID. // optionally looking up the specified target NodeID.
func (c *Core) DHTPing(keyString, coordString, targetString string) (DHTRes, error) { func (c *Core) DHTPing(key crypto.BoxPubKey, coords []uint64, target *crypto.NodeID) (DHTRes, error) {
var key crypto.BoxPubKey
if keyBytes, err := hex.DecodeString(keyString); err != nil {
return DHTRes{}, err
} else {
copy(key[:], keyBytes)
}
var coords []byte
for _, cstr := range strings.Split(strings.Trim(coordString, "[]"), " ") {
if cstr == "" {
// Special case, happens if trimmed is the empty string, e.g. this is the root
continue
}
if u64, err := strconv.ParseUint(cstr, 10, 8); err != nil {
return DHTRes{}, err
} else {
coords = append(coords, uint8(u64))
}
}
resCh := make(chan *dhtRes, 1) resCh := make(chan *dhtRes, 1)
info := dhtInfo{ info := dhtInfo{
key: key, key: key,
coords: coords, coords: coordsUint64stoBytes(coords),
} }
target := *info.getNodeID() if target == nil {
if targetString == "none" { target = info.getNodeID()
// Leave the default target in place
} else if targetBytes, err := hex.DecodeString(targetString); err != nil {
return DHTRes{}, err
} else if len(targetBytes) != len(target) {
return DHTRes{}, errors.New("Incorrect target NodeID length")
} else {
var target crypto.NodeID
copy(target[:], targetBytes)
} }
rq := dhtReqKey{info.key, target} rq := dhtReqKey{info.key, *target}
sendPing := func() { sendPing := func() {
c.dht.addCallback(&rq, func(res *dhtRes) { c.dht.addCallback(&rq, func(res *dhtRes) {
resCh <- res resCh <- res
}) })
c.dht.ping(&info, &target) c.dht.ping(&info, &rq.dest)
} }
c.router.doAdmin(sendPing) c.router.doAdmin(sendPing)
// TODO: do something better than the below... // TODO: do something better than the below...
res := <-resCh res := <-resCh
if res != nil { if res != nil {
r := DHTRes{ r := DHTRes{
Coords: append([]byte{}, res.Coords...), Coords: append([]uint64{}, coordsBytestoUint64s(res.Coords)...),
} }
copy(r.PublicKey[:], res.Key[:]) copy(r.PublicKey[:], res.Key[:])
for _, i := range res.Infos { for _, i := range res.Infos {
e := DHTEntry{ e := DHTEntry{
Coords: append([]byte{}, i.coords...), Coords: append([]uint64{}, coordsBytestoUint64s(i.coords)...),
} }
copy(e.PublicKey[:], i.key[:]) copy(e.PublicKey[:], i.key[:])
r.Infos = append(r.Infos, e) r.Infos = append(r.Infos, e)
} }
return r, nil return r, nil
} }
return DHTRes{}, fmt.Errorf("DHT ping timeout: %s", keyString) return DHTRes{}, fmt.Errorf("DHT ping timeout: %s", hex.EncodeToString(key[:]))
} }

View File

@ -137,6 +137,27 @@ type peerInfo struct {
// This is just a uint64 with a named type for clarity reasons. // This is just a uint64 with a named type for clarity reasons.
type switchPort uint64 type switchPort uint64
func coordsUint64stoBytes(in []uint64) (out []byte) {
for _, coord := range in {
c := wire_encode_uint64(coord)
out = append(out, c...)
}
return out
}
func coordsBytestoUint64s(in []byte) (out []uint64) {
offset := 0
for {
coord, length := wire_decode_uint64(in[offset:])
if length == 0 {
break
}
out = append(out, coord)
offset += length
}
return out
}
// This is the subset of the information about a peer needed to make routing decisions, and it stored separately in an atomically accessed table, which gets hammered in the "hot loop" of the routing logic (see: peer.handleTraffic in peers.go). // This is the subset of the information about a peer needed to make routing decisions, and it stored separately in an atomically accessed table, which gets hammered in the "hot loop" of the routing logic (see: peer.handleTraffic in peers.go).
type tableElem struct { type tableElem struct {
port switchPort port switchPort