fix(sm): an OnCER or OnDWR hook that closes the connection aborts processing
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 thatClosehas been called, or that the server has finished with the connection.Closepublishes 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 callc.Close().
- Hooks. After
OnCERorOnDWRreturns, the state machine stops if the connection is closed. Then there are no metadata, no admission, no CEA or DWA, noOnCEA,OnHandshakeorOnDWA, 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
Closedbefore the transport closes. - Mutations caught:
- no check after the hook;
- the flag published before handlers finish;
- the flag never published on read-loop exit;
Shutdownor 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()todiam.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 publishClosed. ClosingConnection()directly is not detected; the hook docs say to callc.Close().
Breaking change
- External
diam.Connimplementations must addClosed() bool.