From 0059baf36c9202f6327f4434f58825171b21ec90 Mon Sep 17 00:00:00 2001 From: Arceliar Date: Fri, 26 Apr 2019 18:07:57 -0500 Subject: [PATCH] add a newConn function that returns a pointer to a Conn with atomics properly initialized --- src/tuntap/tun.go | 4 ++-- src/yggdrasil/conn.go | 24 ++++++++++++++++++++---- src/yggdrasil/dialer.go | 21 +++++++-------------- src/yggdrasil/session.go | 9 +-------- 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/src/tuntap/tun.go b/src/tuntap/tun.go index 01cafaa4..c19764c3 100644 --- a/src/tuntap/tun.go +++ b/src/tuntap/tun.go @@ -412,9 +412,9 @@ func (tun *TunAdapter) ifaceReader() error { // Dial to the remote node if c, err := tun.dialer.DialByNodeIDandMask(dstNodeID, dstNodeIDMask); err == nil { // We've been given a connection so start the connection reader goroutine - go tun.connReader(&c) + go tun.connReader(c) // Then update our reference to the connection - conn, isIn = &c, true + conn, isIn = c, true } else { // We weren't able to dial for some reason so there's no point in // continuing this iteration - skip to the next one diff --git a/src/yggdrasil/conn.go b/src/yggdrasil/conn.go index 8d36a60a..08591c4a 100644 --- a/src/yggdrasil/conn.go +++ b/src/yggdrasil/conn.go @@ -15,12 +15,26 @@ type Conn struct { core *Core nodeID *crypto.NodeID nodeMask *crypto.NodeID - mutex *sync.RWMutex + mutex sync.RWMutex session *sessionInfo readDeadline atomic.Value // time.Time // TODO timer writeDeadline atomic.Value // time.Time // TODO timer searching atomic.Value // bool - searchwait chan interface{} + searchwait chan struct{} +} + +// TODO func NewConn() that initializes atomic and channel fields so things don't crash or block indefinitely +func newConn(core *Core, nodeID *crypto.NodeID, nodeMask *crypto.NodeID, session *sessionInfo) *Conn { + conn := Conn{ + core: core, + nodeID: nodeID, + nodeMask: nodeMask, + session: session, + searchwait: make(chan struct{}), + } + conn.SetDeadline(time.Time{}) + conn.searching.Store(false) + return &conn } func (c *Conn) String() string { @@ -33,9 +47,9 @@ func (c *Conn) startSearch() { searchCompleted := func(sinfo *sessionInfo, err error) { // Make sure that any blocks on read/write operations are lifted defer func() { + defer func() { recover() }() // In case searchwait was closed by another goroutine c.searching.Store(false) - close(c.searchwait) - c.searchwait = make(chan interface{}) + close(c.searchwait) // Never reset this to an open channel }() // If the search failed for some reason, e.g. it hit a dead end or timed // out, then do nothing @@ -106,6 +120,8 @@ func (c *Conn) Read(b []byte) (int, error) { c.mutex.RLock() sinfo := c.session c.mutex.RUnlock() + timer := time.NewTimer(0) + util.TimerStop(timer) // If there is a search in progress then wait for the result if sinfo == nil { // Wait for the search to complete diff --git a/src/yggdrasil/dialer.go b/src/yggdrasil/dialer.go index 325c6b76..1943c859 100644 --- a/src/yggdrasil/dialer.go +++ b/src/yggdrasil/dialer.go @@ -5,7 +5,6 @@ import ( "errors" "strconv" "strings" - "sync" "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) @@ -18,7 +17,7 @@ type Dialer struct { // Dial opens a session to the given node. The first paramter should be "nodeid" // and the second parameter should contain a hexadecimal representation of the // target node ID. -func (d *Dialer) Dial(network, address string) (Conn, error) { +func (d *Dialer) Dial(network, address string) (*Conn, error) { var nodeID crypto.NodeID var nodeMask crypto.NodeID // Process @@ -28,11 +27,11 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { if tokens := strings.Split(address, "/"); len(tokens) == 2 { len, err := strconv.Atoi(tokens[1]) if err != nil { - return Conn{}, err + return nil, err } dest, err := hex.DecodeString(tokens[0]) if err != nil { - return Conn{}, err + return nil, err } copy(nodeID[:], dest) for idx := 0; idx < len; idx++ { @@ -41,7 +40,7 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { } else { dest, err := hex.DecodeString(tokens[0]) if err != nil { - return Conn{}, err + return nil, err } copy(nodeID[:], dest) for i := range nodeMask { @@ -51,19 +50,13 @@ func (d *Dialer) Dial(network, address string) (Conn, error) { return d.DialByNodeIDandMask(&nodeID, &nodeMask) default: // An unexpected address type was given, so give up - return Conn{}, errors.New("unexpected address type") + return nil, errors.New("unexpected address type") } } // DialByNodeIDandMask opens a session to the given node based on raw // NodeID parameters. -func (d *Dialer) DialByNodeIDandMask(nodeID, nodeMask *crypto.NodeID) (Conn, error) { - conn := Conn{ - core: d.core, - mutex: &sync.RWMutex{}, - nodeID: nodeID, - nodeMask: nodeMask, - searchwait: make(chan interface{}), - } +func (d *Dialer) DialByNodeIDandMask(nodeID, nodeMask *crypto.NodeID) (*Conn, error) { + conn := newConn(d.core, nodeID, nodeMask, nil) return conn, nil } diff --git a/src/yggdrasil/session.go b/src/yggdrasil/session.go index bf35e8c3..724152dd 100644 --- a/src/yggdrasil/session.go +++ b/src/yggdrasil/session.go @@ -456,14 +456,7 @@ func (ss *sessions) handlePing(ping *sessionPing) { // Check and see if there's a Listener waiting to accept connections // TODO: this should not block if nothing is accepting if !ping.IsPong && ss.listener != nil { - conn := &Conn{ - core: ss.core, - session: sinfo, - mutex: &sync.RWMutex{}, - nodeID: crypto.GetNodeID(&sinfo.theirPermPub), - nodeMask: &crypto.NodeID{}, - searchwait: make(chan interface{}), - } + conn := newConn(ss.core, crypto.GetNodeID(&sinfo.theirPermPub), &crypto.NodeID{}, sinfo) for i := range conn.nodeMask { conn.nodeMask[i] = 0xFF }