Update AutoInterface and UDPInterface to use net.PacketConn for better compatibility with TinyGo. Update methods to handle errors related to unsupported features in TinyGo, including interface enumeration and multicast UDP.

This commit is contained in:
2025-10-30 19:01:33 -05:00
parent 1b3f4e59db
commit f599cc4d43
2 changed files with 35 additions and 74 deletions

View File

@@ -31,16 +31,16 @@ type AutoInterface struct {
peers map[string]*Peer peers map[string]*Peer
linkLocalAddrs []string linkLocalAddrs []string
adoptedInterfaces map[string]string adoptedInterfaces map[string]string
interfaceServers map[string]*net.UDPConn interfaceServers map[string]net.PacketConn
multicastEchoes map[string]time.Time multicastEchoes map[string]time.Time
mutex sync.RWMutex mutex sync.RWMutex
outboundConn *net.UDPConn outboundConn net.PacketConn
} }
type Peer struct { type Peer struct {
ifaceName string ifaceName string
lastHeard time.Time lastHeard time.Time
conn *net.UDPConn conn net.PacketConn
} }
func NewAutoInterface(name string, config *common.InterfaceConfig) (*AutoInterface, error) { func NewAutoInterface(name string, config *common.InterfaceConfig) (*AutoInterface, error) {
@@ -81,70 +81,19 @@ func NewAutoInterface(name string, config *common.InterfaceConfig) (*AutoInterfa
} }
func (ai *AutoInterface) Start() error { func (ai *AutoInterface) Start() error {
interfaces, err := net.Interfaces() // TinyGo doesn't support net.Interfaces() or multicast UDP
if err != nil { // AutoInterface requires these features, so return an error
return fmt.Errorf("failed to list interfaces: %v", err) return fmt.Errorf("AutoInterface not supported in TinyGo - requires interface enumeration and multicast UDP")
}
for _, iface := range interfaces {
if err := ai.configureInterface(&iface); err != nil {
log.Printf("Failed to configure interface %s: %v", iface.Name, err)
continue
}
}
if len(ai.adoptedInterfaces) == 0 {
return fmt.Errorf("no suitable interfaces found")
}
// Mark interface as online
ai.Online = true
ai.Enabled = true
go ai.peerJobs()
return nil
} }
func (ai *AutoInterface) configureInterface(iface *net.Interface) error { func (ai *AutoInterface) configureInterface(iface *net.Interface) error {
addrs, err := iface.Addrs() // Not supported in TinyGo
if err != nil { return fmt.Errorf("configureInterface not supported in TinyGo")
return err
}
for _, addr := range addrs {
if ipnet, ok := addr.(*net.IPNet); ok && ipnet.IP.IsLinkLocalUnicast() {
ai.adoptedInterfaces[iface.Name] = ipnet.IP.String()
ai.multicastEchoes[iface.Name] = time.Now()
if err := ai.startDiscoveryListener(iface); err != nil {
return err
}
if err := ai.startDataListener(iface); err != nil {
return err
}
break
}
}
return nil
} }
func (ai *AutoInterface) startDiscoveryListener(iface *net.Interface) error { func (ai *AutoInterface) startDiscoveryListener(iface *net.Interface) error {
addr := &net.UDPAddr{ // Multicast UDP not supported in TinyGo
IP: net.ParseIP(fmt.Sprintf("ff%s%s::1", ai.discoveryScope, SCOPE_LINK)), return fmt.Errorf("startDiscoveryListener not supported in TinyGo - requires multicast UDP")
Port: ai.discoveryPort,
Zone: iface.Name,
}
conn, err := net.ListenMulticastUDP("udp6", iface, addr)
if err != nil {
return err
}
go ai.handleDiscovery(conn, iface.Name)
return nil
} }
func (ai *AutoInterface) startDataListener(iface *net.Interface) error { func (ai *AutoInterface) startDataListener(iface *net.Interface) error {
@@ -154,7 +103,7 @@ func (ai *AutoInterface) startDataListener(iface *net.Interface) error {
Zone: iface.Name, Zone: iface.Name,
} }
conn, err := net.ListenUDP("udp6", addr) conn, err := net.ListenPacket("udp6", addr.String())
if err != nil { if err != nil {
return err return err
} }
@@ -164,23 +113,29 @@ func (ai *AutoInterface) startDataListener(iface *net.Interface) error {
return nil return nil
} }
func (ai *AutoInterface) handleDiscovery(conn *net.UDPConn, ifaceName string) { func (ai *AutoInterface) handleDiscovery(conn net.PacketConn, ifaceName string) {
buf := make([]byte, 1024) buf := make([]byte, 1024)
for { for {
_, remoteAddr, err := conn.ReadFromUDP(buf) _, addr, err := conn.ReadFrom(buf)
if err != nil { if err != nil {
log.Printf("Discovery read error: %v", err) log.Printf("Discovery read error: %v", err)
continue continue
} }
remoteAddr, ok := addr.(*net.UDPAddr)
if !ok {
log.Printf("Error: received non-UDP address in discovery")
continue
}
ai.handlePeerAnnounce(remoteAddr, ifaceName) ai.handlePeerAnnounce(remoteAddr, ifaceName)
} }
} }
func (ai *AutoInterface) handleData(conn *net.UDPConn) { func (ai *AutoInterface) handleData(conn net.PacketConn) {
buf := make([]byte, ai.GetMTU()) buf := make([]byte, ai.GetMTU())
for { for {
n, _, err := conn.ReadFromUDP(buf) n, _, err := conn.ReadFrom(buf)
if err != nil { if err != nil {
if !ai.IsDetached() { if !ai.IsDetached() {
log.Printf("Data read error: %v", err) log.Printf("Data read error: %v", err)
@@ -248,13 +203,13 @@ func (ai *AutoInterface) Send(data []byte, address string) error {
if ai.outboundConn == nil { if ai.outboundConn == nil {
var err error var err error
ai.outboundConn, err = net.ListenUDP("udp6", &net.UDPAddr{Port: 0}) ai.outboundConn, err = net.ListenPacket("udp6", ":0")
if err != nil { if err != nil {
return err return err
} }
} }
if _, err := ai.outboundConn.WriteToUDP(data, addr); err != nil { if _, err := ai.outboundConn.WriteTo(data, addr); err != nil {
log.Printf("Failed to send to peer %s: %v", address, err) log.Printf("Failed to send to peer %s: %v", address, err)
continue continue
} }

View File

@@ -11,7 +11,7 @@ import (
type UDPInterface struct { type UDPInterface struct {
BaseInterface BaseInterface
conn *net.UDPConn conn net.PacketConn
addr *net.UDPAddr addr *net.UDPAddr
targetAddr *net.UDPAddr targetAddr *net.UDPAddr
mutex sync.RWMutex mutex sync.RWMutex
@@ -127,7 +127,7 @@ func (ui *UDPInterface) ProcessOutgoing(data []byte) error {
return fmt.Errorf("no target address configured") return fmt.Errorf("no target address configured")
} }
_, err := ui.conn.WriteToUDP(data, ui.targetAddr) _, err := ui.conn.WriteTo(data, ui.targetAddr)
if err != nil { if err != nil {
return fmt.Errorf("UDP write failed: %v", err) return fmt.Errorf("UDP write failed: %v", err)
} }
@@ -176,23 +176,23 @@ func (ui *UDPInterface) Disable() {
} }
func (ui *UDPInterface) Start() error { func (ui *UDPInterface) Start() error {
conn, err := net.ListenUDP("udp", ui.addr) conn, err := net.ListenPacket("udp", ui.addr.String())
if err != nil { if err != nil {
return err return err
} }
ui.conn = conn ui.conn = conn
ui.Online = true ui.Online = true
// Start the read loop in a goroutine // Start the read loop in a goroutine
go ui.readLoop() go ui.readLoop()
return nil return nil
} }
func (ui *UDPInterface) readLoop() { func (ui *UDPInterface) readLoop() {
buffer := make([]byte, common.DEFAULT_MTU) buffer := make([]byte, common.DEFAULT_MTU)
for ui.IsOnline() && !ui.IsDetached() { for ui.IsOnline() && !ui.IsDetached() {
n, remoteAddr, err := ui.conn.ReadFromUDP(buffer) n, addr, err := ui.conn.ReadFrom(buffer)
if err != nil { if err != nil {
if ui.IsOnline() { if ui.IsOnline() {
log.Printf("Error reading from UDP interface %s: %v", ui.Name, err) log.Printf("Error reading from UDP interface %s: %v", ui.Name, err)
@@ -200,6 +200,12 @@ func (ui *UDPInterface) readLoop() {
return return
} }
remoteAddr, ok := addr.(*net.UDPAddr)
if !ok {
log.Printf("Error: received non-UDP address from UDP interface %s", ui.Name)
continue
}
ui.mutex.Lock() ui.mutex.Lock()
if ui.targetAddr == nil { if ui.targetAddr == nil {
log.Printf("[DEBUG-7] UDP interface %s discovered peer %s", ui.Name, remoteAddr) log.Printf("[DEBUG-7] UDP interface %s discovered peer %s", ui.Name, remoteAddr)