mirror of
				https://github.com/yggdrasil-network/yggdrasil-go.git
				synced 2025-11-04 11:15:07 +03:00 
			
		
		
		
	Merge pull request #528 from yggdrasil-network/documentation
Documentation updates
This commit is contained in:
		
						commit
						d27891aaf6
					
				
					 10 changed files with 472 additions and 115 deletions
				
			
		| 
						 | 
					@ -1,22 +1,24 @@
 | 
				
			||||||
 | 
					// Package address contains the types used by yggdrasil to represent IPv6 addresses or prefixes, as well as functions for working with these types.
 | 
				
			||||||
 | 
					// Of particular importance are the functions used to derive addresses or subnets from a NodeID, or to get the NodeID and bitmask of the bits visible from an address, which is needed for DHT searches.
 | 
				
			||||||
package address
 | 
					package address
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import "github.com/yggdrasil-network/yggdrasil-go/src/crypto"
 | 
					import "github.com/yggdrasil-network/yggdrasil-go/src/crypto"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// address represents an IPv6 address in the yggdrasil address range.
 | 
					// Address represents an IPv6 address in the yggdrasil address range.
 | 
				
			||||||
type Address [16]byte
 | 
					type Address [16]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// subnet represents an IPv6 /64 subnet in the yggdrasil subnet range.
 | 
					// Subnet represents an IPv6 /64 subnet in the yggdrasil subnet range.
 | 
				
			||||||
type Subnet [8]byte
 | 
					type Subnet [8]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// address_prefix is the prefix used for all addresses and subnets in the network.
 | 
					// GetPrefix returns the address prefix used by yggdrasil.
 | 
				
			||||||
// The current implementation requires this to be a muliple of 8 bits + 7 bits.
 | 
					// The current implementation requires this to be a muliple of 8 bits + 7 bits.
 | 
				
			||||||
// The 8th bit of the last byte is used to signal nodes (0) or /64 prefixes (1).
 | 
					// The 8th bit of the last byte is used to signal nodes (0) or /64 prefixes (1).
 | 
				
			||||||
// Nodes that configure this differently will be unable to communicate with eachother, though routing and the DHT machinery *should* still work.
 | 
					// Nodes that configure this differently will be unable to communicate with eachother using IP packets, though routing and the DHT machinery *should* still work.
 | 
				
			||||||
