Skip to content

fix(sm): an OnCER or OnDWR hook that closes the connection aborts processing - #74

Merged
gomaja merged 1 commit into
mainfrom
fix/i70-oncer-abort
Oct 10, 2026
Merged

gomaja merged 1 commit into
mainfrom
fix/i70-oncer-abort

Conversation

@gomaja

@gomaja gomaja commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Settings.OnCER promises that closing the connection from the hook aborts the handshake. The CER handler ignored that and carried on:

  • it published the peer's metadata;
  • it admitted the peer;
  • it called OnCEA;
  • it wrote the CEA to the closed connection and logged the failed write at Error.

OnDWR had the same gap for the DWA.

Change

  • diam.Conn.Closed() (new). It reports that Close has been called, or that the server has finished with the connection.
    • Close publishes it before closing the transport.
    • When the read loop ends, the server first waits for the handlers already running, so a CER or DWR that arrived before the peer's FIN is still answered (RFC 6733 §5.6 processes events in order).
    • Every server-side close goes through the same path, including Shutdown's forced close and the multistream error handler.
    • Closing Connection() directly is not observed, and the hook docs say to call c.Close().
  • Hooks. After OnCER or OnDWR returns, the state machine stops if the connection is closed. Then there are no metadata, no admission, no CEA or DWA, no OnCEA, OnHandshake or OnDWA, and nothing logged above Debug.

API change: implementations of diam.Conn outside this module must add Closed() bool. An optional interface found through ConnAs was considered and rejected: opaque wrappers that embed only the core methods would hide it, and the abort would then fail silently.

Tests

  • Hook abort: TCP and SCTP in every handler wiring and dispatch mode (30 SCTP subtests, none skipped), plus admission observed directly.
  • Half-close: a CER or DWR followed by the peer's FIN must be answered in every one of 50 runs, in sequential and concurrent dispatch. A first version of this change answered 7/50 CERs and 0/50 DWRs under concurrent dispatch. tshark captures confirm 50/50 CEAs and DWAs with matching identifiers.
  • Shutdown: a hook still running when Shutdown's deadline expires produces no answer and no Error log.
  • Multistream: a multistream read error publishes Closed before the transport closes.
  • Mutations caught:
    • no check after the hook;
    • the flag published before handlers finish;
    • the flag never published on read-loop exit;
    • Shutdown or the multistream handler bypassing the flag.

Validation

go build ./..., go test ./... -count=1, go test -race ./diam/... -count=1, go vet ./..., staticcheck ./... and golangci-lint run ./... all pass, and gofmt -l . is empty. The examples/middleware build, vet and test pass.

Fixes #70


Summary by cubic

Fixes #70. A Settings.OnCER or Settings.OnDWR hook that closes the connection now aborts processing: previously it continued publishing peer metadata, admitting the peer, calling OnCEA/OnDWA, writing the answer to the closed connection, and logging the failed write at Error.

  • Adds Closed() to diam.Conn; Close() publishes it before closing the transport, and read-loop exit waits for running handlers first so a CER or DWR received before the peer's FIN is still answered (RFC 6733 §5.6).
  • All server-side closes, including Shutdown's forced close and the multistream error handler, now publish Closed. Closing Connection() directly is not detected; the hook docs say to call c.Close().

Breaking change

  • External diam.Conn implementations must add Closed() bool.

Written for commit 9a6c0ec. Summary will update on new commits.

View guided diff Turn on auto-fix

Copilot AI balanced review requested due to automatic review settings October 10, 2026 00:52
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 9946af7f-a35b-4947-8b31-f28e27cfccad

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…cessing

Settings.OnCER promised that closing the connection from the hook aborts
the handshake, but the CER handler went on regardless: it published the
peer's metadata, admitted the peer, called OnCEA, wrote the CEA to the
closed connection and logged the failed write at Error. OnDWR had the same
gap for the DWA.

- diam.Conn gains Closed, reporting that Close has been called or that the
  server has finished with the connection. Close publishes it before
  closing the transport; when the read loop ends, the server first waits
  for the handlers already running, so a CER or DWR that arrived before the
  peer's FIN is still answered (RFC 6733 §5.6). Every server-side close,
  including Shutdown's forced close and the multistream error handler,
  goes through the same path. Closing Connection() directly is not
  observed; the hook docs say to call c.Close().
- After OnCER or OnDWR returns, the state machine stops if the connection
  is closed: no metadata, no admission, no CEA or DWA, no OnCEA,
  OnHandshake or OnDWA, and nothing logged above Debug.

Implementations of diam.Conn outside this module must add Closed.

Tests cover TCP and SCTP in every handler wiring and dispatch mode, a CER
or DWR followed by the peer's FIN in sequential and concurrent dispatch,
a hook still running when Shutdown's deadline expires, and the
multistream read error.

Fixes #70
@gomaja
gomaja force-pushed the fix/i70-oncer-abort branch from 50ea84b to 9a6c0ec Compare October 10, 2026 01:10
@gomaja

gomaja commented Oct 10, 2026

Copy link
Copy Markdown
Owner Author

The lint failure is not from this change: staticcheck 2026.2.1 cannot read the export data of Go 1.27.2, the stable release CI now installs, so it stopped before analysing any package. Under Go 1.27.2, a staticcheck built from go-tools master (f1838cc3, which carries the fix) and golangci-lint both report no issues on this branch. The workflow pin is updated in a separate change.

@gomaja
gomaja merged commit 3ce778f into main Oct 10, 2026
16 of 17 checks passed
@gomaja
gomaja deleted the fix/i70-oncer-abort branch October 10, 2026 01:14
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.

Settings.OnCER closing the connection does not abort the handshake

2 participants