diff --git a/src/core/api.go b/src/core/api.go index adfec61a..999acd4c 100644 --- a/src/core/api.go +++ b/src/core/api.go @@ -106,15 +106,15 @@ func (c *Core) GetSessions() []Session { // ListenTCP starts a new TCP listener. The input URI should match that of the // "Listen" configuration item, e.g. // tcp://a.b.c.d:e -func (c *Core) ListenTCP(uri string) (*TcpListener, error) { - return c.links.tcp.listen(uri, nil) +func (c *Core) ListenTCP(uri string, metric uint8) (*TcpListener, error) { + return c.links.tcp.listen(uri, nil, metric) } // ListenTLS starts a new TLS listener. The input URI should match that of the // "Listen" configuration item, e.g. // tls://a.b.c.d:e -func (c *Core) ListenTLS(uri string) (*TcpListener, error) { - return c.links.tcp.listen(uri, c.links.tcp.tls.forListener) +func (c *Core) ListenTLS(uri string, metric uint8) (*TcpListener, error) { + return c.links.tcp.listen(uri, c.links.tcp.tls.forListener, metric) } // Address gets the IPv6 address of the Yggdrasil node. This is always a /128 diff --git a/src/core/link.go b/src/core/link.go index aac5d1a6..5993d767 100644 --- a/src/core/link.go +++ b/src/core/link.go @@ -8,6 +8,7 @@ import ( "io" "net" "net/url" + "strconv" "strings" "sync" @@ -52,6 +53,7 @@ type link struct { type linkOptions struct { pinnedEd25519Keys map[keyArray]struct{} + metric uint8 } func (l *links) init(c *Core) error { @@ -90,6 +92,10 @@ func (l *links) call(u *url.URL, sintf string) error { } } } + if ms := u.Query()["metric"]; len(ms) == 1 { + m64, _ := strconv.ParseUint(ms[0], 10, 8) + tcpOpts.metric = uint8(m64) + } switch u.Scheme { case "tcp": l.tcp.call(u.Host, tcpOpts, sintf) @@ -110,23 +116,6 @@ func (l *links) call(u *url.URL, sintf string) error { return nil } -func (l *links) listen(uri string) error { - u, err := url.Parse(uri) - if err != nil { - return fmt.Errorf("listener %s is not correctly formatted (%s)", uri, err) - } - switch u.Scheme { - case "tcp": - _, err := l.tcp.listen(u.Host, nil) - return err - case "tls": - _, err := l.tcp.listen(u.Host, l.tcp.tls.forListener) - return err - default: - return errors.New("unknown listen scheme: " + u.Scheme) - } -} - func (l *links) create(conn net.Conn, name, linkType, local, remote string, incoming, force bool, options linkOptions) (*link, error) { // Technically anything unique would work for names, but let's pick something human readable, just for debugging intf := link{ @@ -158,7 +147,7 @@ func (intf *link) handler() (chan struct{}, error) { defer intf.conn.Close() meta := version_getBaseMetadata() meta.key = intf.links.core.public - // TODO set meta.metric + meta.metric = intf.options.metric metric := uint64(meta.metric) metaBytes := meta.encode() // TODO timeouts on send/recv (goroutine for send/recv, channel select w/ timer) diff --git a/src/core/tcp.go b/src/core/tcp.go index 3500364f..588da698 100644 --- a/src/core/tcp.go +++ b/src/core/tcp.go @@ -20,6 +20,7 @@ import ( "math/rand" "net" "net/url" + "strconv" "strings" "sync" "time" @@ -50,7 +51,7 @@ type tcp struct { // multicast interfaces. type TcpListener struct { Listener net.Listener - upgrade *TcpUpgrade + opts tcpOptions stop chan struct{} } @@ -112,13 +113,18 @@ func (t *tcp) init(l *links) error { if err != nil { t.links.core.log.Errorln("Failed to parse listener: listener", listenaddr, "is not correctly formatted, ignoring") } + var metric uint8 // TODO parse from url + if ms := u.Query()["metric"]; len(ms) == 1 { + m64, _ := strconv.ParseUint(ms[0], 10, 8) + metric = uint8(m64) + } switch u.Scheme { case "tcp": - if _, err := t.listen(u.Host, nil); err != nil { + if _, err := t.listen(u.Host, nil, metric); err != nil { return err } case "tls": - if _, err := t.listen(u.Host, t.tls.forListener); err != nil { + if _, err := t.listen(u.Host, t.tls.forListener, metric); err != nil { return err } default: @@ -179,7 +185,7 @@ func (t *tcp) reconfigure() { */ } -func (t *tcp) listen(listenaddr string, upgrade *TcpUpgrade) (*TcpListener, error) { +func (t *tcp) listen(listenaddr string, upgrade *TcpUpgrade, metric uint8) (*TcpListener, error) { var err error ctx := context.Background() @@ -190,9 +196,10 @@ func (t *tcp) listen(listenaddr string, upgrade *TcpUpgrade) (*TcpListener, erro if err == nil { l := TcpListener{ Listener: listener, - upgrade: upgrade, + opts: tcpOptions{upgrade: upgrade}, stop: make(chan struct{}), } + l.opts.metric = metric t.waitgroup.Add(1) go t.listener(&l, listenaddr) return &l, nil @@ -243,9 +250,7 @@ func (t *tcp) listener(l *TcpListener, listenaddr string) { continue } t.waitgroup.Add(1) - options := tcpOptions{ - upgrade: l.upgrade, - } + options := l.opts go t.handler(sock, true, options) } } diff --git a/src/multicast/multicast.go b/src/multicast/multicast.go index b7334da1..56f46133 100644 --- a/src/multicast/multicast.go +++ b/src/multicast/multicast.go @@ -274,7 +274,8 @@ func (m *Multicast) _announce() { if nfo, ok := m.listeners[iface.Name]; !ok || nfo.listener.Listener == nil { // No listener was found - let's create one listenaddr := fmt.Sprintf("[%s%%%s]:%d", addrIP, iface.Name, m.listenPort) - if li, err := m.core.ListenTCP(listenaddr); err == nil { + var metric uint8 // TODO parse this from config + if li, err := m.core.ListenTCP(listenaddr, metric); err == nil { m.log.Debugln("Started multicasting on", iface.Name) // Store the listener so that we can stop it later if needed info = &listenerInfo{listener: li, time: time.Now()}