package vl1 import ( "fmt" "log/slog" "net" "sync" "syscall" "time" ) type Transport struct { conn *net.UDPConn port int mu sync.RWMutex closed bool log *slog.Logger } func NewTransport(port int, log *slog.Logger) (*Transport, error) { addr := &net.UDPAddr{Port: port} conn, err := net.ListenUDP("udp", addr) if err != nil { return nil, fmt.Errorf("bind UDP port %d: %w", port, err) } actualPort := conn.LocalAddr().(*net.UDPAddr).Port log.Info("VL1 transport listening", "port", actualPort) return &Transport{ conn: conn, port: actualPort, log: log, }, nil } func (t *Transport) Port() int { return t.port } func (t *Transport) ReadFrom(buf []byte) (int, *net.UDPAddr, error) { n, addr, err := t.conn.ReadFromUDP(buf) return n, addr, err } func (t *Transport) SendTo(data []byte, addr *net.UDPAddr) error { t.mu.RLock() defer t.mu.RUnlock() if t.closed { return fmt.Errorf("transport closed") } _, err := t.conn.WriteToUDP(data, addr) return err } func (t *Transport) SendPacket(pkt *Packet, addr *net.UDPAddr) error { return t.SendTo(pkt.Encode(), addr) } func (t *Transport) Close() error { t.mu.Lock() defer t.mu.Unlock() t.closed = true return t.conn.Close() } func (t *Transport) SetSocketBuffers(rcvBuf, sndBuf int) error { rawConn, err := t.conn.SyscallConn() if err != nil { return fmt.Errorf("get raw conn: %w", err) } var setErr error err = rawConn.Control(func(fd uintptr) { if rcvBuf > 0 { if e := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF, rcvBuf); e != nil { setErr = fmt.Errorf("set SO_RCVBUF=%d: %w", rcvBuf, e) return } } if sndBuf > 0 { if e := syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_SNDBUF, sndBuf); e != nil { setErr = fmt.Errorf("set SO_SNDBUF=%d: %w", sndBuf, e) return } } }) if err != nil { return err } return setErr } func (t *Transport) LocalAddr() net.Addr { return t.conn.LocalAddr() } func (t *Transport) SetReadDeadline(deadline time.Time) error { return t.conn.SetReadDeadline(deadline) } var packetBufPool = sync.Pool{ New: func() interface{} { buf := make([]byte, MaxPacketSize) return &buf }, } func GetPacketBuf() *[]byte { return packetBufPool.Get().(*[]byte) } func PutPacketBuf(buf *[]byte) { packetBufPool.Put(buf) }