diff --git a/arp_linux.go b/arp_linux.go index c1d2a0f..0755b39 100644 --- a/arp_linux.go +++ b/arp_linux.go @@ -36,6 +36,11 @@ func (t *Tendrils) parseARPTable() []arpEntry { continue } + flags := fields[2] + if flags == "0x0" { + continue + } + macStr := fields[3] if macStr == "00:00:00:00:00:00" { continue diff --git a/artnet.go b/artnet.go index f790a2f..7693da8 100644 --- a/artnet.go +++ b/artnet.go @@ -30,20 +30,15 @@ type ArtNetNode struct { LastSeen time.Time `json:"last_seen"` } -func (t *Tendrils) listenArtNet(ctx context.Context, iface net.Interface) { - srcIP, _ := getInterfaceIPv4(iface) - if srcIP == nil { - return - } - - conn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: srcIP, Port: artNetPort}) +func (t *Tendrils) startArtNetListener(ctx context.Context) { + conn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: artNetPort}) if err != nil { - log.Printf("[ERROR] failed to listen artnet on %s: %v", iface.Name, err) + log.Printf("[ERROR] failed to listen artnet: %v", err) return } defer conn.Close() - go t.runArtNetPoller(ctx, iface, conn) + t.artnetConn = conn buf := make([]byte, 65536) for { @@ -62,11 +57,39 @@ func (t *Tendrils) listenArtNet(ctx context.Context, iface net.Interface) { continue } - t.handleArtNetPacket(iface.Name, src.IP, buf[:n]) + t.handleArtNetPacket(src.IP, buf[:n]) } } -func (t *Tendrils) handleArtNetPacket(ifaceName string, srcIP net.IP, data []byte) { +func (t *Tendrils) startArtNetPoller(ctx context.Context, iface net.Interface) { + srcIP, broadcast := getInterfaceIPv4(iface) + if srcIP == nil || broadcast == nil { + return + } + + sendConn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: srcIP, Port: 0}) + if err != nil { + log.Printf("[ERROR] failed to create artnet send socket on %s: %v", iface.Name, err) + return + } + defer sendConn.Close() + + ticker := time.NewTicker(10 * time.Second) + defer ticker.Stop() + + t.sendArtPoll(sendConn, broadcast, iface.Name) + + for { + select { + case <-ctx.Done(): + return + case <-ticker.C: + t.sendArtPoll(sendConn, broadcast, iface.Name) + } + } +} + +func (t *Tendrils) handleArtNetPacket(srcIP net.IP, data []byte) { if len(data) < 12 { return } @@ -79,11 +102,11 @@ func (t *Tendrils) handleArtNetPacket(ifaceName string, srcIP net.IP, data []byt switch opcode { case opPollReply: - t.handleArtPollReply(ifaceName, srcIP, data) + t.handleArtPollReply(srcIP, data) } } -func (t *Tendrils) handleArtPollReply(ifaceName string, srcIP net.IP, data []byte) { +func (t *Tendrils) handleArtPollReply(srcIP net.IP, data []byte) { if len(data) < 207 { return } @@ -123,7 +146,7 @@ func (t *Tendrils) handleArtPollReply(ifaceName string, srcIP net.IP, data []byt } if t.DebugArtNet { - log.Printf("[artnet] %s: %s %s short=%q long=%q numPorts=%d portTypes=%v in=%v out=%v", ifaceName, ip, mac, shortName, longName, numPorts, data[174:178], inputs, outputs) + log.Printf("[artnet] %s %s short=%q long=%q numPorts=%d portTypes=%v in=%v out=%v", ip, mac, shortName, longName, numPorts, data[174:178], inputs, outputs) } name := longName @@ -146,27 +169,6 @@ func (t *Tendrils) handleArtPollReply(ifaceName string, srcIP net.IP, data []byt } } -func (t *Tendrils) runArtNetPoller(ctx context.Context, iface net.Interface, conn *net.UDPConn) { - _, broadcast := getInterfaceIPv4(iface) - if broadcast == nil { - return - } - - ticker := time.NewTicker(10 * time.Second) - defer ticker.Stop() - - t.sendArtPoll(conn, broadcast, iface.Name) - - for { - select { - case <-ctx.Done(): - return - case <-ticker.C: - t.sendArtPoll(conn, broadcast, iface.Name) - } - } -} - func (t *Tendrils) sendArtPoll(conn *net.UDPConn, broadcast net.IP, ifaceName string) { packet := make([]byte, 14) copy(packet[0:8], artNetID) diff --git a/tendrils.go b/tendrils.go index de603be..052bf45 100644 --- a/tendrils.go +++ b/tendrils.go @@ -34,6 +34,7 @@ type Tendrils struct { activeInterfaces map[string]context.CancelFunc nodes *Nodes artnet *ArtNetNodes + artnetConn *net.UDPConn danteFlows *DanteFlows errors *ErrorTracker ping *PingManager @@ -158,6 +159,10 @@ func (t *Tendrils) Run() { go t.pollARP(ctx) } + if !t.DisableArtNet { + go t.startArtNetListener(ctx) + } + ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() @@ -294,7 +299,7 @@ func (t *Tendrils) startInterface(ctx context.Context, iface net.Interface) { go t.listenMDNS(ctx, iface) } if !t.DisableArtNet { - go t.listenArtNet(ctx, iface) + go t.startArtNetPoller(ctx, iface) } if !t.DisableDante { go t.listenDante(ctx, iface)