Wrap the metadata with a mutex to guarantee thread safety across core/router/sessions

This commit is contained in:
Neil Alexander 2018-12-12 22:40:49 +00:00
parent 97464feba9
commit 042a3400fe
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
4 changed files with 40 additions and 14 deletions

View File

@ -80,11 +80,6 @@ func GetBuildVersion() string {
return buildVersion return buildVersion
} }
// Gets the friendly name of this node, as specified in the NodeConfig.
func (c *Core) GetMeta() metadata {
return c.sessions.myMetadata
}
// Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging // Starts up Yggdrasil using the provided NodeConfig, and outputs debug logging
// through the provided log.Logger. The started stack will include TCP and UDP // through the provided log.Logger. The started stack will include TCP and UDP
// sockets, a multicast discovery socket, an admin socket, router, switch and // sockets, a multicast discovery socket, an admin socket, router, switch and
@ -245,6 +240,16 @@ func (c *Core) GetSubnet() *net.IPNet {
return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)} return &net.IPNet{IP: subnet, Mask: net.CIDRMask(64, 128)}
} }
// Gets the node metadata.
func (c *Core) GetMetadata() metadata {
return c.sessions.getMetadata()
}
// Sets the node metadata.
func (c *Core) SetMetadata(meta metadata) {
c.sessions.setMetadata(meta)
}
// Sets the output logger of the Yggdrasil node after startup. This may be // Sets the output logger of the Yggdrasil node after startup. This may be
// useful if you want to redirect the output later. // useful if you want to redirect the output later.
func (c *Core) SetLogger(log *log.Logger) { func (c *Core) SetLogger(log *log.Logger) {

View File

@ -58,7 +58,9 @@ func (r *router) init(core *Core) {
r.addr = *address_addrForNodeID(&r.core.dht.nodeID) r.addr = *address_addrForNodeID(&r.core.dht.nodeID)
r.subnet = *address_subnetForNodeID(&r.core.dht.nodeID) r.subnet = *address_subnetForNodeID(&r.core.dht.nodeID)
in := make(chan []byte, 32) // TODO something better than this... in := make(chan []byte, 32) // TODO something better than this...
r.core.sessions.myMetadataMutex.RLock()
p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}, "(self)", r.core.sessions.myMetadata) p := r.core.peers.newPeer(&r.core.boxPub, &r.core.sigPub, &boxSharedKey{}, "(self)", r.core.sessions.myMetadata)
r.core.sessions.myMetadataMutex.RUnlock()
p.out = func(packet []byte) { p.out = func(packet []byte) {
// This is to make very sure it never blocks // This is to make very sure it never blocks
select { select {

View File

@ -7,6 +7,7 @@ package yggdrasil
import ( import (
"bytes" "bytes"
"encoding/hex" "encoding/hex"
"sync"
"time" "time"
) )
@ -129,6 +130,7 @@ type sessions struct {
sessionFirewallBlacklist []string sessionFirewallBlacklist []string
// Metadata for this node // Metadata for this node
myMetadata metadata myMetadata metadata
myMetadataMutex sync.RWMutex
} }
// Initializes the session struct. // Initializes the session struct.
@ -143,8 +145,17 @@ func (ss *sessions) init(core *Core) {
ss.lastCleanup = time.Now() ss.lastCleanup = time.Now()
} }
// Enable or disable the session firewall // Get the metadata
func (ss *sessions) getMetadata() metadata {
ss.myMetadataMutex.RLock()
defer ss.myMetadataMutex.RUnlock()
return ss.myMetadata
}
// Set the metadata
func (ss *sessions) setMetadata(meta metadata) { func (ss *sessions) setMetadata(meta metadata) {
ss.myMetadataMutex.Lock()
defer ss.myMetadataMutex.Unlock()
ss.myMetadata = meta ss.myMetadata = meta
} }
@ -485,18 +496,23 @@ func (ss *sessions) handlePing(ping *sessionPing) {
bs, sinfo.packet = sinfo.packet, nil bs, sinfo.packet = sinfo.packet, nil
ss.core.router.sendPacket(bs) ss.core.router.sendPacket(bs)
} }
if time.Since(sinfo.metaResTime).Minutes() > 15 { // This requests metadata from the remote side fairly quickly after
if time.Since(sinfo.metaReqTime).Minutes() > 1 { // establishing the session, and if other time constraints apply (no more
ss.sendMeta(sinfo, false) // often than 15 minutes since receiving the last metadata)
} //if time.Since(sinfo.metaResTime).Minutes() > 15 {
} // if time.Since(sinfo.metaReqTime).Minutes() > 1 {
// ss.sendMeta(sinfo, false)
// }
//}
} }
func (ss *sessions) sendMeta(sinfo *sessionInfo, isResponse bool) { func (ss *sessions) sendMeta(sinfo *sessionInfo, isResponse bool) {
ss.myMetadataMutex.RLock()
meta := sessionMeta{ meta := sessionMeta{
IsResponse: isResponse, IsResponse: isResponse,
Metadata: ss.myMetadata, Metadata: ss.myMetadata,
} }
ss.myMetadataMutex.RUnlock()
bs := meta.encode() bs := meta.encode()
shared := ss.getSharedKey(&ss.core.boxPriv, &sinfo.theirPermPub) shared := ss.getSharedKey(&ss.core.boxPriv, &sinfo.theirPermPub)
payload, nonce := boxSeal(shared, bs, nil) payload, nonce := boxSeal(shared, bs, nil)

View File

@ -355,7 +355,7 @@ func (p *sessionPing) decode(bs []byte) bool {
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Encodes a sessionPing into its wire format. // Encodes a sessionMeta into its wire format.
func (p *sessionMeta) encode() []byte { func (p *sessionMeta) encode() []byte {
var pTypeVal uint64 var pTypeVal uint64
if p.IsResponse { if p.IsResponse {
@ -370,7 +370,7 @@ func (p *sessionMeta) encode() []byte {
return bs return bs
} }
// Decodes an encoded sessionPing into the struct, returning true if successful. // Decodes an encoded sessionMeta into the struct, returning true if successful.
func (p *sessionMeta) decode(bs []byte) bool { func (p *sessionMeta) decode(bs []byte) bool {
var pType uint64 var pType uint64
switch { switch {
@ -380,6 +380,9 @@ func (p *sessionMeta) decode(bs []byte) bool {
return false return false
} }
if p.IsResponse = pType == wire_SessionMetaResponse; p.IsResponse { if p.IsResponse = pType == wire_SessionMetaResponse; p.IsResponse {
if len(bs) == 0 {
return false
}
p.Metadata = make(metadata, len(bs)) p.Metadata = make(metadata, len(bs))
if !wire_chop_slice(p.Metadata[:], &bs) { if !wire_chop_slice(p.Metadata[:], &bs) {
return false return false