Fix ARP incomplete entries and Art-Net broadcast reception
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,11 @@ func (t *Tendrils) parseARPTable() []arpEntry {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
flags := fields[2]
|
||||||
|
if flags == "0x0" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
macStr := fields[3]
|
macStr := fields[3]
|
||||||
if macStr == "00:00:00:00:00:00" {
|
if macStr == "00:00:00:00:00:00" {
|
||||||
continue
|
continue
|
||||||
|
|||||||
72
artnet.go
72
artnet.go
@@ -30,20 +30,15 @@ type ArtNetNode struct {
|
|||||||
LastSeen time.Time `json:"last_seen"`
|
LastSeen time.Time `json:"last_seen"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *Tendrils) listenArtNet(ctx context.Context, iface net.Interface) {
|
func (t *Tendrils) startArtNetListener(ctx context.Context) {
|
||||||
srcIP, _ := getInterfaceIPv4(iface)
|
conn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: artNetPort})
|
||||||
if srcIP == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
conn, err := net.ListenUDP("udp4", &net.UDPAddr{IP: srcIP, Port: artNetPort})
|
|
||||||
if err != nil {
|
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
|
return
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
go t.runArtNetPoller(ctx, iface, conn)
|
t.artnetConn = conn
|
||||||
|
|
||||||
buf := make([]byte, 65536)
|
buf := make([]byte, 65536)
|
||||||
for {
|
for {
|
||||||
@@ -62,11 +57,39 @@ func (t *Tendrils) listenArtNet(ctx context.Context, iface net.Interface) {
|
|||||||
continue
|
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 {
|
if len(data) < 12 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -79,11 +102,11 @@ func (t *Tendrils) handleArtNetPacket(ifaceName string, srcIP net.IP, data []byt
|
|||||||
|
|
||||||
switch opcode {
|
switch opcode {
|
||||||
case opPollReply:
|
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 {
|
if len(data) < 207 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -123,7 +146,7 @@ func (t *Tendrils) handleArtPollReply(ifaceName string, srcIP net.IP, data []byt
|
|||||||
}
|
}
|
||||||
|
|
||||||
if t.DebugArtNet {
|
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
|
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) {
|
func (t *Tendrils) sendArtPoll(conn *net.UDPConn, broadcast net.IP, ifaceName string) {
|
||||||
packet := make([]byte, 14)
|
packet := make([]byte, 14)
|
||||||
copy(packet[0:8], artNetID)
|
copy(packet[0:8], artNetID)
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ type Tendrils struct {
|
|||||||
activeInterfaces map[string]context.CancelFunc
|
activeInterfaces map[string]context.CancelFunc
|
||||||
nodes *Nodes
|
nodes *Nodes
|
||||||
artnet *ArtNetNodes
|
artnet *ArtNetNodes
|
||||||
|
artnetConn *net.UDPConn
|
||||||
danteFlows *DanteFlows
|
danteFlows *DanteFlows
|
||||||
errors *ErrorTracker
|
errors *ErrorTracker
|
||||||
ping *PingManager
|
ping *PingManager
|
||||||
@@ -158,6 +159,10 @@ func (t *Tendrils) Run() {
|
|||||||
go t.pollARP(ctx)
|
go t.pollARP(ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !t.DisableArtNet {
|
||||||
|
go t.startArtNetListener(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(1 * time.Second)
|
ticker := time.NewTicker(1 * time.Second)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
|
|
||||||
@@ -294,7 +299,7 @@ func (t *Tendrils) startInterface(ctx context.Context, iface net.Interface) {
|
|||||||
go t.listenMDNS(ctx, iface)
|
go t.listenMDNS(ctx, iface)
|
||||||
}
|
}
|
||||||
if !t.DisableArtNet {
|
if !t.DisableArtNet {
|
||||||
go t.listenArtNet(ctx, iface)
|
go t.startArtNetPoller(ctx, iface)
|
||||||
}
|
}
|
||||||
if !t.DisableDante {
|
if !t.DisableDante {
|
||||||
go t.listenDante(ctx, iface)
|
go t.listenDante(ctx, iface)
|
||||||
|
|||||||
Reference in New Issue
Block a user