158 lines
4.5 KiB
Markdown
158 lines
4.5 KiB
Markdown
# 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
|
||
```
|