2019-05-18 16:21:02 +00:00
|
|
|
package yggdrasil
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/hex"
|
|
|
|
"errors"
|
2019-05-20 18:51:44 +00:00
|
|
|
"fmt"
|
2019-05-18 16:21:02 +00:00
|
|
|
"net"
|
|
|
|
"sort"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/gologme/log"
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/address"
|
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
2019-08-28 00:43:54 +00:00
|
|
|
|
|
|
|
"github.com/Arceliar/phony"
|
2019-05-18 16:21:02 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Peer represents a single peer object. This contains information from the
|
|
|
|
// preferred switch port for this peer, although there may be more than one in
|
|
|
|
// reality.
|
|
|
|
type Peer struct {
|
|
|
|
PublicKey crypto.BoxPubKey
|
|
|
|
Endpoint string
|
|
|
|
BytesSent uint64
|
|
|
|
BytesRecvd uint64
|
|
|
|
Protocol string
|
|
|
|
Port uint64
|
|
|
|
Uptime time.Duration
|
|
|
|
}
|
|
|
|
|
|
|
|
// SwitchPeer represents a switch connection to a peer. Note that there may be
|
|
|
|
// multiple switch peers per actual peer, e.g. if there are multiple connections
|
|
|
|
// to a given node.
|
|
|
|
type SwitchPeer struct {
|
|
|
|
PublicKey crypto.BoxPubKey
|
2019-08-05 09:17:19 +00:00
|
|
|
Coords []uint64
|
2019-05-18 16:21:02 +00:00
|
|
|
BytesSent uint64
|
|
|
|
BytesRecvd uint64
|
|
|
|
Port uint64
|
|
|
|
Protocol string
|
2019-05-19 16:27:48 +00:00
|
|
|
Endpoint string
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2019-05-19 15:29:04 +00:00
|
|
|
// DHTEntry represents a single DHT entry that has been learned or cached from
|
|
|
|
// DHT searches.
|
2019-05-18 16:21:02 +00:00
|
|
|
type DHTEntry struct {
|
|
|
|
PublicKey crypto.BoxPubKey
|
2019-08-04 23:30:12 +00:00
|
|
|
Coords []uint64
|
2019-05-18 16:21:02 +00:00
|
|
|
LastSeen time.Duration
|
|
|
|
}
|
|
|
|
|
2019-05-20 18:51:44 +00:00
|
|
|
// DHTRes represents a DHT response, as returned by DHTPing.
|
|
|
|
type DHTRes struct {
|
|
|
|
PublicKey crypto.BoxPubKey // key of the sender
|
2019-08-04 23:30:12 +00:00
|
|
|
Coords []uint64 // coords of the sender
|
2019-05-20 18:51:44 +00:00
|
|
|
Dest crypto.NodeID // the destination node ID
|
|
|
|
Infos []DHTEntry // response
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodeInfoPayload represents a RequestNodeInfo response, in bytes.
|
2019-07-28 10:30:24 +00:00
|
|
|
type NodeInfoPayload []byte
|
2019-05-20 18:51:44 +00:00
|
|
|
|
2019-05-19 15:29:04 +00:00
|
|
|
// SwitchQueues represents information from the switch related to link
|
|
|
|
// congestion and a list of switch queues created in response to congestion on a
|
|
|
|
// given link.
|
|
|
|
type SwitchQueues struct {
|
|
|
|
Queues []SwitchQueue
|
|
|
|
Count uint64
|
|
|
|
Size uint64
|
|
|
|
HighestCount uint64
|
|
|
|
HighestSize uint64
|
|
|
|
MaximumSize uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// SwitchQueue represents a single switch queue, which is created in response
|
|
|
|
// to congestion on a given link.
|
|
|
|
type SwitchQueue struct {
|
|
|
|
ID string
|
|
|
|
Size uint64
|
|
|
|
Packets uint64
|
|
|
|
Port uint64
|
|
|
|
}
|
|
|
|
|
|
|
|
// Session represents an open session with another node.
|
|
|
|
type Session struct {
|
|
|
|
PublicKey crypto.BoxPubKey
|
2019-08-05 09:17:19 +00:00
|
|
|
Coords []uint64
|
2019-05-19 15:29:04 +00:00
|
|
|
BytesSent uint64
|
|
|
|
BytesRecvd uint64
|
|
|
|
MTU uint16
|
2019-05-29 11:59:36 +00:00
|
|
|
Uptime time.Duration
|
2019-05-19 15:29:04 +00:00
|
|
|
WasMTUFixed bool
|
|
|
|
}
|
2019-05-18 16:21:02 +00:00
|
|
|
|
|
|
|
// GetPeers returns one or more Peer objects containing information about active
|
|
|
|
// peerings with other Yggdrasil nodes, where one of the responses always
|
|
|
|
// includes information about the current node (with a port number of 0). If
|
|
|
|
// there is exactly one entry then this node is not connected to any other nodes
|
|
|
|
// and is therefore isolated.
|
|
|
|
func (c *Core) GetPeers() []Peer {
|
|
|
|
ports := c.peers.ports.Load().(map[switchPort]*peer)
|
|
|
|
var peers []Peer
|
|
|
|
var ps []switchPort
|
|
|
|
for port := range ports {
|
|
|
|
ps = append(ps, port)
|
|
|
|
}
|
|
|
|
sort.Slice(ps, func(i, j int) bool { return ps[i] < ps[j] })
|
|
|
|
for _, port := range ps {
|
|
|
|
p := ports[port]
|
2019-08-24 19:24:42 +00:00
|
|
|
var info Peer
|
2019-08-28 00:43:54 +00:00
|
|
|
phony.Block(p, func() {
|
2019-08-24 19:24:42 +00:00
|
|
|
info = Peer{
|
|
|
|
Endpoint: p.intf.name,
|
|
|
|
BytesSent: p.bytesSent,
|
|
|
|
BytesRecvd: p.bytesRecvd,
|
|
|
|
Protocol: p.intf.info.linkType,
|
|
|
|
Port: uint64(port),
|
|
|
|
Uptime: time.Since(p.firstSeen),
|
|
|
|
}
|
|
|
|
copy(info.PublicKey[:], p.box[:])
|
|
|
|
})
|
2019-05-18 16:21:02 +00:00
|
|
|
peers = append(peers, info)
|
|
|
|
}
|
|
|
|
return peers
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetSwitchPeers returns zero or more SwitchPeer objects containing information
|
|
|
|
// about switch port connections with other Yggdrasil nodes. Note that, unlike
|
|
|
|
// GetPeers, GetSwitchPeers does not include information about the current node,
|
|
|
|
// therefore it is possible for this to return zero elements if the node is
|
|
|
|
// isolated or not connected to any peers.
|
|
|
|
func (c *Core) GetSwitchPeers() []SwitchPeer {
|
|
|
|
var switchpeers []SwitchPeer
|
|
|
|
table := c.switchTable.table.Load().(lookupTable)
|
|
|
|
peers := c.peers.ports.Load().(map[switchPort]*peer)
|
|
|
|
for _, elem := range table.elems {
|
|
|
|
peer, isIn := peers[elem.port]
|
|
|
|
if !isIn {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
coords := elem.locator.getCoords()
|
2019-08-24 19:24:42 +00:00
|
|
|
var info SwitchPeer
|
2019-08-28 00:43:54 +00:00
|
|
|
phony.Block(peer, func() {
|
2019-08-24 19:24:42 +00:00
|
|
|
info = SwitchPeer{
|
|
|
|
Coords: append([]uint64{}, wire_coordsBytestoUint64s(coords)...),
|
|
|
|
BytesSent: peer.bytesSent,
|
|
|
|
BytesRecvd: peer.bytesRecvd,
|
|
|
|
Port: uint64(elem.port),
|
|
|
|
Protocol: peer.intf.info.linkType,
|
|
|
|
Endpoint: peer.intf.info.remote,
|
|
|
|
}
|
|
|
|
copy(info.PublicKey[:], peer.box[:])
|
|
|
|
})
|
2019-05-18 16:21:02 +00:00
|
|
|
switchpeers = append(switchpeers, info)
|
|
|
|
}
|
|
|
|
return switchpeers
|
|
|
|
}
|
|
|
|
|
2019-05-19 15:29:04 +00:00
|
|
|
// GetDHT returns zero or more entries as stored in the DHT, cached primarily
|
|
|
|
// from searches that have already taken place.
|
2019-05-18 16:21:02 +00:00
|
|
|
func (c *Core) GetDHT() []DHTEntry {
|
2019-05-19 15:29:04 +00:00
|
|
|
var dhtentries []DHTEntry
|
|
|
|
getDHT := func() {
|
|
|
|
now := time.Now()
|
|
|
|
var dhtentry []*dhtInfo
|
2019-08-24 01:26:15 +00:00
|
|
|
for _, v := range c.router.dht.table {
|
2019-05-19 15:29:04 +00:00
|
|
|
dhtentry = append(dhtentry, v)
|
|
|
|
}
|
|
|
|
sort.SliceStable(dhtentry, func(i, j int) bool {
|
2019-08-24 01:26:15 +00:00
|
|
|
return dht_ordered(&c.router.dht.nodeID, dhtentry[i].getNodeID(), dhtentry[j].getNodeID())
|
2019-05-19 15:29:04 +00:00
|
|
|
})
|
|
|
|
for _, v := range dhtentry {
|
|
|
|
info := DHTEntry{
|
2019-08-05 09:17:19 +00:00
|
|
|
Coords: append([]uint64{}, wire_coordsBytestoUint64s(v.coords)...),
|
2019-05-19 15:29:04 +00:00
|
|
|
LastSeen: now.Sub(v.recv),
|
|
|
|
}
|
|
|
|
copy(info.PublicKey[:], v.key[:])
|
|
|
|
dhtentries = append(dhtentries, info)
|
|
|
|
}
|
|
|
|
}
|
2019-08-28 11:26:44 +00:00
|
|
|
phony.Block(&c.router, getDHT)
|
2019-05-19 15:29:04 +00:00
|
|
|
return dhtentries
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2019-05-19 15:29:04 +00:00
|
|
|
// GetSwitchQueues returns information about the switch queues that are
|
|
|
|
// currently in effect. These values can change within an instant.
|
|
|
|
func (c *Core) GetSwitchQueues() SwitchQueues {
|
|
|
|
var switchqueues SwitchQueues
|
|
|
|
switchTable := &c.switchTable
|
|
|
|
getSwitchQueues := func() {
|
|
|
|
switchqueues = SwitchQueues{
|
|
|
|
Count: uint64(len(switchTable.queues.bufs)),
|
|
|
|
Size: switchTable.queues.size,
|
|
|
|
HighestCount: uint64(switchTable.queues.maxbufs),
|
|
|
|
HighestSize: switchTable.queues.maxsize,
|
2019-08-24 20:22:46 +00:00
|
|
|
MaximumSize: switchTable.queues.totalMaxSize,
|
2019-05-19 15:29:04 +00:00
|
|
|
}
|
|
|
|
for k, v := range switchTable.queues.bufs {
|
|
|
|
nexthop := switchTable.bestPortForCoords([]byte(k))
|
|
|
|
queue := SwitchQueue{
|
|
|
|
ID: k,
|
|
|
|
Size: v.size,
|
|
|
|
Packets: uint64(len(v.packets)),
|
|
|
|
Port: uint64(nexthop),
|
|
|
|
}
|
|
|
|
switchqueues.Queues = append(switchqueues.Queues, queue)
|
|
|
|
}
|
|
|
|
}
|
2019-08-28 11:26:44 +00:00
|
|
|
phony.Block(&c.switchTable, getSwitchQueues)
|
2019-05-19 15:29:04 +00:00
|
|
|
return switchqueues
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2019-05-19 15:29:04 +00:00
|
|
|
// GetSessions returns a list of open sessions from this node to other nodes.
|
2019-05-18 16:21:02 +00:00
|
|
|
func (c *Core) GetSessions() []Session {
|
2019-05-19 15:29:04 +00:00
|
|
|
var sessions []Session
|
|
|
|
getSessions := func() {
|
2019-08-24 01:26:15 +00:00
|
|
|
for _, sinfo := range c.router.sessions.sinfos {
|
2019-06-29 23:56:26 +00:00
|
|
|
var session Session
|
|
|
|
workerFunc := func() {
|
2019-06-30 00:25:34 +00:00
|
|
|
session = Session{
|
2019-08-05 09:17:19 +00:00
|
|
|
Coords: append([]uint64{}, wire_coordsBytestoUint64s(sinfo.coords)...),
|
2019-08-24 01:05:18 +00:00
|
|
|
MTU: sinfo._getMTU(),
|
2019-06-29 23:56:26 +00:00
|
|
|
BytesSent: sinfo.bytesSent,
|
|
|
|
BytesRecvd: sinfo.bytesRecvd,
|
|
|
|
Uptime: time.Now().Sub(sinfo.timeOpened),
|
|
|
|
WasMTUFixed: sinfo.wasMTUFixed,
|
|
|
|
}
|
|
|
|
copy(session.PublicKey[:], sinfo.theirPermPub[:])
|
|
|
|
}
|
2019-08-30 02:59:28 +00:00
|
|
|
phony.Block(sinfo, workerFunc)
|
2019-06-29 23:56:26 +00:00
|
|
|
// TODO? skipped known but timed out sessions?
|
2019-05-19 15:29:04 +00:00
|
|
|
sessions = append(sessions, session)
|
|
|
|
}
|
|
|
|
}
|
2019-08-28 11:26:44 +00:00
|
|
|
phony.Block(&c.router, getSessions)
|
2019-05-19 15:29:04 +00:00
|
|
|
return sessions
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-28 10:35:16 +00:00
|
|
|
// ConnListen returns a listener for Yggdrasil session connections.
|
2019-05-18 16:21:02 +00:00
|
|
|
func (c *Core) ConnListen() (*Listener, error) {
|
2019-08-24 01:26:15 +00:00
|
|
|
c.router.sessions.listenerMutex.Lock()
|
|
|
|
defer c.router.sessions.listenerMutex.Unlock()
|
|
|
|
if c.router.sessions.listener != nil {
|
2019-05-18 16:21:02 +00:00
|
|
|
return nil, errors.New("a listener already exists")
|
|
|
|
}
|
2019-08-24 01:26:15 +00:00
|
|
|
c.router.sessions.listener = &Listener{
|
2019-05-18 16:21:02 +00:00
|
|
|
core: c,
|
|
|
|
conn: make(chan *Conn),
|
|
|
|
close: make(chan interface{}),
|
|
|
|
}
|
2019-08-24 01:26:15 +00:00
|
|
|
return c.router.sessions.listener, nil
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ConnDialer returns a dialer for Yggdrasil session connections.
|
|
|
|
func (c *Core) ConnDialer() (*Dialer, error) {
|
|
|
|
return &Dialer{
|
|
|
|
core: c,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// ListenTCP starts a new TCP listener. The input URI should match that of the
|
|
|
|
// "Listen" configuration item, e.g.
|
|
|
|
// tcp://a.b.c.d:e
|
|
|
|
func (c *Core) ListenTCP(uri string) (*TcpListener, error) {
|
|
|
|
return c.link.tcp.listen(uri)
|
|
|
|
}
|
|
|
|
|
|
|
|
// NodeID gets the node ID.
|
|
|
|
func (c *Core) NodeID() *crypto.NodeID {
|
|
|
|
return crypto.GetNodeID(&c.boxPub)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TreeID gets the tree ID.
|
|
|
|
func (c *Core) TreeID() *crypto.TreeID {
|
|
|
|
return crypto.GetTreeID(&c.sigPub)
|
|
|
|
}
|
|
|
|
|
2019-07-28 10:35:16 +00:00
|
|
|
// SigningPublicKey gets the node's signing public key.
|
2019-07-28 10:30:24 +00:00
|
|
|
func (c *Core) SigningPublicKey() string {
|
2019-05-18 16:21:02 +00:00
|
|
|
return hex.EncodeToString(c.sigPub[:])
|
|
|
|
}
|
|
|
|
|
2019-07-28 10:35:16 +00:00
|
|
|
// EncryptionPublicKey gets the node's encryption public key.
|
2019-07-28 10:30:24 +00:00
|
|
|
func (c *Core) EncryptionPublicKey() string {
|
2019-05-18 16:21:02 +00:00
|
|
|
return hex.EncodeToString(c.boxPub[:])
|
|
|
|
}
|
|
|
|
|
2019-05-19 16:27:48 +00:00
|
|
|
// Coords returns the current coordinates of the node.
|
2019-08-05 09:17:19 +00:00
|
|
|
func (c *Core) Coords() []uint64 {
|
2019-05-19 16:27:48 +00:00
|
|
|
table := c.switchTable.table.Load().(lookupTable)
|
2019-08-05 09:17:19 +00:00
|
|
|
return wire_coordsBytestoUint64s(table.self.getCoords())
|
2019-05-19 16:27:48 +00:00
|
|
|
}
|
|
|
|
|
2019-05-18 16:21:02 +00:00
|
|
|
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
|
|
|
|
// address.
|
2019-07-28 10:30:24 +00:00
|
|
|
func (c *Core) Address() net.IP {
|
2019-05-18 16:21:02 +00:00
|
|
|
address := net.IP(address.AddrForNodeID(c.NodeID())[:])
|
2019-07-28 10:30:24 +00:00
|
|
|
return address
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
|
|
|
|
// /64 subnet.
|
2019-07-28 10:30:24 +00:00
|
|
|
func (c *Core) Subnet() net.IPNet {
|
2019-05-18 16:21:02 +00:00
|
|
|
subnet := address.SubnetForNodeID(c.NodeID())[:]
|
|
|
|
subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
|
2019-07-28 10:30:24 +00:00
|
|
|
return net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
|
|
|
|
2019-07-28 10:30:24 +00:00
|
|
|
// MyNodeInfo gets the currently configured nodeinfo.
|
|
|
|
func (c *Core) MyNodeInfo() NodeInfoPayload {
|
2019-05-18 16:21:02 +00:00
|
|
|
return c.router.nodeinfo.getNodeInfo()
|
|
|
|
}
|
|
|
|
|
2019-08-05 09:17:19 +00:00
|
|
|
// SetNodeInfo sets the local nodeinfo. Note that nodeinfo can be any value or
|
|
|
|
// struct, it will be serialised into JSON automatically.
|
2019-05-18 16:21:02 +00:00
|
|
|
func (c *Core) SetNodeInfo(nodeinfo interface{}, nodeinfoprivacy bool) {
|
|
|
|
c.router.nodeinfo.setNodeInfo(nodeinfo, nodeinfoprivacy)
|
|
|
|
}
|
|
|
|
|
2019-05-20 18:51:44 +00:00
|
|
|
// GetNodeInfo requests nodeinfo from a remote node, as specified by the public
|
|
|
|
// key and coordinates specified. The third parameter specifies whether a cached
|
|
|
|
// result is acceptable - this results in less traffic being generated than is
|
|
|
|
// necessary when, e.g. crawling the network.
|
2019-08-05 09:17:19 +00:00
|
|
|
func (c *Core) GetNodeInfo(key crypto.BoxPubKey, coords []uint64, nocache bool) (NodeInfoPayload, error) {
|
2019-07-28 10:30:24 +00:00
|
|
|
response := make(chan *NodeInfoPayload, 1)
|
2019-05-20 18:51:44 +00:00
|
|
|
sendNodeInfoRequest := func() {
|
2019-07-28 10:30:24 +00:00
|
|
|
c.router.nodeinfo.addCallback(key, func(nodeinfo *NodeInfoPayload) {
|
2019-05-20 18:51:44 +00:00
|
|
|
defer func() { recover() }()
|
|
|
|
select {
|
|
|
|
case response <- nodeinfo:
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
})
|
2019-08-05 09:17:19 +00:00
|
|
|
c.router.nodeinfo.sendNodeInfo(key, wire_coordsUint64stoBytes(coords), false)
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
2019-08-28 11:26:44 +00:00
|
|
|
phony.Block(&c.router, sendNodeInfoRequest)
|
2019-08-25 22:00:02 +00:00
|
|
|
timer := time.AfterFunc(6*time.Second, func() { close(response) })
|
|
|
|
defer timer.Stop()
|
2019-05-20 18:51:44 +00:00
|
|
|
for res := range response {
|
2019-07-28 10:30:24 +00:00
|
|
|
return *res, nil
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
2019-08-04 23:30:12 +00:00
|
|
|
return NodeInfoPayload{}, fmt.Errorf("getNodeInfo timeout: %s", hex.EncodeToString(key[:]))
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
|
|
|
|
2019-06-11 09:52:21 +00:00
|
|
|
// SetSessionGatekeeper allows you to configure a handler function for deciding
|
|
|
|
// whether a session should be allowed or not. The default session firewall is
|
|
|
|
// implemented in this way. The function receives the public key of the remote
|
2019-06-11 11:52:13 +00:00
|
|
|
// side and a boolean which is true if we initiated the session or false if we
|
|
|
|
// received an incoming session request. The function should return true to
|
|
|
|
// allow the session or false to reject it.
|
2019-06-11 09:52:21 +00:00
|
|
|
func (c *Core) SetSessionGatekeeper(f func(pubkey *crypto.BoxPubKey, initiator bool) bool) {
|
2019-08-24 01:26:15 +00:00
|
|
|
c.router.sessions.isAllowedMutex.Lock()
|
|
|
|
defer c.router.sessions.isAllowedMutex.Unlock()
|
2019-06-11 09:52:21 +00:00
|
|
|
|
2019-08-24 01:26:15 +00:00
|
|
|
c.router.sessions.isAllowedHandler = f
|
2019-06-11 09:52:21 +00:00
|
|
|
}
|
|
|
|
|
2019-05-18 16:21:02 +00:00
|
|
|
// SetLogger sets the output logger of the Yggdrasil node after startup. This
|
|
|
|
// may be useful if you want to redirect the output later.
|
|
|
|
func (c *Core) SetLogger(log *log.Logger) {
|
|
|
|
c.log = log
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddPeer adds a peer. This should be specified in the peer URI format, e.g.:
|
|
|
|
// tcp://a.b.c.d:e
|
|
|
|
// socks://a.b.c.d:e/f.g.h.i:j
|
|
|
|
// This adds the peer to the peer list, so that they will be called again if the
|
|
|
|
// connection drops.
|
|
|
|
func (c *Core) AddPeer(addr string, sintf string) error {
|
|
|
|
if err := c.CallPeer(addr, sintf); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
c.config.Mutex.Lock()
|
|
|
|
if sintf == "" {
|
|
|
|
c.config.Current.Peers = append(c.config.Current.Peers, addr)
|
|
|
|
} else {
|
|
|
|
c.config.Current.InterfacePeers[sintf] = append(c.config.Current.InterfacePeers[sintf], addr)
|
|
|
|
}
|
|
|
|
c.config.Mutex.Unlock()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-05-20 18:51:44 +00:00
|
|
|
// RemovePeer is not implemented yet.
|
|
|
|
func (c *Core) RemovePeer(addr string, sintf string) error {
|
|
|
|
// TODO: Implement a reverse of AddPeer, where we look up the port number
|
|
|
|
// based on the addr and sintf, disconnect it and then remove it from the
|
|
|
|
// peers list so we don't reconnect to it later
|
|
|
|
return errors.New("not implemented")
|
|
|
|
}
|
|
|
|
|
2019-05-18 16:21:02 +00:00
|
|
|
// CallPeer calls a peer once. This should be specified in the peer URI format,
|
|
|
|
// e.g.:
|
|
|
|
// tcp://a.b.c.d:e
|
|
|
|
// socks://a.b.c.d:e/f.g.h.i:j
|
|
|
|
// This does not add the peer to the peer list, so if the connection drops, the
|
|
|
|
// peer will not be called again automatically.
|
|
|
|
func (c *Core) CallPeer(addr string, sintf string) error {
|
|
|
|
return c.link.call(addr, sintf)
|
|
|
|
}
|
|
|
|
|
2019-05-20 18:51:44 +00:00
|
|
|
// DisconnectPeer disconnects a peer once. This should be specified as a port
|
|
|
|
// number.
|
|
|
|
func (c *Core) DisconnectPeer(port uint64) error {
|
|
|
|
c.peers.removePeer(switchPort(port))
|
2019-05-19 16:27:48 +00:00
|
|
|
return nil
|
2019-05-18 16:21:02 +00:00
|
|
|
}
|
2019-05-20 18:51:44 +00:00
|
|
|
|
|
|
|
// GetAllowedEncryptionPublicKeys returns the public keys permitted for incoming
|
|
|
|
// peer connections.
|
|
|
|
func (c *Core) GetAllowedEncryptionPublicKeys() []string {
|
|
|
|
return c.peers.getAllowedEncryptionPublicKeys()
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddAllowedEncryptionPublicKey whitelists a key for incoming peer connections.
|
|
|
|
func (c *Core) AddAllowedEncryptionPublicKey(bstr string) (err error) {
|
|
|
|
c.peers.addAllowedEncryptionPublicKey(bstr)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RemoveAllowedEncryptionPublicKey removes a key from the whitelist for
|
|
|
|
// incoming peer connections. If none are set, an empty list permits all
|
|
|
|
// incoming connections.
|
|
|
|
func (c *Core) RemoveAllowedEncryptionPublicKey(bstr string) (err error) {
|
|
|
|
c.peers.removeAllowedEncryptionPublicKey(bstr)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-07-28 10:35:16 +00:00
|
|
|
// DHTPing sends a DHT ping to the node with the provided key and coords,
|
|
|
|
// optionally looking up the specified target NodeID.
|
2019-08-04 23:30:12 +00:00
|
|
|
func (c *Core) DHTPing(key crypto.BoxPubKey, coords []uint64, target *crypto.NodeID) (DHTRes, error) {
|
2019-05-20 18:51:44 +00:00
|
|
|
resCh := make(chan *dhtRes, 1)
|
|
|
|
info := dhtInfo{
|
|
|
|
key: key,
|
2019-08-05 09:17:19 +00:00
|
|
|
coords: wire_coordsUint64stoBytes(coords),
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
2019-08-04 23:30:12 +00:00
|
|
|
if target == nil {
|
|
|
|
target = info.getNodeID()
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
2019-08-04 23:30:12 +00:00
|
|
|
rq := dhtReqKey{info.key, *target}
|
2019-05-20 18:51:44 +00:00
|
|
|
sendPing := func() {
|
2019-08-24 01:26:15 +00:00
|
|
|
c.router.dht.addCallback(&rq, func(res *dhtRes) {
|
2019-06-26 00:31:29 +00:00
|
|
|
resCh <- res
|
2019-05-20 18:51:44 +00:00
|
|
|
})
|
2019-08-24 01:26:15 +00:00
|
|
|
c.router.dht.ping(&info, &rq.dest)
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
2019-08-28 11:26:44 +00:00
|
|
|
phony.Block(&c.router, sendPing)
|
2019-05-20 18:51:44 +00:00
|
|
|
// TODO: do something better than the below...
|
2019-06-26 00:31:29 +00:00
|
|
|
res := <-resCh
|
|
|
|
if res != nil {
|
2019-05-20 18:51:44 +00:00
|
|
|
r := DHTRes{
|
2019-08-05 09:17:19 +00:00
|
|
|
Coords: append([]uint64{}, wire_coordsBytestoUint64s(res.Coords)...),
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
|
|
|
copy(r.PublicKey[:], res.Key[:])
|
|
|
|
for _, i := range res.Infos {
|
|
|
|
e := DHTEntry{
|
2019-08-05 09:17:19 +00:00
|
|
|
Coords: append([]uint64{}, wire_coordsBytestoUint64s(i.coords)...),
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|
|
|
|
copy(e.PublicKey[:], i.key[:])
|
|
|
|
r.Infos = append(r.Infos, e)
|
|
|
|
}
|
|
|
|
return r, nil
|
|
|
|
}
|
2019-08-04 23:30:12 +00:00
|
|
|
return DHTRes{}, fmt.Errorf("DHT ping timeout: %s", hex.EncodeToString(key[:]))
|
2019-05-20 18:51:44 +00:00
|
|
|
}
|