2017-12-28 22:16:20 -06:00
|
|
|
package yggdrasil
|
|
|
|
|
2018-06-12 17:50:08 -05:00
|
|
|
import (
|
|
|
|
"encoding/hex"
|
2019-07-16 09:49:28 +01:00
|
|
|
"errors"
|
2018-06-12 17:50:08 -05:00
|
|
|
"io/ioutil"
|
2019-01-14 17:21:15 +00:00
|
|
|
"time"
|
2018-06-12 17:50:08 -05:00
|
|
|
|
2019-08-28 12:17:19 +01:00
|
|
|
"github.com/Arceliar/phony"
|
2019-01-27 13:31:43 +00:00
|
|
|
"github.com/gologme/log"
|
|
|
|
|
2018-12-07 19:56:04 -06:00
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/config"
|
2018-12-14 18:30:36 -06:00
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/crypto"
|
2019-08-11 00:31:22 +03:00
|
|
|
"github.com/yggdrasil-network/yggdrasil-go/src/version"
|
2018-06-12 17:50:08 -05:00
|
|
|
)
|
2017-12-28 22:16:20 -06:00
|
|
|
|
2018-05-27 22:13:37 +01:00
|
|
|
// The Core object represents the Yggdrasil node. You should create a Core
|
|
|
|
// object for each Yggdrasil node you plan to run.
|
2017-12-28 22:16:20 -06:00
|
|
|
type Core struct {
|
2018-01-04 22:37:51 +00:00
|
|
|
// This is the main data structure that holds everything else for a node
|
2018-12-29 18:51:51 +00:00
|
|
|
// We're going to keep our own copy of the provided config - that way we can
|
|
|
|
// guarantee that it will be covered by the mutex
|
2019-08-28 19:31:04 +01:00
|
|
|
phony.Inbox
|
2019-09-18 15:22:17 +01:00
|
|
|
config config.NodeState // Config
|
|
|
|
boxPub crypto.BoxPubKey
|
|
|
|
boxPriv crypto.BoxPrivKey
|
|
|
|
sigPub crypto.SigPubKey
|
|
|
|
sigPriv crypto.SigPrivKey
|
|
|
|
switchTable switchTable
|
|
|
|
peers peers
|
|
|
|
router router
|
|
|
|
link link
|
|
|
|
log *log.Logger
|
|
|
|
addPeerTimer *time.Timer
|
2017-12-28 22:16:20 -06:00
|
|
|
}
|
|
|
|
|
2019-08-28 19:53:52 +01:00
|
|
|
func (c *Core) _init() error {
|
2018-01-04 22:37:51 +00:00
|
|
|
// TODO separate init and start functions
|
|
|
|
// Init sets up structs
|
|
|
|
// Start launches goroutines that depend on structs being set up
|
2018-01-26 17:30:51 -06:00
|
|
|
// This is pretty much required to completely avoid race conditions
|
2018-05-27 22:13:37 +01:00
|
|
|
if c.log == nil {
|
|
|
|
c.log = log.New(ioutil.Discard, "", 0)
|
|
|
|
}
|
2018-12-29 19:14:26 +00:00
|
|
|
|
2019-07-27 15:00:09 +01:00
|
|
|
current := c.config.GetCurrent()
|
2019-03-28 00:30:25 +00:00
|
|
|
|
|
|
|
boxPrivHex, err := hex.DecodeString(current.EncryptionPrivateKey)
|
2018-12-29 19:14:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-07-16 09:49:28 +01:00
|
|
|
if len(boxPrivHex) < crypto.BoxPrivKeyLen {
|
|
|
|
return errors.New("EncryptionPrivateKey is incorrect length")
|
2018-12-29 19:14:26 +00:00
|
|
|
}
|
2019-07-16 09:49:28 +01:00
|
|
|
|
2019-03-28 00:30:25 +00:00
|
|
|
sigPrivHex, err := hex.DecodeString(current.SigningPrivateKey)
|
2018-12-29 19:14:26 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-07-16 09:49:28 +01:00
|
|
|
if len(sigPrivHex) < crypto.SigPrivKeyLen {
|
|
|
|
return errors.New("SigningPrivateKey is incorrect length")
|
|
|
|
}
|
2018-12-29 19:14:26 +00:00
|
|
|
|
|
|
|
copy(c.boxPriv[:], boxPrivHex)
|
|
|
|
copy(c.sigPriv[:], sigPrivHex)
|
|
|
|
|
2019-07-16 09:49:28 +01:00
|
|
|
boxPub, sigPub := c.boxPriv.Public(), c.sigPriv.Public()
|
|
|
|
|
|
|
|
copy(c.boxPub[:], boxPub[:])
|
|
|
|
copy(c.sigPub[:], sigPub[:])
|
|
|
|
|
|
|
|
if bp := hex.EncodeToString(c.boxPub[:]); current.EncryptionPublicKey != bp {
|
|
|
|
c.log.Warnln("EncryptionPublicKey in config is incorrect, should be", bp)
|
|
|
|
}
|
|
|
|
if sp := hex.EncodeToString(c.sigPub[:]); current.SigningPublicKey != sp {
|
|
|
|
c.log.Warnln("SigningPublicKey in config is incorrect, should be", sp)
|
|
|
|
}
|
|
|
|
|
2018-01-04 22:37:51 +00:00
|
|
|
c.peers.init(c)
|
|
|
|
c.router.init(c)
|
2018-12-29 19:14:26 +00:00
|
|
|
c.switchTable.init(c) // TODO move before peers? before router?
|
|
|
|
|
|
|
|
return nil
|
2017-12-28 22:16:20 -06:00
|
|
|
}
|
|
|
|
|
2019-01-14 17:21:15 +00:00
|
|
|
// If any static peers were provided in the configuration above then we should
|
|
|
|
// configure them. The loop ensures that disconnected peers will eventually
|
|
|
|
// be reconnected with.
|
2019-08-28 19:53:52 +01:00
|
|
|
func (c *Core) _addPeerLoop() {
|
|
|
|
// Get the peers from the config - these could change!
|
|
|
|
current := c.config.GetCurrent()
|
2019-01-14 17:21:15 +00:00
|
|
|
|
2019-08-28 19:53:52 +01:00
|
|
|
// Add peers from the Peers section
|
|
|
|
for _, peer := range current.Peers {
|
2019-09-18 16:15:33 +01:00
|
|
|
go func(peer, intf string) {
|
2019-09-18 18:46:03 -05:00
|
|
|
if err := c.CallPeer(peer, intf); err != nil {
|
2019-09-18 15:01:19 +01:00
|
|
|
c.log.Errorln("Failed to add peer:", err)
|
|
|
|
}
|
2019-09-18 16:15:33 +01:00
|
|
|
}(peer, "") // TODO: this should be acted and not in a goroutine?
|
2019-08-28 19:53:52 +01:00
|
|
|
}
|
2019-01-14 17:21:15 +00:00
|
|
|
|
2019-08-28 19:53:52 +01:00
|
|
|
// Add peers from the InterfacePeers section
|
|
|
|
for intf, intfpeers := range current.InterfacePeers {
|
|
|
|
for _, peer := range intfpeers {
|
2019-09-18 16:15:33 +01:00
|
|
|
go func(peer, intf string) {
|
2019-09-18 18:46:03 -05:00
|
|
|
if err := c.CallPeer(peer, intf); err != nil {
|
2019-09-18 15:01:19 +01:00
|
|
|
c.log.Errorln("Failed to add peer:", err)
|
|
|
|
}
|
2019-09-18 16:15:33 +01:00
|
|
|
}(peer, intf) // TODO: this should be acted and not in a goroutine?
|
2019-08-28 19:53:52 +01:00
|
|
|
}
|
2019-01-14 17:21:15 +00:00
|
|
|
}
|
2019-08-28 19:53:52 +01:00
|
|
|
|
2019-09-18 15:22:17 +01:00
|
|
|
c.addPeerTimer = time.AfterFunc(time.Minute, func() {
|
2019-09-18 18:46:03 -05:00
|
|
|
c.Act(nil, c._addPeerLoop)
|
2019-08-28 19:53:52 +01:00
|
|
|
})
|
2019-01-14 17:21:15 +00:00
|
|
|
}
|
|
|
|
|
2019-03-29 18:05:17 +00:00
|
|
|
// UpdateConfig updates the configuration in Core with the provided
|
|
|
|
// config.NodeConfig and then signals the various module goroutines to
|
|
|
|
// reconfigure themselves if needed.
|
2018-12-29 18:51:51 +00:00
|
|
|
func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
2019-08-28 19:53:52 +01:00
|
|
|
c.Act(nil, func() {
|
|
|
|
c.log.Debugln("Reloading node configuration...")
|
2019-03-01 18:26:52 +00:00
|
|
|
|
2019-08-28 19:53:52 +01:00
|
|
|
// Replace the active configuration with the supplied one
|
|
|
|
c.config.Replace(*config)
|
2019-03-01 18:26:52 +00:00
|
|
|
|
2019-08-28 19:53:52 +01:00
|
|
|
// Notify the router and switch about the new configuration
|
|
|
|
c.router.Act(c, c.router.reconfigure)
|
|
|
|
c.switchTable.Act(c, c.switchTable.reconfigure)
|
|
|
|
})
|
2018-12-29 18:51:51 +00:00
|
|
|
}
|
|
|
|
|
2019-03-29 18:05:17 +00:00
|
|
|
// Start starts up Yggdrasil using the provided config.NodeConfig, and outputs
|
|
|
|
// debug logging through the provided log.Logger. The started stack will include
|
|
|
|
// TCP and UDP sockets, a multicast discovery socket, an admin socket, router,
|
|
|
|
// switch and DHT node. A config.NodeState is returned which contains both the
|
|
|
|
// current and previous configurations (from reconfigures).
|
2019-08-28 19:53:52 +01:00
|
|
|
func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) (conf *config.NodeState, err error) {
|
|
|
|
phony.Block(c, func() {
|
|
|
|
conf, err = c._start(nc, log)
|
|
|
|
})
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is unsafe and should only be ran by the core actor.
|
|
|
|
func (c *Core) _start(nc *config.NodeConfig, log *log.Logger) (*config.NodeState, error) {
|
2018-05-27 22:13:37 +01:00
|
|
|
c.log = log
|
2018-12-07 22:24:01 +00:00
|
|
|
|
2019-03-28 00:30:25 +00:00
|
|
|
c.config = config.NodeState{
|
|
|
|
Current: *nc,
|
|
|
|
Previous: *nc,
|
|
|
|
}
|
|
|
|
|
2019-08-11 00:31:22 +03:00
|
|
|
if name := version.BuildName(); name != "unknown" {
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Infoln("Build name:", name)
|
2018-12-07 22:24:01 +00:00
|
|
|
}
|
2019-08-11 00:31:22 +03:00
|
|
|
if version := version.BuildVersion(); version != "unknown" {
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Infoln("Build version:", version)
|
2018-12-07 22:24:01 +00:00
|
|
|
}
|
|
|
|
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Infoln("Starting up...")
|
2019-08-28 19:53:52 +01:00
|
|
|
c._init()
|
2018-05-27 22:13:37 +01:00
|
|
|
|
2019-01-19 12:19:24 +00:00
|
|
|
if err := c.link.init(c); err != nil {
|
2019-01-27 20:54:21 +00:00
|
|
|
c.log.Errorln("Failed to start link interfaces")
|
2019-03-28 19:09:19 +00:00
|
|
|
return nil, err
|
2019-01-19 00:42:53 +00:00
|
|
|
}
|
2019-01-04 17:14:40 +00:00
|
|
|
|
2018-06-23 19:08:32 -05:00
|
|
|
if err := c.switchTable.start(); err != nil {
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Errorln("Failed to start switch")
|
2019-03-28 19:09:19 +00:00
|
|
|
return nil, err
|
2018-06-23 19:08:32 -05:00
|
|
|
}
|
|
|
|
|
2018-05-27 22:13:37 +01:00
|
|
|
if err := c.router.start(); err != nil {
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Errorln("Failed to start router")
|
2019-03-28 19:09:19 +00:00
|
|
|
return nil, err
|
2018-05-27 22:13:37 +01:00
|
|
|
}
|
|
|
|
|
2019-09-18 15:34:26 +01:00
|
|
|
c.Act(c, c._addPeerLoop)
|
2019-01-14 17:21:15 +00:00
|
|
|
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Infoln("Startup complete")
|
2019-03-28 19:09:19 +00:00
|
|
|
return &c.config, nil
|
2018-05-27 22:13:37 +01:00
|
|
|
}
|
|
|
|
|
2019-03-29 18:05:17 +00:00
|
|
|
// Stop shuts down the Yggdrasil node.
|
2018-05-27 22:13:37 +01:00
|
|
|
func (c *Core) Stop() {
|
2019-08-28 19:53:52 +01:00
|
|
|
phony.Block(c, c._stop)
|
|
|
|
}
|
|
|
|
|
|
|
|
// This function is unsafe and should only be ran by the core actor.
|
|
|
|
func (c *Core) _stop() {
|
2019-01-27 13:31:43 +00:00
|
|
|
c.log.Infoln("Stopping...")
|
2019-09-18 15:34:26 +01:00
|
|
|
if c.addPeerTimer != nil {
|
|
|
|
c.addPeerTimer.Stop()
|
|
|
|
}
|
2019-09-18 16:32:22 +01:00
|
|
|
c.link.stop()
|
2019-09-18 15:22:17 +01:00
|
|
|
for _, peer := range c.GetPeers() {
|
|
|
|
c.DisconnectPeer(peer.Port)
|
|
|
|
}
|
2019-09-18 16:32:22 +01:00
|
|
|
c.log.Infoln("Stopped")
|
2018-05-27 22:13:37 +01:00
|
|
|
}
|