113 lines
2.3 KiB
Go
113 lines
2.3 KiB
Go
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)
|
|
}
|