Squash a whole load of races (and mutex half the world)

This commit is contained in:
Neil Alexander 2019-04-20 11:53:38 +01:00
parent 24281d4049
commit f3e742a297
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
4 changed files with 66 additions and 20 deletions

View file

@ -3,6 +3,7 @@ package yggdrasil
import (
"encoding/hex"
"errors"
"sync"
"sync/atomic"
"time"
@ -15,6 +16,7 @@ type Conn struct {
nodeID *crypto.NodeID
nodeMask *crypto.NodeID
session *sessionInfo
sessionMutex *sync.RWMutex
readDeadline time.Time
writeDeadline time.Time
expired bool
@ -28,7 +30,9 @@ func (c *Conn) startSearch() {
return
}
if sinfo != nil {
c.sessionMutex.Lock()
c.session = sinfo
c.sessionMutex.Unlock()
}
}
doSearch := func() {
@ -61,15 +65,20 @@ func (c *Conn) startSearch() {
}
func (c *Conn) Read(b []byte) (int, error) {
c.sessionMutex.RLock()
defer c.sessionMutex.RUnlock()
if c.expired {
return 0, errors.New("session is closed")
}
if c.session == nil {
return 0, errors.New("searching for remote side")
}
c.session.initMutex.RLock()
if !c.session.init {
c.session.initMutex.RUnlock()
return 0, errors.New("waiting for remote side to accept")
}
c.session.initMutex.RUnlock()
select {
case p, ok := <-c.session.recv:
if !ok {
@ -93,7 +102,9 @@ func (c *Conn) Read(b []byte) (int, error) {
b = b[:len(bs)]
}
c.session.updateNonce(&p.Nonce)
c.session.timeMutex.Lock()
c.session.time = time.Now()
c.session.timeMutex.Unlock()
return nil
}()
if err != nil {
@ -108,6 +119,8 @@ func (c *Conn) Read(b []byte) (int, error) {
}
func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
c.sessionMutex.RLock()
defer c.sessionMutex.RUnlock()
if c.expired {
return 0, errors.New("session is closed")
}
@ -118,12 +131,16 @@ func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
return 0, errors.New("searching for remote side")
}
defer util.PutBytes(b)
c.session.initMutex.RLock()
if !c.session.init {
// To prevent using empty session keys
c.session.initMutex.RUnlock()
return 0, errors.New("waiting for remote side to accept")
}
c.session.initMutex.RUnlock()
// code isn't multithreaded so appending to this is safe
c.session.coordsMutex.RLock()
coords := c.session.coords
c.session.coordsMutex.RUnlock()
// Prepare the payload
c.session.myNonceMutex.Lock()
payload, nonce := crypto.BoxSeal(&c.session.sharedSesKey, b, &c.session.myNonce)