PR5 ready. CI green. #481
No reviewers
Labels
No labels
bug
dependencies
documentation
duplicate
enhancement
good first issue
help wanted
invalid
question
refactor
rust
technical-debt
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
navicore/patch-seq!481
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "net-pr5"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Changes:
ToSocketAddrs. Instead it calls crate::dns::resolve(host) (cooperative via the worker pool), parses returned
strings to IpAddr, and walks the resulting addresses building typed SocketAddr::new(ip, port) values for
send_to. Multi-address fallback semantics match the TCP-connect path: first send_to that doesn't error wins,
transparently handling the v4-only-socket + v6-first-DNS case for localhost-style hostnames. Public signature
unchanged.
(a DNS name, not IP literal) and asserts the round-trip. On Linux's localhost → ::1, 127.0.0.1 resolution this
exercises both the new DNS path and the multi-address walk.
multi-address walk, and the carrier-non-blocking guarantee.
Design-doc checkpoint #9 (the send-to host-resolution fix) is now satisfied.
The full 5-PR slicing of docs/design/NONBLOCKING_NETWORKING.md is complete: DNS (PR1) → TCP connect (PR2) → TLS
client (PR3) → HTTP rewrite (PR4) → UDP send-to via DNS (PR5). Since docs/design/done/ is the established
convention for completed designs, you may want to mv docs/design/NONBLOCKING_NETWORKING.md docs/design/done/ and
stage that as part of the PR5 commit.
Outstanding follow-ups carried across all five PRs (in case you want a consolidated list for backlog tickets):
timeout from PR4, EOF-framed-body hang from PR4).
to fully private (PR3).
part of this gap.
inspection, User-Agent override (PR3/PR4).
(PR4).
17-byte rustls drop-trampoline residue (PR4).
Review — PR5 (UDP send-to via DNS pool)
Reviewed against
origin/net-pr5. Small, well-scoped PR that closes the last remaining blocking-getaddrinfohazard in the networking stack. The fix mirrors the PR2 TCP-connect pattern: pre-resolve via the may-aware DNS pool, walk typedSocketAddr::new(ip, port)values rather than building ahost:portstring (so the IPv6-bracket trap can't reappear here either), and fall back across the resolved address list. No public-signature change, doc explains the new semantics, and the integration test exercises the new path againstlocalhost. Looks good to merge with a couple of small clarifications.What works well
Arc<UdpSocket>clone before thedns::resolvecall. The socket is checked out of the registry before the (possibly yielding) DNS lookup, so a concurrentudp.closethat drops the registry slot can't yank the socket out from under the send. The Arc keeps it alive for the duration; the existing comment atudp.rs:223-226captures this. Same invariant the PR1/PR2 cooperative patterns rely on, preserved correctly here.SocketAddr::new(ip, port)end-to-end. The IPv6-bracket bug we hit in PR2 is structurally impossible on this path because nothing ever sees a string-form address.addrs.iter().any(...)short-circuits on the firstOk, so a successful v6 send doesn't get followed by a needless v4 send. Standard.Worth tightening (small)
Per-syscall "doesn't error" vs per-peer reachability — doc could be sharper. The new paragraph in
STDLIB_REFERENCE.mdsays "the firstsend_tothat doesn't error wins." For TCPconnectthat phrasing reads naturally as "first peer that completes the handshake." For UDP it means "first address whose family the local socket actually supports" —send_toreturningOkmeans the kernel queued the datagram, not that the peer received it. The code comment atudp.rs:247-250already nails this ("typically address-family mismatches"); the doc should pick up the same framing so users don't read this as a delivery-validation guarantee. One sentence: "Note that for UDP,send_toreturning OK means the kernel accepted the datagram for the chosen address family — it doesn't confirm peer delivery." Otherwise people will (reasonably) expect this to keep walking if the first peer is unreachable, which it can't.Multi-address walk test coverage depends on
/etc/hostsconfiguration. The test comment claims "On Linux's localhost → ::1, 127.0.0.1 resolution" — true on stock distros, but minimal containers, Alpine variants, and some BSD-derived/etc/hostssetups list only127.0.0.1. On those, the test still passes (single-address walk hits the first entry), but the v6-fails-then-v4-succeeds path is silently not exercised. Test isn't wrong — it does prove DNS-through-the-pool works — just that "verifies the multi-address fallback" in the test comment is conditional on the runner's hosts file. Either weaken the comment ("on dual-stack/etc/hostsconfigurations this also exercises…") or add a parallel test using an IPv6 literal ("::1") bound on a v6 socket so the walk semantics get explicit coverage. Optional — the architectural property is the same as TCP-connect, which already has dual-stack test coverage.filter_mapsilently drops parse failures.dns::resolvereturns strings produced bySocketAddr::ip().to_string(), so a non-parseable result would be a runtime invariant violation. The TCP-connect path made the same call with a one-line comment explaining the skip-rather-than-panic rationale; PR5 doesn't carry that comment forward here. Worth a one-liner so a future reader doesn't wonder if they should be propagating an error:Optional follow-ups (not for this PR)
dns::resolve("127.0.0.1")goes through the worker-pool channel, the cache, etc., even though the resolver'sgetaddrinfonumeric-host arm returns trivially. Same shape applies to TCP-connect. Ahostname.parse::<IpAddr>().ok()short-circuit beforedns::resolvewould skip the pool round-trip for literal calls — measurable on tight loops, irrelevant otherwise. Worth doing once across all three call sites (TCP-connect, UDP send-to, the HTTP client) rather than per-PR.Verdict
LGTM. The doc clarification on UDP-OK-isn't-delivery is the only item I'd want before merge; the comment-forward on
filter_mapis a 30-second nice-to-have; the test-comment caveat is informational. None block.The "all five PRs delivered" arc closes out a clean refactor of the networking surface — happy to see the consolidated follow-up list in the PR description; that's the right shape for a backlog pass.
Second pass
All three clarifications landed cleanly:
filter_maprationale comment is in and cross-referencestcp::patch_seq_tcp_connect, which makes the invariant discoverable for someone landing inudp.rsfirst.LGTM. Ship it.