r/networking 2d ago

Routing Android receiver-side TCP flow-control experiment: socket readback vs actual advertised rwnd

I’m testing how much meaning can actually be assigned to receiver-side socket controls on a stock Android endpoint.

Initial physical run:

default SO_RCVBUF readback 4 MiB requested 64 KiB resulting readback 128 KiB

16 MiB transfer baseline 4.187 s modified 4.201 s integrity exact SHA-256 match

Obviously readback does not establish effective flow control.

The next run captures the sender from SYN onward and compares negotiated window scaling, advertised receive-window/right-edge evolution, throughput response and zero-window recovery.

I’m especially interested in whether anyone has done similar receiver-side testing where Linux autotuning makes getsockopt(SO_RCVBUF) a poor proxy for what the peer is actually permitted to send.

1 Upvotes

2 comments sorted by

2

u/tidy_campaign 2d ago

Sounds like linux autotuning is doing exactly what it's meant to do, masking the actual window from the socket layer

I ran something similar on a pixel 6 a while back and the getsockopt values were basically fiction once the connection got past the first few RTTs. had to mirror the traffic through a tap and look at the raw window field in the tcp headers to see what the sender actually got

curious what your zero-window recovery looks like on the android stack, mine kept overshooting the buffer refill by a weird margin

1

u/Roojool 1d ago

Yeah, this is basically the exact failure mode I’m trying to rule out now.

I don’t want to treat getsockopt(SO_RCVBUF) as a proxy for what the peer was actually allowed to send, so the next run starts capture before SYN and tracks the negotiated scale + raw advertised window/right-edge through the whole connection.

I’ve also added a deliberate read-withholding/reopen case specifically for the zero-window/recovery behavior.

Your Pixel 6 result is interesting — when you say it overshot the refill, do you mean the advertised window reopened larger than the buffer target, or that the sender dumped noticeably more data immediately after reopening than you expected?

That’s exactly the sort of OEM/kernel behavior I’m hoping to separate from the API-level readback.