Link refactoring, admin socket changes

This commit is contained in:
Neil Alexander 2023-04-06 21:45:49 +01:00
parent c7ee7d9681
commit 7afa23be4c
No known key found for this signature in database
GPG key ID: A02A2019A2BB0944
32 changed files with 1206 additions and 1130 deletions

View file

@ -6,7 +6,6 @@ import (
"net"
"net/url"
"strconv"
"strings"
"time"
"github.com/Arceliar/phony"
@ -15,19 +14,19 @@ import (
type linkTCP struct {
phony.Inbox
*links
listener *net.ListenConfig
_listeners map[*Listener]context.CancelFunc
listenconfig *net.ListenConfig
_listeners map[*Listener]context.CancelFunc
}
func (l *links) newLinkTCP() *linkTCP {
lt := &linkTCP{
links: l,
listener: &net.ListenConfig{
listenconfig: &net.ListenConfig{
KeepAlive: -1,
},
_listeners: map[*Listener]context.CancelFunc{},
}
lt.listener.Control = lt.tcpContext
lt.listenconfig.Control = lt.tcpContext
return lt
}
@ -37,7 +36,7 @@ type tcpDialer struct {
addr *net.TCPAddr
}
func (l *linkTCP) dialersFor(url *url.URL, options linkOptions, sintf string) ([]*tcpDialer, error) {
func (l *linkTCP) dialersFor(url *url.URL, info linkInfo) ([]*tcpDialer, error) {
host, p, err := net.SplitHostPort(url.Host)
if err != nil {
return nil, err
@ -56,14 +55,10 @@ func (l *linkTCP) dialersFor(url *url.URL, options linkOptions, sintf string) ([
IP: ip,
Port: port,
}
dialer, err := l.dialerFor(addr, sintf)
dialer, err := l.dialerFor(addr, info.sintf)
if err != nil {
continue
}
info := linkInfoFor("tcp", sintf, tcpIDFor(dialer.LocalAddr, addr))
if l.links.isConnectedTo(info) {
return nil, nil
}
dialers = append(dialers, &tcpDialer{
info: info,
dialer: dialer,
@ -73,13 +68,16 @@ func (l *linkTCP) dialersFor(url *url.URL, options linkOptions, sintf string) ([
return dialers, nil
}
func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error {
dialers, err := l.dialersFor(url, options, sintf)
func (l *linkTCP) dial(url *url.URL, info linkInfo, options linkOptions) (net.Conn, error) {
if l.core.isTLSOnly() {
return nil, fmt.Errorf("TCP peer prohibited in TLS-only mode")
}
dialers, err := l.dialersFor(url, info)
if err != nil {
return err
return nil, err
}
if len(dialers) == 0 {
return nil
return nil, nil
}
for _, d := range dialers {
var conn net.Conn
@ -88,72 +86,22 @@ func (l *linkTCP) dial(url *url.URL, options linkOptions, sintf string) error {
l.core.log.Warnf("Failed to connect to %s: %s", d.addr, err)
continue
}
name := strings.TrimRight(strings.SplitN(url.String(), "?", 2)[0], "/")
dial := &linkDial{
url: url,
sintf: sintf,
}
return l.handler(dial, name, d.info, conn, options, false, false)
return conn, nil
}
return fmt.Errorf("failed to connect via %d address(es), last error: %w", len(dialers), err)
return nil, err
}
func (l *linkTCP) listen(url *url.URL, sintf string) (*Listener, error) {
ctx, cancel := context.WithCancel(l.core.ctx)
func (l *linkTCP) listen(ctx context.Context, url *url.URL, sintf string) (net.Listener, error) {
if l.core.isTLSOnly() {
return nil, fmt.Errorf("TCP listener prohibited in TLS-only mode")
}
hostport := url.Host
if sintf != "" {
if host, port, err := net.SplitHostPort(hostport); err == nil {
hostport = fmt.Sprintf("[%s%%%s]:%s", host, sintf, port)
}
}
listener, err := l.listener.Listen(ctx, "tcp", hostport)
if err != nil {
cancel()
return nil, err
}
entry := &Listener{
Listener: listener,
closed: make(chan struct{}),
}
phony.Block(l, func() {
l._listeners[entry] = cancel
})
l.core.log.Printf("TCP listener started on %s", listener.Addr())
go func() {
defer phony.Block(l, func() {
delete(l._listeners, entry)
})
for {
conn, err := listener.Accept()
if err != nil {
cancel()
break
}
laddr := conn.LocalAddr().(*net.TCPAddr)
raddr := conn.RemoteAddr().(*net.TCPAddr)
name := fmt.Sprintf("tcp://%s", raddr)
info := linkInfoFor("tcp", sintf, tcpIDFor(laddr, raddr))
if err = l.handler(nil, name, info, conn, linkOptionsForListener(url), true, raddr.IP.IsLinkLocalUnicast()); err != nil {
l.core.log.Errorln("Failed to create inbound link:", err)
}
}
_ = listener.Close()
close(entry.closed)
l.core.log.Printf("TCP listener stopped on %s", listener.Addr())
}()
return entry, nil
}
func (l *linkTCP) handler(dial *linkDial, name string, info linkInfo, conn net.Conn, options linkOptions, incoming, force bool) error {
return l.links.create(
conn, // connection
dial, // connection URL
name, // connection name
info, // connection info
incoming, // not incoming
force, // not forced
options, // connection options
)
return l.listenconfig.Listen(ctx, "tcp", hostport)
}
// Returns the address of the listener.
@ -163,8 +111,8 @@ func (l *linkTCP) getAddr() *net.TCPAddr {
// doesn't have the ability to send more than one address in a packet either
var addr *net.TCPAddr
phony.Block(l, func() {
for listener := range l._listeners {
addr = listener.Addr().(*net.TCPAddr)
for li := range l._listeners {
addr = li.listener.Addr().(*net.TCPAddr)
}
})
return addr
@ -228,16 +176,3 @@ func (l *linkTCP) dialerFor(dst *net.TCPAddr, sintf string) (*net.Dialer, error)
}
return dialer, nil
}
func tcpIDFor(local net.Addr, remoteAddr *net.TCPAddr) string {
if localAddr, ok := local.(*net.TCPAddr); ok && localAddr.IP.Equal(remoteAddr.IP) {
// Nodes running on the same host — include both the IP and port.
return remoteAddr.String()
}
if remoteAddr.IP.IsLinkLocalUnicast() {
// Nodes discovered via multicast — include the IP only.
return remoteAddr.IP.String()
}
// Nodes connected remotely — include both the IP and port.
return remoteAddr.String()
}