51 lines
1.1 KiB
Go
51 lines
1.1 KiB
Go
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()
|
|
}
|