mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 03:05:07 +03:00 
			
		
		
		
	start migrating the router to an actor
This commit is contained in:
		
							parent
							
								
									562a7d1f19
								
							
						
					
					
						commit
						9d7e7288c6
					
				
					 8 changed files with 51 additions and 54 deletions
				
			
		
							
								
								
									
										1
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
										
									
									
									
								
							| 
						 | 
					@ -1,6 +1,7 @@
 | 
				
			||||||
module github.com/yggdrasil-network/yggdrasil-go
 | 
					module github.com/yggdrasil-network/yggdrasil-go
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require (
 | 
					require (
 | 
				
			||||||
 | 
						github.com/Arceliar/phony v0.0.0-20190821233739-c7f353f14438
 | 
				
			||||||
	github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8
 | 
						github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8
 | 
				
			||||||
	github.com/hashicorp/go-syslog v1.0.0
 | 
						github.com/hashicorp/go-syslog v1.0.0
 | 
				
			||||||
	github.com/hjson/hjson-go v0.0.0-20181010104306-a25ecf6bd222
 | 
						github.com/hjson/hjson-go v0.0.0-20181010104306-a25ecf6bd222
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
										
									
									
									
								
							| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					github.com/Arceliar/phony v0.0.0-20190821233739-c7f353f14438 h1:t4tRgrItIq2ap4O31yOuWm17lUiyzf8gf/P+bEfgmrw=
 | 
				
			||||||
 | 
					github.com/Arceliar/phony v0.0.0-20190821233739-c7f353f14438/go.mod h1:2Q9yJvg2PlMrnOEa3RTEy9hElWAICo/D8HTUDqAHUAo=
 | 
				
			||||||
github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8 h1:WD8iJ37bRNwvETMfVTusVSAi0WdXTpfNVGY2aHycNKY=
 | 
					github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8 h1:WD8iJ37bRNwvETMfVTusVSAi0WdXTpfNVGY2aHycNKY=
 | 
				
			||||||
github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U=
 | 
					github.com/gologme/log v0.0.0-20181207131047-4e5d8ccb38e8/go.mod h1:gq31gQ8wEHkR+WekdWsqDuf8pXTUZA9BnnzTuPz1Y9U=
 | 
				
			||||||
github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
 | 
					github.com/hashicorp/go-syslog v1.0.0 h1:KaodqZuhUoZereWVIYmpUgZysurB1kBLX2j0MwMrUAE=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -134,7 +134,7 @@ func (c *Conn) doSearch() {
 | 
				
			||||||
			sinfo.continueSearch()
 | 
								sinfo.continueSearch()
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	go func() { c.core.router.admin <- routerWork }()
 | 
						go c.core.router.doAdmin(routerWork)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (c *Conn) getDeadlineCancellation(value *atomic.Value) (util.Cancellation, bool) {
 | 
					func (c *Conn) getDeadlineCancellation(value *atomic.Value) (util.Cancellation, bool) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -68,7 +68,6 @@ type dht struct {
 | 
				
			||||||
	core        *Core
 | 
						core        *Core
 | 
				
			||||||
	reconfigure chan chan error
 | 
						reconfigure chan chan error
 | 
				
			||||||
	nodeID      crypto.NodeID
 | 
						nodeID      crypto.NodeID
 | 
				
			||||||
	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
 | 
				
			||||||
	callbacks   map[dhtReqKey][]dht_callbackInfo // Search and admin lookup callbacks
 | 
						callbacks   map[dhtReqKey][]dht_callbackInfo // Search and admin lookup callbacks
 | 
				
			||||||
	// These next two could be replaced by a single linked list or similar...
 | 
						// These next two could be replaced by a single linked list or similar...
 | 
				
			||||||
| 
						 | 
					@ -87,7 +86,6 @@ func (t *dht) init(c *Core) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	t.nodeID = *t.core.NodeID()
 | 
						t.nodeID = *t.core.NodeID()
 | 
				
			||||||
	t.peers = make(chan *dhtInfo, 1024)
 | 
					 | 
				
			||||||
	t.callbacks = make(map[dhtReqKey][]dht_callbackInfo)
 | 
						t.callbacks = make(map[dhtReqKey][]dht_callbackInfo)
 | 
				
			||||||
	t.reset()
 | 
						t.reset()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -210,7 +210,7 @@ func (p *peer) linkLoop() {
 | 
				
			||||||
		case dinfo = <-p.dinfo:
 | 
							case dinfo = <-p.dinfo:
 | 
				
			||||||
		case _ = <-tick.C:
 | 
							case _ = <-tick.C:
 | 
				
			||||||
			if dinfo != nil {
 | 
								if dinfo != nil {
 | 
				
			||||||
				p.core.dht.peers <- dinfo
 | 
									p.core.router.insertPeer(&p.core.router, dinfo)
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -30,19 +30,19 @@ import (
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/address"
 | 
				
			||||||
	"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/util"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"github.com/Arceliar/phony"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// The router struct has channels to/from the adapter device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
 | 
					// The router struct has channels to/from the adapter device and a self peer (0), which is how messages are passed between this node and the peers/switch layer.
 | 
				
			||||||
// 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 {
 | 
				
			||||||
 | 
						phony.Actor
 | 
				
			||||||
	core        *Core
 | 
						core        *Core
 | 
				
			||||||
	reconfigure chan chan error
 | 
						reconfigure chan chan error
 | 
				
			||||||
	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"
 | 
					 | 
				
			||||||
	out         func([]byte) // packets we're sending to the network, link to peer's "in"
 | 
						out         func([]byte) // packets we're sending to the network, link to peer's "in"
 | 
				
			||||||
	reset       chan struct{}   // signal that coords changed (re-init sessions/dht)
 | 
					 | 
				
			||||||
	admin       chan func()     // pass a lambda for the admin socket to query stuff
 | 
					 | 
				
			||||||
	nodeinfo    nodeinfo
 | 
						nodeinfo    nodeinfo
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -52,7 +52,6 @@ func (r *router) init(core *Core) {
 | 
				
			||||||
	r.reconfigure = make(chan chan error, 1)
 | 
						r.reconfigure = make(chan chan error, 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, 1) // TODO something better than this...
 | 
					 | 
				
			||||||
	self := linkInterface{
 | 
						self := linkInterface{
 | 
				
			||||||
		name: "(self)",
 | 
							name: "(self)",
 | 
				
			||||||
		info: linkInfo{
 | 
							info: linkInfo{
 | 
				
			||||||
| 
						 | 
					@ -62,8 +61,10 @@ func (r *router) init(core *Core) {
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &crypto.BoxSharedKey{}, &self, nil)
 | 
						p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &crypto.BoxSharedKey{}, &self, nil)
 | 
				
			||||||
	p.out = func(packets [][]byte) { in <- packets }
 | 
						p.out = func(packets [][]byte) {
 | 
				
			||||||
	r.in = in
 | 
							// TODO make peers and/or the switch into actors, have them pass themselves as the from field
 | 
				
			||||||
 | 
							r.handlePackets(r, packets)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	out := make(chan []byte, 32)
 | 
						out := make(chan []byte, 32)
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		for packet := range out {
 | 
							for packet := range out {
 | 
				
			||||||
| 
						 | 
					@ -90,8 +91,6 @@ func (r *router) init(core *Core) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
	r.out = func(packet []byte) { out2 <- packet }
 | 
						r.out = func(packet []byte) { out2 <- packet }
 | 
				
			||||||
	r.reset = make(chan struct{}, 1)
 | 
					 | 
				
			||||||
	r.admin = make(chan func(), 32)
 | 
					 | 
				
			||||||
	r.nodeinfo.init(r.core)
 | 
						r.nodeinfo.init(r.core)
 | 
				
			||||||
	r.core.config.Mutex.RLock()
 | 
						r.core.config.Mutex.RLock()
 | 
				
			||||||
	r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy)
 | 
						r.nodeinfo.setNodeInfo(r.core.config.Current.NodeInfo, r.core.config.Current.NodeInfoPrivacy)
 | 
				
			||||||
| 
						 | 
					@ -105,42 +104,55 @@ func (r *router) start() error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Takes traffic from the adapter and passes it to router.send, or from r.in and handles incoming traffic.
 | 
					// In practice, the switch will call this with 1 packet
 | 
				
			||||||
// Also adds new peer info to the DHT.
 | 
					func (r *router) handlePackets(from phony.IActor, packets [][]byte) {
 | 
				
			||||||
// Also resets the DHT and sesssions in the event of a coord change.
 | 
						r.EnqueueFrom(from, func() {
 | 
				
			||||||
// Also does periodic maintenance stuff.
 | 
							for _, packet := range packets {
 | 
				
			||||||
 | 
								r.handlePacket(packet)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Insert a peer info into the dht, TODO? make the dht a separate actor
 | 
				
			||||||
 | 
					func (r *router) insertPeer(from phony.IActor, info *dhtInfo) {
 | 
				
			||||||
 | 
						r.EnqueueFrom(from, func() {
 | 
				
			||||||
 | 
							r.core.dht.insertPeer(info)
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Reset sessions and DHT after the switch sees our coords change
 | 
				
			||||||
 | 
					func (r *router) reset(from phony.IActor) {
 | 
				
			||||||
 | 
						r.EnqueueFrom(from, func() {
 | 
				
			||||||
 | 
							r.core.sessions.reset()
 | 
				
			||||||
 | 
							r.core.dht.reset()
 | 
				
			||||||
 | 
						})
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TODO remove reconfigure so this is just a ticker loop
 | 
				
			||||||
 | 
					// and then find something better than a ticker loop to schedule things...
 | 
				
			||||||
func (r *router) mainLoop() {
 | 
					func (r *router) mainLoop() {
 | 
				
			||||||
	ticker := time.NewTicker(time.Second)
 | 
						ticker := time.NewTicker(time.Second)
 | 
				
			||||||
	defer ticker.Stop()
 | 
						defer ticker.Stop()
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
		select {
 | 
							select {
 | 
				
			||||||
		case ps := <-r.in:
 | 
					 | 
				
			||||||
			for _, p := range ps {
 | 
					 | 
				
			||||||
				r.handleIn(p)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		case info := <-r.core.dht.peers:
 | 
					 | 
				
			||||||
			r.core.dht.insertPeer(info)
 | 
					 | 
				
			||||||
		case <-r.reset:
 | 
					 | 
				
			||||||
			r.core.sessions.reset()
 | 
					 | 
				
			||||||
			r.core.dht.reset()
 | 
					 | 
				
			||||||
		case <-ticker.C:
 | 
							case <-ticker.C:
 | 
				
			||||||
			{
 | 
								r.SyncExec(func() {
 | 
				
			||||||
				// Any periodic maintenance stuff goes here
 | 
									// Any periodic maintenance stuff goes here
 | 
				
			||||||
				r.core.switchTable.doMaintenance()
 | 
									r.core.switchTable.doMaintenance()
 | 
				
			||||||
				r.core.dht.doMaintenance()
 | 
									r.core.dht.doMaintenance()
 | 
				
			||||||
				r.core.sessions.cleanup()
 | 
									r.core.sessions.cleanup()
 | 
				
			||||||
			}
 | 
								})
 | 
				
			||||||
		case f := <-r.admin:
 | 
					 | 
				
			||||||
			f()
 | 
					 | 
				
			||||||
		case e := <-r.reconfigure:
 | 
							case e := <-r.reconfigure:
 | 
				
			||||||
 | 
								r.SyncExec(func() {
 | 
				
			||||||
				current := r.core.config.GetCurrent()
 | 
									current := r.core.config.GetCurrent()
 | 
				
			||||||
				e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
 | 
									e <- r.nodeinfo.setNodeInfo(current.NodeInfo, current.NodeInfoPrivacy)
 | 
				
			||||||
 | 
								})
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Checks incoming traffic type and passes it to the appropriate handler.
 | 
					// Checks incoming traffic type and passes it to the appropriate handler.
 | 
				
			||||||
func (r *router) handleIn(packet []byte) {
 | 
					func (r *router) handlePacket(packet []byte) {
 | 
				
			||||||
	pType, pTypeLen := wire_decode_uint64(packet)
 | 
						pType, pTypeLen := wire_decode_uint64(packet)
 | 
				
			||||||
	if pTypeLen == 0 {
 | 
						if pTypeLen == 0 {
 | 
				
			||||||
		return
 | 
							return
 | 
				
			||||||
| 
						 | 
					@ -263,17 +275,7 @@ func (r *router) handleNodeInfo(bs []byte, fromKey *crypto.BoxPubKey) {
 | 
				
			||||||
	r.nodeinfo.handleNodeInfo(&req)
 | 
						r.nodeinfo.handleNodeInfo(&req)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Passed a function to call.
 | 
					// TODO remove this, have things either be actors that send message or else call SyncExec directly
 | 
				
			||||||
// This will send the function to r.admin and block until it finishes.
 | 
					 | 
				
			||||||
// It's used by the admin socket to ask the router mainLoop goroutine about information in the session or dht structs, which cannot be read safely from outside that goroutine.
 | 
					 | 
				
			||||||
func (r *router) doAdmin(f func()) {
 | 
					func (r *router) doAdmin(f func()) {
 | 
				
			||||||
	// Pass this a function that needs to be run by the router's main goroutine
 | 
						r.SyncExec(f)
 | 
				
			||||||
	// It will pass the function to the router and wait for the router to finish
 | 
					 | 
				
			||||||
	done := make(chan struct{})
 | 
					 | 
				
			||||||
	newF := func() {
 | 
					 | 
				
			||||||
		f()
 | 
					 | 
				
			||||||
		close(done)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	r.admin <- newF
 | 
					 | 
				
			||||||
	<-done
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -165,7 +165,7 @@ func (sinfo *searchInfo) continueSearch() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
		time.Sleep(search_RETRY_TIME)
 | 
							time.Sleep(search_RETRY_TIME)
 | 
				
			||||||
		sinfo.core.router.admin <- retryLater
 | 
							sinfo.core.router.doAdmin(retryLater)
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -245,10 +245,7 @@ func (t *switchTable) cleanRoot() {
 | 
				
			||||||
		if t.data.locator.root != t.key {
 | 
							if t.data.locator.root != t.key {
 | 
				
			||||||
			t.data.seq++
 | 
								t.data.seq++
 | 
				
			||||||
			t.updater.Store(&sync.Once{})
 | 
								t.updater.Store(&sync.Once{})
 | 
				
			||||||
			select {
 | 
								t.core.router.reset(&t.core.router)
 | 
				
			||||||
			case t.core.router.reset <- struct{}{}:
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		t.data.locator = switchLocator{root: t.key, tstamp: now.Unix()}
 | 
							t.data.locator = switchLocator{root: t.key, tstamp: now.Unix()}
 | 
				
			||||||
		t.core.peers.sendSwitchMsgs()
 | 
							t.core.peers.sendSwitchMsgs()
 | 
				
			||||||
| 
						 | 
					@ -511,10 +508,7 @@ func (t *switchTable) unlockedHandleMsg(msg *switchMsg, fromPort switchPort, rep
 | 
				
			||||||
		if !equiv(&sender.locator, &t.data.locator) {
 | 
							if !equiv(&sender.locator, &t.data.locator) {
 | 
				
			||||||
			doUpdate = true
 | 
								doUpdate = true
 | 
				
			||||||
			t.data.seq++
 | 
								t.data.seq++
 | 
				
			||||||
			select {
 | 
								t.core.router.reset(&t.core.router)
 | 
				
			||||||
			case t.core.router.reset <- struct{}{}:
 | 
					 | 
				
			||||||
			default:
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		if t.data.locator.tstamp != sender.locator.tstamp {
 | 
							if t.data.locator.tstamp != sender.locator.tstamp {
 | 
				
			||||||
			t.time = now
 | 
								t.time = now
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue