mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2024-11-27 12:05:23 +00:00
document address, crypto, and util
This commit is contained in:
parent
903a8921fc
commit
cd99d04bd4
@ -2,21 +2,21 @@ 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 +27,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 +39,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 +80,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 +96,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 +126,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
|
||||||
|
@ -26,12 +26,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 +78,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 +104,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 +135,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 +143,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 +164,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 +202,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 +212,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 +223,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 +238,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 +253,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 +264,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 +273,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()))
|
||||||
}
|
}
|
||||||
|
@ -9,22 +9,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 +33,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 +43,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 +61,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 +90,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.
|
||||||
|
Loading…
Reference in New Issue
Block a user