The IRC accept loop does the reverse DNS lookup before handing the connection off, so one slow lookup stalls every new IRC connection #156

Closed
opened 2026-10-20 17:14:52 +02:00 by clawbot · 0 comments
Collaborator

acceptLoop in internal/ircserver/server.go calls newConn for each accepted socket, and newConn (internal/ircserver/conn.go) calls resolveHost, a reverse DNS lookup with a three-second timeout, before the loop reaches go client.serve(ctx). While the lookup runs nothing else is accepted. A peer whose address has no answering reverse DNS costs three seconds of accept time per connection, so a stream of such connections, which one client can produce, keeps the listener from accepting anyone else, and every connect waits behind the lookups of others. The HTTP API resolves inside the request's own goroutine (executeCreateSession in internal/handlers/api.go) and has no such stall. Not reproduced live, since the test host cannot be given an unanswering reverse DNS; the order of calls is plain in acceptLoop.

Fix: move the lookup onto the connection's goroutine (at the top of serve, or in completeRegistration, where the hostname is first needed), so the accept loop only accepts.

Definition of done

  1. acceptLoop does no network lookup; the hostname is resolved on the connection's own goroutine before registration completes.
  2. A test in internal/ircserver that a second connection is accepted and can register while the first one's lookup is still pending (a resolver that blocks, injected for the test).
  3. One reviewed PR against next.

Model: fable-5-1

`acceptLoop` in `internal/ircserver/server.go` calls `newConn` for each accepted socket, and `newConn` (`internal/ircserver/conn.go`) calls `resolveHost`, a reverse DNS lookup with a three-second timeout, before the loop reaches `go client.serve(ctx)`. While the lookup runs nothing else is accepted. A peer whose address has no answering reverse DNS costs three seconds of accept time per connection, so a stream of such connections, which one client can produce, keeps the listener from accepting anyone else, and every connect waits behind the lookups of others. The HTTP API resolves inside the request's own goroutine (`executeCreateSession` in `internal/handlers/api.go`) and has no such stall. Not reproduced live, since the test host cannot be given an unanswering reverse DNS; the order of calls is plain in `acceptLoop`. Fix: move the lookup onto the connection's goroutine (at the top of `serve`, or in `completeRegistration`, where the hostname is first needed), so the accept loop only accepts. ## Definition of done 1. `acceptLoop` does no network lookup; the hostname is resolved on the connection's own goroutine before registration completes. 2. A test in `internal/ircserver` that a second connection is accepted and can register while the first one's lookup is still pending (a resolver that blocks, injected for the test). 3. One reviewed PR against `next`. Model: fable-5-1
clawbot self-assigned this 2026-10-20 17:14:52 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/neoirc#156