Fix race on tun conns, but still deadlocks if more than one connection is opened

This commit is contained in:
Neil Alexander 2019-04-21 12:00:31 +01:00
parent 79bcfbf175
commit 781cd7571f
No known key found for this signature in database
GPG Key ID: A02A2019A2BB0944
3 changed files with 18 additions and 8 deletions

View File

@ -265,7 +265,6 @@ func main() {
// Start the TUN/TAP interface // Start the TUN/TAP interface
if listener, err := n.core.ConnListen(); err == nil { if listener, err := n.core.ConnListen(); err == nil {
if dialer, err := n.core.ConnDialer(); err == nil { if dialer, err := n.core.ConnDialer(); err == nil {
logger.Println("Got listener", listener, "and dialer", dialer)
n.tuntap.Init(state, logger, listener, dialer) n.tuntap.Init(state, logger, listener, dialer)
if err := n.tuntap.Start(); err != nil { if err := n.tuntap.Start(); err != nil {
logger.Errorln("An error occurred starting TUN/TAP:", err) logger.Errorln("An error occurred starting TUN/TAP:", err)

View File

@ -30,7 +30,6 @@ type TunAdapter struct {
config *config.NodeState config *config.NodeState
log *log.Logger log *log.Logger
reconfigure chan chan error reconfigure chan chan error
conns map[crypto.NodeID]*yggdrasil.Conn
listener *yggdrasil.Listener listener *yggdrasil.Listener
dialer *yggdrasil.Dialer dialer *yggdrasil.Dialer
addr address.Address addr address.Address
@ -39,6 +38,7 @@ type TunAdapter struct {
mtu int mtu int
iface *water.Interface iface *water.Interface
mutex sync.RWMutex // Protects the below mutex sync.RWMutex // Protects the below
conns map[crypto.NodeID]*yggdrasil.Conn
isOpen bool isOpen bool
} }
@ -173,13 +173,24 @@ func (tun *TunAdapter) handler() error {
tun.log.Errorln("TUN/TAP error accepting connection:", err) tun.log.Errorln("TUN/TAP error accepting connection:", err)
return err return err
} }
tun.log.Println("Accepted connection from", conn.RemoteAddr())
go tun.connReader(conn) go tun.connReader(conn)
} }
} }
func (tun *TunAdapter) connReader(conn *yggdrasil.Conn) error { func (tun *TunAdapter) connReader(conn *yggdrasil.Conn) error {
tun.conns[conn.RemoteAddr()] = conn remoteNodeID := conn.RemoteAddr()
tun.mutex.Lock()
if _, isIn := tun.conns[remoteNodeID]; isIn {
tun.mutex.Unlock()
return errors.New("duplicate connection")
}
tun.conns[remoteNodeID] = conn
tun.mutex.Unlock()
defer func() {
tun.mutex.Lock()
delete(tun.conns, remoteNodeID)
tun.mutex.Unlock()
}()
b := make([]byte, 65535) b := make([]byte, 65535)
for { for {
n, err := conn.Read(b) n, err := conn.Read(b)
@ -242,8 +253,9 @@ func (tun *TunAdapter) ifaceReader() error {
} }
dstNodeID, dstNodeIDMask = dstAddr.GetNodeIDandMask() dstNodeID, dstNodeIDMask = dstAddr.GetNodeIDandMask()
// Do we have an active connection for this node ID? // Do we have an active connection for this node ID?
tun.mutex.Lock()
if conn, isIn := tun.conns[*dstNodeID]; isIn { if conn, isIn := tun.conns[*dstNodeID]; isIn {
tun.log.Println("Got", &conn) tun.mutex.Unlock()
w, err := conn.Write(bs) w, err := conn.Write(bs)
if err != nil { if err != nil {
tun.log.Println("Unable to write to remote:", err) tun.log.Println("Unable to write to remote:", err)
@ -253,11 +265,12 @@ func (tun *TunAdapter) ifaceReader() error {
continue continue
} }
} else { } else {
tun.log.Println("Opening connection for", *dstNodeID)
if conn, err := tun.dialer.DialByNodeIDandMask(dstNodeID, dstNodeIDMask); err == nil { if conn, err := tun.dialer.DialByNodeIDandMask(dstNodeID, dstNodeIDMask); err == nil {
tun.conns[*dstNodeID] = &conn tun.conns[*dstNodeID] = &conn
tun.mutex.Unlock()
go tun.connReader(&conn) go tun.connReader(&conn)
} else { } else {
tun.mutex.Unlock()
tun.log.Println("Error dialing:", err) tun.log.Println("Error dialing:", err)
} }
} }

View File

@ -2,7 +2,6 @@ package yggdrasil
import ( import (
"errors" "errors"
"fmt"
"sync" "sync"
"sync/atomic" "sync/atomic"
"time" "time"
@ -124,7 +123,6 @@ func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
return 0, errors.New("session is closed") return 0, errors.New("session is closed")
} }
if c.session == nil { if c.session == nil {
fmt.Println("No session found, starting search for", &c)
c.core.router.doAdmin(func() { c.core.router.doAdmin(func() {
c.startSearch() c.startSearch()
}) })