mirror of
https://github.com/cwinfo/yggdrasil-go.git
synced 2024-11-23 06:31:35 +00:00
Listen-Accept-Read-Write pattern now works, amazingly
This commit is contained in:
parent
27b78b925d
commit
aac88adbed
@ -61,11 +61,10 @@ func (c *Conn) startSearch() {
|
|||||||
|
|
||||||
func (c *Conn) Read(b []byte) (int, error) {
|
func (c *Conn) Read(b []byte) (int, error) {
|
||||||
if c.session == nil {
|
if c.session == nil {
|
||||||
return 0, errors.New("session not open")
|
return 0, errors.New("session not ready yet")
|
||||||
}
|
}
|
||||||
if !c.session.init {
|
if !c.session.init {
|
||||||
// To prevent blocking forever on a session that isn't initialised
|
return 0, errors.New("waiting for remote side to accept")
|
||||||
return 0, errors.New("session not initialised")
|
|
||||||
}
|
}
|
||||||
select {
|
select {
|
||||||
case p, ok := <-c.session.recv:
|
case p, ok := <-c.session.recv:
|
||||||
@ -84,6 +83,7 @@ func (c *Conn) Read(b []byte) (int, error) {
|
|||||||
util.PutBytes(bs)
|
util.PutBytes(bs)
|
||||||
return errors.New("packet dropped due to decryption failure")
|
return errors.New("packet dropped due to decryption failure")
|
||||||
}
|
}
|
||||||
|
// c.core.log.Println("HOW MANY BYTES?", len(bs))
|
||||||
b = b[:0]
|
b = b[:0]
|
||||||
b = append(b, bs...)
|
b = append(b, bs...)
|
||||||
c.session.updateNonce(&p.Nonce)
|
c.session.updateNonce(&p.Nonce)
|
||||||
@ -96,7 +96,7 @@ func (c *Conn) Read(b []byte) (int, error) {
|
|||||||
atomic.AddUint64(&c.session.bytesRecvd, uint64(len(b)))
|
atomic.AddUint64(&c.session.bytesRecvd, uint64(len(b)))
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
case <-c.session.closed:
|
case <-c.session.closed:
|
||||||
return len(b), errors.New("session was closed")
|
return len(b), errors.New("session closed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,12 +105,12 @@ func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
|
|||||||
c.core.router.doAdmin(func() {
|
c.core.router.doAdmin(func() {
|
||||||
c.startSearch()
|
c.startSearch()
|
||||||
})
|
})
|
||||||
return 0, errors.New("session not open")
|
return 0, errors.New("session not ready yet")
|
||||||
}
|
}
|
||||||
defer util.PutBytes(b)
|
defer util.PutBytes(b)
|
||||||
if !c.session.init {
|
if !c.session.init {
|
||||||
// To prevent using empty session keys
|
// To prevent using empty session keys
|
||||||
return 0, errors.New("session not initialised")
|
return 0, errors.New("waiting for remote side to accept")
|
||||||
}
|
}
|
||||||
// code isn't multithreaded so appending to this is safe
|
// code isn't multithreaded so appending to this is safe
|
||||||
coords := c.session.coords
|
coords := c.session.coords
|
||||||
@ -130,13 +130,14 @@ func (c *Conn) Write(b []byte) (bytesWritten int, err error) {
|
|||||||
select {
|
select {
|
||||||
case c.session.send <- packet:
|
case c.session.send <- packet:
|
||||||
case <-c.session.closed:
|
case <-c.session.closed:
|
||||||
return len(b), errors.New("session was closed")
|
return len(b), errors.New("session closed")
|
||||||
}
|
}
|
||||||
c.session.core.router.out(packet)
|
c.session.core.router.out(packet)
|
||||||
return len(b), nil
|
return len(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Conn) Close() error {
|
func (c *Conn) Close() error {
|
||||||
|
c.session.close()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +254,20 @@ func (c *Core) Stop() {
|
|||||||
c.admin.close()
|
c.admin.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListenConn returns a listener for Yggdrasil session connections.
|
||||||
|
func (c *Core) ListenConn() (*Listener, error) {
|
||||||
|
c.sessions.listenerMutex.Lock()
|
||||||
|
defer c.sessions.listenerMutex.Unlock()
|
||||||
|
if c.sessions.listener != nil {
|
||||||
|
return nil, errors.New("a listener already exists")
|
||||||
|
}
|
||||||
|
c.sessions.listener = &Listener{
|
||||||
|
conn: make(chan *Conn),
|
||||||
|
close: make(chan interface{}),
|
||||||
|
}
|
||||||
|
return c.sessions.listener, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Dial opens a session to the given node. The first paramter should be "nodeid"
|
// 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
|
// and the second parameter should contain a hexadecimal representation of the
|
||||||
// target node ID.
|
// target node ID.
|
||||||
|
41
src/yggdrasil/listener.go
Normal file
41
src/yggdrasil/listener.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Listener waits for incoming sessions
|
||||||
|
type Listener struct {
|
||||||
|
conn chan *Conn
|
||||||
|
close chan interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept blocks until a new incoming session is received
|
||||||
|
func (l *Listener) Accept() (*Conn, error) {
|
||||||
|
select {
|
||||||
|
case c, ok := <-l.conn:
|
||||||
|
if !ok {
|
||||||
|
return nil, errors.New("listener closed")
|
||||||
|
}
|
||||||
|
return c, nil
|
||||||
|
case <-l.close:
|
||||||
|
return nil, errors.New("listener closed")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close will stop the listener
|
||||||
|
func (l *Listener) Close() (err error) {
|
||||||
|
defer func() {
|
||||||
|
recover()
|
||||||
|
err = errors.New("already closed")
|
||||||
|
}()
|
||||||
|
close(l.close)
|
||||||
|
close(l.conn)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr is not implemented for this type yet
|
||||||
|
func (l *Listener) Addr() net.Addr {
|
||||||
|
return nil
|
||||||
|
}
|
@ -105,16 +105,18 @@ func (s *sessionInfo) timedout() bool {
|
|||||||
// Sessions are indexed by handle.
|
// Sessions are indexed by handle.
|
||||||
// Additionally, stores maps of address/subnet onto keys, and keys onto handles.
|
// Additionally, stores maps of address/subnet onto keys, and keys onto handles.
|
||||||
type sessions struct {
|
type sessions struct {
|
||||||
core *Core
|
core *Core
|
||||||
reconfigure chan chan error
|
listener *Listener
|
||||||
lastCleanup time.Time
|
listenerMutex sync.Mutex
|
||||||
permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey // Maps known permanent keys to their shared key, used by DHT a lot
|
reconfigure chan chan error
|
||||||
sinfos map[crypto.Handle]*sessionInfo // Maps (secret) handle onto session info
|
lastCleanup time.Time
|
||||||
conns map[crypto.Handle]*Conn // Maps (secret) handle onto connections
|
permShared map[crypto.BoxPubKey]*crypto.BoxSharedKey // Maps known permanent keys to their shared key, used by DHT a lot
|
||||||
byMySes map[crypto.BoxPubKey]*crypto.Handle // Maps mySesPub onto handle
|
sinfos map[crypto.Handle]*sessionInfo // Maps (secret) handle onto session info
|
||||||
byTheirPerm map[crypto.BoxPubKey]*crypto.Handle // Maps theirPermPub onto handle
|
conns map[crypto.Handle]*Conn // Maps (secret) handle onto connections
|
||||||
addrToPerm map[address.Address]*crypto.BoxPubKey
|
byMySes map[crypto.BoxPubKey]*crypto.Handle // Maps mySesPub onto handle
|
||||||
subnetToPerm map[address.Subnet]*crypto.BoxPubKey
|
byTheirPerm map[crypto.BoxPubKey]*crypto.Handle // Maps theirPermPub onto handle
|
||||||
|
addrToPerm map[address.Address]*crypto.BoxPubKey
|
||||||
|
subnetToPerm map[address.Subnet]*crypto.BoxPubKey
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initializes the session struct.
|
// Initializes the session struct.
|
||||||
@ -461,6 +463,22 @@ func (ss *sessions) handlePing(ping *sessionPing) {
|
|||||||
if !isIn {
|
if !isIn {
|
||||||
panic("This should not happen")
|
panic("This should not happen")
|
||||||
}
|
}
|
||||||
|
ss.listenerMutex.Lock()
|
||||||
|
if ss.listener != nil {
|
||||||
|
conn := &Conn{
|
||||||
|
core: ss.core,
|
||||||
|
session: sinfo,
|
||||||
|
nodeID: crypto.GetNodeID(&sinfo.theirPermPub),
|
||||||
|
nodeMask: &crypto.NodeID{},
|
||||||
|
}
|
||||||
|
for i := range conn.nodeMask {
|
||||||
|
conn.nodeMask[i] = 0xFF
|
||||||
|
}
|
||||||
|
ss.listener.conn <- conn
|
||||||
|
} else {
|
||||||
|
ss.core.log.Debugln("Received new session but there is no listener, ignoring")
|
||||||
|
}
|
||||||
|
ss.listenerMutex.Unlock()
|
||||||
}
|
}
|
||||||
// Update the session
|
// Update the session
|
||||||
if !sinfo.update(ping) { /*panic("Should not happen in testing")*/
|
if !sinfo.update(ping) { /*panic("Should not happen in testing")*/
|
||||||
|
Loading…
Reference in New Issue
Block a user