Skip to content

feat(sm): DialContext and DialTLSContext; DialNetworkTLS binds laddr - #76

Merged
gomaja merged 1 commit into
mainfrom
feat/i71-dial-context
Oct 10, 2026
Merged

gomaja merged 1 commit into
mainfrom
feat/i71-dial-context

Conversation

@gomaja

@gomaja gomaja commented Oct 10, 2026 •

Copy link
Copy Markdown
Owner

Two issues on sm.Client's dial path:

Change

  • New context-aware dials. sm.Client.DialContext(ctx, network, addr, laddr) and DialTLSContext(ctx, network, addr, certFile, keyFile, laddr) bound the whole dial with the context:

    • name resolution (SCTP through go-sctp's ResolveAddrContext);
    • the transport connect;
    • the TLS handshake;
    • the CER/CEA exchange and its retransmissions (RFC 6733 §5.3).
  • When the context ends:

    • the unfinished connection is aborted (an SCTP association gets an ABORT, RFC 9260 §9.1, instead of waiting out a graceful shutdown);
    • no watchdog starts;
    • a CEA that has not yet been accepted is refused;
    • the error matches ctx.Err().

    Once the dial has returned, the context no longer affects the connection. One race is documented: if the CEA was accepted just before cancellation, OnHandshake may already have run.

  • One dial path. diam.Server gains DialContext and DialTLSContext. Every existing dial function in diam and sm.Client is a wrapper over the context-aware path, and keeps its previous timeout semantics:

    • over TCP the timeout covers name resolution and the connect;
    • over SCTP it starts after name resolution;
    • it never covers TLS negotiation or CER/CEA.
  • sm.Client.DialNetworkTLS ignores its laddr argument #69: DialNetworkTLS passes laddr through.

  • Dependency: go-sctp moves to da2f7fb, which adds ResolveAddrContext.

Tests

  • Cancellation points: cancellation and deadlines are tested during:
    • the TCP and SCTP CER wait;
    • a blocked CER write;
    • the TLS handshake (both sm and diam.Server);
    • SCTP name resolution;
    • a full-backlog TCP connect.
  • Other cases:
    • an already-cancelled context;
    • a successful dial surviving cancellation;
    • no goroutine left behind;
    • a late CEA racing cancellation;
    • the CER timer being reset after each write;
    • legacy TLS error consistency;
    • the bound source address for DialNetworkTLS and DialTLSExt.
  • Before the fix:
    • DialNetworkTLS was seen on the wrong source port;
    • cancellation during the CER wait took the full retransmission time;
    • SCTP hostname resolution ignored cancellation;
    • a late CEA ran OnHandshake after cancellation.
  • Unresponsive SCTP peer. An optional harness (-tags sctpblackhole, which needs a privileged container; see the README) removes the peer's address after the CER. On the old code, cancellation returned after 3.0 s of graceful shutdown. With this change it returns within about 0.2 ms, for CER and TLS over SCTP alike, and tshark shows ABORT with no SHUTDOWN wait.
  • Mutations caught:
    • the CAS that refuses a late CEA removed;
    • the context-TLS dial made lazy;
    • each transport ignoring the context;
    • the CER timer's Reset removed;
    • the abort path removed;
    • the cancellation callback left attached after success.

Validation

Under Go 1.27.2:

  • go build ./..., go test ./... -count=1, go test -race ./diam/... -count=1 and go vet ./... (also with -tags sctpblackhole) pass;
  • staticcheck at the go-tools commit that reads Go 1.27.2 export data and golangci-lint run ./... report no issues, and gofmt -l . is empty;
  • the examples/middleware build, vet and test pass;
  • SCTP tests ran with no skips.

Fixes #71
Fixes #69


Summary by cubic

Adds context-aware dialing to sm.Client and diam.Server, so a dial can be cancelled or time out during transport connect, TLS handshake, and CER/CEA exchange instead of waiting for retransmissions to exhaust.

  • sm.Client.DialContext(ctx, network, addr, laddr) and DialTLSContext bound the whole dial; on cancellation, an unfinished SCTP association is aborted (RFC 9260 §9.1) rather than closed gracefully, no watchdog starts, a CEA not yet accepted is refused, and the error matches ctx.Err().
  • Once a dial succeeds, cancelling the context has no effect on the connection, except one documented race: if a CEA was accepted just before cancellation, OnHandshake may still run.
  • diam.Server gains DialContext and DialTLSContext; all existing dial functions in diam and sm.Client are wrappers over the context-aware path, keeping their previous timeout semantics (TCP: name resolution and connect; SCTP: after name resolution; never TLS or CER/CEA).
  • DialNetworkTLS now passes laddr through, fixing the dropped source address (issue sm.Client.DialNetworkTLS ignores its laddr argument #69).
  • go-sctp is bumped to a version that adds ResolveAddrContext, covering SCTP name resolution with cancellation.
  • Adds tests for cancellation at each dial stage, a race with a late CEA, no goroutine leaks, and a sctpblackhole harness that verifies an abort takes about 0.2 ms against an unresponsive SCTP peer.

Written for commit 4eef779. Summary will update on new commits.

View guided diff Turn on auto-fix

sm.Client could not abandon a dial: the timeout argument bounded only the
transport connect, and the CER/CEA exchange ran until its retransmissions
were exhausted. DialNetworkTLS also dropped its laddr argument, so the
connection used an ephemeral source address.

- DialContext and DialTLSContext bound the whole dial with a context:
  name resolution (SCTP through go-sctp's ResolveAddrContext), the
  transport connect, the TLS handshake and the CER/CEA exchange with its
  retransmissions (RFC 6733 §5.3). When the context ends, the unfinished
  connection is aborted (an SCTP association with ABORT, RFC 9260 §9.1,
  instead of waiting for a graceful shutdown), no watchdog starts, a CEA
  that has not yet been accepted is refused, and the error matches
  ctx.Err(). Once the dial has returned, the context no longer affects
  the connection.
- diam.Server gains DialContext and DialTLSContext, and every existing
  dial function, in diam and in sm.Client, is a wrapper over the
  context-aware path with its previous timeout semantics: over TCP the
  timeout covers name resolution and the connect, over SCTP it starts
  after name resolution, and it never covers TLS negotiation or CER/CEA.
- DialNetworkTLS passes laddr through.
- go-sctp moves to da2f7fb, which adds ResolveAddrContext.

Tests cancel during the TCP and SCTP CER wait, a blocked CER write, the
TLS handshake, SCTP name resolution and a full-backlog TCP connect, and
race a late CEA against cancellation;
check deadlines, an already-cancelled context, that a successful dial
survives cancellation, and that no goroutine is left behind; and check
the bound source address for DialNetworkTLS and DialTLSExt.

Fixes #71
Fixes #69
Copilot AI balanced review requested due to automatic review settings October 10, 2026 02:09
@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: 8be7036b-fc72-4e2b-b88a-8f221d4b5252

  • 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.

@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 bbb6867 into main Oct 10, 2026
15 of 16 checks passed
@gomaja
gomaja deleted the feat/i71-dial-context branch October 10, 2026 02:12
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.

sm.Client has no context-aware dial; an in-flight dial or CER exchange cannot be cancelled sm.Client.DialNetworkTLS ignores its laddr argument

2 participants