initial: ZeroTier-like P2P mesh VPN server with multi-tenant Web UI
This commit is contained in:
112
internal/vl1/transport.go
Normal file
112
internal/vl1/transport.go
Normal file
@@ -0,0 +1,112 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user