Is there an existing issue for this?
Is your issue described in the documentation?
Is your issue present in the latest beta/pre-release?
This issue is present in the latest pre-release
Describe the Bug
Over a port-forwarded WAN connection, every outbound video/ping UDP packet fails with WSASendMsg() failed: 10022 (WSAEINVAL). The stream reaches CLIENT CONNECTED and the encoder is created fine, but not a single UDP packet leaves the host, so the client hits Initial Ping Timeout after ~10s.
LAN streaming is 100% fine — including dialing the host's own public IP and letting it NAT-loopback. Only genuine external clients arriving through the router's port-forward fail. The first 10022 appears ~17ms after the encoder is created, on the initial small ping reply (single packet via send(), no USO cmsg), so this is not USO/offload related.
I reduced it to a minimal repro and it still fails identically on both Sunshine and Apollo (shared Windows send path).
Ruled out with single-variable A/B tests (each with logs):
| Hypothesis |
Test |
Result |
| Encoder/GPU |
— |
ruled out; the YUV444 / NvEncUnregisterAsyncEvent lines are normal encoder-probe noise between the "// Testing for available encoders //" banners; all NVENC encoders create fine |
| Video encryption |
wan_encryption_mode=0 |
still 10022 |
| IPv4-mapped / dual-stack |
address_family=ipv4 (client logged as bare IPv4, no ::ffff:) |
still 10022 |
| Multiple NICs / IP forwarding / virtual adapters |
reduced to a single Ethernet adapter, forwarding disabled |
still 10022 |
| Routing |
single default route, in/out interface identical |
not the cause |
| Implementation |
Sunshine -> Apollo |
identical 10022 |
Expected Behavior
A client connecting over WAN through a router port-forward should stream normally (outbound UDP packets are sent), exactly as it does on LAN.
Additional Context
Root cause: in src/platform/windows/misc.cpp, both send() and send_batch() unconditionally attach an IP_PKTINFO control message pinning the source address:
IN_PKTINFO pktInfo;
SOCKADDR_IN saddr_v4 = to_sockaddr(send_info.source_address.to_v4(), 0);
pktInfo.ipi_addr = saddr_v4.sin_addr;
pktInfo.ipi_ifindex = 0;
cm->cmsg_level = IPPROTO_IP;
cm->cmsg_type = IP_PKTINFO;
With ipi_ifindex=0, Windows derives the outgoing interface from routing to the destination and then requires ipi_addr to be a unicast address assigned to that interface, else WSASendMsg returns WSAEINVAL. For a port-forwarded WAN client, send_info.source_address is not a locally-assigned address on the interface that routes to the client's public IP, so every packet is rejected. This is why LAN / native-IPv6 / mesh-VPN paths work (the dialed address is a real local interface address) but NAT port-forward does not. send() also has no fallback — on failure it just logs and returns false.
Suggested fix: on WSAEINVAL, retry without the IP_PKTINFO cmsg (plain send with no source pinning). A single-homed host doesn't need forced source selection — which is exactly why LAN already works. Small, low-risk change.
Adding a one-line debug log of send_info.source_address right before the WSASendMsg call would confirm the exact address being pinned on the WAN path. Happy to build a patched binary and test any fallback patch — the repro is deterministic.
Related: #3043 (closed as stale), #2120, ClassicOldSong/Apollo#1041 (open).
Host Operating System
Windows
Operating System Version
Windows 11, 10.0.26200
Architecture
amd64/x86_64
Package
Windows - msi installer (recommended)
GPU Type
NVIDIA
GPU Model
NVIDIA GeForce RTX 4060 Laptop GPU
GPU Driver/Mesa Version
610.62
Capture Method
Desktop Duplication API (Windows)
Apps
Log output
Online logs
<script src="https://gist.github.com/MathLeee/0302cb461bbb7b9fc52d7b86e8e7a073.js"></script>
Is there an existing issue for this?
Is your issue described in the documentation?
Is your issue present in the latest beta/pre-release?
This issue is present in the latest pre-release
Describe the Bug
Over a port-forwarded WAN connection, every outbound video/ping UDP packet fails with
WSASendMsg() failed: 10022(WSAEINVAL). The stream reaches CLIENT CONNECTED and the encoder is created fine, but not a single UDP packet leaves the host, so the client hits Initial Ping Timeout after ~10s.LAN streaming is 100% fine — including dialing the host's own public IP and letting it NAT-loopback. Only genuine external clients arriving through the router's port-forward fail. The first 10022 appears ~17ms after the encoder is created, on the initial small ping reply (single packet via send(), no USO cmsg), so this is not USO/offload related.
I reduced it to a minimal repro and it still fails identically on both Sunshine and Apollo (shared Windows send path).
Ruled out with single-variable A/B tests (each with logs):
Expected Behavior
A client connecting over WAN through a router port-forward should stream normally (outbound UDP packets are sent), exactly as it does on LAN.
Additional Context
Root cause: in src/platform/windows/misc.cpp, both send() and send_batch() unconditionally attach an IP_PKTINFO control message pinning the source address:
With ipi_ifindex=0, Windows derives the outgoing interface from routing to the destination and then requires ipi_addr to be a unicast address assigned to that interface, else WSASendMsg returns WSAEINVAL. For a port-forwarded WAN client, send_info.source_address is not a locally-assigned address on the interface that routes to the client's public IP, so every packet is rejected. This is why LAN / native-IPv6 / mesh-VPN paths work (the dialed address is a real local interface address) but NAT port-forward does not. send() also has no fallback — on failure it just logs and returns false.
Suggested fix: on WSAEINVAL, retry without the IP_PKTINFO cmsg (plain send with no source pinning). A single-homed host doesn't need forced source selection — which is exactly why LAN already works. Small, low-risk change.
Adding a one-line debug log of send_info.source_address right before the WSASendMsg call would confirm the exact address being pinned on the WAN path. Happy to build a patched binary and test any fallback patch — the repro is deterministic.
Related: #3043 (closed as stale), #2120, ClassicOldSong/Apollo#1041 (open).
Host Operating System
Windows
Operating System Version
Windows 11, 10.0.26200
Architecture
amd64/x86_64
Package
Windows - msi installer (recommended)
GPU Type
NVIDIA
GPU Model
NVIDIA GeForce RTX 4060 Laptop GPU
GPU Driver/Mesa Version
610.62
Capture Method
Desktop Duplication API (Windows)
Apps
Log output
Online logs
<script src="https://gist.github.com/MathLeee/0302cb461bbb7b9fc52d7b86e8e7a073.js"></script>