package node import ( "io" "log" "net" "net/netip" "sync" ) // ---------------------------------------------------------------------------- type connWriter struct { lock sync.Mutex conn *net.UDPConn } func newConnWriter(conn *net.UDPConn) *connWriter { return &connWriter{conn: conn} } func (w *connWriter) WriteTo(packet []byte, addr netip.AddrPort) { // Even though a conn is safe for concurrent use, it turns out that a mutex // in Go is more fair when there's contention. Without this lock, control // packets may fail to be sent in a timely manner causing timeouts. w.lock.Lock() if _, err := w.conn.WriteToUDPAddrPort(packet, addr); err != nil { log.Fatalf("Failed to write to UDP port: %v", err) } w.lock.Unlock() } // ---------------------------------------------------------------------------- type ifWriter struct { lock sync.Mutex iface io.ReadWriteCloser } func newIFWriter(iface io.ReadWriteCloser) *ifWriter { return &ifWriter{iface: iface} } func (w *ifWriter) Write(packet []byte) { w.lock.Lock() if _, err := w.iface.Write(packet); err != nil { log.Fatalf("Failed to write to interface: %v", err) } w.lock.Unlock() }