Skip to content

Fix client hang on req-id collision and no_ports port-wrap crash - #248

Merged
RoadRunnr merged 4 commits into
feature/next-majorfrom
fix/client-hang-and-port-wrap
Jun 4, 2026
Merged

Fix client hang on req-id collision and no_ports port-wrap crash#248
RoadRunnr merged 4 commits into
feature/next-majorfrom
fix/client-hang-and-port-wrap

Conversation

@RoadRunnr

Copy link
Copy Markdown
Member

Summary

  • Bound eradius_client_socket:send_request/5 call timeout (was infinity) so a caller whose pending entry is overwritten by a same-ReqId request returns {error, timeout} instead of hanging forever. Uses Timeout + ?CALL_TIMEOUT_MARGIN and maps exit:{timeout,_} to {error, timeout}; infinity is passed through unchanged.
  • Reply {error, unknown_request} to unexpected handle_call in both the client socket and the client manager (the manager previously returned {noreply, State}, which would now time out instead of erroring fast).
  • Fix next_port_and_req_id/3: rem NumberOfPorts (was NumberOfPorts - 1) — fixes the off-by-one that skipped the last port and the badarith (rem 0) crash when no_ports = 1.

Test Plan

  • New CT case no_ports_one_wraps — 257 allocations force the req-id wrap branch with no_ports = 1; fails with badarith before the fix, passes after.
  • New CT case clobber_does_not_hang — a pending request whose entry is clobbered by a same-ReqId request returns {error, timeout} instead of hanging; fails ("P1 hung") before the fix, passes after.
  • Full rebar3 ct green on OTP 28.3 — all 111 tests pass (both new cases run across ipv4, ipv4_mapped_ipv6, ipv6).
  • rebar3 fmt clean.

Deferred: safe ReqId reuse (duplicate-detection-aware allocation with time-based quarantine) — the structural root cause — is intentionally out of scope and tracked separately.

🤖 Generated with Claude Code

RoadRunnr and others added 4 commits April 2, 2026 08:19
- .github/workflows/main.yml: artifact path was .tar.xz but the tar
  command produces .tar.zst; upload would always silently fail
- src/eradius_eap_packet.erl: fix doc typos 'endecode a EPA' -> 'encode an EAP'
- src/eradius_dict.erl: code_change returned {ok, state} (atom) instead
  of {ok, State} (variable), corrupting server state on hot code upgrade
- src/eradius_client_socket.erl: handle_call catch-all returned {noreply}
  which would hang callers; use {reply, {error, bad_call}, State}
- src/eradius.app.src: capitalize 'Github' -> 'GitHub'
- src/eradius_log.erl: line/1 and format_sender/1 always used server_addr
  but the docstring says '<Client-IP>'; add peer_addr/1 helper that picks
  client_addr (peer/NAS on server side) and falls back to server_addr
  (remote server on client side)
- test/eradius_client_SUITE.erl: fix typo 'Adress' -> 'Address'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
(NumberOfPorts - 1) skipped the last port and crashed with badarith
(rem 0) when no_ports = 1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gen_server:call used infinity; if a pending request entry was
overwritten by a same-ReqId request the caller waited forever. Use
Timeout + margin and map exit:{timeout,_} to {error,timeout}. Reply to
unknown calls instead of leaving them unanswered.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@RoadRunnr
RoadRunnr marked this pull request as ready for review June 4, 2026 07:32
@RoadRunnr
RoadRunnr requested a review from a team as a code owner June 4, 2026 07:32
@RoadRunnr
RoadRunnr merged commit e04e741 into feature/next-major Jun 4, 2026
4 checks passed
@RoadRunnr
RoadRunnr deleted the fix/client-hang-and-port-wrap branch June 4, 2026 07:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant