# UDPGW (NapsterV framing) — `udpgw.go` A lightweight TCP↔UDP gateway that speaks the “NapsterV” UDPGW framing: - Listens on TCP (default `0.0.0.0:7400`). - For each TCP client, opens **one UDP socket** (stable source port) and forwards framed payloads to UDP targets. - Tracks a short-lived mapping so UDP replies are routed back to the correct `connID` + `X` byte. - **IPv4 only** (UDP replies are dropped if they’re not IPv4). ## Build Single-file build: ```bash # Linux static-ish build (recommended) CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o udpgw ./udpgw.go ``` Run help: ```bash ./udpgw -h ``` ## Minimal RAM/CPU start command (recommended profile) This profile is tuned to **minimize per-client kernel buffer memory** and reduce background CPU (slower map reaping), while keeping behavior safe for most traffic: ```bash GOMAXPROCS=1 ./udpgw -listen 0.0.0.0:7400 -debug=false -write-chan 256 -udp-rbuf $((256*1024)) -udp-wbuf $((256*1024)) -map-ttl 60s -reap-every 30s ``` Notes: - `GOMAXPROCS=1` limits Go’s scheduler to one OS thread for CPU predictability. - `-udp-rbuf/-udp-wbuf` are the biggest memory knobs because they are applied **per TCP client UDP socket**. - If you see packet loss under load, raise `-udp-rbuf/-udp-wbuf` to `524288` (512 KiB) or `1048576` (1 MiB) first. ## How framing works Each TCP frame is: - `LEN` (2 bytes, little-endian) - `PAYLOAD` (`LEN` bytes) `PAYLOAD` format for both directions: - `connID` (2 bytes, big-endian) - `X` (1 byte) - `IPv4` (4 bytes) - `port` (2 bytes, big-endian) - `data` (remaining bytes) (See `readPayload()` and `buildFrame()` in the source.) ## Configuration flags All runtime knobs are flags (defaults shown): - `-listen 0.0.0.0:7400` TCP listen address. - `-max-frame 65536` Max frame payload length (DoS protection). Frames larger than this are rejected. - `-debug=false` Verbose logs. - `-hexdump 64` When `-debug=true`, hex-dump the first N bytes of payload. - `-write-chan 4096` TCP write queue depth. Larger can help bursty traffic (e.g., games) but increases worst-case RAM. - `-udp-bind ""` Bind the per-client UDP socket to a specific local IP (optional). - `-udp-rbuf 8388608` UDP read buffer bytes (socket option). **Applied per TCP client**. - `-udp-wbuf 8388608` UDP write buffer bytes (socket option). **Applied per TCP client**. - `-map-ttl 90s` Destination→`connID` mapping TTL. - `-reap-every 10s` How often to delete expired mappings. ## Tuning guide (what affects RAM/CPU the most) ### RAM hotspots 1. **Kernel UDP buffers per TCP client** Roughly proportional to: `udp-rbuf + udp-wbuf` *per connected client*. Defaults are high (8 MiB + 8 MiB). If you expect many concurrent TCP clients, reduce these. 2. **TCP write queue (`-write-chan`)** Each queued element is a `[]byte` frame. Bigger `-write-chan` allows more buffering but can grow memory. 3. **Per-client TCP reader buffer (fixed)** The code uses `bufio.NewReaderSize(conn, 256*1024)` per client (256 KiB). This is not configurable via flags. ### CPU hotspots 1. `-debug=true` (logging) Turn off for production. 2. Reaper frequency (`-reap-every`) A longer interval reduces wakeups/CPU at the cost of keeping expired mappings a bit longer. ## Recommended profiles ### 1) Ultra-low memory (many clients, light traffic) ```bash GOMAXPROCS=1 ./udpgw -listen 0.0.0.0:7400 -write-chan 128 -udp-rbuf $((128*1024)) -udp-wbuf $((128*1024)) -map-ttl 45s -reap-every 45s ``` ### 2) Balanced (good default for most servers) ```bash ./udpgw -listen 0.0.0.0:7400 -write-chan 512 -udp-rbuf $((1024*1024)) -udp-wbuf $((1024*1024)) -map-ttl 90s -reap-every 15s ``` ### 3) Low-latency / games (avoid drops under bursts) ```bash ./udpgw -listen 0.0.0.0:7400 -write-chan 4096 -udp-rbuf $((4*1024*1024)) -udp-wbuf $((4*1024*1024)) -map-ttl 120s -reap-every 10s ``` ## Operational notes - Run behind a firewall; expose only the TCP listen port you need. - If you bind `-udp-bind`, ensure that IP is present on the host. - The program will drop UDP replies that are not IPv4. ## systemd (optional) Example unit (adjust paths/flags): ```ini [Unit] Description=udpgw (NapsterV) After=network.target [Service] Type=simple WorkingDirectory=/opt/udpgw Environment=GOMAXPROCS=1 ExecStart=/opt/udpgw/udpgw -listen 0.0.0.0:7400 -write-chan 256 -udp-rbuf 262144 -udp-wbuf 262144 -map-ttl 60s -reap-every 30s Restart=on-failure NoNewPrivileges=true PrivateTmp=true [Install] WantedBy=multi-user.target ```