Searches called from api.go, various other tweaks, searches now have a callback for success/failure, node ID now reported by admin socket

This commit is contained in:
Neil Alexander 2019-04-18 23:38:23 +01:00
parent eef2a02d0a
commit 160e01e84f
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
7 changed files with 177 additions and 81 deletions

View file

@ -6,11 +6,13 @@ import (
"time"
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
"github.com/yggdrasil-network/yggdrasil-go/src/util"
)
func (c *Core) Dial(network, address string) (Conn, error) {
var nodeID *crypto.NodeID
var nodeMask *crypto.NodeID
conn := Conn{}
nodeID := crypto.NodeID{}
nodeMask := crypto.NodeID{}
// Process
switch network {
case "nodeid":
@ -20,22 +22,51 @@ func (c *Core) Dial(network, address string) (Conn, error) {
return Conn{}, err
}
copy(nodeID[:], dest)
var m crypto.NodeID
for i := range dest {
m[i] = 0xFF
for i := range nodeMask {
nodeMask[i] = 0xFF
}
copy(nodeMask[:], m[:])
default:
// An unexpected address type was given, so give up
return Conn{}, errors.New("unexpected address type")
}
conn.core = c
conn.nodeID = &nodeID
conn.nodeMask = &nodeMask
conn.core.router.doAdmin(func() {
conn.startSearch()
})
return conn, nil
}
type Conn struct {
core *Core
nodeID *crypto.NodeID
nodeMask *crypto.NodeID
session *sessionInfo
readDeadline time.Time
writeDeadline time.Time
}
// This method should only be called from the router goroutine
func (c *Conn) startSearch() {
searchCompleted := func(sinfo *sessionInfo, err error) {
if err != nil {
c.core.log.Debugln("DHT search failed:", err)
return
}
if sinfo != nil {
c.session = sinfo
c.core.log.Println("Search from API found", hex.EncodeToString(sinfo.theirPermPub[:]))
}
}
// Try and search for the node on the network
doSearch := func() {
sinfo, isIn := c.searches.searches[*nodeID]
sinfo, isIn := c.core.searches.searches[*c.nodeID]
if !isIn {
sinfo = c.searches.newIterSearch(nodeID, nodeMask)
c.core.log.Debugln("Starting search for", hex.EncodeToString(c.nodeID[:]))
sinfo = c.core.searches.newIterSearch(c.nodeID, c.nodeMask, searchCompleted)
}
c.searches.continueSearch(sinfo)
c.core.searches.continueSearch(sinfo)
}
var sinfo *sessionInfo
var isIn bool
@ -61,27 +92,62 @@ func (c *Core) Dial(network, address string) (Conn, error) {
if time.Since(sinfo.pingSend) > time.Second {
// Send at most 1 ping per second
sinfo.pingSend = now
c.sessions.sendPingPong(sinfo, false)
c.core.sessions.sendPingPong(sinfo, false)
}
}
}
return Conn{
session: sinfo,
}, nil
}
type Conn struct {
session *sessionInfo
readDeadline time.Time
writeDeadline time.Time
}
func (c *Conn) Read(b []byte) (int, error) {
return 0, nil
if c.session == nil {
return 0, errors.New("invalid session")
}
p := <-c.session.recv
defer util.PutBytes(p.Payload)
if !c.session.nonceIsOK(&p.Nonce) {
return 0, errors.New("invalid nonce")
}
bs, isOK := crypto.BoxOpen(&c.session.sharedSesKey, p.Payload, &p.Nonce)
if !isOK {
util.PutBytes(bs)
return 0, errors.New("failed to decrypt")
}
b = b[:0]
b = append(b, bs...)
c.session.updateNonce(&p.Nonce)
c.session.time = time.Now()
c.session.bytesRecvd += uint64(len(bs))
return len(b), nil
}
func (c *Conn) Write(b []byte) (int, error) {
return 0, nil
if c.session == nil {
c.core.router.doAdmin(func() {
c.startSearch()
})
return 0, errors.New("invalid session")
}
defer util.PutBytes(b)
if !c.session.init {
// To prevent using empty session keys
return 0, errors.New("session not initialised")
}
// code isn't multithreaded so appending to this is safe
coords := c.session.coords
// Prepare the payload
payload, nonce := crypto.BoxSeal(&c.session.sharedSesKey, b, &c.session.myNonce)
defer util.PutBytes(payload)
p := wire_trafficPacket{
Coords: coords,
Handle: c.session.theirHandle,
Nonce: *nonce,
Payload: payload,
}
packet := p.encode()
c.session.bytesSent += uint64(len(b))
c.session.send <- packet
//c.session.core.router.out(packet)
return len(b), nil
}
func (c *Conn) Close() error {