~fnux/yggdrasil-go-coap

aa153d0ed9914005406bb4d0fba100b526cd0f3c — Timothée Floure 1 year, 7 months ago 0796edb
Implement initial YggdrasilListener
3 files changed, 103 insertions(+), 0 deletions(-)

A net/yggdrasil.go
A net/yggdrasillistener.go
M server.go
A net/yggdrasil.go => net/yggdrasil.go +11 -0
@@ 0,0 1,11 @@
package net

import (
  "github.com/yggdrasil-network/yggdrasil-go/src/config"
  "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
)

type YggdrasilNode struct {
  Core   yggdrasil.Core
  Config *config.NodeConfig
}

A net/yggdrasillistener.go => net/yggdrasillistener.go +72 -0
@@ 0,0 1,72 @@
package net

import (
  "context"
  "fmt"
  "time"
  "net"
  "sync/atomic"
  "github.com/yggdrasil-network/yggdrasil-go/src/yggdrasil"
)

type YggdrasilListener struct {
	listener  *yggdrasil.Listener
	heartBeat time.Duration
	deadline atomic.Value
}

func NewYggdrasilListener(node YggdrasilNode, heartBeat time.Duration) (*YggdrasilListener, error) {
	listener, err := node.Core.ConnListen()
	if err != nil {
		return nil, fmt.Errorf("cannot create new Yggdrasil listener: %v", err)
	}
	return &YggdrasilListener{listener: listener, heartBeat: heartBeat}, nil
}

// AcceptWithContext waits with context for a generic Conn.
func (l *YggdrasilListener) AcceptWithContext(ctx context.Context) (net.Conn, error) {
	for {
		select {
		case <-ctx.Done():
			if ctx.Err() != nil {
				return nil, fmt.Errorf("cannot accept connections: %v", ctx.Err())
			}
			return nil, nil
		default:
		}
		err := l.SetDeadline(time.Now().Add(l.heartBeat))
		if err != nil {
			return nil, fmt.Errorf("cannot accept connections: %v", err)
		}
    // FIXME: Handle deadline!
		rw, err := l.listener.Accept()
		if err != nil {
			if isTemporary(err) {
				continue
			}
			return nil, fmt.Errorf("cannot accept connections: %v", err)
		}
		return rw, nil
	}
}

// Accept waits for a generic Conn.
func (l *YggdrasilListener) Accept() (net.Conn, error) {
	return l.AcceptWithContext(context.Background())
}

// SetDeadline sets deadline for accept operation.
func (l *YggdrasilListener) SetDeadline(t time.Time) error {
	l.deadline.Store(t)
	return nil
}

// Close closes the connection.
func (l *YggdrasilListener) Close() error {
	return l.listener.Close()
}

// Addr represents a network end point address.
func (l *YggdrasilListener) Addr() net.Addr {
	return l.listener.Addr()
}

M server.go => server.go +20 -0
@@ 112,6 112,18 @@ func ListenAndServeDTLS(network string, addr string, config *dtls.Config, handle
	return server.ListenAndServe()
}

// Yggdrasil support.
func ListenAndServeYggdrasil(node coapNet.YggdrasilNode, handler Handler) error {
  server := &Server{
    Addr: node.Core.Address().String(),
    Net: "yggdrasil",
    YggdrasilNode: node,
    Handler: handler,
  }

  return server.ListenAndServe()
}

// ActivateAndServe activates a server with a listener from systemd,
// l and p should not both be non-nil.
// If both l and p are not nil only p will be used.


@@ 127,6 139,8 @@ type Server struct {
	Addr string
	// if "tcp" or "tcp-tls" (COAP over TLS) it will invoke a TCP listener, otherwise an UDP one
	Net string
	// YggdrasilNode
	YggdrasilNode coapNet.YggdrasilNode
	// TCP Listener to use, this is to aid in systemd's socket activation.
	Listener Listener
	// TLS connection configuration


@@ 310,6 324,12 @@ func (srv *Server) ListenAndServe() error {
			return fmt.Errorf("cannot listen and serve: %v", err)
		}
		defer listener.Close()
	case "yggdrasil":
		listener, err = coapNet.NewYggdrasilListener(srv.YggdrasilNode, srv.heartBeat())
		if err != nil {
			return fmt.Errorf("cannot listen and serve: %v", err)
		}
		defer listener.Close()
	default:
		return ErrInvalidNetParameter
	}