Skip to content

Feat/tcp connecotr hardening#179

Open
lxsaah wants to merge 5 commits into
mainfrom
feat/tcp-connecotr-hardening
Open

Feat/tcp connecotr hardening#179
lxsaah wants to merge 5 commits into
mainfrom
feat/tcp-connecotr-hardening

Conversation

@lxsaah

@lxsaah lxsaah commented Jul 12, 2026

Copy link
Copy Markdown
Contributor

Changes

  • Yield on synchronous accept() errors. embassy-net's TcpSocket::accept() can fail synchronously (a port-0 local_endpoint rejected as InvalidPort), and the Err arms of serve_socket_slot and the Listener<1> compat path had no await point — a tight loop with zero yields that starves the cooperative executor. Both now embassy_futures::yield_now().await, degrading a static misconfig to a debuggable warn-loop. New optional embassy-futures dep.
  • Runtime smoke test (_test-embassy-loopback). The socket pool is welded to a concrete embassy_net::tcp::TcpSocket, so its recycling and waker handoff were review-only. Now exercised over two real embassy-net stacks wired by an in-memory driver-channel crossover: recycle → re-accept, concurrent accept slots, and dialer redial after a failed connect / dropped link. Uses a wall-clock host time driver (the frozen stub clock stalls the delayed-ACK timer and hangs the first flush()). Kept off embassy-runtime and out of [dev-dependencies]; wired into make check.
  • Review cleanups. Reworded the TcpSocketSlot SAFETY comment (dialer/worker/listener-owned, not just "dialer-owned") and documented the intentional double-abort() on the recycle path.
  • Docs. New aimdb-tcp-connector/CHANGELOG.md (initial) + global changelog index link.

@lxsaah lxsaah requested a review from thaodt July 12, 2026 09:43
@lxsaah lxsaah self-assigned this Jul 12, 2026
@lxsaah lxsaah marked this pull request as ready for review July 12, 2026 09:43

@thaodt thaodt left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved with some small changes then we're good to go.

aimdb-tokio-adapter = { version = "0.6.0", path = "../aimdb-tokio-adapter", optional = true }

# test-only (see `_test-embassy-loopback`)
embassy-net-driver-channel = { path = "../_external/embassy/embassy-net-driver-channel", optional = true }

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

When aimdb-tcp-connector is packaged or published, this dep makes Cargo reject the manifest: cargo package -p aimdb-tcp-connector --allow-dirty --no-verify fails because registry packages require a version and strip path.
You may want to add the matching registry version alongside path or mark the crate non-publishable.

Comment on lines +55 to +56
// Workspace pins `embassy-time` at tick-hz-32_768.
(start.elapsed().as_micros() * 32_768 / 1_000_000) as u64

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

With _test-embassy-loopback, no tick-hz-* feature is enabled on embassy-time-driver, so its active fallback is 1000000 Hz rather than 32768 Hz. This advances stack time about 30.5x too slowly, stretching delayed ACK, retransmit and timeout behavior.

Lets derive the scale from embassy_time_driver::TICK_HZ or enable a matching tick feature.

Comment on lines +205 to +208
let mut listener_a = TcpListener::new(server_stack, 7001u16, buf(), buf());
let mut listener_b = TcpListener::new(server_stack, 7002u16, buf(), buf());
let dialer_a = TcpDialer::new(client_stack, endpoint(7001), buf(), buf());
let dialer_b = TcpDialer::new(client_stack, endpoint(7002), buf(), buf());

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Lets make this test exercise the pooled-listener path it is intended to cover.
This creates two unrelated TcpListener<1> values on different ports and never calls TcpListener<N>::with_buffers or TcpServer<N>.
The test therefore passes even if same-port fan-out or pooled worker creation is broken and no other in-tree test exercises with_buffers, please use one pooled N=2 endpoint with two clients.

futures::executor::block_on(async {
pin_mut!(foreground);
pin_mut!(background);
match select(foreground, background).await {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Because background is intentionally non-terminating and each foreground accept, connect or recv can stay pending forever, any networking regression or dropped crossover packet leaves block_on running until the outer CI timeout instead of failing the test.
You can race the foreground against a bounded wall-clock watchdog so make test fails promptly.

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.

2 participants