Backport Win2000 per-socket TCP keepalive timers (SIO_KEEPALIVE_VALS time/interval)
- Dominant language
- C
- Stars
- 11
- Forks
- 2
- PR merge metrics
- No merged PRs in 30d
Description
## Context
`WSAIoctl(SIO_KEEPALIVE_VALS)` and `setsockopt(SO_KEEPALIVE)` are now wired end-to-end (ws2_32 → AFD → TCP via `IOCTL_TCP_SET_INFORMATION_EX(TCP_SOCKET_KEEPALIVE)`): the `tcp_keepalive.onoff` field genuinely enables/disables keepalive on the connection. See the WSAIoctl/keepalive work (issue #7).
What is **deliberately not** honored: the per-socket `keepalivetime` / `keepaliveinterval` fields of `struct tcp_keepalive`. They are accepted by `WSAIoctl` and then ignored — the connection uses the stack's **global** timers (`KeepAliveTime` ≈ 2h, `KAInterval` ≈ 1s).
## Why it's deferred (the dating)
Per-socket keepalive timers are a **Windows 2000 (NT 5.0)** feature, verified against the reference trees:
- **NT 3.5** (our base, `NTOS/TDI/TCPIP/TCP/INFO.C`) and **NT 4.0** (`stuff/WinNT4/.../tcp/info.c:797`, `tcp.h:244`) both implement keepalive as an **on/off flag with global timers only** — no per-connection timer fields, no `tcp_keepalive`, no `SIO_KEEPALIVE_VALS`.
- **Win2000 / Server 2003** added option `TCP_SOCKET_KEEPALIVE_VALS = 7` with per-connection `tc_tcbkatime` / `tc_tcbkainterval` (`stuff/srv03rtm-anika/net/tcpip/driver/tcp/{info.c:1129,tcpconn.h:83}`), surfaced via `mstcpip.w`.
Our TCP sits exactly at the NT4 line, so honoring the timers is a forward-port, not a restore — kept out of the WSAIoctl unblock to stay NT4-faithful.
## Who wants it
`SIO_KEEPALIVE_VALS` with real per-socket timers is widely used: **tokio** (on Windows), **libevent**, **curl**, **freetds**, **libzmq**. Workloads tuning keepalive aggressively (short idle + interval) will silently fall back to the 2h global today.
## What backporting requires (srv03 reference in hand)
1. **TCP transport** — add `tc_tcbkatime` / `tc_tcbkainterval` to our `TCPConn` (ref `srv03 .../tcp/tcpconn.h:83-84`); handle option `TCP_SOCKET_KEEPALIVE_VALS=7` in `NTOS/TDI/TCPIP/TCP/INFO.C` (read `TCPKeepalive {onoff, keepalivetime, keepaliveinterval}`, store `MS_TO_TICKS(...)`, set the `KEEPALIVE` flag — ref `srv03 .../tcp/info.c:1129-1200`).
2. **Keepalive timer loop** — our `TCBTimeout` (`NTOS/TDI/TCPIP/TCP/TCB.C:721`) uses a `tcb_alive`/`tcb_kacount` delta-compare against the **globals**; change it to consume the per-conn values, falling back to the globals when only plain `TCP_SOCKET_KEEPALIVE` was set. NOTE: srv03's own timer loop uses a timer-wheel (`KA_TIMER`/`START_TCB_TIMER_R`, `tcb.c:1806`) that **cannot be lifted verbatim** into our delta-compare scheme — port the per-conn field *concept*, not the loop.
3. **AFD** — extend the keepalive push to carry the full `tcp_keepalive` vals (a new `AFD_KEEPALIVE_VALS` info code + `TCP_SOCKET_KEEPALIVE_VALS` set-info), not just the on/off `AFD_KEEPALIVE`.
4. **ws2_32** — `WSAMISC.c WSAIoctl` currently extracts only `onoff`; pass the time/interval through; mirror in the buffer-and-apply-at-connect path.
## Acceptance
`socket.ioctl(SIO_KEEPALIVE_VALS, (1, 10000, 3000))` results in first probe after ~10s idle, then ~3s interval (observable via packet capture / connection timeout), instead of the 2h global.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.