mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-23 18:15:24 +00:00
Support notifying components for config reload, listen for SIGHUP
This commit is contained in:
parent
b4a7dab34d
commit
219fb96553
@ -314,7 +314,9 @@ func main() {
|
|||||||
logger.Printf("Your IPv6 subnet is %s", subnet.String())
|
logger.Printf("Your IPv6 subnet is %s", subnet.String())
|
||||||
// Catch interrupts from the operating system to exit gracefully.
|
// Catch interrupts from the operating system to exit gracefully.
|
||||||
c := make(chan os.Signal, 1)
|
c := make(chan os.Signal, 1)
|
||||||
|
r := make(chan os.Signal, 1)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
|
signal.Notify(r, os.Interrupt, syscall.SIGHUP)
|
||||||
// Create a function to capture the service being stopped on Windows.
|
// Create a function to capture the service being stopped on Windows.
|
||||||
winTerminate := func() {
|
winTerminate := func() {
|
||||||
c <- os.Interrupt
|
c <- os.Interrupt
|
||||||
@ -322,5 +324,13 @@ func main() {
|
|||||||
minwinsvc.SetOnExit(winTerminate)
|
minwinsvc.SetOnExit(winTerminate)
|
||||||
// Wait for the terminate/interrupt signal. Once a signal is received, the
|
// Wait for the terminate/interrupt signal. Once a signal is received, the
|
||||||
// deferred Stop function above will run which will shut down TUN/TAP.
|
// deferred Stop function above will run which will shut down TUN/TAP.
|
||||||
<-c
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-r:
|
||||||
|
n.core.UpdateConfig(cfg)
|
||||||
|
case _ = <-c:
|
||||||
|
goto exit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
|
|
||||||
type admin struct {
|
type admin struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
listenaddr string
|
listenaddr string
|
||||||
listener net.Listener
|
listener net.Listener
|
||||||
handlers []admin_handlerInfo
|
handlers []admin_handlerInfo
|
||||||
@ -53,6 +54,21 @@ func (a *admin) addHandler(name string, args []string, handler func(admin_info)
|
|||||||
// init runs the initial admin setup.
|
// init runs the initial admin setup.
|
||||||
func (a *admin) init(c *Core, listenaddr string) {
|
func (a *admin) init(c *Core, listenaddr string) {
|
||||||
a.core = c
|
a.core = c
|
||||||
|
a.reconfigure = make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-a.reconfigure:
|
||||||
|
a.core.configMutex.RLock()
|
||||||
|
a.core.log.Println("Notified: admin")
|
||||||
|
if a.core.config.AdminListen != a.core.configOld.AdminListen {
|
||||||
|
a.core.log.Println("AdminListen has changed!")
|
||||||
|
}
|
||||||
|
a.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
a.listenaddr = listenaddr
|
a.listenaddr = listenaddr
|
||||||
a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) {
|
a.addHandler("list", []string{}, func(in admin_info) (admin_info, error) {
|
||||||
handlers := make(map[string]interface{})
|
handlers := make(map[string]interface{})
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"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"
|
||||||
@ -17,14 +18,26 @@ import (
|
|||||||
var buildName string
|
var buildName string
|
||||||
var buildVersion string
|
var buildVersion string
|
||||||
|
|
||||||
|
type module interface {
|
||||||
|
init(*config.NodeConfig) error
|
||||||
|
start() error
|
||||||
|
}
|
||||||
|
|
||||||
// The Core object represents the Yggdrasil node. You should create a Core
|
// The Core object represents the Yggdrasil node. You should create a Core
|
||||||
// object for each Yggdrasil node you plan to run.
|
// object for each Yggdrasil node you plan to run.
|
||||||
type Core struct {
|
type Core struct {
|
||||||
// This is the main data structure that holds everything else for a node
|
// This is the main data structure that holds everything else for a node
|
||||||
|
// 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
|
||||||
|
config config.NodeConfig // Active config
|
||||||
|
configOld config.NodeConfig // Previous config
|
||||||
|
configMutex sync.RWMutex // Protects both config and configOld
|
||||||
|
// Core-specific config
|
||||||
boxPub crypto.BoxPubKey
|
boxPub crypto.BoxPubKey
|
||||||
boxPriv crypto.BoxPrivKey
|
boxPriv crypto.BoxPrivKey
|
||||||
sigPub crypto.SigPubKey
|
sigPub crypto.SigPubKey
|
||||||
sigPriv crypto.SigPrivKey
|
sigPriv crypto.SigPrivKey
|
||||||
|
// Modules
|
||||||
switchTable switchTable
|
switchTable switchTable
|
||||||
peers peers
|
peers peers
|
||||||
sessions sessions
|
sessions sessions
|
||||||
@ -35,6 +48,7 @@ type Core struct {
|
|||||||
multicast multicast
|
multicast multicast
|
||||||
nodeinfo nodeinfo
|
nodeinfo nodeinfo
|
||||||
tcp tcpInterface
|
tcp tcpInterface
|
||||||
|
// Other bits
|
||||||
log *log.Logger
|
log *log.Logger
|
||||||
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
|
ifceExpr []*regexp.Regexp // the zone of link-local IPv6 peers must match this
|
||||||
}
|
}
|
||||||
@ -62,8 +76,26 @@ func (c *Core) init(bpub *crypto.BoxPubKey,
|
|||||||
c.switchTable.init(c, c.sigPub) // TODO move before peers? before router?
|
c.switchTable.init(c, c.sigPub) // TODO move before peers? before router?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the current build name. This is usually injected if built from git,
|
// UpdateConfig updates the configuration in Core and then signals the
|
||||||
// or returns "unknown" otherwise.
|
// various module goroutines to reconfigure themselves if needed
|
||||||
|
func (c *Core) UpdateConfig(config *config.NodeConfig) {
|
||||||
|
c.configMutex.Lock()
|
||||||
|
c.configOld = c.config
|
||||||
|
c.config = *config
|
||||||
|
c.configMutex.Unlock()
|
||||||
|
|
||||||
|
c.admin.reconfigure <- true
|
||||||
|
c.searches.reconfigure <- true
|
||||||
|
c.dht.reconfigure <- true
|
||||||
|
c.sessions.reconfigure <- true
|
||||||
|
c.multicast.reconfigure <- true
|
||||||
|
c.peers.reconfigure <- true
|
||||||
|
c.router.reconfigure <- true
|
||||||
|
c.switchTable.reconfigure <- true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBuildName gets the current build name. This is usually injected if built
|
||||||
|
// from git, or returns "unknown" otherwise.
|
||||||
func GetBuildName() string {
|
func GetBuildName() string {
|
||||||
if buildName == "" {
|
if buildName == "" {
|
||||||
return "unknown"
|
return "unknown"
|
||||||
@ -96,6 +128,11 @@ func (c *Core) Start(nc *config.NodeConfig, log *log.Logger) error {
|
|||||||
|
|
||||||
c.log.Println("Starting up...")
|
c.log.Println("Starting up...")
|
||||||
|
|
||||||
|
c.configMutex.Lock()
|
||||||
|
c.config = *nc
|
||||||
|
c.configOld = c.config
|
||||||
|
c.configMutex.Unlock()
|
||||||
|
|
||||||
var boxPub crypto.BoxPubKey
|
var boxPub crypto.BoxPubKey
|
||||||
var boxPriv crypto.BoxPrivKey
|
var boxPriv crypto.BoxPrivKey
|
||||||
var sigPub crypto.SigPubKey
|
var sigPub crypto.SigPubKey
|
||||||
|
@ -66,6 +66,7 @@ type dhtReqKey struct {
|
|||||||
// The main DHT struct.
|
// The main DHT struct.
|
||||||
type dht struct {
|
type dht struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
nodeID crypto.NodeID
|
nodeID crypto.NodeID
|
||||||
peers chan *dhtInfo // other goroutines put incoming dht updates here
|
peers chan *dhtInfo // other goroutines put incoming dht updates here
|
||||||
reqs map[dhtReqKey]time.Time // Keeps track of recent outstanding requests
|
reqs map[dhtReqKey]time.Time // Keeps track of recent outstanding requests
|
||||||
@ -78,6 +79,18 @@ type dht struct {
|
|||||||
// Initializes the DHT.
|
// Initializes the DHT.
|
||||||
func (t *dht) init(c *Core) {
|
func (t *dht) init(c *Core) {
|
||||||
t.core = c
|
t.core = c
|
||||||
|
t.reconfigure = make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-t.reconfigure:
|
||||||
|
t.core.configMutex.RLock()
|
||||||
|
t.core.log.Println("Notified: dht")
|
||||||
|
t.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
t.nodeID = *t.core.GetNodeID()
|
t.nodeID = *t.core.GetNodeID()
|
||||||
t.peers = make(chan *dhtInfo, 1024)
|
t.peers = make(chan *dhtInfo, 1024)
|
||||||
t.callbacks = make(map[dhtReqKey]dht_callbackInfo)
|
t.callbacks = make(map[dhtReqKey]dht_callbackInfo)
|
||||||
|
@ -11,12 +11,25 @@ import (
|
|||||||
|
|
||||||
type multicast struct {
|
type multicast struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
sock *ipv6.PacketConn
|
sock *ipv6.PacketConn
|
||||||
groupAddr string
|
groupAddr string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multicast) init(core *Core) {
|
func (m *multicast) init(core *Core) {
|
||||||
m.core = core
|
m.core = core
|
||||||
|
m.reconfigure = make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-m.reconfigure:
|
||||||
|
m.core.configMutex.RLock()
|
||||||
|
m.core.log.Println("Notified: multicast")
|
||||||
|
m.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
m.groupAddr = "[ff02::114]:9001"
|
m.groupAddr = "[ff02::114]:9001"
|
||||||
// Check if we've been given any expressions
|
// Check if we've been given any expressions
|
||||||
if len(m.core.ifceExpr) == 0 {
|
if len(m.core.ifceExpr) == 0 {
|
||||||
|
@ -19,6 +19,7 @@ import (
|
|||||||
// In other cases, it's link protocol traffic used to build the spanning tree, in which case this checks signatures and passes the message along to the switch.
|
// In other cases, it's link protocol traffic used to build the spanning tree, in which case this checks signatures and passes the message along to the switch.
|
||||||
type peers struct {
|
type peers struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
mutex sync.Mutex // Synchronize writes to atomic
|
mutex sync.Mutex // Synchronize writes to atomic
|
||||||
ports atomic.Value //map[switchPort]*peer, use CoW semantics
|
ports atomic.Value //map[switchPort]*peer, use CoW semantics
|
||||||
authMutex sync.RWMutex
|
authMutex sync.RWMutex
|
||||||
@ -31,6 +32,18 @@ func (ps *peers) init(c *Core) {
|
|||||||
defer ps.mutex.Unlock()
|
defer ps.mutex.Unlock()
|
||||||
ps.putPorts(make(map[switchPort]*peer))
|
ps.putPorts(make(map[switchPort]*peer))
|
||||||
ps.core = c
|
ps.core = c
|
||||||
|
ps.reconfigure = make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-ps.reconfigure:
|
||||||
|
ps.core.configMutex.RLock()
|
||||||
|
ps.core.log.Println("Notified: peers")
|
||||||
|
ps.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
ps.allowedEncryptionPublicKeys = make(map[crypto.BoxPubKey]struct{})
|
ps.allowedEncryptionPublicKeys = make(map[crypto.BoxPubKey]struct{})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ import (
|
|||||||
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
|
// The router's mainLoop goroutine is responsible for managing all information related to the dht, searches, and crypto sessions.
|
||||||
type router struct {
|
type router struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
addr address.Address
|
addr address.Address
|
||||||
subnet address.Subnet
|
subnet address.Subnet
|
||||||
in <-chan []byte // packets we received from the network, link to peer's "out"
|
in <-chan []byte // packets we received from the network, link to peer's "out"
|
||||||
@ -61,6 +62,7 @@ type router_recvPacket struct {
|
|||||||
// Initializes the router struct, which includes setting up channels to/from the tun/tap.
|
// Initializes the router struct, which includes setting up channels to/from the tun/tap.
|
||||||
func (r *router) init(core *Core) {
|
func (r *router) init(core *Core) {
|
||||||
r.core = core
|
r.core = core
|
||||||
|
r.reconfigure = make(chan bool, 1)
|
||||||
r.addr = *address.AddrForNodeID(&r.core.dht.nodeID)
|
r.addr = *address.AddrForNodeID(&r.core.dht.nodeID)
|
||||||
r.subnet = *address.SubnetForNodeID(&r.core.dht.nodeID)
|
r.subnet = *address.SubnetForNodeID(&r.core.dht.nodeID)
|
||||||
in := make(chan []byte, 32) // TODO something better than this...
|
in := make(chan []byte, 32) // TODO something better than this...
|
||||||
@ -124,6 +126,11 @@ func (r *router) mainLoop() {
|
|||||||
}
|
}
|
||||||
case f := <-r.admin:
|
case f := <-r.admin:
|
||||||
f()
|
f()
|
||||||
|
case _ = <-r.reconfigure:
|
||||||
|
r.core.configMutex.RLock()
|
||||||
|
r.core.log.Println("Notified: router")
|
||||||
|
r.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,12 +43,25 @@ type searchInfo struct {
|
|||||||
// This stores a map of active searches.
|
// This stores a map of active searches.
|
||||||
type searches struct {
|
type searches struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
searches map[crypto.NodeID]*searchInfo
|
searches map[crypto.NodeID]*searchInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intializes the searches struct.
|
// Intializes the searches struct.
|
||||||
func (s *searches) init(core *Core) {
|
func (s *searches) init(core *Core) {
|
||||||
s.core = core
|
s.core = core
|
||||||
|
s.reconfigure = make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case _ = <-s.reconfigure:
|
||||||
|
s.core.configMutex.RLock()
|
||||||
|
s.core.log.Println("Notified: searches")
|
||||||
|
s.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
s.searches = make(map[crypto.NodeID]*searchInfo)
|
s.searches = make(map[crypto.NodeID]*searchInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ import (
|
|||||||
// This includes coords, permanent and ephemeral keys, handles and nonces, various sorts of timing information for timeout and maintenance, and some metadata for the admin API.
|
// This includes coords, permanent and ephemeral keys, handles and nonces, various sorts of timing information for timeout and maintenance, and some metadata for the admin API.
|
||||||
type sessionInfo struct {
|
type sessionInfo struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
theirAddr address.Address
|
theirAddr address.Address
|
||||||
theirSubnet address.Subnet
|
theirSubnet address.Subnet
|
||||||
theirPermPub crypto.BoxPubKey
|
theirPermPub crypto.BoxPubKey
|
||||||
@ -101,6 +102,7 @@ func (s *sessionInfo) timedout() bool {
|
|||||||
// Additionally, stores maps of address/subnet onto keys, and keys onto handles.
|
// Additionally, stores maps of address/subnet onto keys, and keys onto handles.
|
||||||
type sessions struct {
|
type sessions struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
lastCleanup time.Time
|
lastCleanup time.Time
|
||||||
// Maps known permanent keys to their shared key, used by DHT a lot
|
// Maps known permanent keys to their shared key, used by DHT a lot
|
||||||
permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey
|
permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey
|
||||||
@ -124,6 +126,22 @@ type sessions struct {
|
|||||||
// Initializes the session struct.
|
// Initializes the session struct.
|
||||||
func (ss *sessions) init(core *Core) {
|
func (ss *sessions) init(core *Core) {
|
||||||
ss.core = core
|
ss.core = core
|
||||||
|
ss.reconfigure = make(chan bool, 1)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case newConfig := <-ss.reconfigure:
|
||||||
|
ss.core.configMutex.RLock()
|
||||||
|
ss.core.log.Println("Notified: sessions")
|
||||||
|
ss.core.configMutex.RUnlock()
|
||||||
|
|
||||||
|
for _, sinfo := range ss.sinfos {
|
||||||
|
sinfo.reconfigure <- newConfig
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
ss.permShared = make(map[crypto.BoxPubKey]*crypto.BoxSharedKey)
|
ss.permShared = make(map[crypto.BoxPubKey]*crypto.BoxSharedKey)
|
||||||
ss.sinfos = make(map[crypto.Handle]*sessionInfo)
|
ss.sinfos = make(map[crypto.Handle]*sessionInfo)
|
||||||
ss.byMySes = make(map[crypto.BoxPubKey]*crypto.Handle)
|
ss.byMySes = make(map[crypto.BoxPubKey]*crypto.Handle)
|
||||||
@ -271,6 +289,7 @@ func (ss *sessions) createSession(theirPermKey *crypto.BoxPubKey) *sessionInfo {
|
|||||||
}
|
}
|
||||||
sinfo := sessionInfo{}
|
sinfo := sessionInfo{}
|
||||||
sinfo.core = ss.core
|
sinfo.core = ss.core
|
||||||
|
sinfo.reconfigure = make(chan bool, 1)
|
||||||
sinfo.theirPermPub = *theirPermKey
|
sinfo.theirPermPub = *theirPermKey
|
||||||
pub, priv := crypto.NewBoxKeys()
|
pub, priv := crypto.NewBoxKeys()
|
||||||
sinfo.mySesPub = *pub
|
sinfo.mySesPub = *pub
|
||||||
@ -539,6 +558,11 @@ func (sinfo *sessionInfo) doWorker() {
|
|||||||
} else {
|
} else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case _ = <-sinfo.reconfigure:
|
||||||
|
sinfo.core.configMutex.RLock()
|
||||||
|
sinfo.core.log.Println("Notified: sessionInfo")
|
||||||
|
sinfo.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -162,6 +162,7 @@ type switchData struct {
|
|||||||
// All the information stored by the switch.
|
// All the information stored by the switch.
|
||||||
type switchTable struct {
|
type switchTable struct {
|
||||||
core *Core
|
core *Core
|
||||||
|
reconfigure chan bool
|
||||||
key crypto.SigPubKey // Our own key
|
key crypto.SigPubKey // Our own key
|
||||||
time time.Time // Time when locator.tstamp was last updated
|
time time.Time // Time when locator.tstamp was last updated
|
||||||
drop map[crypto.SigPubKey]int64 // Tstamp associated with a dropped root
|
drop map[crypto.SigPubKey]int64 // Tstamp associated with a dropped root
|
||||||
@ -184,6 +185,7 @@ const SwitchQueueTotalMinSize = 4 * 1024 * 1024
|
|||||||
func (t *switchTable) init(core *Core, key crypto.SigPubKey) {
|
func (t *switchTable) init(core *Core, key crypto.SigPubKey) {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
t.core = core
|
t.core = core
|
||||||
|
t.reconfigure = make(chan bool, 1)
|
||||||
t.key = key
|
t.key = key
|
||||||
locator := switchLocator{root: key, tstamp: now.Unix()}
|
locator := switchLocator{root: key, tstamp: now.Unix()}
|
||||||
peers := make(map[switchPort]peerInfo)
|
peers := make(map[switchPort]peerInfo)
|
||||||
@ -808,6 +810,11 @@ func (t *switchTable) doWorker() {
|
|||||||
}
|
}
|
||||||
case f := <-t.admin:
|
case f := <-t.admin:
|
||||||
f()
|
f()
|
||||||
|
case _ = <-t.reconfigure:
|
||||||
|
t.core.configMutex.RLock()
|
||||||
|
t.core.log.Println("Notified: switchTable")
|
||||||
|
t.core.configMutex.RUnlock()
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user