LizardByte / LizardByte/Sunshine

WSASendMsg() failed: 10022 (WSAEINVAL) on every WAN / port-forwarded UDP send — IP_PKTINFO source address rejected. Minimal single-NIC repro

Open
#5,443 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
41.3k
Forks
2.1k
Avg merge
23h 47m
Merged PRs (30d)
124

Description

### Is there an existing issue for this?

- [x] I have searched the existing issues

### Is your issue described in the documentation?

- [x] I have read 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

```json

```

### Log output

```shell

```

### Online logs

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in src/platform/windows/misc.cpp, focusing on the send() and send_batch() paths that construct the IP_PKTINFO control message. Reproduce the failure with a single-NIC Windows host and a port-forwarded WAN client, then verify that outbound UDP packets are sent successfully while LAN streaming remains working.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
networking
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.