func GetPrefix() [1]byte {
 | 
					func GetPrefix() [1]byte {
 | 
				
			||||||
	return [...]byte{0x02}
 | 
						return [...]byte{0x02}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// isValid returns true if an address falls within the range used by nodes in the network.
 | 
					// IsValid returns true if an address falls within the range used by nodes in the network.
 | 
				
			||||||
func (a *Address) IsValid() bool {
 | 
					func (a *Address) IsValid() bool {
 | 
				
			||||||
	prefix := GetPrefix()
 | 
						prefix := GetPrefix()
 | 
				
			||||||
	for idx := range prefix {
 | 
						for idx := range prefix {
 | 
				
			||||||
| 
						 | 
					@ -27,7 +29,7 @@ func (a *Address) IsValid() bool {
 | 
				
			||||||
	return true
 | 
						return true
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// isValid returns true if a prefix falls within the range usable by the network.
 | 
					// IsValid returns true if a prefix falls within the range usable by the network.
 | 
				
			||||||
func (s *Subnet) IsValid() bool {
 | 
					func (s *Subnet) IsValid() bool {
 | 
				
			||||||
	prefix := GetPrefix()
 | 
						prefix := GetPrefix()
 | 
				
			||||||
	l := len(prefix)
 | 
						l := len(prefix)
 | 
				
			||||||
| 
						 | 
					@ -39,8 +41,8 @@ func (s *Subnet) IsValid() bool {
 | 
				
			||||||
	return (*s)[l-1] == prefix[l-1]|0x01
 | 
						return (*s)[l-1] == prefix[l-1]|0x01
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// address_addrForNodeID takes a *NodeID as an argument and returns an *address.
 | 
					// AddrForNodeID takes a *NodeID as an argument and returns an *Address.
 | 
				
			||||||
// This subnet begins with the address prefix, with the last bit set to 0 to indicate an address.
 | 
					// This address begins with the contents of GetPrefix(), with the last bit set to 0 to indicate an address.
 | 
				
			||||||
// The following 8 bits are set to the number of leading 1 bits in the NodeID.
 | 
					// The following 8 bits are set to the number of leading 1 bits in the NodeID.
 | 
				
			||||||
// The NodeID, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the address.
 | 
					// The NodeID, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the address.
 | 
				
			||||||
func AddrForNodeID(nid *crypto.NodeID) *Address {
 | 
					func AddrForNodeID(nid *crypto.NodeID) *Address {
 | 
				
			||||||
| 
						 | 
					@ -80,7 +82,7 @@ func AddrForNodeID(nid *crypto.NodeID) *Address {
 | 
				
			||||||
	return &addr
 | 
						return &addr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// address_subnetForNodeID takes a *NodeID as an argument and returns a *subnet.
 | 
					// SubnetForNodeID takes a *NodeID as an argument and returns an *Address.
 | 
				
			||||||
// This subnet begins with the address prefix, with the last bit set to 1 to indicate a prefix.
 | 
					// This subnet begins with the address prefix, with the last bit set to 1 to indicate a prefix.
 | 
				
			||||||
// The following 8 bits are set to the number of leading 1 bits in the NodeID.
 | 
					// The following 8 bits are set to the number of leading 1 bits in the NodeID.
 | 
				
			||||||
// The NodeID, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the subnet.
 | 
					// The NodeID, excluding the leading 1 bits and the first leading 0 bit, is truncated to the appropriate length and makes up the remainder of the subnet.
 | 
				
			||||||
| 
						 | 
					@ -96,10 +98,10 @@ func SubnetForNodeID(nid *crypto.NodeID) *Subnet {
 | 
				
			||||||
	return &snet
 | 
						return &snet
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getNodeIDandMask returns two *NodeID.
 | 
					// GetNodeIDandMask returns two *NodeID.
 | 
				
			||||||
// The first is a NodeID with all the bits known from the address set to their correct values.
 | 
					// The first is a NodeID with all the bits known from the Address set to their correct values.
 | 
				
			||||||
// The second is a bitmask with 1 bit set for each bit that was known from the address.
 | 
					// The second is a bitmask with 1 bit set for each bit that was known from the Address.
 | 
				
			||||||
// This is used to look up NodeIDs in the DHT and tell if they match an address.
 | 
					// This is used to look up NodeIDs in the DHT and tell if they match an Address.
 | 
				
			||||||
func (a *Address) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) {
 | 
					func (a *Address) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) {
 | 
				
			||||||
	// Mask is a bitmask to mark the bits visible from the address
 | 
						// Mask is a bitmask to mark the bits visible from the address
 | 
				
			||||||
	// This means truncated leading 1s, first leading 0, and visible part of addr
 | 
						// This means truncated leading 1s, first leading 0, and visible part of addr
 | 
				
			||||||
| 
						 | 
					@ -126,10 +128,10 @@ func (a *Address) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) {
 | 
				
			||||||
	return &nid, &mask
 | 
						return &nid, &mask
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// getNodeIDandMask returns two *NodeID.
 | 
					// GetNodeIDandMask returns two *NodeID.
 | 
				
			||||||
// The first is a NodeID with all the bits known from the address set to their correct values.
 | 
					// The first is a NodeID with all the bits known from the Subnet set to their correct values.
 | 
				
			||||||
// The second is a bitmask with 1 bit set for each bit that was known from the subnet.
 | 
					// The second is a bitmask with 1 bit set for each bit that was known from the Subnet.
 | 
				
			||||||
// This is used to look up NodeIDs in the DHT and tell if they match a subnet.
 | 
					// This is used to look up NodeIDs in the DHT and tell if they match a Subnet.
 | 
				
			||||||
func (s *Subnet) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) {
 | 
					func (s *Subnet) GetNodeIDandMask() (*crypto.NodeID, *crypto.NodeID) {
 | 
				
			||||||
	// As with the address version, but visible parts of the subnet prefix instead
 | 
						// As with the address version, but visible parts of the subnet prefix instead
 | 
				
			||||||
	var nid crypto.NodeID
 | 
						var nid crypto.NodeID
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,19 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					The config package contains structures related to the configuration of an
 | 
				
			||||||
 | 
					Yggdrasil node.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The configuration contains, amongst other things, encryption keys which are used
 | 
				
			||||||
 | 
					to derive a node's identity, information about peerings and node information
 | 
				
			||||||
 | 
					that is shared with the network. There are also some module-specific options
 | 
				
			||||||
 | 
					related to TUN/TAP, multicast and the admin socket.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order for a node to maintain the same identity across restarts, you should
 | 
				
			||||||
 | 
					persist the configuration onto the filesystem or into some configuration storage
 | 
				
			||||||
 | 
					so that the encryption keys (and therefore the node ID) do not change.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that Yggdrasil will automatically populate sane defaults for any
 | 
				
			||||||
 | 
					configuration option that is not provided.
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
package config
 | 
					package config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
| 
						 | 
					@ -8,30 +24,30 @@ import (
 | 
				
			||||||
	"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
 | 
						"github.com/yggdrasil-network/yggdrasil-go/src/defaults"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NodeState represents the active and previous configuration of the node and
 | 
					// NodeState represents the active and previous configuration of an Yggdrasil
 | 
				
			||||||
// protects it with a mutex
 | 
					// node. A NodeState object is returned when starting an Yggdrasil node. Note
 | 
				
			||||||
 | 
					// that this structure and related functions are likely to disappear soon.
 | 
				
			||||||
type NodeState struct {
 | 
					type NodeState struct {
 | 
				
			||||||
	Current  NodeConfig
 | 
						Current  NodeConfig
 | 
				
			||||||
	Previous NodeConfig
 | 
						Previous NodeConfig
 | 
				
			||||||
	Mutex    sync.RWMutex
 | 
						Mutex    sync.RWMutex
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Current returns the current node config
 | 
					// Current returns the active node configuration.
 | 
				
			||||||
func (s *NodeState) GetCurrent() NodeConfig {
 | 
					func (s *NodeState) GetCurrent() NodeConfig {
 | 
				
			||||||
	s.Mutex.RLock()
 | 
						s.Mutex.RLock()
 | 
				
			||||||
	defer s.Mutex.RUnlock()
 | 
						defer s.Mutex.RUnlock()
 | 
				
			||||||
	return s.Current
 | 
						return s.Current
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Previous returns the previous node config
 | 
					// Previous returns the previous node configuration.
 | 
				
			||||||
func (s *NodeState) GetPrevious() NodeConfig {
 | 
					func (s *NodeState) GetPrevious() NodeConfig {
 | 
				
			||||||
	s.Mutex.RLock()
 | 
						s.Mutex.RLock()
 | 
				
			||||||
	defer s.Mutex.RUnlock()
 | 
						defer s.Mutex.RUnlock()
 | 
				
			||||||
	return s.Previous
 | 
						return s.Previous
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Replace the node configuration with new configuration. This method returns
 | 
					// Replace the node configuration with new configuration.
 | 
				
			||||||
// both the new and the previous node configs
 | 
					 | 
				
			||||||
func (s *NodeState) Replace(n NodeConfig) {
 | 
					func (s *NodeState) Replace(n NodeConfig) {
 | 
				
			||||||
	s.Mutex.Lock()
 | 
						s.Mutex.Lock()
 | 
				
			||||||
	defer s.Mutex.Unlock()
 | 
						defer s.Mutex.Unlock()
 | 
				
			||||||
| 
						 | 
					@ -39,7 +55,9 @@ func (s *NodeState) Replace(n NodeConfig) {
 | 
				
			||||||
	s.Current = n
 | 
						s.Current = n
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NodeConfig defines all configuration values needed to run a signle yggdrasil node
 | 
					// NodeConfig is the main configuration structure, containing configuration
 | 
				
			||||||
 | 
					// options that are necessary for an Yggdrasil node to run. You will need to
 | 
				
			||||||
 | 
					// supply one of these structs to the Yggdrasil core when starting a node.
 | 
				
			||||||
type NodeConfig struct {
 | 
					type NodeConfig struct {
 | 
				
			||||||
	Peers                       []string               `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
 | 
						Peers                       []string               `comment:"List of connection strings for outbound peer connections in URI format,\ne.g. tcp://a.b.c.d:e or socks://a.b.c.d:e/f.g.h.i:j. These connections\nwill obey the operating system routing table, therefore you should\nuse this section when you may connect via different interfaces."`
 | 
				
			||||||
	InterfacePeers              map[string][]string    `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tcp://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."`
 | 
						InterfacePeers              map[string][]string    `comment:"List of connection strings for outbound peer connections in URI format,\narranged by source interface, e.g. { \"eth0\": [ tcp://a.b.c.d:e ] }.\nNote that SOCKS peerings will NOT be affected by this option and should\ngo in the \"Peers\" section instead."`
 | 
				
			||||||
| 
						 | 
					@ -62,7 +80,7 @@ type NodeConfig struct {
 | 
				
			||||||
	NodeInfo                    map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."`
 | 
						NodeInfo                    map[string]interface{} `comment:"Optional node info. This must be a { \"key\": \"value\", ... } map\nor set as null. This is entirely optional but, if set, is visible\nto the whole network on request."`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SessionFirewall controls the session firewall configuration
 | 
					// SessionFirewall controls the session firewall configuration.
 | 
				
			||||||
type SessionFirewall struct {
 | 
					type SessionFirewall struct {
 | 
				
			||||||
	Enable                        bool     `comment:"Enable or disable the session firewall. If disabled, network traffic\nfrom any node will be allowed. If enabled, the below rules apply."`
 | 
						Enable                        bool     `comment:"Enable or disable the session firewall. If disabled, network traffic\nfrom any node will be allowed. If enabled, the below rules apply."`
 | 
				
			||||||
	AllowFromDirect               bool     `comment:"Allow network traffic from directly connected peers."`
 | 
						AllowFromDirect               bool     `comment:"Allow network traffic from directly connected peers."`
 | 
				
			||||||
| 
						 | 
					@ -72,7 +90,8 @@ type SessionFirewall struct {
 | 
				
			||||||
	BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
 | 
						BlacklistEncryptionPublicKeys []string `comment:"List of public keys from which network traffic is always rejected,\nregardless of the whitelist, AllowFromDirect or AllowFromRemote."`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TunnelRouting contains the crypto-key routing tables for tunneling
 | 
					// TunnelRouting contains the crypto-key routing tables for tunneling regular
 | 
				
			||||||
 | 
					// IPv4 or IPv6 subnets across the Yggdrasil network.
 | 
				
			||||||
type TunnelRouting struct {
 | 
					type TunnelRouting struct {
 | 
				
			||||||
	Enable            bool              `comment:"Enable or disable tunnel routing."`
 | 
						Enable            bool              `comment:"Enable or disable tunnel routing."`
 | 
				
			||||||
	IPv6RemoteSubnets map[string]string `comment:"IPv6 subnets belonging to remote nodes, mapped to the node's public\nkey, e.g. { \"aaaa:bbbb:cccc::/e\": \"boxpubkey\", ... }"`
 | 
						IPv6RemoteSubnets map[string]string `comment:"IPv6 subnets belonging to remote nodes, mapped to the node's public\nkey, e.g. { \"aaaa:bbbb:cccc::/e\": \"boxpubkey\", ... }"`
 | 
				
			||||||
| 
						 | 
					@ -81,18 +100,15 @@ type TunnelRouting struct {
 | 
				
			||||||
	IPv4LocalSubnets  []string          `comment:"IPv4 subnets belonging to this node's end of the tunnels. Only traffic\nfrom these ranges will be tunnelled."`
 | 
						IPv4LocalSubnets  []string          `comment:"IPv4 subnets belonging to this node's end of the tunnels. Only traffic\nfrom these ranges will be tunnelled."`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SwitchOptions contains tuning options for the switch
 | 
					// SwitchOptions contains tuning options for the switch. These are advanced
 | 
				
			||||||
 | 
					// options and shouldn't be changed unless necessary.
 | 
				
			||||||
type SwitchOptions struct {
 | 
					type SwitchOptions struct {
 | 
				
			||||||
	MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."`
 | 
						MaxTotalQueueSize uint64 `comment:"Maximum size of all switch queues combined (in bytes)."`
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Generates default configuration. This is used when outputting the -genconf
 | 
					// Generates default configuration and returns a pointer to the resulting
 | 
				
			||||||
// parameter and also when using -autoconf. The isAutoconf flag is used to
 | 
					// NodeConfig. This is used when outputting the -genconf parameter and also when
 | 
				
			||||||
// determine whether the operating system should select a free port by itself
 | 
					// using -autoconf.
 | 
				
			||||||
// (which guarantees that there will not be a conflict with any other services)
 | 
					 | 
				
			||||||
// or whether to generate a random port number. The only side effect of setting
 | 
					 | 
				
			||||||
// isAutoconf is that the TCP and UDP ports will likely end up with different
 | 
					 | 
				
			||||||
// port numbers.
 | 
					 | 
				
			||||||
func GenerateConfig() *NodeConfig {
 | 
					func GenerateConfig() *NodeConfig {
 | 
				
			||||||
	// Generate encryption keys.
 | 
						// Generate encryption keys.
 | 
				
			||||||
	bpub, bpriv := crypto.NewBoxKeys()
 | 
						bpub, bpriv := crypto.NewBoxKeys()
 | 
				
			||||||
| 
						 | 
					@ -122,16 +138,19 @@ func GenerateConfig() *NodeConfig {
 | 
				
			||||||
	return &cfg
 | 
						return &cfg
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewEncryptionKeys generates a new encryption keypair. The encryption keys are
 | 
					// NewEncryptionKeys replaces the encryption keypair in the NodeConfig with a
 | 
				
			||||||
// used to encrypt traffic and to derive the IPv6 address/subnet of the node.
 | 
					// new encryption keypair. The encryption keys are used by the router to encrypt
 | 
				
			||||||
 | 
					// traffic and to derive the node ID and IPv6 address/subnet of the node, so
 | 
				
			||||||
 | 
					// this is equivalent to discarding the node's identity on the network.
 | 
				
			||||||
func (cfg *NodeConfig) NewEncryptionKeys() {
 | 
					func (cfg *NodeConfig) NewEncryptionKeys() {
 | 
				
			||||||
	bpub, bpriv := crypto.NewBoxKeys()
 | 
						bpub, bpriv := crypto.NewBoxKeys()
 | 
				
			||||||
	cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:])
 | 
						cfg.EncryptionPublicKey = hex.EncodeToString(bpub[:])
 | 
				
			||||||
	cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:])
 | 
						cfg.EncryptionPrivateKey = hex.EncodeToString(bpriv[:])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NewSigningKeys generates a new signing keypair. The signing keys are used to
 | 
					// NewSigningKeys replaces the signing keypair in the NodeConfig with a new
 | 
				
			||||||
// derive the structure of the spanning tree.
 | 
					// signing keypair. The signing keys are used by the switch to derive the
 | 
				
			||||||
 | 
					// structure of the spanning tree.
 | 
				
			||||||
func (cfg *NodeConfig) NewSigningKeys() {
 | 
					func (cfg *NodeConfig) NewSigningKeys() {
 | 
				
			||||||
	spub, spriv := crypto.NewSigKeys()
 | 
						spub, spriv := crypto.NewSigKeys()
 | 
				
			||||||
	cfg.SigningPublicKey = hex.EncodeToString(spub[:])
 | 
						cfg.SigningPublicKey = hex.EncodeToString(spub[:])
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,6 @@
 | 
				
			||||||
 | 
					// Package crypto is a wrapper around packages under golang.org/x/crypto/, particulaly curve25519, ed25519, and nacl/box.
 | 
				
			||||||
 | 
					// This is used to avoid explicitly importing and using these packages throughout yggdrasil.
 | 
				
			||||||
 | 
					// It also includes the all-important NodeID and TreeID types, which are used to identify nodes in the DHT and in the spanning tree's root selection algorithm, respectively.
 | 
				
			||||||
package crypto
 | 
					package crypto
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
| 
						 | 
					@ -26,12 +29,21 @@ import (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NodeID and TreeID
 | 
					// NodeID and TreeID
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NodeIDLen is the length (in bytes) of a NodeID.
 | 
				
			||||||
const NodeIDLen = sha512.Size
 | 
					const NodeIDLen = sha512.Size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TreeIDLen is the length (in bytes) of a TreeID.
 | 
				
			||||||
const TreeIDLen = sha512.Size
 | 
					const TreeIDLen = sha512.Size
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// handleLen is the length (in bytes) of a Handle.
 | 
				
			||||||
const handleLen = 8
 | 
					const handleLen = 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NodeID is how a yggdrasil node is identified in the DHT, and is used to derive IPv6 addresses and subnets in the main executable. It is a sha512sum hash of the node's BoxPubKey
 | 
				
			||||||
type NodeID [NodeIDLen]byte
 | 
					type NodeID [NodeIDLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// TreeID is how a yggdrasil node is identified in the root selection algorithm used to construct the spanning tree.
 | 
				
			||||||
type TreeID [TreeIDLen]byte
 | 
					type TreeID [TreeIDLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type Handle [handleLen]byte
 | 
					type Handle [handleLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (n *NodeID) String() string {
 | 
					func (n *NodeID) String() string {
 | 
				
			||||||
| 
						 | 
					@ -69,16 +81,19 @@ func (n *NodeID) PrefixLength() int {
 | 
				
			||||||
	return len
 | 
						return len
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetNodeID returns the NodeID associated with a BoxPubKey.
 | 
				
			||||||
func GetNodeID(pub *BoxPubKey) *NodeID {
 | 
					func GetNodeID(pub *BoxPubKey) *NodeID {
 | 
				
			||||||
	h := sha512.Sum512(pub[:])
 | 
						h := sha512.Sum512(pub[:])
 | 
				
			||||||
	return (*NodeID)(&h)
 | 
						return (*NodeID)(&h)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetTreeID returns the TreeID associated with a BoxPubKey
 | 
				
			||||||
func GetTreeID(pub *SigPubKey) *TreeID {
 | 
					func GetTreeID(pub *SigPubKey) *TreeID {
 | 
				
			||||||
	h := sha512.Sum512(pub[:])
 | 
						h := sha512.Sum512(pub[:])
 | 
				
			||||||
	return (*TreeID)(&h)
 | 
						return (*TreeID)(&h)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewHandle returns a new (cryptographically random) Handle, used by the session code to identify which session an incoming packet is associated with.
 | 
				
			||||||
func NewHandle() *Handle {
 | 
					func NewHandle() *Handle {
 | 
				
			||||||
	var h Handle
 | 
						var h Handle
 | 
				
			||||||
	_, err := rand.Read(h[:])
 | 
						_, err := rand.Read(h[:])
 | 
				
			||||||
| 
						 | 
					@ -92,14 +107,25 @@ func NewHandle() *Handle {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Signatures
 | 
					// Signatures
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SigPubKeyLen is the length of a SigPubKey in bytes.
 | 
				
			||||||
const SigPubKeyLen = ed25519.PublicKeySize
 | 
					const SigPubKeyLen = ed25519.PublicKeySize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SigPrivKeyLen is the length of a SigPrivKey in bytes.
 | 
				
			||||||
const SigPrivKeyLen = ed25519.PrivateKeySize
 | 
					const SigPrivKeyLen = ed25519.PrivateKeySize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SigLen is the length of SigBytes.
 | 
				
			||||||
const SigLen = ed25519.SignatureSize
 | 
					const SigLen = ed25519.SignatureSize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SigPubKey is a public ed25519 signing key.
 | 
				
			||||||
type SigPubKey [SigPubKeyLen]byte
 | 
					type SigPubKey [SigPubKeyLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SigPrivKey is a private ed25519 signing key.
 | 
				
			||||||
type SigPrivKey [SigPrivKeyLen]byte
 | 
					type SigPrivKey [SigPrivKeyLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SigBytes is an ed25519 signature.
 | 
				
			||||||
type SigBytes [SigLen]byte
 | 
					type SigBytes [SigLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewSigKeys generates a public/private ed25519 key pair.
 | 
				
			||||||
func NewSigKeys() (*SigPubKey, *SigPrivKey) {
 | 
					func NewSigKeys() (*SigPubKey, *SigPrivKey) {
 | 
				
			||||||
	var pub SigPubKey
 | 
						var pub SigPubKey
 | 
				
			||||||
	var priv SigPrivKey
 | 
						var priv SigPrivKey
 | 
				
			||||||
| 
						 | 
					@ -112,6 +138,7 @@ func NewSigKeys() (*SigPubKey, *SigPrivKey) {
 | 
				
			||||||
	return &pub, &priv
 | 
						return &pub, &priv
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Sign returns the SigBytes signing a message.
 | 
				
			||||||
func Sign(priv *SigPrivKey, msg []byte) *SigBytes {
 | 
					func Sign(priv *SigPrivKey, msg []byte) *SigBytes {
 | 
				
			||||||
	var sig SigBytes
 | 
						var sig SigBytes
 | 
				
			||||||
	sigSlice := ed25519.Sign(priv[:], msg)
 | 
						sigSlice := ed25519.Sign(priv[:], msg)
 | 
				
			||||||
| 
						 | 
					@ -119,12 +146,14 @@ func Sign(priv *SigPrivKey, msg []byte) *SigBytes {
 | 
				
			||||||
	return &sig
 | 
						return &sig
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Verify returns true if the provided signature matches the key and message.
 | 
				
			||||||
func Verify(pub *SigPubKey, msg []byte, sig *SigBytes) bool {
 | 
					func Verify(pub *SigPubKey, msg []byte, sig *SigBytes) bool {
 | 
				
			||||||
	// Should sig be an array instead of a slice?...
 | 
						// Should sig be an array instead of a slice?...
 | 
				
			||||||
	// It's fixed size, but
 | 
						// It's fixed size, but
 | 
				
			||||||
	return ed25519.Verify(pub[:], msg, sig[:])
 | 
						return ed25519.Verify(pub[:], msg, sig[:])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Public returns the SigPubKey associated with this SigPrivKey.
 | 
				
			||||||
func (p SigPrivKey) Public() SigPubKey {
 | 
					func (p SigPrivKey) Public() SigPubKey {
 | 
				
			||||||
	priv := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
 | 
						priv := make(ed25519.PrivateKey, ed25519.PrivateKeySize)
 | 
				
			||||||
	copy(priv[:], p[:])
 | 
						copy(priv[:], p[:])
 | 
				
			||||||
| 
						 | 
					@ -138,17 +167,34 @@ func (p SigPrivKey) Public() SigPubKey {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NaCl-like crypto "box" (curve25519+xsalsa20+poly1305)
 | 
					// NaCl-like crypto "box" (curve25519+xsalsa20+poly1305)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxPubKeyLen is the length of a BoxPubKey in bytes.
 | 
				
			||||||
const BoxPubKeyLen = 32
 | 
					const BoxPubKeyLen = 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxPrivKeyLen is the length of a BoxPrivKey in bytes.
 | 
				
			||||||
const BoxPrivKeyLen = 32
 | 
					const BoxPrivKeyLen = 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxSharedKeyLen is the length of a BoxSharedKey in bytes.
 | 
				
			||||||
const BoxSharedKeyLen = 32
 | 
					const BoxSharedKeyLen = 32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxNonceLen is the length of a BoxNonce in bytes.
 | 
				
			||||||
const BoxNonceLen = 24
 | 
					const BoxNonceLen = 24
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxOverhead is the length of the overhead from boxing something.
 | 
				
			||||||
const BoxOverhead = box.Overhead
 | 
					const BoxOverhead = box.Overhead
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxPubKey is a NaCl-like "box" public key (curve25519+xsalsa20+poly1305).
 | 
				
			||||||
type BoxPubKey [BoxPubKeyLen]byte
 | 
					type BoxPubKey [BoxPubKeyLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxPrivKey is a NaCl-like "box" private key (curve25519+xsalsa20+poly1305).
 | 
				
			||||||
type BoxPrivKey [BoxPrivKeyLen]byte
 | 
					type BoxPrivKey [BoxPrivKeyLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxSharedKey is a NaCl-like "box" shared key (curve25519+xsalsa20+poly1305).
 | 
				
			||||||
type BoxSharedKey [BoxSharedKeyLen]byte
 | 
					type BoxSharedKey [BoxSharedKeyLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxNonce is the nonce used in NaCl-like crypto "box" operations (curve25519+xsalsa20+poly1305), and must not be reused for different messages encrypted using the same BoxSharedKey.
 | 
				
			||||||
type BoxNonce [BoxNonceLen]byte
 | 
					type BoxNonce [BoxNonceLen]byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewBoxKeys generates a new pair of public/private crypto box keys.
 | 
				
			||||||
func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) {
 | 
					func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) {
 | 
				
			||||||
	pubBytes, privBytes, err := box.GenerateKey(rand.Reader)
 | 
						pubBytes, privBytes, err := box.GenerateKey(rand.Reader)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -159,6 +205,7 @@ func NewBoxKeys() (*BoxPubKey, *BoxPrivKey) {
 | 
				
			||||||
	return pub, priv
 | 
						return pub, priv
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetSharedKey returns the shared key derived from your private key and the destination's public key.
 | 
				
			||||||
func GetSharedKey(myPrivKey *BoxPrivKey,
 | 
					func GetSharedKey(myPrivKey *BoxPrivKey,
 | 
				
			||||||
	othersPubKey *BoxPubKey) *BoxSharedKey {
 | 
						othersPubKey *BoxPubKey) *BoxSharedKey {
 | 
				
			||||||
	var shared [BoxSharedKeyLen]byte
 | 
						var shared [BoxSharedKeyLen]byte
 | 
				
			||||||
| 
						 | 
					@ -168,6 +215,7 @@ func GetSharedKey(myPrivKey *BoxPrivKey,
 | 
				
			||||||
	return (*BoxSharedKey)(&shared)
 | 
						return (*BoxSharedKey)(&shared)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxOpen returns a message and true if it successfull opens a crypto box using the provided shared key and nonce.
 | 
				
			||||||
func BoxOpen(shared *BoxSharedKey,
 | 
					func BoxOpen(shared *BoxSharedKey,
 | 
				
			||||||
	boxed []byte,
 | 
						boxed []byte,
 | 
				
			||||||
	nonce *BoxNonce) ([]byte, bool) {
 | 
						nonce *BoxNonce) ([]byte, bool) {
 | 
				
			||||||
| 
						 | 
					@ -178,6 +226,9 @@ func BoxOpen(shared *BoxSharedKey,
 | 
				
			||||||
	return unboxed, success
 | 
						return unboxed, success
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// BoxSeal seals a crypto box using the provided shared key, returning the box and the nonce needed to decrypt it.
 | 
				
			||||||
 | 
					// If nonce is nil, a random BoxNonce will be used and returned.
 | 
				
			||||||
 | 
					// If nonce is non-nil, then nonce.Increment() will be called before using it, and the incremented BoxNonce is what is returned.
 | 
				
			||||||
func BoxSeal(shared *BoxSharedKey, unboxed []byte, nonce *BoxNonce) ([]byte, *BoxNonce) {
 | 
					func BoxSeal(shared *BoxSharedKey, unboxed []byte, nonce *BoxNonce) ([]byte, *BoxNonce) {
 | 
				
			||||||
	if nonce == nil {
 | 
						if nonce == nil {
 | 
				
			||||||
		nonce = NewBoxNonce()
 | 
							nonce = NewBoxNonce()
 | 
				
			||||||
| 
						 | 
					@ -190,6 +241,7 @@ func BoxSeal(shared *BoxSharedKey, unboxed []byte, nonce *BoxNonce) ([]byte, *Bo
 | 
				
			||||||
	return boxed, nonce
 | 
						return boxed, nonce
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewBoxNonce generates a (cryptographically) random BoxNonce.
 | 
				
			||||||
func NewBoxNonce() *BoxNonce {
 | 
					func NewBoxNonce() *BoxNonce {
 | 
				
			||||||
	var nonce BoxNonce
 | 
						var nonce BoxNonce
 | 
				
			||||||
	_, err := rand.Read(nonce[:])
 | 
						_, err := rand.Read(nonce[:])
 | 
				
			||||||
| 
						 | 
					@ -204,6 +256,7 @@ func NewBoxNonce() *BoxNonce {
 | 
				
			||||||
	return &nonce
 | 
						return &nonce
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Increment adds 2 to a BoxNonce, which is useful if one node intends to send only with odd BoxNonce values, and the other only with even BoxNonce values.
 | 
				
			||||||
func (n *BoxNonce) Increment() {
 | 
					func (n *BoxNonce) Increment() {
 | 
				
			||||||
	oldNonce := *n
 | 
						oldNonce := *n
 | 
				
			||||||
	n[len(n)-1] += 2
 | 
						n[len(n)-1] += 2
 | 
				
			||||||
| 
						 | 
					@ -214,6 +267,7 @@ func (n *BoxNonce) Increment() {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Public returns the BoxPubKey associated with this BoxPrivKey.
 | 
				
			||||||
func (p BoxPrivKey) Public() BoxPubKey {
 | 
					func (p BoxPrivKey) Public() BoxPubKey {
 | 
				
			||||||
	var boxPub [BoxPubKeyLen]byte
 | 
						var boxPub [BoxPubKeyLen]byte
 | 
				
			||||||
	var boxPriv [BoxPrivKeyLen]byte
 | 
						var boxPriv [BoxPrivKeyLen]byte
 | 
				
			||||||
| 
						 | 
					@ -222,9 +276,9 @@ func (p BoxPrivKey) Public() BoxPubKey {
 | 
				
			||||||
	return boxPub
 | 
						return boxPub
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Used to subtract one nonce from another, staying in the range +- 64.
 | 
					// Minus is the result of subtracting the provided BoNonce from this BoxNonce, bounded at +- 64.
 | 
				
			||||||
// This is used by the nonce progression machinery to advance the bitmask of recently received packets (indexed by nonce), or to check the appropriate bit of the bitmask.
 | 
					// It's primarily used to determine if a new BoxNonce is higher than the last known BoxNonce from a crypto session, and by how much.
 | 
				
			||||||
// It's basically part of the machinery that prevents replays and duplicate packets.
 | 
					// This is used in the machinery that makes sure replayed packets can't keep a session open indefinitely or stuck using old/bad information about a node.
 | 
				
			||||||
func (n *BoxNonce) Minus(m *BoxNonce) int64 {
 | 
					func (n *BoxNonce) Minus(m *BoxNonce) int64 {
 | 
				
			||||||
	diff := int64(0)
 | 
						diff := int64(0)
 | 
				
			||||||
	for idx := range n {
 | 
						for idx := range n {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,12 +8,14 @@ func init() {
 | 
				
			||||||
	debug.SetGCPercent(25)
 | 
						debug.SetGCPercent(25)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// On mobile, just return a nil slice.
 | 
					// GetBytes always returns a nil slice on mobile platforms.
 | 
				
			||||||
func GetBytes() []byte {
 | 
					func GetBytes() []byte {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// On mobile, don't do anything.
 | 
					// PutBytes does literally nothing on mobile platforms.
 | 
				
			||||||
 | 
					// This is done rather than keeping a free list of bytes on platforms with memory constraints.
 | 
				
			||||||
 | 
					// It's needed to help keep memory usage low enough to fall under the limits set for e.g. iOS NEPacketTunnelProvider apps.
 | 
				
			||||||
func PutBytes(bs []byte) {
 | 
					func PutBytes(bs []byte) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,12 +7,12 @@ import "sync"
 | 
				
			||||||
// This is used to buffer recently used slices of bytes, to prevent allocations in the hot loops.
 | 
					// This is used to buffer recently used slices of bytes, to prevent allocations in the hot loops.
 | 
				
			||||||
var byteStore = sync.Pool{New: func() interface{} { return []byte(nil) }}
 | 
					var byteStore = sync.Pool{New: func() interface{} { return []byte(nil) }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Gets an empty slice from the byte store.
 | 
					// GetBytes returns a 0-length (possibly nil) slice of bytes from a free list, so it may have a larger capacity.
 | 
				
			||||||
func GetBytes() []byte {
 | 
					func GetBytes() []byte {
 | 
				
			||||||
	return byteStore.Get().([]byte)[:0]
 | 
						return byteStore.Get().([]byte)[:0]
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Puts a slice in the store.
 | 
					// PutBytes stores a slice in a free list, where it can potentially be reused to prevent future allocations.
 | 
				
			||||||
func PutBytes(bs []byte) {
 | 
					func PutBytes(bs []byte) {
 | 
				
			||||||
	byteStore.Put(bs)
 | 
						byteStore.Put(bs)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,15 +7,22 @@ import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Cancellation is used to signal when things should shut down, such as signaling anything associated with a Conn to exit.
 | 
				
			||||||
 | 
					// This is and is similar to a context, but with an error to specify the reason for the cancellation.
 | 
				
			||||||
type Cancellation interface {
 | 
					type Cancellation interface {
 | 
				
			||||||
	Finished() <-chan struct{}
 | 
						Finished() <-chan struct{} // Finished returns a channel which will be closed when Cancellation.Cancel is first called.
 | 
				
			||||||
	Cancel(error) error
 | 
						Cancel(error) error // Cancel closes the channel returned by Finished and sets the error returned by error, or else returns the existing error if the Cancellation has already run.
 | 
				
			||||||
	Error() error
 | 
						Error() error // Error returns the error provided to Cancel, or nil if no error has been provided.
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CancellationFinalized is an error returned if a cancellation object was garbage collected and the finalizer was run.
 | 
				
			||||||
 | 
					// If you ever see this, then you're probably doing something wrong with your code.
 | 
				
			||||||
var CancellationFinalized = errors.New("finalizer called")
 | 
					var CancellationFinalized = errors.New("finalizer called")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CancellationTimeoutError is used when a CancellationWithTimeout or CancellationWithDeadline is cancelled due to said timeout.
 | 
				
			||||||
var CancellationTimeoutError = errors.New("timeout")
 | 
					var CancellationTimeoutError = errors.New("timeout")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CancellationFinalizer is set as a finalizer when creating a new cancellation with NewCancellation(), and generally shouldn't be needed by the user, but is included in case other implementations of the same interface want to make use of it.
 | 
				
			||||||
func CancellationFinalizer(c Cancellation) {
 | 
					func CancellationFinalizer(c Cancellation) {
 | 
				
			||||||
	c.Cancel(CancellationFinalized)
 | 
						c.Cancel(CancellationFinalized)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -27,6 +34,7 @@ type cancellation struct {
 | 
				
			||||||
	done   bool
 | 
						done   bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// NewCancellation returns a pointer to a struct satisfying the Cancellation interface.
 | 
				
			||||||
func NewCancellation() Cancellation {
 | 
					func NewCancellation() Cancellation {
 | 
				
			||||||
	c := cancellation{
 | 
						c := cancellation{
 | 
				
			||||||
		cancel: make(chan struct{}),
 | 
							cancel: make(chan struct{}),
 | 
				
			||||||
| 
						 | 
					@ -35,10 +43,12 @@ func NewCancellation() Cancellation {
 | 
				
			||||||
	return &c
 | 
						return &c
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Finished returns a channel which will be closed when Cancellation.Cancel is first called.
 | 
				
			||||||
func (c *cancellation) Finished() <-chan struct{} {
 | 
					func (c *cancellation) Finished() <-chan struct{} {
 | 
				
			||||||
	return c.cancel
 | 
						return c.cancel
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Cancel closes the channel returned by Finished and sets the error returned by error, or else returns the existing error if the Cancellation has already run.
 | 
				
			||||||
func (c *cancellation) Cancel(err error) error {
 | 
					func (c *cancellation) Cancel(err error) error {
 | 
				
			||||||
	c.mutex.Lock()
 | 
						c.mutex.Lock()
 | 
				
			||||||
	defer c.mutex.Unlock()
 | 
						defer c.mutex.Unlock()
 | 
				
			||||||
| 
						 | 
					@ -52,6 +62,7 @@ func (c *cancellation) Cancel(err error) error {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Error returns the error provided to Cancel, or nil if no error has been provided.
 | 
				
			||||||
func (c *cancellation) Error() error {
 | 
					func (c *cancellation) Error() error {
 | 
				
			||||||
	c.mutex.RLock()
 | 
						c.mutex.RLock()
 | 
				
			||||||
	err := c.err
 | 
						err := c.err
 | 
				
			||||||
| 
						 | 
					@ -59,6 +70,7 @@ func (c *cancellation) Error() error {
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CancellationChild returns a new Cancellation which can be Cancelled independently of the parent, but which will also be Cancelled if the parent is Cancelled first.
 | 
				
			||||||
func CancellationChild(parent Cancellation) Cancellation {
 | 
					func CancellationChild(parent Cancellation) Cancellation {
 | 
				
			||||||
	child := NewCancellation()
 | 
						child := NewCancellation()
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -71,6 +83,7 @@ func CancellationChild(parent Cancellation) Cancellation {
 | 
				
			||||||
	return child
 | 
						return child
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CancellationWithTimeout returns a ChildCancellation that will automatically be Cancelled with a CancellationTimeoutError after the timeout.
 | 
				
			||||||
func CancellationWithTimeout(parent Cancellation, timeout time.Duration) Cancellation {
 | 
					func CancellationWithTimeout(parent Cancellation, timeout time.Duration) Cancellation {
 | 
				
			||||||
	child := CancellationChild(parent)
 | 
						child := CancellationChild(parent)
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -85,6 +98,7 @@ func CancellationWithTimeout(parent Cancellation, timeout time.Duration) Cancell
 | 
				
			||||||
	return child
 | 
						return child
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// CancellationWithTimeout returns a ChildCancellation that will automatically be Cancelled with a CancellationTimeoutError after the specified deadline.
 | 
				
			||||||
func CancellationWithDeadline(parent Cancellation, deadline time.Time) Cancellation {
 | 
					func CancellationWithDeadline(parent Cancellation, deadline time.Time) Cancellation {
 | 
				
			||||||
	return CancellationWithTimeout(parent, deadline.Sub(time.Now()))
 | 
						return CancellationWithTimeout(parent, deadline.Sub(time.Now()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,3 +1,5 @@
 | 
				
			||||||
 | 
					// Package util contains miscellaneous utilities used by yggdrasil.
 | 
				
			||||||
 | 
					// In particular, this includes a crypto worker pool, Cancellation machinery, and a sync.Pool used to reuse []byte.
 | 
				
			||||||
package util
 | 
					package util
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// These are misc. utility functions that didn't really fit anywhere else
 | 
					// These are misc. utility functions that didn't really fit anywhere else
 | 
				
			||||||
| 
						 | 
					@ -9,22 +11,22 @@ import (
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A wrapper around runtime.Gosched() so it doesn't need to be imported elsewhere.
 | 
					// Yield just executes runtime.Gosched(), and is included so we don't need to explicitly import runtime elsewhere.
 | 
				
			||||||
func Yield() {
 | 
					func Yield() {
 | 
				
			||||||
	runtime.Gosched()
 | 
						runtime.Gosched()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A wrapper around runtime.LockOSThread() so it doesn't need to be imported elsewhere.
 | 
					// LockThread executes runtime.LockOSThread(), and is included so we don't need to explicitly import runtime elsewhere.
 | 
				
			||||||
func LockThread() {
 | 
					func LockThread() {
 | 
				
			||||||
	runtime.LockOSThread()
 | 
						runtime.LockOSThread()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// A wrapper around runtime.UnlockOSThread() so it doesn't need to be imported elsewhere.
 | 
					// UnlockThread executes runtime.UnlockOSThread(), and is included so we don't need to explicitly import runtime elsewhere.
 | 
				
			||||||
func UnlockThread() {
 | 
					func UnlockThread() {
 | 
				
			||||||
	runtime.UnlockOSThread()
 | 
						runtime.UnlockOSThread()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Gets a slice of the appropriate length, reusing existing slice capacity when possible
 | 
					// ResizeBytes returns a slice of the specified length. If the provided slice has sufficient capacity, it will be resized and returned rather than allocating a new slice.
 | 
				
			||||||
func ResizeBytes(bs []byte, length int) []byte {
 | 
					func ResizeBytes(bs []byte, length int) []byte {
 | 
				
			||||||
	if cap(bs) >= length {
 | 
						if cap(bs) >= length {
 | 
				
			||||||
		return bs[:length]
 | 
							return bs[:length]
 | 
				
			||||||
| 
						 | 
					@ -33,7 +35,7 @@ func ResizeBytes(bs []byte, length int) []byte {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This is a workaround to go's broken timer implementation
 | 
					// TimerStop stops a timer and makes sure the channel is drained, returns true if the timer was stopped before firing.
 | 
				
			||||||
func TimerStop(t *time.Timer) bool {
 | 
					func TimerStop(t *time.Timer) bool {
 | 
				
			||||||
	stopped := t.Stop()
 | 
						stopped := t.Stop()
 | 
				
			||||||
	select {
 | 
						select {
 | 
				
			||||||
| 
						 | 
					@ -43,10 +45,8 @@ func TimerStop(t *time.Timer) bool {
 | 
				
			||||||
	return stopped
 | 
						return stopped
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Run a blocking function with a timeout.
 | 
					// FuncTimeout runs the provided function in a separate goroutine, and returns true if the function finishes executing before the timeout passes, or false if the timeout passes.
 | 
				
			||||||
// Returns true if the function returns.
 | 
					// It includes no mechanism to stop the function if the timeout fires, so the user is expected to do so on their own (such as with a Cancellation or a context).
 | 
				
			||||||
// Returns false if the timer fires.
 | 
					 | 
				
			||||||
// The blocked function remains blocked--the caller is responsible for somehow killing it.
 | 
					 | 
				
			||||||
func FuncTimeout(f func(), timeout time.Duration) bool {
 | 
					func FuncTimeout(f func(), timeout time.Duration) bool {
 | 
				
			||||||
	success := make(chan struct{})
 | 
						success := make(chan struct{})
 | 
				
			||||||
	go func() {
 | 
						go func() {
 | 
				
			||||||
| 
						 | 
					@ -63,9 +63,8 @@ func FuncTimeout(f func(), timeout time.Duration) bool {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// This calculates the difference between two arrays and returns items
 | 
					// Difference loops over two strings and returns the elements of A which do not appear in B.
 | 
				
			||||||
// that appear in A but not in B - useful somewhat when reconfiguring
 | 
					// This is somewhat useful when needing to determine which elements of a configuration file have changed.
 | 
				
			||||||
// and working out what configuration items changed
 | 
					 | 
				
			||||||
func Difference(a, b []string) []string {
 | 
					func Difference(a, b []string) []string {
 | 
				
			||||||
	ab := []string{}
 | 
						ab := []string{}
 | 
				
			||||||
	mb := map[string]bool{}
 | 
						mb := map[string]bool{}
 | 
				
			||||||
| 
						 | 
					@ -93,7 +92,7 @@ func DecodeCoordString(in string) (out []uint64) {
 | 
				
			||||||
	return out
 | 
						return out
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetFlowLabel takes an IP packet as an argument and returns some information about the traffic flow.
 | 
					// GetFlowKey takes an IP packet as an argument and returns some information about the traffic flow.
 | 
				
			||||||
// For IPv4 packets, this is derived from the source and destination protocol and port numbers.
 | 
					// For IPv4 packets, this is derived from the source and destination protocol and port numbers.
 | 
				
			||||||
// For IPv6 packets, this is derived from the FlowLabel field of the packet if this was set, otherwise it's handled like IPv4.
 | 
					// For IPv6 packets, this is derived from the FlowLabel field of the packet if this was set, otherwise it's handled like IPv4.
 | 
				
			||||||
// The FlowKey is then used internally by Yggdrasil for congestion control.
 | 
					// The FlowKey is then used internally by Yggdrasil for congestion control.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,29 +16,37 @@ import (
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Peer represents a single peer object. This contains information from the
 | 
					// 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
 | 
					// preferred switch port for this peer, although there may be more than one
 | 
				
			||||||
// reality.
 | 
					// active switch port connection to the peer in reality.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This struct is informational only - you cannot manipulate peer connections
 | 
				
			||||||
 | 
					// using instances of this struct. You should use the AddPeer or RemovePeer
 | 
				
			||||||
 | 
					// functions instead.
 | 
				
			||||||
type Peer struct {
 | 
					type Peer struct {
 | 
				
			||||||
	PublicKey  crypto.BoxPubKey
 | 
						PublicKey  crypto.BoxPubKey // The public key of the remote node
 | 
				
			||||||
	Endpoint   string
 | 
						Endpoint   string           // The connection string used to connect to the peer
 | 
				
			||||||
	BytesSent  uint64
 | 
						BytesSent  uint64           // Number of bytes sent to this peer
 | 
				
			||||||
	BytesRecvd uint64
 | 
						BytesRecvd uint64           // Number of bytes received from this peer
 | 
				
			||||||
	Protocol   string
 | 
						Protocol   string           // The transport protocol that this peer is connected with, typically "tcp"
 | 
				
			||||||
	Port       uint64
 | 
						Port       uint64           // Switch port number for this peer connection
 | 
				
			||||||
	Uptime     time.Duration
 | 
						Uptime     time.Duration    // How long this peering has been active for
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SwitchPeer represents a switch connection to a peer. Note that there may be
 | 
					// 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
 | 
					// multiple switch peers per actual peer, e.g. if there are multiple connections
 | 
				
			||||||
// to a given node.
 | 
					// to a given node.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This struct is informational only - you cannot manipulate switch peer
 | 
				
			||||||
 | 
					// connections using instances of this struct. You should use the AddPeer or
 | 
				
			||||||
 | 
					// RemovePeer functions instead.
 | 
				
			||||||
type SwitchPeer struct {
 | 
					type SwitchPeer struct {
 | 
				
			||||||
	PublicKey  crypto.BoxPubKey
 | 
						PublicKey  crypto.BoxPubKey // The public key of the remote node
 | 
				
			||||||
	Coords     []uint64
 | 
						Coords     []uint64         // The coordinates of the remote node
 | 
				
			||||||
	BytesSent  uint64
 | 
						BytesSent  uint64           // Number of bytes sent via this switch port
 | 
				
			||||||
	BytesRecvd uint64
 | 
						BytesRecvd uint64           // Number of bytes received via this switch port
 | 
				
			||||||
	Port       uint64
 | 
						Port       uint64           // Switch port number for this switch peer
 | 
				
			||||||
	Protocol   string
 | 
						Protocol   string           // The transport protocol that this switch port is connected with, typically "tcp"
 | 
				
			||||||
	Endpoint   string
 | 
						Endpoint   string           // The connection string used to connect to the switch peer
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// DHTEntry represents a single DHT entry that has been learned or cached from
 | 
					// DHTEntry represents a single DHT entry that has been learned or cached from
 | 
				
			||||||
| 
						 | 
					@ -64,32 +72,36 @@ type NodeInfoPayload []byte
 | 
				
			||||||
// congestion and a list of switch queues created in response to congestion on a
 | 
					// congestion and a list of switch queues created in response to congestion on a
 | 
				
			||||||
// given link.
 | 
					// given link.
 | 
				
			||||||
type SwitchQueues struct {
 | 
					type SwitchQueues struct {
 | 
				
			||||||
	Queues       []SwitchQueue
 | 
						Queues       []SwitchQueue // An array of SwitchQueue objects containing information about individual queues
 | 
				
			||||||
	Count        uint64
 | 
						Count        uint64        // The current number of active switch queues
 | 
				
			||||||
	Size         uint64
 | 
						Size         uint64        // The current total size of active switch queues
 | 
				
			||||||
	HighestCount uint64
 | 
						HighestCount uint64        // The highest recorded number of switch queues so far
 | 
				
			||||||
	HighestSize  uint64
 | 
						HighestSize  uint64        // The highest recorded total size of switch queues so far
 | 
				
			||||||
	MaximumSize  uint64
 | 
						MaximumSize  uint64        // The maximum allowed total size of switch queues, as specified by config
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SwitchQueue represents a single switch queue, which is created in response
 | 
					// SwitchQueue represents a single switch queue. Switch queues are only created
 | 
				
			||||||
// to congestion on a given link.
 | 
					// in response to congestion on a given link and represent how much data has
 | 
				
			||||||
 | 
					// been temporarily cached for sending once the congestion has cleared.
 | 
				
			||||||
type SwitchQueue struct {
 | 
					type SwitchQueue struct {
 | 
				
			||||||
	ID      string
 | 
						ID      string // The ID of the switch queue
 | 
				
			||||||
	Size    uint64
 | 
						Size    uint64 // The total size, in bytes, of the queue
 | 
				
			||||||
	Packets uint64
 | 
						Packets uint64 // The number of packets in the queue
 | 
				
			||||||
	Port    uint64
 | 
						Port    uint64 // The switch port to which the queue applies
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Session represents an open session with another node.
 | 
					// Session represents an open session with another node. Sessions are opened in
 | 
				
			||||||
 | 
					// response to traffic being exchanged between two nodes using Conn objects.
 | 
				
			||||||
 | 
					// Note that sessions will automatically be closed by Yggdrasil if no traffic is
 | 
				
			||||||
 | 
					// exchanged for around two minutes.
 | 
				
			||||||
type Session struct {
 | 
					type Session struct {
 | 
				
			||||||
	PublicKey   crypto.BoxPubKey
 | 
						PublicKey   crypto.BoxPubKey // The public key of the remote node
 | 
				
			||||||
	Coords      []uint64
 | 
						Coords      []uint64         // The coordinates of the remote node
 | 
				
			||||||
	BytesSent   uint64
 | 
						BytesSent   uint64           // Bytes sent to the session
 | 
				
			||||||
	BytesRecvd  uint64
 | 
						BytesRecvd  uint64           // Bytes received from the session
 | 
				
			||||||
	MTU         uint16
 | 
						MTU         uint16           // The maximum supported message size of the session
 | 
				
			||||||
	Uptime      time.Duration
 | 
						Uptime      time.Duration    // How long this session has been active for
 | 
				
			||||||
	WasMTUFixed bool
 | 
						WasMTUFixed bool             // This field is no longer used
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetPeers returns one or more Peer objects containing information about active
 | 
					// GetPeers returns one or more Peer objects containing information about active
 | 
				
			||||||
| 
						 | 
					@ -236,7 +248,10 @@ func (c *Core) GetSessions() []Session {
 | 
				
			||||||
	return sessions
 | 
						return sessions
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ConnListen returns a listener for Yggdrasil session connections.
 | 
					// ConnListen returns a listener for Yggdrasil session connections. You can only
 | 
				
			||||||
 | 
					// call this function once as each Yggdrasil node can only have a single
 | 
				
			||||||
 | 
					// ConnListener. Make sure to keep the reference to this for as long as it is
 | 
				
			||||||
 | 
					// needed.
 | 
				
			||||||
func (c *Core) ConnListen() (*Listener, error) {
 | 
					func (c *Core) ConnListen() (*Listener, error) {
 | 
				
			||||||
	c.router.sessions.listenerMutex.Lock()
 | 
						c.router.sessions.listenerMutex.Lock()
 | 
				
			||||||
	defer c.router.sessions.listenerMutex.Unlock()
 | 
						defer c.router.sessions.listenerMutex.Unlock()
 | 
				
			||||||
| 
						 | 
					@ -251,7 +266,10 @@ func (c *Core) ConnListen() (*Listener, error) {
 | 
				
			||||||
	return c.router.sessions.listener, nil
 | 
						return c.router.sessions.listener, nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// ConnDialer returns a dialer for Yggdrasil session connections.
 | 
					// ConnDialer returns a dialer for Yggdrasil session connections. Since
 | 
				
			||||||
 | 
					// ConnDialers are stateless, you can request as many dialers as you like,
 | 
				
			||||||
 | 
					// although ideally you should request only one and keep the reference to it for
 | 
				
			||||||
 | 
					// as long as it is needed.
 | 
				
			||||||
func (c *Core) ConnDialer() (*Dialer, error) {
 | 
					func (c *Core) ConnDialer() (*Dialer, error) {
 | 
				
			||||||
	return &Dialer{
 | 
						return &Dialer{
 | 
				
			||||||
		core: c,
 | 
							core: c,
 | 
				
			||||||
| 
						 | 
					@ -265,48 +283,69 @@ func (c *Core) ListenTCP(uri string) (*TcpListener, error) {
 | 
				
			||||||
	return c.link.tcp.listen(uri)
 | 
						return c.link.tcp.listen(uri)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// NodeID gets the node ID.
 | 
					// NodeID gets the node ID. This is derived from your router encryption keys.
 | 
				
			||||||
 | 
					// Remote nodes wanting to open connections to your node will need to know your
 | 
				
			||||||
 | 
					// node ID.
 | 
				
			||||||
func (c *Core) NodeID() *crypto.NodeID {
 | 
					func (c *Core) NodeID() *crypto.NodeID {
 | 
				
			||||||
	return crypto.GetNodeID(&c.boxPub)
 | 
						return crypto.GetNodeID(&c.boxPub)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TreeID gets the tree ID.
 | 
					// TreeID gets the tree ID. This is derived from your switch signing keys. There
 | 
				
			||||||
 | 
					// is typically no need to share this key.
 | 
				
			||||||
func (c *Core) TreeID() *crypto.TreeID {
 | 
					func (c *Core) TreeID() *crypto.TreeID {
 | 
				
			||||||
	return crypto.GetTreeID(&c.sigPub)
 | 
						return crypto.GetTreeID(&c.sigPub)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SigningPublicKey gets the node's signing public key.
 | 
					// SigningPublicKey gets the node's signing public key, as used by the switch.
 | 
				
			||||||
func (c *Core) SigningPublicKey() string {
 | 
					func (c *Core) SigningPublicKey() string {
 | 
				
			||||||
	return hex.EncodeToString(c.sigPub[:])
 | 
						return hex.EncodeToString(c.sigPub[:])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// EncryptionPublicKey gets the node's encryption public key.
 | 
					// EncryptionPublicKey gets the node's encryption public key, as used by the
 | 
				
			||||||
 | 
					// router.
 | 
				
			||||||
func (c *Core) EncryptionPublicKey() string {
 | 
					func (c *Core) EncryptionPublicKey() string {
 | 
				
			||||||
	return hex.EncodeToString(c.boxPub[:])
 | 
						return hex.EncodeToString(c.boxPub[:])
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Coords returns the current coordinates of the node.
 | 
					// Coords returns the current coordinates of the node. Note that these can
 | 
				
			||||||
 | 
					// change at any time for a number of reasons, not limited to but including
 | 
				
			||||||
 | 
					// changes to peerings (either yours or a parent nodes) or changes to the network
 | 
				
			||||||
 | 
					// root.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// This function may return an empty array - this is normal behaviour if either
 | 
				
			||||||
 | 
					// you are the root of the network that you are connected to, or you are not
 | 
				
			||||||
 | 
					// connected to any other nodes (effectively making you the root of a
 | 
				
			||||||
 | 
					// single-node network).
 | 
				
			||||||
func (c *Core) Coords() []uint64 {
 | 
					func (c *Core) Coords() []uint64 {
 | 
				
			||||||
	table := c.switchTable.table.Load().(lookupTable)
 | 
						table := c.switchTable.table.Load().(lookupTable)
 | 
				
			||||||
	return wire_coordsBytestoUint64s(table.self.getCoords())
 | 
						return wire_coordsBytestoUint64s(table.self.getCoords())
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
 | 
					// Address gets the IPv6 address of the Yggdrasil node. This is always a /128
 | 
				
			||||||
// address.
 | 
					// address. The IPv6 address is only relevant when the node is operating as an
 | 
				
			||||||
 | 
					// IP router and often is meaningless when embedded into an application, unless
 | 
				
			||||||
 | 
					// that application also implements either VPN functionality or deals with IP
 | 
				
			||||||
 | 
					// packets specifically.
 | 
				
			||||||
func (c *Core) Address() net.IP {
 | 
					func (c *Core) Address() net.IP {
 | 
				
			||||||
	address := net.IP(address.AddrForNodeID(c.NodeID())[:])
 | 
						address := net.IP(address.AddrForNodeID(c.NodeID())[:])
 | 
				
			||||||
	return address
 | 
						return address
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
 | 
					// Subnet gets the routed IPv6 subnet of the Yggdrasil node. This is always a
 | 
				
			||||||
// /64 subnet.
 | 
					// /64 subnet. The IPv6 subnet is only relevant when the node is operating as an
 | 
				
			||||||
 | 
					// IP router and often is meaningless when embedded into an application, unless
 | 
				
			||||||
 | 
					// that application also implements either VPN functionality or deals with IP
 | 
				
			||||||
 | 
					// packets specifically.
 | 
				
			||||||
func (c *Core) Subnet() net.IPNet {
 | 
					func (c *Core) Subnet() net.IPNet {
 | 
				
			||||||
	subnet := address.SubnetForNodeID(c.NodeID())[:]
 | 
						subnet := address.SubnetForNodeID(c.NodeID())[:]
 | 
				
			||||||
	subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
 | 
						subnet = append(subnet, 0, 0, 0, 0, 0, 0, 0, 0)
 | 
				
			||||||
	return net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
 | 
						return net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MyNodeInfo gets the currently configured nodeinfo.
 | 
					// MyNodeInfo gets the currently configured nodeinfo. NodeInfo is typically
 | 
				
			||||||
 | 
					// specified through the "NodeInfo" option in the node configuration or using
 | 
				
			||||||
 | 
					// the SetNodeInfo function, although it may also contain other built-in values
 | 
				
			||||||
 | 
					// such as "buildname", "buildversion" etc.
 | 
				
			||||||
func (c *Core) MyNodeInfo() NodeInfoPayload {
 | 
					func (c *Core) MyNodeInfo() NodeInfoPayload {
 | 
				
			||||||
	return c.router.nodeinfo.getNodeInfo()
 | 
						return c.router.nodeinfo.getNodeInfo()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -356,7 +395,9 @@ func (c *Core) SetSessionGatekeeper(f func(pubkey *crypto.BoxPubKey, initiator b
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetLogger sets the output logger of the Yggdrasil node after startup. This
 | 
					// SetLogger sets the output logger of the Yggdrasil node after startup. This
 | 
				
			||||||
// may be useful if you want to redirect the output later.
 | 
					// may be useful if you want to redirect the output later. Note that this
 | 
				
			||||||
 | 
					// expects a Logger from the github.com/gologme/log package and not from Go's
 | 
				
			||||||
 | 
					// built-in log package.
 | 
				
			||||||
func (c *Core) SetLogger(log *log.Logger) {
 | 
					func (c *Core) SetLogger(log *log.Logger) {
 | 
				
			||||||
	c.log = log
 | 
						c.log = log
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -427,12 +468,17 @@ func (c *Core) DisconnectPeer(port uint64) error {
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// GetAllowedEncryptionPublicKeys returns the public keys permitted for incoming
 | 
					// GetAllowedEncryptionPublicKeys returns the public keys permitted for incoming
 | 
				
			||||||
// peer connections.
 | 
					// peer connections. If this list is empty then all incoming peer connections
 | 
				
			||||||
 | 
					// are accepted by default.
 | 
				
			||||||
func (c *Core) GetAllowedEncryptionPublicKeys() []string {
 | 
					func (c *Core) GetAllowedEncryptionPublicKeys() []string {
 | 
				
			||||||
	return c.peers.getAllowedEncryptionPublicKeys()
 | 
						return c.peers.getAllowedEncryptionPublicKeys()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// AddAllowedEncryptionPublicKey whitelists a key for incoming peer connections.
 | 
					// AddAllowedEncryptionPublicKey whitelists a key for incoming peer connections.
 | 
				
			||||||
 | 
					// By default all incoming peer connections are accepted, but adding public keys
 | 
				
			||||||
 | 
					// to the whitelist using this function enables strict checking from that point
 | 
				
			||||||
 | 
					// forward. Once the whitelist is enabled, only peer connections from
 | 
				
			||||||
 | 
					// whitelisted public keys will be accepted.
 | 
				
			||||||
func (c *Core) AddAllowedEncryptionPublicKey(bstr string) (err error) {
 | 
					func (c *Core) AddAllowedEncryptionPublicKey(bstr string) (err error) {
 | 
				
			||||||
	c.peers.addAllowedEncryptionPublicKey(bstr)
 | 
						c.peers.addAllowedEncryptionPublicKey(bstr)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -53,6 +53,9 @@ func (e *ConnError) Closed() bool {
 | 
				
			||||||
	return e.closed
 | 
						return e.closed
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// The Conn struct is a reference to an active connection session between the
 | 
				
			||||||
 | 
					// local node and a remote node. Conn implements the io.ReadWriteCloser
 | 
				
			||||||
 | 
					// interface and is used to send and receive traffic with a remote node.
 | 
				
			||||||
type Conn struct {
 | 
					type Conn struct {
 | 
				
			||||||
	phony.Inbox
 | 
						phony.Inbox
 | 
				
			||||||
	core          *Core
 | 
						core          *Core
 | 
				
			||||||
| 
						 | 
					@ -78,6 +81,11 @@ func newConn(core *Core, nodeID *crypto.NodeID, nodeMask *crypto.NodeID, session
 | 
				
			||||||
	return &conn
 | 
						return &conn
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// String returns a string that uniquely identifies a connection. Currently this
 | 
				
			||||||
 | 
					// takes a form similar to "conn=0x0000000", which contains a memory reference
 | 
				
			||||||
 | 
					// to the Conn object. While this value should always be unique for each Conn
 | 
				
			||||||
 | 
					// object, the format of this is not strictly defined and may change in the
 | 
				
			||||||
 | 
					// future.
 | 
				
			||||||
func (c *Conn) String() string {
 | 
					func (c *Conn) String() string {
 | 
				
			||||||
	var s string
 | 
						var s string
 | 
				
			||||||
	phony.Block(c, func() { s = fmt.Sprintf("conn=%p", c) })
 | 
						phony.Block(c, func() { s = fmt.Sprintf("conn=%p", c) })
 | 
				
			||||||
| 
						 | 
					@ -162,7 +170,12 @@ func (c *Conn) _getDeadlineCancellation(t *time.Time) (util.Cancellation, bool)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// SetReadCallback sets a callback which will be called whenever a packet is received.
 | 
					// SetReadCallback allows you to specify a function that will be called whenever
 | 
				
			||||||
 | 
					// a packet is received. This should be used if you wish to implement
 | 
				
			||||||
 | 
					// asynchronous patterns for receiving data from the remote node.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Note that if a read callback has been supplied, you should no longer attempt
 | 
				
			||||||
 | 
					// to use the synchronous Read function.
 | 
				
			||||||
func (c *Conn) SetReadCallback(callback func([]byte)) {
 | 
					func (c *Conn) SetReadCallback(callback func([]byte)) {
 | 
				
			||||||
	c.Act(nil, func() {
 | 
						c.Act(nil, func() {
 | 
				
			||||||
		c.readCallback = callback
 | 
							c.readCallback = callback
 | 
				
			||||||
| 
						 | 
					@ -217,7 +230,14 @@ func (c *Conn) readNoCopy() ([]byte, error) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Implements net.Conn.Read
 | 
					// Read allows you to read from the connection in a synchronous fashion. The
 | 
				
			||||||
 | 
					// function will block up until the point that either new data is available, the
 | 
				
			||||||
 | 
					// connection has been closed or the read deadline has been reached. If the
 | 
				
			||||||
 | 
					// function succeeds, the number of bytes read from the connection will be
 | 
				
			||||||
 | 
					// returned. Otherwise, an error condition will be returned.
 | 
				
			||||||
 | 
					//
 | 
				
			||||||
 | 
					// Note that you can also implement asynchronous reads by using SetReadCallback.
 | 
				
			||||||
 | 
					// If you do that, you should no longer attempt to use the Read function.
 | 
				
			||||||
func (c *Conn) Read(b []byte) (int, error) {
 | 
					func (c *Conn) Read(b []byte) (int, error) {
 | 
				
			||||||
	bs, err := c.readNoCopy()
 | 
						bs, err := c.readNoCopy()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
| 
						 | 
					@ -259,9 +279,9 @@ func (c *Conn) _write(msg FlowKeyMessage) error {
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// WriteFrom should be called by a phony.Actor, and tells the Conn to send a message.
 | 
					// WriteFrom should be called by a phony.Actor, and tells the Conn to send a
 | 
				
			||||||
// This is used internaly by Write.
 | 
					// message. This is used internaly by Write. If the callback is called with a
 | 
				
			||||||
// If the callback is called with a non-nil value, then it is safe to reuse the argument FlowKeyMessage.
 | 
					// non-nil value, then it is safe to reuse the argument FlowKeyMessage.
 | 
				
			||||||
func (c *Conn) WriteFrom(from phony.Actor, msg FlowKeyMessage, callback func(error)) {
 | 
					func (c *Conn) WriteFrom(from phony.Actor, msg FlowKeyMessage, callback func(error)) {
 | 
				
			||||||
	c.Act(from, func() {
 | 
						c.Act(from, func() {
 | 
				
			||||||
		callback(c._write(msg))
 | 
							callback(c._write(msg))
 | 
				
			||||||
| 
						 | 
					@ -291,7 +311,11 @@ func (c *Conn) writeNoCopy(msg FlowKeyMessage) error {
 | 
				
			||||||
	return err
 | 
						return err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Write implement the Write function of a net.Conn, and makes use of WriteNoCopy under the hood.
 | 
					// Write allows you to write to the connection in a synchronous fashion. This
 | 
				
			||||||
 | 
					// function may block until either the write has completed, the connection has
 | 
				
			||||||
 | 
					// been closed or the write deadline has been reached. If the function succeeds,
 | 
				
			||||||
 | 
					// the number of written bytes is returned. Otherwise, an error condition is
 | 
				
			||||||
 | 
					// returned.
 | 
				
			||||||
func (c *Conn) Write(b []byte) (int, error) {
 | 
					func (c *Conn) Write(b []byte) (int, error) {
 | 
				
			||||||
	written := len(b)
 | 
						written := len(b)
 | 
				
			||||||
	msg := FlowKeyMessage{Message: append(util.GetBytes(), b...)}
 | 
						msg := FlowKeyMessage{Message: append(util.GetBytes(), b...)}
 | 
				
			||||||
| 
						 | 
					@ -303,6 +327,10 @@ func (c *Conn) Write(b []byte) (int, error) {
 | 
				
			||||||
	return written, err
 | 
						return written, err
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Close will close an open connection and any blocking operations on the
 | 
				
			||||||
 | 
					// connection will unblock and return. From this point forward, the connection
 | 
				
			||||||
 | 
					// can no longer be used and you should no longer attempt to Read or Write to
 | 
				
			||||||
 | 
					// the connection.
 | 
				
			||||||
func (c *Conn) Close() (err error) {
 | 
					func (c *Conn) Close() (err error) {
 | 
				
			||||||
	phony.Block(c, func() {
 | 
						phony.Block(c, func() {
 | 
				
			||||||
		if c.session != nil {
 | 
							if c.session != nil {
 | 
				
			||||||
| 
						 | 
					@ -317,10 +345,13 @@ func (c *Conn) Close() (err error) {
 | 
				
			||||||
	return
 | 
						return
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// LocalAddr returns the complete node ID of the local side of the connection.
 | 
				
			||||||
 | 
					// This is always going to return your own node's node ID.
 | 
				
			||||||
func (c *Conn) LocalAddr() crypto.NodeID {
 | 
					func (c *Conn) LocalAddr() crypto.NodeID {
 | 
				
			||||||
	return *crypto.GetNodeID(&c.core.boxPub)
 | 
						return *crypto.GetNodeID(&c.core.boxPub)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// RemoteAddr returns the complete node ID of the remote side of the connection.
 | 
				
			||||||
func (c *Conn) RemoteAddr() crypto.NodeID {
 | 
					func (c *Conn) RemoteAddr() crypto.NodeID {
 | 
				
			||||||
	// TODO warn that this can block while waiting for the Conn actor to run, so don't call it from other actors...
 | 
						// TODO warn that this can block while waiting for the Conn actor to run, so don't call it from other actors...
 | 
				
			||||||
	var n crypto.NodeID
 | 
						var n crypto.NodeID
 | 
				
			||||||
| 
						 | 
					@ -328,18 +359,32 @@ func (c *Conn) RemoteAddr() crypto.NodeID {
 | 
				
			||||||
	return n
 | 
						return n
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetDeadline is equivalent to calling both SetReadDeadline and
 | 
				
			||||||
 | 
					// SetWriteDeadline with the same value, configuring the maximum amount of time
 | 
				
			||||||
 | 
					// that synchronous Read and Write operations can block for. If no deadline is
 | 
				
			||||||
 | 
					// configured, Read and Write operations can potentially block indefinitely.
 | 
				
			||||||
func (c *Conn) SetDeadline(t time.Time) error {
 | 
					func (c *Conn) SetDeadline(t time.Time) error {
 | 
				
			||||||
	c.SetReadDeadline(t)
 | 
						c.SetReadDeadline(t)
 | 
				
			||||||
	c.SetWriteDeadline(t)
 | 
						c.SetWriteDeadline(t)
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetReadDeadline configures the maximum amount of time that a synchronous Read
 | 
				
			||||||
 | 
					// operation can block for. A Read operation will unblock at the point that the
 | 
				
			||||||
 | 
					// read deadline is reached if no other condition (such as data arrival or
 | 
				
			||||||
 | 
					// connection closure) happens first. If no deadline is configured, Read
 | 
				
			||||||
 | 
					// operations can potentially block indefinitely.
 | 
				
			||||||
func (c *Conn) SetReadDeadline(t time.Time) error {
 | 
					func (c *Conn) SetReadDeadline(t time.Time) error {
 | 
				
			||||||
	// TODO warn that this can block while waiting for the Conn actor to run, so don't call it from other actors...
 | 
						// TODO warn that this can block while waiting for the Conn actor to run, so don't call it from other actors...
 | 
				
			||||||
	phony.Block(c, func() { c.readDeadline = &t })
 | 
						phony.Block(c, func() { c.readDeadline = &t })
 | 
				
			||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// SetWriteDeadline configures the maximum amount of time that a synchronous
 | 
				
			||||||
 | 
					// Write operation can block for. A Write operation will unblock at the point
 | 
				
			||||||
 | 
					// that the read deadline is reached if no other condition (such as data sending
 | 
				
			||||||
 | 
					// or connection closure) happens first. If no deadline is configured, Write
 | 
				
			||||||
 | 
					// operations can potentially block indefinitely.
 | 
				
			||||||
func (c *Conn) SetWriteDeadline(t time.Time) error {
 | 
					func (c *Conn) SetWriteDeadline(t time.Time) error {
 | 
				
			||||||
	// TODO warn that this can block while waiting for the Conn actor to run, so don't call it from other actors...
 | 
						// TODO warn that this can block while waiting for the Conn actor to run, so don't call it from other actors...
 | 
				
			||||||
	phony.Block(c, func() { c.writeDeadline = &t })
 | 
						phony.Block(c, func() { c.writeDeadline = &t })
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										176
									
								
								src/yggdrasil/doc.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										176
									
								
								src/yggdrasil/doc.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,176 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					Package yggdrasil implements the core functionality of the Yggdrasil Network.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Introduction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Yggdrasil is a proof-of-concept mesh network which provides end-to-end encrypted
 | 
				
			||||||
 | 
					communication between nodes in a decentralised fashion. The network is arranged
 | 
				
			||||||
 | 
					using a globally-agreed spanning tree which provides each node with a locator
 | 
				
			||||||
 | 
					(coordinates relative to the root) and a distributed hash table (DHT) mechanism
 | 
				
			||||||
 | 
					for finding other nodes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each node also implements a router, which is responsible for encryption of
 | 
				
			||||||
 | 
					traffic, searches and connections, and a switch, which is responsible ultimately
 | 
				
			||||||
 | 
					for forwarding traffic across the network.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					While many Yggdrasil nodes in existence today are IP nodes - that is, they are
 | 
				
			||||||
 | 
					transporting IPv6 packets, like a kind of mesh VPN - it is also possible to
 | 
				
			||||||
 | 
					integrate Yggdrasil into your own applications and use it as a generic data
 | 
				
			||||||
 | 
					transport, similar to UDP.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This library is what you need to integrate and use Yggdrasil in your own
 | 
				
			||||||
 | 
					application.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Basics
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to start an Yggdrasil node, you should start by generating node
 | 
				
			||||||
 | 
					configuration, which amongst other things, includes encryption keypairs which
 | 
				
			||||||
 | 
					are used to generate the node's identity, and supply a logger which Yggdrasil's
 | 
				
			||||||
 | 
					output will be written to.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This may look something like this:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  import (
 | 
				
			||||||
 | 
					    "os"
 | 
				
			||||||
 | 
					    "github.com/gologme/log"
 | 
				
			||||||
 | 
					    "github.com/yggdrasil-network/yggdrasil-go/src/config"
 | 
				
			||||||
 | 
					    "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
 | 
				
			||||||
 | 
					  )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  type node struct {
 | 
				
			||||||
 | 
					    core   yggdrasil.Core
 | 
				
			||||||
 | 
					    config *config.NodeConfig
 | 
				
			||||||
 | 
					    log    *log.Logger
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You then can supply node configuration and a logger:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  n := node{}
 | 
				
			||||||
 | 
					  n.log = log.New(os.Stdout, "", log.Flags())
 | 
				
			||||||
 | 
					  n.config = config.GenerateConfig()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the above example, we ask the config package to supply new configuration each
 | 
				
			||||||
 | 
					time, which results in fresh encryption keys and therefore a new identity. It is
 | 
				
			||||||
 | 
					normally preferable in most cases to persist node configuration onto the
 | 
				
			||||||
 | 
					filesystem or into some configuration store so that the node's identity does not
 | 
				
			||||||
 | 
					change each time that the program starts. Note that Yggdrasil will automatically
 | 
				
			||||||
 | 
					fill in any missing configuration items with sane defaults.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once you have supplied a logger and some node configuration, you can then start
 | 
				
			||||||
 | 
					the node:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  n.core.Start(n.config, n.log)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Add some peers to connect to the network:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  n.core.AddPeer("tcp://some-host.net:54321", "")
 | 
				
			||||||
 | 
					  n.core.AddPeer("tcp://[2001::1:2:3]:54321", "")
 | 
				
			||||||
 | 
					  n.core.AddPeer("tcp://1.2.3.4:54321", "")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can also ask the API for information about our node:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  n.log.Println("My node ID is", n.core.NodeID())
 | 
				
			||||||
 | 
					  n.log.Println("My public key is", n.core.EncryptionPublicKey())
 | 
				
			||||||
 | 
					  n.log.Println("My coords are", n.core.Coords())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Incoming Connections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once your node is started, you can then listen for connections from other nodes
 | 
				
			||||||
 | 
					by asking the API for a Listener:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  listener, err := n.core.ConnListen()
 | 
				
			||||||
 | 
					  if err != nil {
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The Listener has a blocking Accept function which will wait for incoming
 | 
				
			||||||
 | 
					connections from remote nodes. It will return a Conn when a connection is
 | 
				
			||||||
 | 
					received. If the node never receives any incoming connections then this function
 | 
				
			||||||
 | 
					can block forever, so be prepared for that, perhaps by listening in a separate
 | 
				
			||||||
 | 
					goroutine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Assuming that you have defined a myConnectionHandler function to deal with
 | 
				
			||||||
 | 
					incoming connections:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for {
 | 
				
			||||||
 | 
					    conn, err := listener.Accept()
 | 
				
			||||||
 | 
					    if err != nil {
 | 
				
			||||||
 | 
					      // ...
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We've got a new connection
 | 
				
			||||||
 | 
					    go myConnectionHandler(conn)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Outgoing Connections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you know the node ID of the remote node that you want to talk to, you can
 | 
				
			||||||
 | 
					dial an outbound connection to it. To do this, you should first ask the API for
 | 
				
			||||||
 | 
					a Dialer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dialer, err := n.core.ConnDialer()
 | 
				
			||||||
 | 
					  if err != nil {
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can then dial using the 16-byte node ID in hexadecimal format, for example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  conn, err := dialer.Dial("nodeid", "24a58cfce691ec016b0f698f7be1bee983cea263781017e99ad3ef62b4ef710a45d6c1a072c5ce46131bd574b78818c9957042cafeeed13966f349e94eb771bf")
 | 
				
			||||||
 | 
					  if err != nil {
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Using Connections
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Conn objects are implementations of io.ReadWriteCloser, and as such, you can
 | 
				
			||||||
 | 
					Read, Write and Close them as necessary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each Read or Write operation can deal with a buffer with a maximum size of 65535
 | 
				
			||||||
 | 
					bytes - any bigger than this and the operation will return an error.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example, to write to the Conn from the supplied buffer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  buf := []byte{1, 2, 3, 4, 5}
 | 
				
			||||||
 | 
					  w, err := conn.Write(buf)
 | 
				
			||||||
 | 
					  if err != nil {
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // written w bytes
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Reading from the Conn into the supplied buffer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  buf := make([]byte, 65535)
 | 
				
			||||||
 | 
					  r, err := conn.Read(buf)
 | 
				
			||||||
 | 
					  if err != nil {
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					    // read r bytes
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you are happy that a connection is no longer required, you can discard it:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  err := conn.Close()
 | 
				
			||||||
 | 
					  if err != nil {
 | 
				
			||||||
 | 
					    // ...
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Limitations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You should be aware of the following limitations when working with the Yggdrasil
 | 
				
			||||||
 | 
					library:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Individual messages written through Yggdrasil connections can not exceed 65535
 | 
				
			||||||
 | 
					bytes in size. Yggdrasil has no concept of fragmentation, so if you try to send
 | 
				
			||||||
 | 
					a message that exceeds 65535 bytes in size, it will be dropped altogether and
 | 
				
			||||||
 | 
					an error will be returned.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Yggdrasil connections are unreliable by nature. Messages are delivered on a
 | 
				
			||||||
 | 
					best-effort basis, and employs congestion control where appropriate to ensure
 | 
				
			||||||
 | 
					that congestion does not affect message transport, but Yggdrasil will not
 | 
				
			||||||
 | 
					retransmit any messages that have been lost. If reliable delivery is important
 | 
				
			||||||
 | 
					then you should manually implement acknowledgement and retransmission of
 | 
				
			||||||
 | 
					messages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					package yggdrasil
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue