Skip to content

Add Unix domain socket support and collapse reactor backends#228

Open
mvandeberg wants to merge 1 commit intocppalliance:developfrom
mvandeberg:pr/122-unix-sockets-2
Open

Add Unix domain socket support and collapse reactor backends#228
mvandeberg wants to merge 1 commit intocppalliance:developfrom
mvandeberg:pr/122-unix-sockets-2

Conversation

@mvandeberg
Copy link
Copy Markdown
Contributor

@mvandeberg mvandeberg commented Apr 9, 2026

Add local_stream_socket, local_stream_acceptor, local_datagram_socket, local_endpoint, and local_socket_pair for Unix domain socket I/O. The public API mirrors TCP/UDP with protocol-appropriate differences (path-based endpoints, socketpair, release_socket for fd passing).

Replace 42 per-backend reactor files (14 each for epoll, kqueue, select) with parameterized templates instantiated from per-backend traits structs. Each backend provides a traits type capturing its platform-specific socket creation, write policy, and accept policy.

The reactor_types template in reactor_backend.hpp generates all concrete socket, service, acceptor, and op types. Virtual method overrides move into the CRTP bases, and select's notify_reactor() moves into register_op() via a compile-time trait, eliminating all select-specific method overrides.

New files:

  • {epoll,kqueue,select}_traits.hpp: per-backend policies
  • reactor_{stream,datagram}_ops.hpp: parameterized op types
  • reactor_socket_finals.hpp: final socket/acceptor types
  • reactor_service_finals.hpp: per-protocol service types
  • reactor_backend.hpp: accept impl and reactor_types bundle

Benchmarks

Benchmark develop branch delta dev CV br CV
burst/10 3924.5 4074.5 +3.8% 1.7% 1.0%
burst/100 376.6 394.4 +4.7% 1.4% 0.5%
burst_lockless/10 3930.1 4087.9 +4.0% 1.2% 0.5%
burst_lockless/100 380.4 395.8 +4.0% 1.2% 0.4%
concurrent/1 87738.9 130753.7 +49.0% 47.4% 63.2%
concurrent/4 91645.8 138229.4 +50.8% 48.1% 64.6%
concurrent/16 92340.6 140507.5 +52.2% 48.6% 65.3%
concurrent/32 112678.3 113751.3 +1.0% 0.9% 0.6%
concurrent_lockless/1 127191.8 190606.4 +49.9% 0.8% 34.7%
concurrent_lockless/4 131428.5 205483.3 +56.3% 0.9% 37.5%
concurrent_lockless/16 132461.7 208093.9 +57.1% 0.8% 37.8%
concurrent_parents/1 7252.0 7357.2 +1.5% 1.4% 0.3%
concurrent_parents/4 7066.0 7181.5 +1.6% 1.4% 0.3%
concurrent_parents/16 6888.1 7022.5 +2.0% 1.5% 0.4%
concurrent_parents_lockless/1 7307.4 7410.3 +1.4% 1.3% 0.3%
concurrent_parents_lockless/4 7108.4 7214.9 +1.5% 1.5% 0.4%
concurrent_parents_lockless/16 6904.1 7054.9 +2.2% 1.8% 0.5%
fork_join/1 100015.7 101440.9 +1.4% 1.2% 0.4%
fork_join/4 28002.7 28373.6 +1.3% 1.4% 0.3%
fork_join/16 7229.8 7346.0 +1.6% 1.2% 0.2%
fork_join/64 1765.3 1795.3 +1.7% 1.4% 0.4%
fork_join_lockless/1 101721.4 102573.3 +0.8% 1.3% 0.5%
fork_join_lockless/4 28331.2 28655.0 +1.1% 1.3% 0.4%
fork_join_lockless/16 7309.7 7400.4 +1.2% 1.7% 0.3%
fork_join_lockless/64 1779.2 1807.2 +1.6% 1.6% 0.5%
multithread/1 112600.7 113712.7 +1.0% 0.8% 0.8%
multithread/2 210394.1 214443.6 +1.9% 1.3% 0.5%
multithread/4 357140.2 360153.6 +0.8% 2.1% 1.0%
multithread/8 536246.6 550344.6 +2.6% 2.9% 3.5%
multithread/16 514167.4 614794.6 +19.6% 11.2% 10.5%
nested/4 7207.1 7318.2 +1.5% 1.5% 0.2%
nested/16 1748.1 1777.4 +1.7% 1.7% 0.4%
nested_lockless/4 7260.4 7347.9 +1.2% 1.6% 0.4%
nested_lockless/16 1763.6 1786.2 +1.3% 1.5% 0.4%
pingpong/1 125964.5 191636.8 +52.1% 0.8% 35.5%
pingpong/64 126236.3 190563.1 +51.0% 0.7% 35.1%
pingpong/1024 125105.7 185131.7 +48.0% 0.7% 33.8%
pingpong_lockless/1 126994.7 192111.0 +51.3% 0.8% 35.2%
pingpong_lockless/64 126873.3 192553.3 +51.8% 0.9% 35.5%
pingpong_lockless/1024 125733.8 187990.6 +49.5% 0.7% 34.5%
sequential 32415.5 33318.1 +2.8% 0.5% 0.7%
sequential_lockless 32499.3 33459.9 +3.0% 0.5% 0.6%
single_conn 104419.9 105626.6 +1.2% 0.7% 0.7%
single_conn_lockless 105687.2 106656.6 +0.9% 0.6% 0.6%
Benchmark corosio asio coro asio cb vs coro vs cb unit
unix_socket_latency/concurrent/1 251032.3 213903.5 222541.6 +17.4% +12.8% ops/s
unix_socket_latency/concurrent/4 275749.1 277373.3 292439.9 -0.6% -5.7% ops/s
unix_socket_latency/concurrent/16 281511.6 305375.1 322748.8 -7.8% -12.8% ops/s
unix_socket_latency/concurrent_lockless/1 255319.4 220815.5 232292.2 +15.6% +9.9% ops/s
unix_socket_latency/concurrent_lockless/4 277189.4 287263.7 305615.0 -3.5% -9.3% ops/s
unix_socket_latency/concurrent_lockless/16 281976.4 315188.3 336719.8 -10.5% -16.3% ops/s
unix_socket_latency/pingpong/1 255522.8 211528.6 222705.3 +20.8% +14.7% ops/s
unix_socket_latency/pingpong/64 253745.9 212484.9 221299.0 +19.4% +14.7% ops/s
unix_socket_latency/pingpong/1024 250702.4 210179.0 215189.6 +19.3% +16.5% ops/s
unix_socket_latency/pingpong_lockless/1 253920.1 221009.7 234015.9 +14.9% +8.5% ops/s
unix_socket_latency/pingpong_lockless/64 251236.3 223418.7 233011.5 +12.5% +7.8% ops/s
unix_socket_latency/pingpong_lockless/1024 250352.4 218640.1 221307.8 +14.5% +13.1% ops/s
unix_socket_throughput/bidirectional/1024 605.6 573.8 596.6 +5.5% +1.5% MB/s
unix_socket_throughput/bidirectional/4096 1989.1 1859.3 1903.8 +7.0% +4.5% MB/s
unix_socket_throughput/bidirectional/16384 6490.7 6064.1 6183.0 +7.0% +5.0% MB/s
unix_socket_throughput/bidirectional/65536 9369.8 9688.2 9821.1 -3.3% -4.6% MB/s
unix_socket_throughput/bidirectional/262144 10937.8 11328.2 11566.6 -3.4% -5.4% MB/s
unix_socket_throughput/bidirectional/1048576 10821.8 11449.0 11559.8 -5.5% -6.4% MB/s
unix_socket_throughput/bidirectional_lockless/1024 606.0 573.7 622.9 +5.6% -2.7% MB/s
unix_socket_throughput/bidirectional_lockless/4096 1991.4 1885.1 1971.1 +5.6% +1.0% MB/s
unix_socket_throughput/bidirectional_lockless/16384 6496.7 6137.8 6474.9 +5.8% +0.3% MB/s
unix_socket_throughput/bidirectional_lockless/65536 9386.3 9549.1 9858.0 -1.7% -4.8% MB/s
unix_socket_throughput/bidirectional_lockless/262144 10994.6 11463.4 11455.1 -4.1% -4.0% MB/s
unix_socket_throughput/bidirectional_lockless/1048576 10977.4 11397.8 11534.0 -3.7% -4.8% MB/s
unix_socket_throughput/unidirectional/1024 584.1 509.8 544.5 +14.6% +7.3% MB/s
unix_socket_throughput/unidirectional/4096 1930.4 1676.4 1776.0 +15.2% +8.7% MB/s
unix_socket_throughput/unidirectional/16384 6351.6 5652.4 5798.9 +12.4% +9.5% MB/s
unix_socket_throughput/unidirectional/65536 9610.2 9529.2 9756.5 +0.8% -1.5% MB/s
unix_socket_throughput/unidirectional/262144 11162.2 12091.4 12106.9 -7.7% -7.8% MB/s
unix_socket_throughput/unidirectional/1048576 11321.8 12061.8 11278.5 -6.1% +0.4% MB/s
unix_socket_throughput/unidirectional_lockless/1024 584.8 521.1 546.3 +12.2% +7.0% MB/s
unix_socket_throughput/unidirectional_lockless/4096 1929.2 1730.2 1817.5 +11.5% +6.1% MB/s
unix_socket_throughput/unidirectional_lockless/16384 6340.8 5818.8 5947.7 +9.0% +6.6% MB/s
unix_socket_throughput/unidirectional_lockless/65536 9588.2 9581.2 9855.8 +0.1% -2.7% MB/s
unix_socket_throughput/unidirectional_lockless/262144 11346.2 11598.3 12031.8 -2.2% -5.7% MB/s
unix_socket_throughput/unidirectional_lockless/1048576 11357.1 11845.0 12175.3 -4.1% -6.7% MB/s

Summary by CodeRabbit

  • New Features

    • Unix-domain support: local stream & datagram sockets, local endpoints, and socket-pair factories.
    • New public enums: message_flags and shutdown_type.
  • API

    • UDP send/receive overloads accept message_flags.
    • Awaitables for stream/datagram I/O provide unified cancellation semantics.
  • Refactor

    • Consolidated awaitable base to standardize cancellation, error, and byte-count behavior.
  • Chores

    • Added Clang diagnostic helper macros.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

Umbrella header extended; reactor backend refactored into trait-driven parameterized reactor templates and finals; POSIX local stream/datagram public APIs and services added; many legacy per-backend op/service headers removed; awaitable/op base, message_flags, and shutdown_type introduced.

Changes

Cohort / File(s) Summary
Umbrella & native includes
include/boost/corosio.hpp, include/boost/corosio/native/native_tcp_socket.hpp, include/boost/corosio/native/native_tcp_acceptor.hpp, include/boost/corosio/native/native_udp_socket.hpp
Added local/tcp/udp public includes to umbrella; removed direct per-backend includes from non-doc MRDOCS paths and updated io_context to construct services via backend type aliases.
Public local-socket API
include/boost/corosio/local_endpoint.hpp, include/boost/corosio/local_stream.hpp, include/boost/corosio/local_stream_socket.hpp, include/boost/corosio/local_stream_acceptor.hpp, include/boost/corosio/local_datagram.hpp, include/boost/corosio/local_datagram_socket.hpp, include/boost/corosio/local_socket_pair.hpp
Introduced POSIX local endpoint, protocol descriptors, local stream/datagram sockets and acceptor public types, socket-pair factory declarations and related APIs.
Local-socket implementations
src/corosio/src/local_endpoint.cpp, src/corosio/src/local_stream.cpp, src/corosio/src/local_stream_socket.cpp, src/corosio/src/local_stream_acceptor.cpp, src/corosio/src/local_datagram.cpp, src/corosio/src/local_datagram_socket.cpp, src/corosio/src/local_socket_pair.cpp
Added POSIX implementations for local endpoint, stream/datagram sockets, acceptor, and socket-pair factories (open/assign/bind/listen/accept/release/etc.).
Local service abstractions
include/boost/corosio/detail/local_stream_service.hpp, include/boost/corosio/detail/local_stream_acceptor_service.hpp, include/boost/corosio/detail/local_datagram_service.hpp
Added abstract backend service interfaces for local stream/acceptor/datagram with pure-virtual open/assign/bind/accept/listen hooks.
Awaitable / op base & refactor
include/boost/corosio/detail/op_base.hpp, include/boost/corosio/io/io_read_stream.hpp, include/boost/corosio/io/io_write_stream.hpp
Added CRTP awaitable bases (bytes_op_base, void_op_base) and refactored read/write awaitables to inherit them and use dispatch/executor-based suspension.
Message flags & shutdown
include/boost/corosio/message_flags.hpp, include/boost/corosio/shutdown_type.hpp
Added scoped message_flags bitmask with bitwise operators and a centralized shutdown_type enum for socket shutdown APIs.
UDP API & Windows IOCP flags
include/boost/corosio/udp_socket.hpp, include/boost/corosio/native/detail/iocp/win_udp_service.hpp, include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
Propagated int flags through UDP backend APIs, added to_native_msg_flags helper, and added public UDP overloads accepting message_flags.
Reactor core — parameterized backend
include/boost/corosio/native/detail/reactor/reactor_backend.hpp, include/boost/corosio/native/detail/reactor/...
Introduced trait-driven reactor backend templates, reactor_types bundle, reactor acceptor implementation, and new reactor finals/factory wrappers.
Reactor ops & completion changes
include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp, .../reactor_datagram_ops.hpp, .../reactor_op.hpp, .../reactor_op_complete.hpp
Generalized stream/datagram op templates to carry Endpoint/msg_flags, added completion helpers and peer-length handling for accept/datagram flows.
Final wrappers & service finals
include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp, .../reactor_service_finals.hpp, .../reactor_acceptor_service.hpp
Added final CRTP wrappers and final service implementations that instantiate backend behavior via Traits and endpoint/impl selection.
Platform trait headers added
include/boost/corosio/native/detail/epoll/epoll_traits.hpp, .../select/select_traits.hpp, .../kqueue/kqueue_traits.hpp
Added per-backend trait definitions (socket creation/configure, write/accept policies, hooks, needs_write_notification flags).
Legacy per-backend removals
include/boost/corosio/native/detail/epoll/*, .../select/*, .../kqueue/* (many deleted headers)
Removed many epoll/select/kqueue-specific op/service/socket headers and inline implementations in favor of trait-based reactor finals.
Endpoint conversion
include/boost/corosio/native/detail/endpoint_convert.hpp
Added POSIX local_endpoint ↔ sockaddr conversion helpers and family-aware overloads.
io_object handle lookup
include/boost/corosio/io/io_object.hpp
create_handle now attempts keyed lookup via Service::key_type when present, falling back to Service.
IO context wiring
src/corosio/src/io_context.cpp
Construct backend services using backend aliases and pre-create local stream/datagram services for POSIX backends.
Bench macro
perf/common/native_includes.hpp
Added COROSIO_SUITE_INSTANTIATE_POSIX(decl) macro to instantiate POSIX backends only.
Misc config
include/boost/corosio/detail/config.hpp
Added Clang diagnostic push/pop/disable helper macros.
TCP changes
include/boost/corosio/tcp_socket.hpp, src/corosio/src/tcp_socket.cpp
Replaced nested shutdown enum with alias to corosio::shutdown_type; added noexcept overload returning std::error_code.
Reactor scheduler flags
include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp, .../select/select_scheduler.hpp
Added needs_write_notification compile-time flags for schedulers (reactor: false; select: true).

Sequence Diagram(s)

sequenceDiagram
    participant App as Application
    participant Sock as local_datagram_socket
    participant Reactor as reactor_dgram_socket_final (Traits)
    participant Scheduler as Scheduler (epoll/select/kqueue)
    participant OS as OS Kernel

    App->>+Sock: co_await send_to(buffers, endpoint, flags)
    Sock->>+Reactor: dispatch(h, executor) with flags
    Reactor->>OS: sendmsg(fd, iov, native_flags)
    OS-->>Reactor: result / EAGAIN
    alt immediate completion
        Reactor->>Scheduler: complete inline -> resume coroutine
    else would-block
        Reactor->>Scheduler: register_op(write)
        Scheduler->>OS: wait for writable
        OS-->>Scheduler: fd writable
        Scheduler->>Reactor: operator()() -> resume coroutine
    end
Loading
sequenceDiagram
    participant App as Application
    participant Acceptor as local_stream_acceptor
    participant ReactorAcc as reactor_acceptor_final (Traits)
    participant AcceptorSvc as acceptor service
    participant Scheduler as Scheduler
    participant OS as OS Kernel

    App->>+Acceptor: open(local_stream)
    Acceptor->>+AcceptorSvc: open_acceptor_socket(family,type,protocol)
    AcceptorSvc->>OS: socket + configure
    App->>+Acceptor: co_await accept()
    Acceptor->>+ReactorAcc: accept(h, executor)
    ReactorAcc->>OS: accept syscall
    OS-->>ReactorAcc: peer_fd / EAGAIN
    alt accepted
        ReactorAcc->>Scheduler: setup accepted descriptor -> resume coroutine with peer_socket
    else would-block
        ReactorAcc->>Scheduler: link accept_op to read_op -> wait -> resume upon readable
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested reviewers

  • sgerbino

Poem

🐰 I dug a tunnel in the code, AF_UNIX snug and bright,
I threaded flags through sendmsg hops and made the reactor light.
Endpoints curl in cozy burrows, acceptors hum with cheer,
Traits stitched fins to backends, and the sockets dance — hop, dear! 🥕

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@cppalliance-bot
Copy link
Copy Markdown

cppalliance-bot commented Apr 9, 2026

GCOVR code coverage report https://228.corosio.prtest3.cppalliance.org/gcovr/index.html
LCOV code coverage report https://228.corosio.prtest3.cppalliance.org/genhtml/index.html
Coverage Diff Report https://228.corosio.prtest3.cppalliance.org/diff-report/index.html

Build time: 2026-04-10 22:40:32 UTC

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (7)
include/boost/corosio/detail/io_op_base.hpp (1)

13-22: Add the file-level overview block here.

This header now centralizes the stop-token, error-code, and completion-state plumbing for multiple awaitables, but it jumps straight from the includes into declarations. A short /* */ overview after the includes would make the dispatch/lifetime model much easier to reason about when touching the backend call sites later.

As per coding guidelines, files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/detail/io_op_base.hpp` around lines 13 - 22, Add a
file-level /* */ overview comment immediately after the includes that explains
the header's role in centralizing stop-token handling, std::error_code
propagation, and completion-state dispatch for awaitables in namespace
boost::corosio::detail; describe the lifecycle model (who owns the stop_token,
how/when errors are set and propagated, which path signals completion vs
cancellation), note any expectations callers must meet (e.g., thread/context for
resumption), and reference the key abstractions used by this file (stop_token,
std::error_code, completion-state/awaitable dispatch and any io_op_base-style
types) so future readers can quickly understand dispatch and lifetime
responsibilities before diving into the implementations.
src/corosio/src/io_context.cpp (1)

18-19: Add the required high-level /* */ file overview.

This file now coordinates backend selection, service pre-creation, and scheduler tuning, but it still only has a terse // note after the includes. Please replace it with the repository-standard block overview so the construction order and backend split are documented in one place.

As per coding guidelines, "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/corosio/src/io_context.cpp` around lines 18 - 19, Add a
repository-standard multi-line C-style comment block after the includes in
io_context.cpp that documents the file's high-level purpose: explain that this
translation unit coordinates backend selection (via reactor_backend.hpp /
backend.hpp and the IOCP-specific includes), describes the construction order
(service pre-creation before scheduler/loop start), and summarizes scheduler
tuning decisions and where backend-specific split points occur; place the block
immediately after the include section and reference the relevant symbols
(reactor_backend.hpp, backend.hpp, IOCP) and the functions/classes that perform
service pre-creation and scheduler setup so future readers can quickly
understand the file flow.
src/corosio/src/local_socket_pair.cpp (1)

28-38: Unchecked fcntl() return values may hide configuration failures.

The fallback path for platforms without SOCK_NONBLOCK ignores fcntl() return values. While failures here are rare, silently ignoring them could leave sockets in blocking mode, causing unexpected hangs in async operations.

♻️ Proposed fix to propagate fcntl errors
 void
 make_nonblock_cloexec(int fd)
 {
 `#ifndef` SOCK_NONBLOCK
     int fl = ::fcntl(fd, F_GETFL, 0);
+    if (fl == -1)
+        throw std::system_error(
+            std::error_code(errno, std::system_category()),
+            "fcntl F_GETFL");
-    ::fcntl(fd, F_SETFL, fl | O_NONBLOCK);
-    ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+    if (::fcntl(fd, F_SETFL, fl | O_NONBLOCK) == -1)
+        throw std::system_error(
+            std::error_code(errno, std::system_category()),
+            "fcntl F_SETFL");
+    if (::fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+        throw std::system_error(
+            std::error_code(errno, std::system_category()),
+            "fcntl F_SETFD");
 `#else`
     (void)fd;
 `#endif`
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/corosio/src/local_socket_pair.cpp` around lines 28 - 38, The
make_nonblock_cloexec fallback currently ignores ::fcntl() return values; update
it to check each ::fcntl() call (F_GETFL, F_SETFL, F_SETFD) for -1 and propagate
the error instead of silently continuing—e.g., on failure capture errno and
either throw a std::system_error (or return/abort according to the surrounding
error model) with a descriptive message including the operation and fd so
callers know configuration failed; ensure this change is applied inside
make_nonblock_cloexec so any platform lacking SOCK_NONBLOCK surfaces fcntl
failures.
include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp (1)

122-162: setup_accepted_socket uses sizeof(peer_storage) instead of actual peer address length.

The function receives sockaddr_storage const& peer_storage but not the actual socklen_t returned by accept(). Using sizeof(peer_storage) (Line 155) works for most cases but is inconsistent with how complete_datagram_op correctly uses op.source_addrlen. For AF_UNIX with abstract sockets, the actual length is significant.

Consider passing socklen_t peer_addrlen as a parameter for consistency with the datagram path.

♻️ Proposed signature change
 template<typename SocketImpl, typename AcceptorImpl>
 bool
 setup_accepted_socket(
     AcceptorImpl* acceptor_impl,
     int& accepted_fd,
     sockaddr_storage const& peer_storage,
+    socklen_t peer_addrlen,
     io_object::implementation** impl_out,
     std::error_code* ec_out)
 {
     // ...
     impl.set_endpoints(
         acceptor_impl->local_endpoint(),
         from_sockaddr_as(
             peer_storage,
-            static_cast<socklen_t>(sizeof(peer_storage)),
+            peer_addrlen,
             ep_type{}));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp` around
lines 122 - 162, The setup_accepted_socket function uses sizeof(peer_storage)
when calling from_sockaddr_as which loses the actual peer address length
(important for AF_UNIX abstract sockets); change the signature of
setup_accepted_socket to accept a socklen_t peer_addrlen parameter (e.g.
setup_accepted_socket(..., sockaddr_storage const& peer_storage, socklen_t
peer_addrlen, ...)), pass peer_addrlen into from_sockaddr_as instead of
sizeof(peer_storage), and update all callers (e.g. where accept() results are
processed) to forward the actual addrlen they receive; also validate
non-zero/within-bounds peer_addrlen where appropriate before calling
from_sockaddr_as.
include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp (1)

419-484: Consider extracting shared cancel/claim logic.

do_release_socket() duplicates the cancel/claim pattern from do_close_socket(). This is intentional (release doesn't call ::close()), but the ~35 lines of identical cancel/claim logic could be extracted into a helper to reduce duplication.

Since both methods share the same cancellation semantics and the only difference is the final fd handling, a private helper like cancel_and_claim_ops() could be factored out.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp` around
lines 419 - 484, Extract the duplicated cancel/claim logic from
do_release_socket() and do_close_socket() into a private helper (suggest name
cancel_and_claim_ops()) that captures the sequence: lock
weak_from_this()->lock(), call Derived::for_each_op to request_cancel(), lock
desc_state_.mutex, move reactor_op_base* entries out of descriptor slots into a
local claimed array, reset desc_state_ flags (read_ready, write_ready,
read_cancel_pending, write_cancel_pending, connect_cancel_pending), set
impl_ref_ when is_enqueued_ is true, then after the mutex loop set each
claimed[i].base->impl_ptr = self and call svc_.post(...) followed by
svc_.work_finished(); replace the duplicated blocks in both do_release_socket()
and do_close_socket() with calls to this helper and keep the socket-specific
behavior (do_release_socket must NOT close fd_ while do_close_socket still
closes) so only the final fd handling remains in each function.
include/boost/corosio/local_stream_acceptor.hpp (1)

159-169: Consider throwing instead of asserting on cross-context move-assign.

The assert on line 161 will only trigger in debug builds. In release builds, moving from an acceptor with a different execution_context would silently corrupt state. Consider throwing std::logic_error for a consistent debug/release behavior.

💡 Suggested fix: Throw instead of assert
     local_stream_acceptor& operator=(local_stream_acceptor&& other) noexcept
     {
-        assert(&ctx_ == &other.ctx_ &&
-            "move-assign requires the same execution_context");
+        if (&ctx_ != &other.ctx_)
+            detail::throw_logic_error(
+                "move-assign requires the same execution_context");
         if (this != &other)
         {
             close();
             io_object::operator=(std::move(other));
         }
         return *this;
     }

Note: This would require removing noexcept from the signature.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_acceptor.hpp` around lines 159 - 169, The
move-assignment operator for local_stream_acceptor currently uses assert to
enforce same execution_context (assert(&ctx_ == &other.ctx_)), which only fires
in debug builds; change this to throw a std::logic_error when &ctx_ !=
&other.ctx_ to ensure consistent behavior in release builds, remove noexcept
from local_stream_acceptor& operator=(local_stream_acceptor&& other) noexcept so
it can throw, and keep the existing close() and
io_object::operator=(std::move(other)) logic unchanged after the check; update
any exception-safe invariants or documentation for local_stream_acceptor
accordingly.
include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp (1)

27-36: Consider using named constants for portable flag values.

The magic numbers 1, 2, 4 work correctly but could be more self-documenting by referencing the message_flags enum values directly or adding a brief comment mapping them.

💡 Optional: Add brief comment or use named constants
 inline int
 to_native_msg_flags(int flags) noexcept
 {
     int native = 0;
-    if (flags & 1) native |= MSG_PEEK;
-    if (flags & 2) native |= MSG_OOB;
-    if (flags & 4) native |= MSG_DONTROUTE;
+    if (flags & 1) native |= MSG_PEEK;      // message_flags::peek
+    if (flags & 2) native |= MSG_OOB;       // message_flags::out_of_band
+    if (flags & 4) native |= MSG_DONTROUTE; // message_flags::dont_route
     return native;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp`
around lines 27 - 36, The function to_native_msg_flags currently uses magic
numbers (1, 2, 4); replace those literals with the corresponding portable
message_flags enum constants (or define named constants) and/or add a one-line
comment mapping each portable flag to its MSG_* counterpart so the intent is
clear (e.g., use message_flags::peek, message_flags::oob,
message_flags::dontroute or named constexprs in the checks and then set
MSG_PEEK, MSG_OOB, MSG_DONTROUTE accordingly).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/io/io_read_stream.hpp`:
- Around line 50-64: Update the public documentation for
io_read_stream::read_some to state its cancellation contract: explain that the
operation supports cancellation via the stop_token propagated through the
IoAwaitable protocol and via the i/o object's cancel() member, and that when
cancelled the resulting error_code (the first result) compares equal to
capy::cond::canceled; reference the awaitable type read_some_awaitable and the
shared base detail::io_bytes_op_base which now handles stop-token plumbing so
readers know cancellation can originate from the propagated stop_token or
io_read_stream::cancel().

In `@include/boost/corosio/io/io_write_stream.hpp`:
- Around line 50-64: Update the public documentation for write_some to state the
cancellation contract: document that write_some (and its awaitable type
write_some_awaitable used by io_write_stream) supports cancellation via the
propagated stop_token through the IoAwaitable protocol and via the i/o object's
cancel() member, and that when cancelled the operation completes with an error
value that compares equal to capy::cond::canceled; reference the involved
symbols in the docs (write_some, write_some_awaitable, io_write_stream,
do_write_some, and the shared io_bytes_op_base/token_ mechanism) so callers know
where cancellation is handled and what to expect.

In `@include/boost/corosio/local_endpoint.hpp`:
- Around line 78-89: The doc comment for is_abstract() incorrectly shows a
double-escaped null character ('\\0'); update the `@return` line in the comment
above bool is_abstract() const noexcept to display the single-escaped null
character representation ('\0') so generated docs render correctly (no code
changes to is_abstract(), just fix the text in the comment referencing path_ and
len_).

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 136-144: The move assignment operator for local_stream_socket
currently assigns h_ directly and bypasses base-class logic; change
local_stream_socket::operator=(local_stream_socket&& other) noexcept to call the
base-class move assignment (io_object::operator=(std::move(other))) instead of
assigning h_ directly, mirroring how the move constructor delegates to
io_object(std::move(other)) and matching the pattern used by
local_datagram_socket.

In `@include/boost/corosio/local_stream.hpp`:
- Around line 20-49: Replace the plain block comment above class local_stream
with a proper API docstring that briefly describes its purpose (encapsulates the
Unix domain stream protocol), documents the return semantics of family(),
type(), and protocol(), lists the associated types socket and acceptor
(local_stream_socket, local_stream_acceptor), and explicitly states the
POSIX-only precondition (this protocol is meaningful only on POSIX
builds/AF_UNIX-supporting platforms); also mention relation to
native_local_stream as an inline variant. Ensure the docstring documents
preconditions (POSIX only) and return values for family()/type()/protocol().

In `@include/boost/corosio/message_flags.hpp`:
- Around line 15-47: Add public header docstrings for the message_flags enum and
its bitmask operators to satisfy the documentation guideline: replace the block
comment with Doxygen-style (or project-standard) brief and detailed descriptions
for enum class message_flags explaining each flag's meaning (none, peek,
out_of_band, do_not_route) and that values are platform-agnostic and mapped at
the syscall boundary, and add docstrings for the exported bitwise operators
operator|(message_flags, message_flags), operator&(message_flags, message_flags)
and operator~(message_flags) describing that they perform bitmask combination,
intersection, and bitwise inversion respectively and return a message_flags
result; ensure the documentation is placed in the public header (not a detail
namespace) and follows the project's docstring style so generated references
capture the API and semantics.

---

Nitpick comments:
In `@include/boost/corosio/detail/io_op_base.hpp`:
- Around line 13-22: Add a file-level /* */ overview comment immediately after
the includes that explains the header's role in centralizing stop-token
handling, std::error_code propagation, and completion-state dispatch for
awaitables in namespace boost::corosio::detail; describe the lifecycle model
(who owns the stop_token, how/when errors are set and propagated, which path
signals completion vs cancellation), note any expectations callers must meet
(e.g., thread/context for resumption), and reference the key abstractions used
by this file (stop_token, std::error_code, completion-state/awaitable dispatch
and any io_op_base-style types) so future readers can quickly understand
dispatch and lifetime responsibilities before diving into the implementations.

In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 159-169: The move-assignment operator for local_stream_acceptor
currently uses assert to enforce same execution_context (assert(&ctx_ ==
&other.ctx_)), which only fires in debug builds; change this to throw a
std::logic_error when &ctx_ != &other.ctx_ to ensure consistent behavior in
release builds, remove noexcept from local_stream_acceptor&
operator=(local_stream_acceptor&& other) noexcept so it can throw, and keep the
existing close() and io_object::operator=(std::move(other)) logic unchanged
after the check; update any exception-safe invariants or documentation for
local_stream_acceptor accordingly.

In `@include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp`:
- Around line 419-484: Extract the duplicated cancel/claim logic from
do_release_socket() and do_close_socket() into a private helper (suggest name
cancel_and_claim_ops()) that captures the sequence: lock
weak_from_this()->lock(), call Derived::for_each_op to request_cancel(), lock
desc_state_.mutex, move reactor_op_base* entries out of descriptor slots into a
local claimed array, reset desc_state_ flags (read_ready, write_ready,
read_cancel_pending, write_cancel_pending, connect_cancel_pending), set
impl_ref_ when is_enqueued_ is true, then after the mutex loop set each
claimed[i].base->impl_ptr = self and call svc_.post(...) followed by
svc_.work_finished(); replace the duplicated blocks in both do_release_socket()
and do_close_socket() with calls to this helper and keep the socket-specific
behavior (do_release_socket must NOT close fd_ while do_close_socket still
closes) so only the final fd handling remains in each function.

In `@include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp`:
- Around line 27-36: The function to_native_msg_flags currently uses magic
numbers (1, 2, 4); replace those literals with the corresponding portable
message_flags enum constants (or define named constants) and/or add a one-line
comment mapping each portable flag to its MSG_* counterpart so the intent is
clear (e.g., use message_flags::peek, message_flags::oob,
message_flags::dontroute or named constexprs in the checks and then set
MSG_PEEK, MSG_OOB, MSG_DONTROUTE accordingly).

In `@include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp`:
- Around line 122-162: The setup_accepted_socket function uses
sizeof(peer_storage) when calling from_sockaddr_as which loses the actual peer
address length (important for AF_UNIX abstract sockets); change the signature of
setup_accepted_socket to accept a socklen_t peer_addrlen parameter (e.g.
setup_accepted_socket(..., sockaddr_storage const& peer_storage, socklen_t
peer_addrlen, ...)), pass peer_addrlen into from_sockaddr_as instead of
sizeof(peer_storage), and update all callers (e.g. where accept() results are
processed) to forward the actual addrlen they receive; also validate
non-zero/within-bounds peer_addrlen where appropriate before calling
from_sockaddr_as.

In `@src/corosio/src/io_context.cpp`:
- Around line 18-19: Add a repository-standard multi-line C-style comment block
after the includes in io_context.cpp that documents the file's high-level
purpose: explain that this translation unit coordinates backend selection (via
reactor_backend.hpp / backend.hpp and the IOCP-specific includes), describes the
construction order (service pre-creation before scheduler/loop start), and
summarizes scheduler tuning decisions and where backend-specific split points
occur; place the block immediately after the include section and reference the
relevant symbols (reactor_backend.hpp, backend.hpp, IOCP) and the
functions/classes that perform service pre-creation and scheduler setup so
future readers can quickly understand the file flow.

In `@src/corosio/src/local_socket_pair.cpp`:
- Around line 28-38: The make_nonblock_cloexec fallback currently ignores
::fcntl() return values; update it to check each ::fcntl() call (F_GETFL,
F_SETFL, F_SETFD) for -1 and propagate the error instead of silently
continuing—e.g., on failure capture errno and either throw a std::system_error
(or return/abort according to the surrounding error model) with a descriptive
message including the operation and fd so callers know configuration failed;
ensure this change is applied inside make_nonblock_cloexec so any platform
lacking SOCK_NONBLOCK surfaces fcntl failures.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f6f51880-71b6-4bcd-bd67-f593153ee059

📥 Commits

Reviewing files that changed from the base of the PR and between 17fa5e5 and 77fc9aa.

⛔ Files ignored due to path filters (19)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (74)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/io_op_base.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp

@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from 77fc9aa to d63af20 Compare April 9, 2026 23:10
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp (1)

219-228: ⚠️ Potential issue | 🟡 Minor

Clear remote_endpoint_ on release as well.

do_close_socket() resets the cached peer, but the new release path comes from reactor_basic_socket::do_release_socket() and only clears the local endpoint. After release_socket() the object is no longer open, yet remote_endpoint() can still report the previous peer.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp` around
lines 219 - 228, The release path forgets to clear the cached peer: add an
override for do_release_socket() in this class that calls the base
implementation (reactor_basic_socket::do_release_socket() /
base_type::do_release_socket()) and then resets remote_endpoint_ = Endpoint{} so
that after release_socket() remote_endpoint() no longer reports the previous
peer; keep the method noexcept and mirror the pattern used in do_close_socket().
♻️ Duplicate comments (1)
include/boost/corosio/local_stream_socket.hpp (1)

136-142: ⚠️ Potential issue | 🟠 Major

Use base move assignment instead of directly moving h_.

Line 141 bypasses io_object::operator=(...), which can skip base-class move logic and diverges from the move-constructor pattern.

Proposed fix
 local_stream_socket& operator=(local_stream_socket&& other) noexcept
 {
     if (this != &other)
     {
-        close();
-        h_ = std::move(other.h_);
+        io_object::operator=(std::move(other));
     }
     return *this;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 136 - 142, The
move-assignment for local_stream_socket currently assigns h_ directly, bypassing
base-class move logic; update
local_stream_socket::operator=(local_stream_socket&&) noexcept to invoke the
base class move-assignment (io_object::operator=(std::move(other))) before or
instead of moving h_ so the io_object state is transferred consistently with the
move-constructor, then handle any socket-specific cleanup (close()) and avoid
direct assignment to h_ after the base move.
🧹 Nitpick comments (3)
include/boost/corosio/native/detail/epoll/epoll_traits.hpp (1)

103-134: Consider logging ignored setsockopt errors in configure_ip_* functions.

The configure_ip_socket() and configure_ip_acceptor() functions ignore the return value of setsockopt() for IPV6_V6ONLY. While this is likely intentional (the option is non-fatal), silent failures could complicate debugging dual-stack connectivity issues.

If this is intentional design, a brief comment explaining why errors are ignored would help future maintainers.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/epoll/epoll_traits.hpp` around lines 103
- 134, Check the return value of ::setsockopt calls in configure_ip_socket and
configure_ip_acceptor (the calls that set IPV6_V6ONLY for AF_INET6); if
setsockopt fails, either log the error (including errno) or convert it to and
return a std::error_code (e.g., from errno using std::error_code(errno,
std::generic_category())) so failures aren’t silently dropped — if swallowing is
intentional, add a short comment in configure_ip_socket and
configure_ip_acceptor explaining why the error is intentionally ignored.
include/boost/corosio/local_stream_socket.hpp (1)

212-219: Document the shutdown_send read-side EOF postcondition explicitly.

Please state the expected post-shutdown read behavior (explicit EOF error condition) in this API contract so behavior is unambiguous for callers and tests.

Based on learnings: In boost::corosio, socket::shutdown(shutdown_send) requires subsequent reads to report capy::cond::eof explicitly, not only zero-byte success.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 212 - 219, The
shutdown overloads lack an explicit postcondition for shutdown_send; update the
API doc for void shutdown(shutdown_type what) and void shutdown(shutdown_type
what, std::error_code& ec) noexcept to state that calling
shutdown(shutdown_send) will cause subsequent read operations to report an
explicit EOF condition (capy::cond::eof) rather than merely succeeding with zero
bytes, so callers/tests know to expect capy::cond::eof on reads after
shutdown_send.
include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp (1)

101-113: Consider adding a brief comment explaining the writev choice.

Unlike select_traits which uses sendmsg() with MSG_NOSIGNAL, this uses writev() because macOS lacks MSG_NOSIGNAL and relies on SO_NOSIGPIPE instead (set in set_fd_options). A one-line comment would help maintainers understand this platform-specific choice.

📝 Suggested comment
     struct write_policy
     {
+        // writev() used instead of sendmsg(MSG_NOSIGNAL); macOS relies on SO_NOSIGPIPE.
         static ssize_t write(int fd, iovec* iovecs, int count) noexcept
         {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp` around lines
101 - 113, Add a one-line comment above the write_policy::write implementation
explaining why writev() is used instead of sendmsg() (macOS lacks MSG_NOSIGNAL
and the code relies on SO_NOSIGPIPE set in set_fd_options), referencing the
platform-specific choice and that select_traits uses sendmsg()+MSG_NOSIGNAL for
contrast; this will help future maintainers understand the rationale without
changing behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 224-242: The two accept overloads (accept(local_stream_socket&
peer) and accept()) currently guard only with is_open(), which allows calling
accept after open()/bind() but before listen(), leading to backend null-deref;
change the guard to check the listening state (use is_listening() or equivalent)
instead of is_open(), and keep the same detail::throw_logic_error("accept:
acceptor not listening") behavior; update both callers that return
accept_awaitable(*this, peer) and move_accept_awaitable(*this) to be behind the
is_listening() check so accept() throws as documented when not listening.
- Around line 36-58: Add full public API documentation for local_stream_acceptor
and its operations (e.g., bind(), accept()) in this header: include completion
conditions (what success and error outcomes complete the awaitable),
cancellation behavior (what happens on coroutine cancellation or reactor
shutdown), notable error cases (EADDRINUSE, ENOENT, EACCES, ECONNABORTED, etc.),
and a short `@par` Example showing typical bind/unlink/accept usage; ensure
class-level docstring and each public function (including enum bind_option)
include these sections to meet the repository guideline that all public headers
in non-detail namespaces have docstrings documenting Completion conditions,
Cancellation, and Example.

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 206-209: The release() documentation is contradictory about
whether it returns -1 when not open or throws std::logic_error; decide on a
single contract and make docs and implementation consistent: either (A) keep the
non-throwing behavior—remove the "@throws std::logic_error" sentence, ensure
local_stream_socket::release() returns -1 when not open and document that
explicitly, or (B) keep the throwing behavior—remove the "or -1 if not open"
note, modify local_stream_socket::release() to throw std::logic_error when the
socket is not open, and update the docblock to state it throws; apply the chosen
change to the release() docstring and to the release() implementation and any
callers that rely on its behavior.

In `@include/boost/corosio/native/detail/iocp/win_udp_service.hpp`:
- Around line 395-398: The IOCP UDP backend in win_udp_service.hpp passes
portable message_flags directly to WinSock calls (WSASendTo, WSARecvFrom,
WSASend, WSARecv) causing peek/out_of_band to be inverted; add a
to_native_msg_flags(unsigned flags) helper (mirroring reactor's implementation)
that maps portable peek=1 -> MSG_PEEK and out_of_band=2 -> MSG_OOB and use it to
transform the flags argument before calling
WSASendTo/WSARecvFrom/WSASend/WSARecv (e.g., replace static_cast<DWORD>(flags)
with static_cast<DWORD>(to_native_msg_flags(flags))) so WinSock receives the
correct native constants.

In `@include/boost/corosio/native/detail/reactor/reactor_backend.hpp`:
- Around line 54-89: The code reconstructs the peer endpoint using
sizeof(peer_storage) instead of the actual addrlen returned by accept; update
Traits::accept_policy::do_accept (and the reactor_accept_op that calls it) to
return or output the real socklen_t (e.g., via an out-param or pair return)
alongside the accepted fd, then use that real addrlen when calling
from_sockaddr_as(...) instead of static_cast<socklen_t>(sizeof(peer_storage)) so
Unix-domain socket paths (abstract or non-null-terminated) are preserved; ensure
the new return/out parameter is propagated from accept_policy::do_accept through
reactor_accept_op to the call site where peer_storage and from_sockaddr_as are
used.

---

Outside diff comments:
In `@include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp`:
- Around line 219-228: The release path forgets to clear the cached peer: add an
override for do_release_socket() in this class that calls the base
implementation (reactor_basic_socket::do_release_socket() /
base_type::do_release_socket()) and then resets remote_endpoint_ = Endpoint{} so
that after release_socket() remote_endpoint() no longer reports the previous
peer; keep the method noexcept and mirror the pattern used in do_close_socket().

---

Duplicate comments:
In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 136-142: The move-assignment for local_stream_socket currently
assigns h_ directly, bypassing base-class move logic; update
local_stream_socket::operator=(local_stream_socket&&) noexcept to invoke the
base class move-assignment (io_object::operator=(std::move(other))) before or
instead of moving h_ so the io_object state is transferred consistently with the
move-constructor, then handle any socket-specific cleanup (close()) and avoid
direct assignment to h_ after the base move.

---

Nitpick comments:
In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 212-219: The shutdown overloads lack an explicit postcondition for
shutdown_send; update the API doc for void shutdown(shutdown_type what) and void
shutdown(shutdown_type what, std::error_code& ec) noexcept to state that calling
shutdown(shutdown_send) will cause subsequent read operations to report an
explicit EOF condition (capy::cond::eof) rather than merely succeeding with zero
bytes, so callers/tests know to expect capy::cond::eof on reads after
shutdown_send.

In `@include/boost/corosio/native/detail/epoll/epoll_traits.hpp`:
- Around line 103-134: Check the return value of ::setsockopt calls in
configure_ip_socket and configure_ip_acceptor (the calls that set IPV6_V6ONLY
for AF_INET6); if setsockopt fails, either log the error (including errno) or
convert it to and return a std::error_code (e.g., from errno using
std::error_code(errno, std::generic_category())) so failures aren’t silently
dropped — if swallowing is intentional, add a short comment in
configure_ip_socket and configure_ip_acceptor explaining why the error is
intentionally ignored.

In `@include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp`:
- Around line 101-113: Add a one-line comment above the write_policy::write
implementation explaining why writev() is used instead of sendmsg() (macOS lacks
MSG_NOSIGNAL and the code relies on SO_NOSIGPIPE set in set_fd_options),
referencing the platform-specific choice and that select_traits uses
sendmsg()+MSG_NOSIGNAL for contrast; this will help future maintainers
understand the rationale without changing behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 30d53a5d-2df5-4996-a88b-a16c9feaa3ee

📥 Commits

Reviewing files that changed from the base of the PR and between 77fc9aa and d63af20.

⛔ Files ignored due to path filters (19)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (74)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
✅ Files skipped from review due to trivial changes (17)
  • include/boost/corosio.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/shutdown_type.hpp
  • perf/common/native_includes.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • src/corosio/src/local_stream.cpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
🚧 Files skipped from review as they are similar to previous changes (16)
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • src/corosio/src/local_socket_pair.cpp
  • include/boost/corosio/io/io_write_stream.hpp
  • src/corosio/src/local_stream_acceptor.cpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • src/corosio/src/local_stream_socket.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • src/corosio/src/io_context.cpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp

@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from d63af20 to 1e6c449 Compare April 10, 2026 16:09
@cppalliance-bot
Copy link
Copy Markdown

cppalliance-bot commented Apr 10, 2026

An automated preview of the documentation is available at https://228.corosio.prtest3.cppalliance.org/index.html

If more commits are pushed to the pull request, the docs will rebuild at the same URL.

2026-04-10 22:32:24 UTC

@codecov
Copy link
Copy Markdown

codecov bot commented Apr 10, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.78%. Comparing base (17fa5e5) to head (733f64d).

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff             @@
##           develop     #228      +/-   ##
===========================================
- Coverage    77.85%   77.78%   -0.07%     
===========================================
  Files           96       96              
  Lines         7350     7289      -61     
  Branches      1791     1787       -4     
===========================================
- Hits          5722     5670      -52     
+ Misses        1110     1101       -9     
  Partials       518      518              
Files with missing lines Coverage Δ
include/boost/corosio/io/io_object.hpp 98.30% <ø> (-0.03%) ⬇️
include/boost/corosio/io/io_read_stream.hpp 87.50% <ø> (-8.16%) ⬇️
include/boost/corosio/io/io_write_stream.hpp 87.50% <ø> (-8.16%) ⬇️
...e/boost/corosio/native/detail/endpoint_convert.hpp 96.92% <ø> (ø)
.../corosio/native/detail/select/select_scheduler.hpp 83.33% <ø> (ø)
...clude/boost/corosio/native/native_tcp_acceptor.hpp 90.90% <ø> (ø)
include/boost/corosio/native/native_tcp_socket.hpp 90.41% <ø> (ø)
include/boost/corosio/tcp_socket.hpp 87.17% <ø> (-1.50%) ⬇️
src/corosio/src/io_context.cpp 95.83% <ø> (ø)
src/corosio/src/tcp_socket.cpp 82.69% <ø> (ø)

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 17fa5e5...733f64d. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

♻️ Duplicate comments (4)
include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp (1)

66-74: ⚠️ Potential issue | 🔴 Critical

Run backend fd normalization before init_and_register().

do_assign_fd() skips the same trait-specific setup that do_open_socket() applies. An adopted descriptor can therefore stay blocking, miss FD_CLOEXEC, and bypass select’s FD_SETSIZE guard, which is enough to stall speculative I/O on the reactor thread.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp`
around lines 66 - 74, do_assign_fd currently closes and immediately calls
socket_impl->init_and_register(fd), skipping the trait-specific backend fd
normalization that do_open_socket applies; update do_assign_fd to perform the
same normalization step(s) before init_and_register (i.e., run the trait/backend
fd setup that enforces non-blocking, FD_CLOEXEC and FD_SETSIZE checks used by
do_open_socket) so an adopted descriptor cannot remain blocking or miss CLOEXEC
and so select()/reactor guards are preserved; keep calls to
socket_impl->close_socket() and socket_impl->init_and_register(fd) but insert
the same normalization routine (the trait/backend normalization used by
do_open_socket) between them.
include/boost/corosio/local_stream_acceptor.hpp (1)

210-243: ⚠️ Potential issue | 🟠 Major

Semantic mismatch: is_open() vs listening state.

The comment on line 210 says "Check if the acceptor is listening" but the method name is is_open() and it only checks if the fd exists. This allows accept() to be called after open()/bind() but before listen(), leading to a backend null-pointer crash (per learnings, this is intentional misuse detection).

However, the documentation at line 222/236 promises a std::logic_error "if the acceptor is not listening", which contradicts the actual crash behavior. Consider either:

  1. Rename is_open() to is_listening() if it truly checks listening state
  2. Add a separate is_listening() check in accept() that throws as documented
  3. Update the documentation to reflect the actual misuse behavior

Based on learnings: "Calling accept() before listen() is API misuse and will intentionally crash (nullptr dereference) as a loud programming error, not a bug to defensively guard."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_acceptor.hpp` around lines 210 - 243, The
comments promise accept() throws if the acceptor is not listening, but is_open()
only checks the fd and allows calling accept() before listen(), causing a crash;
fix by adding a proper is_listening() predicate (e.g., bool is_listening() const
noexcept that queries the underlying handle/state) and use is_listening() in
both accept(local_stream_socket& peer) and accept() before returning
accept_awaitable/move_accept_awaitable so they throw the documented
std::logic_error, leaving is_open() unchanged (or alternatively update the
docstrings if you opt to keep the current behavior).
include/boost/corosio/local_stream_socket.hpp (2)

200-210: ⚠️ Potential issue | 🟡 Minor

Resolve contradictory release() contract wording.

Line 206 says "or -1 if not open", while Line 208 says it throws std::logic_error if not open. Please keep a single behavior contract in the docs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 200 - 210, The
documentation for local_stream_socket::release() contains contradictory
behavior; update the comment to a single contract: remove "or -1 if not open"
and state that release() returns the native_handle_type on success and throws
std::logic_error if the socket is not open; ensure the `@return` and `@throws` lines
consistently describe that behavior for the release() method.

136-144: ⚠️ Potential issue | 🟠 Major

Inconsistent move assignment bypasses base class.

The move constructor (line 132) correctly delegates to io_object(std::move(other)), but this move assignment directly assigns h_ instead of calling the base class operator. This could skip any logic in io_object::operator=.

🐛 Proposed fix for consistency with base class
 local_stream_socket& operator=(local_stream_socket&& other) noexcept
 {
     if (this != &other)
     {
         close();
-        h_ = std::move(other.h_);
+        io_object::operator=(std::move(other));
     }
     return *this;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 136 - 144, The
move assignment in local_stream_socket (local_stream_socket&
operator=(local_stream_socket&& other) noexcept) bypasses the base io_object by
assigning h_ directly; change it to call the base move-assignment (e.g.,
io_object::operator=(std::move(other))) after closing the current socket (keep
the close() call) and then let the base assign its members instead of manually
moving h_, ensuring any io_object::operator= logic is executed.
🧹 Nitpick comments (3)
include/boost/corosio/local_stream_socket.hpp (1)

64-99: Add documentation parity with tcp_socket::implementation.

The implementation interface methods lack the detailed parameter documentation present in tcp_socket::implementation (see context snippet 3, lines 89-158). At minimum, connect() should document its parameters (h, ex, ep, token, ec) and return value semantics.

📝 Example documentation for connect
     struct implementation : io_stream::implementation
     {
+        /** Initiate an asynchronous connect to the given endpoint.
+
+            `@param` h Coroutine handle to resume on completion.
+            `@param` ex Executor for dispatching the completion.
+            `@param` ep The local endpoint (path) to connect to.
+            `@param` token Stop token for cancellation.
+            `@param` ec Output error code.
+
+            `@return` Coroutine handle to resume immediately.
+        */
         virtual std::coroutine_handle<> connect(
             std::coroutine_handle<> h,
             capy::executor_ref ex,
             corosio::local_endpoint ep,
             std::stop_token token,
             std::error_code* ec) = 0;

As per coding guidelines: "Docstrings are required for all classes and functions in public headers in non-detail namespaces."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 64 - 99, The
implementation struct lacks docstrings matching tcp_socket::implementation; add
Doxygen-style comments for implementation and for each virtual method (at
minimum connect) documenting parameters and return semantics: for
connect(document h, ex, ep, token, ec and what the returned
std::coroutine_handle<> represents and error reporting via ec), and similar
brief descriptions for shutdown, native_handle, release_socket, cancel,
set_option, get_option, local_endpoint and remote_endpoint so the public header
has parity with tcp_socket::implementation.
include/boost/corosio/local_stream_acceptor.hpp (1)

286-313: Consider adding parameter documentation to implementation interface.

The implementation struct methods lack parameter documentation. While this is an internal backend extension point, adding brief docs for the accept() method signature would help backend implementers understand the contract (coroutine handle semantics, output parameters, etc.).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_acceptor.hpp` around lines 286 - 313, The
implementation interface currently lacks parameter documentation which makes the
backend contract unclear; add brief Doxygen-style comments to the struct
implementation and specifically document the accept(...) method parameters (the
incoming coroutine handle, capy::executor_ref executor, std::stop_token for
cancellation, std::error_code* out_error for reporting, and
io_object::implementation** out_impl for swapping implementations), plus short
notes on return value semantics (what the returned std::coroutine_handle<>
represents and when it is resumed) and similar one-line docs for
local_endpoint(), is_open(), release_socket(), cancel(), set_option() and
get_option() so implementers know expected behavior and ownership/cancellation
guarantees.
src/corosio/src/io_context.cpp (1)

11-20: Add the required file-level overview block.

This file now coordinates backend selection, service pre-creation, and post-construction scheduler tuning, but there is still no /* */ overview comment after the includes. Replacing the ad-hoc include note with the required high-level map would make this much easier to maintain.

As per coding guidelines, "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/corosio/src/io_context.cpp` around lines 11 - 20, Add a file-level /* */
overview block immediately after the include section in
src/corosio/src/io_context.cpp that summarizes the file's responsibilities:
backend selection logic (reactor/backend choice), service pre-creation behavior,
and post-construction scheduler tuning for io_context and related classes
(mention io_context, reactor/backend selection, detail::thread_pool or scheduler
tuning points). Keep the comment concise but high-level, mapping the main
control flow (how backends are chosen, which services are pre-created, and where
scheduler tuning occurs) so maintainers can quickly understand the
implementation without reading all functions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/local_datagram_socket.hpp`:
- Around line 581-615: The docs for release() and shutdown(shutdown_type) must
be made consistent with the implementation: update the release() comment to
state it throws std::logic_error if the socket is not open and otherwise returns
the native_handle_type (remove the “returns -1” claim), and update the
shutdown(shutdown_type) comment to reflect the implementation’s behavior (it
does not propagate service errors—use the noexcept overload
shutdown(shutdown_type, std::error_code&) to observe errors) while documenting
parameters, return behavior, and the thrown exception for release(); reference
the functions release() and shutdown(shutdown_type) in the header so the
contract matches the code.

In `@include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp`:
- Around line 419-483: do_release_socket in reactor_basic_socket only clears
local_endpoint_, so add a CRTP release hook call so derived sockets can clear
their endpoint state (e.g. remote_endpoint_) at release time: introduce a
protected no-op hook method (name it something like on_release_endpoint_state or
release_endpoint_state) on the base CRTP type and call it from
reactor_basic_socket<Derived,...>::do_release_socket before or when clearing
local_endpoint_; update reactor_stream_socket (or the stream-derived class) to
override that hook and clear its remote_endpoint_ there. Ensure the hook has
noexcept and is callable via
static_cast<Derived*>(this)->on_release_endpoint_state() so derived cleanup runs
when the fd is handed off.

In `@include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp`:
- Around line 66-74: do_assign_fd currently just registers the new fd so sockets
that cache endpoints (reactor_basic_socket / reactor_stream_socket via
local_endpoint_ / remote_endpoint_) remain empty; after
socket_impl->init_and_register(fd) refresh the cached endpoints by querying the
socket (e.g. using getsockname/getpeername or an existing helper like
refresh_endpoints on SocketFinal) and store the results into
socket_impl->local_endpoint_ and socket_impl->remote_endpoint_ (handle and
propagate any syscall errors into the returned std::error_code rather than
leaving caches empty), ensuring do_assign_fd updates endpoint caches so
local_endpoint()/remote_endpoint() return correct values.

---

Duplicate comments:
In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 210-243: The comments promise accept() throws if the acceptor is
not listening, but is_open() only checks the fd and allows calling accept()
before listen(), causing a crash; fix by adding a proper is_listening()
predicate (e.g., bool is_listening() const noexcept that queries the underlying
handle/state) and use is_listening() in both accept(local_stream_socket& peer)
and accept() before returning accept_awaitable/move_accept_awaitable so they
throw the documented std::logic_error, leaving is_open() unchanged (or
alternatively update the docstrings if you opt to keep the current behavior).

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 200-210: The documentation for local_stream_socket::release()
contains contradictory behavior; update the comment to a single contract: remove
"or -1 if not open" and state that release() returns the native_handle_type on
success and throws std::logic_error if the socket is not open; ensure the
`@return` and `@throws` lines consistently describe that behavior for the release()
method.
- Around line 136-144: The move assignment in local_stream_socket
(local_stream_socket& operator=(local_stream_socket&& other) noexcept) bypasses
the base io_object by assigning h_ directly; change it to call the base
move-assignment (e.g., io_object::operator=(std::move(other))) after closing the
current socket (keep the close() call) and then let the base assign its members
instead of manually moving h_, ensuring any io_object::operator= logic is
executed.

In `@include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp`:
- Around line 66-74: do_assign_fd currently closes and immediately calls
socket_impl->init_and_register(fd), skipping the trait-specific backend fd
normalization that do_open_socket applies; update do_assign_fd to perform the
same normalization step(s) before init_and_register (i.e., run the trait/backend
fd setup that enforces non-blocking, FD_CLOEXEC and FD_SETSIZE checks used by
do_open_socket) so an adopted descriptor cannot remain blocking or miss CLOEXEC
and so select()/reactor guards are preserved; keep calls to
socket_impl->close_socket() and socket_impl->init_and_register(fd) but insert
the same normalization routine (the trait/backend normalization used by
do_open_socket) between them.

---

Nitpick comments:
In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 286-313: The implementation interface currently lacks parameter
documentation which makes the backend contract unclear; add brief Doxygen-style
comments to the struct implementation and specifically document the accept(...)
method parameters (the incoming coroutine handle, capy::executor_ref executor,
std::stop_token for cancellation, std::error_code* out_error for reporting, and
io_object::implementation** out_impl for swapping implementations), plus short
notes on return value semantics (what the returned std::coroutine_handle<>
represents and when it is resumed) and similar one-line docs for
local_endpoint(), is_open(), release_socket(), cancel(), set_option() and
get_option() so implementers know expected behavior and ownership/cancellation
guarantees.

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 64-99: The implementation struct lacks docstrings matching
tcp_socket::implementation; add Doxygen-style comments for implementation and
for each virtual method (at minimum connect) documenting parameters and return
semantics: for connect(document h, ex, ep, token, ec and what the returned
std::coroutine_handle<> represents and error reporting via ec), and similar
brief descriptions for shutdown, native_handle, release_socket, cancel,
set_option, get_option, local_endpoint and remote_endpoint so the public header
has parity with tcp_socket::implementation.

In `@src/corosio/src/io_context.cpp`:
- Around line 11-20: Add a file-level /* */ overview block immediately after the
include section in src/corosio/src/io_context.cpp that summarizes the file's
responsibilities: backend selection logic (reactor/backend choice), service
pre-creation behavior, and post-construction scheduler tuning for io_context and
related classes (mention io_context, reactor/backend selection,
detail::thread_pool or scheduler tuning points). Keep the comment concise but
high-level, mapping the main control flow (how backends are chosen, which
services are pre-created, and where scheduler tuning occurs) so maintainers can
quickly understand the implementation without reading all functions.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0888560c-1441-4912-86e9-078fe04b66c3

📥 Commits

Reviewing files that changed from the base of the PR and between d63af20 and 1e6c449.

⛔ Files ignored due to path filters (20)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
  • test/unit/tcp_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (75)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
✅ Files skipped from review due to trivial changes (18)
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/shutdown_type.hpp
  • src/corosio/src/local_stream.cpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/local_datagram.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • src/corosio/src/local_endpoint.cpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
🚧 Files skipped from review as they are similar to previous changes (18)
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • perf/common/native_includes.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • src/corosio/src/local_socket_pair.cpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • src/corosio/src/local_stream_socket.cpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/udp_socket.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp

@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from 1e6c449 to 25f6507 Compare April 10, 2026 17:35
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
include/boost/corosio/udp_socket.hpp (1)

505-510: ⚠️ Potential issue | 🟡 Minor

Fix the enum name in the send_to docs.

Line 509 references message_flags::dont_route, but the enum exported by include/boost/corosio/message_flags.hpp is message_flags::do_not_route.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/udp_socket.hpp` around lines 505 - 510, The
documentation for send_to incorrectly references message_flags::dont_route;
update the doc comment for the send_to function (in udp_socket.hpp) to use the
correct enum name message_flags::do_not_route as exported by
include/boost/corosio/message_flags.hpp, ensuring any mention of the flag in the
parameter description and examples is replaced with message_flags::do_not_route.
♻️ Duplicate comments (3)
include/boost/corosio/io/io_read_stream.hpp (1)

97-113: ⚠️ Potential issue | 🟡 Minor

Document read_some cancellation explicitly.

The public contract still omits that cancellation can come from the propagated stop_token or cancel(), and that the first result compares equal to capy::cond::canceled.

As per coding guidelines, "Cancellation — State that the operation supports cancellation via stop_token propagated through the IoAwaitable protocol, or via the i/o object's cancel() member; state that the resulting error compares equal to capy::cond::canceled."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/io/io_read_stream.hpp` around lines 97 - 113, Update
the read_some documentation in io_read_stream.hpp to explicitly state that the
operation supports cancellation via the stop_token propagated through the
IoAwaitable protocol and via the stream's cancel() member (or cancel()), and
clarify that when cancelled the awaitable resumes with an error_code that
compares equal to capy::cond::canceled as the first element of the returned
(error_code, std::size_t) tuple; reference the template function read_some
(template<capy::MutableBufferSequence MB>) so readers can find the documented
behavior.
include/boost/corosio/udp_socket.hpp (1)

505-533: ⚠️ Potential issue | 🟡 Minor

Document cancellation on the new message-flags overloads.

These overloads are now part of the public async API, but their docs still omit stop-token / cancel() behavior and the capy::cond::canceled result contract.

As per coding guidelines, "Cancellation — State that the operation supports cancellation via stop_token propagated through the IoAwaitable protocol, or via the i/o object's cancel() member; state that the resulting error compares equal to capy::cond::canceled."

Also applies to: 535-564, 585-635

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/udp_socket.hpp` around lines 505 - 533, Update the
documentation for the new message-flags overloads (e.g., the template
send_to(Buffers const& buf, endpoint dest, corosio::message_flags flags) and its
two-argument overload calling it) to state that these async operations support
cancellation via a propagated stop_token (IoAwaitable protocol) and via the
socket's cancel()/i/o object cancel() method, and that when cancelled the
awaitable completes with an error that compares equal to capy::cond::canceled;
apply the same documentation wording to the other newly added message_flags
overloads referenced (the similar overloads around the
send_to_awaitable/receive_from_awaitable functions at the other ranges).
include/boost/corosio/local_endpoint.hpp (1)

78-85: ⚠️ Potential issue | 🟡 Minor

Fix the rendered null-character example.

Line 84 still shows the escaped form incorrectly in the docs; it should render as '\0'.

📝 Proposed fix
-        `@return` `true` if the path starts with '\\0'.
+        `@return` `true` if the path starts with `'\0'`.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_endpoint.hpp` around lines 78 - 85, The
documentation comment in include/boost/corosio/local_endpoint.hpp displays the
null-character example as '\\0' instead of the intended '\0'; update the
docstring to render the character literal correctly by replacing the escaped
form with a single-quoted null char `'\0'` (i.e., change the `\\0` instance in
that comment block to `\0` inside quotes/backticks) so the generated docs show
'\0' as intended.
🧹 Nitpick comments (4)
include/boost/corosio/local_endpoint.hpp (1)

26-42: Document the new public type with a real API docstring.

This is a new public header, but the class is still described with a plain block comment and the constructor docs omit key contract details like the portable length limit, abstract-path semantics, and the lifetime expectations of the returned path() view.

As per coding guidelines, "Docstrings are required for all classes and functions in public headers in non-detail namespaces. Docstrings should include a brief description of purpose, document all parameters, return values, and any preconditions, postconditions, or exceptions."

Also applies to: 56-70

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_endpoint.hpp` around lines 26 - 42, Add a proper
API docstring for the public class local_endpoint documenting its purpose as a
Unix domain socket endpoint, the constructor(s) parameters and behavior
(including the portable pathname length limit and how abstract Linux paths
starting with '\0' are handled), the semantics of path() (that it returns a
non-owning view into an internal fixed-size buffer and the lifetime is tied to
the local_endpoint object), the fact the class avoids heap allocation and is
trivially copyable, and the cleanup responsibility (library does NOT unlink
filesystem socket paths); update docstrings for the constructors and path()
accessor to state preconditions (path length limits), postconditions, and
platform-specific notes for abstract paths.
include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp (1)

21-38: Include the standard headers this file relies on.

This header directly uses std::conditional_t, std::is_same_v, std::coroutine_handle, std::stop_token, and std::error_code, but it never includes the standard headers that define them. Right now it only works as long as one of the project headers pulls them in transitively.

🧩 Suggested include set
+#include <coroutine>
+#include <stop_token>
+#include <system_error>
+#include <type_traits>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp` around
lines 21 - 38, The header reactor_socket_finals.hpp uses standard library types
(std::conditional_t, std::is_same_v, std::coroutine_handle, std::stop_token,
std::error_code) but doesn't include the corresponding standard headers; add the
minimal required includes (e.g. <type_traits>, <coroutine> or <coroutine> shim
used in this project, <stop_token>, and <system_error>) at the top of the file
so these symbols are always defined without relying on transitive includes.
include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp (2)

13-28: Add the required file-level overview block.

This header now owns the acceptor fd lifecycle, descriptor registration, cancellation, close, and release paths, but it still jumps straight from includes into declarations. A short /* ... */ overview after the includes would make the ownership and synchronization model much easier to reason about.

As per coding guidelines, "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp` around
lines 13 - 28, Add a file-level overview block comment immediately after the
includes in reactor_acceptor.hpp that briefly describes ownership of the
acceptor file descriptor, how descriptor registration/unregistration is handled,
cancellation/close/release paths, and the synchronization model used to protect
the FD and internal state (e.g., which mutex(es) guard what and whether
operations may be called concurrently). Reference reactor_acceptor.hpp and the
key responsibilities (acceptor fd lifecycle, descriptor registration,
cancellation, close, release) so readers can quickly understand the module
boundaries and threading assumptions before reading class/struct declarations
and functions that implement those behaviors.

252-344: Extract the shared teardown path.

do_close_socket() and do_release_socket() duplicate the same lock/claim/post/reset sequence. Keeping two copies of this concurrency-sensitive cleanup makes it easy for the next descriptor-state fix to land in one path and be missed in the other.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp` around
lines 252 - 344, Both do_close_socket() and do_release_socket() duplicate the
same lock/claim/post/reset sequence; extract that shared teardown into a single
helper (e.g., teardown_descriptor() or release_descriptor_resources()) and call
it from both functions. The helper should capture the weak_from_this() lock,
call acc_.request_cancel(), take the desc_state_.mutex, exchange
desc_state_.read_op to nullptr, set read_ready/write_ready false, set
desc_state_.impl_ref_ if is_enqueued_.load(...), and if a claimed op exists set
acc_.impl_ptr = self then svc_.post(&acc_) and svc_.work_finished(); after
calling the helper each caller should continue its remaining socket-specific
logic (closing/deregistering fd_, resetting desc_state_.fd and
registered_events, and clearing local_endpoint_). Ensure the helper references
acc_, desc_state_, svc_, and weak_from_this() to preserve the exact existing
behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/local_datagram_socket.hpp`:
- Around line 80-123: The docblocks for the backend hook methods now include a
flags parameter but the comments for implementation::send_to,
implementation::recv_from and implementation::send (and the corresponding
docblocks at lines ~141-159) do not document it; update each method's docblock
to add an `@param` flags description describing its purpose and expected
values/behavior, ensure the description is placed with the other parameter
entries for send_to, recv_from and send, and keep wording consistent with
existing param style used in these header comments.
- Around line 437-565: The public async methods connect(), send_to(),
recv_from(), send(), and recv() are missing per-operation docs describing
completion conditions, cancellation behavior, and overlap/serialization rules;
update each method's comment to include: (1) Completion conditions — a bulleted
list of when the awaitable completes (success, remote shutdown/peer closed,
EAGAIN/EWOULDBLOCK, payload bytes transferred, or error codes) referencing the
corresponding awaitable types (connect_awaitable, send_to_awaitable,
recv_from_awaitable, send_awaitable, recv_awaitable); (2) Cancellation — state
that the operation supports cancellation via the stop_token propagated through
the IoAwaitable protocol and/or by calling the socket's cancel() member, and
describe what result/error the awaitable yields on cancellation; and (3)
Overlap/serialization — explicitly state whether multiple concurrent operations
of the same kind are allowed on the socket or must be serialized (e.g., only one
concurrent send/send_to or recv/recv_from), and mention any interactions between
connected vs. unconnected operations (connect() vs. send()/send_to()). Ensure
these notes are added to each method's Doxygen block using the same phrasing
pattern as the class-level thread-safety note.

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 212-230: Update the documentation for
local_stream_socket::shutdown(shutdown_type) and its noexcept overload to state
the stronger postcondition for shutdown_send: when called with shutdown_send,
the socket guarantees that subsequent read operations will not merely return
zero bytes but will report an explicit EOF condition (capy::cond::eof). Mention
this contrasts with close(), and reference the shutdown_type/shutdown_send
values and capy::cond::eof so readers know the expected behavior for
shutdown(shutdown_send) vs close().
- Around line 169-185: Update the connect() documentation to state that the
parameter ep is the peer endpoint (path) to connect to, not the local endpoint,
and expand the awaitable contract for connect_awaitable: list completion
conditions (successful connection completion, failures such as permission denied
/ path not found / connection refused / interrupted, and exceptions thrown when
open() fails), declare cancellation behavior (supports stop_token propagated via
the IoAwaitable protocol and/or can be cancelled via the socket's cancel()
member which will cause the awaitable to complete with operation_aborted),
specify overlap/serialization rules (only one concurrent connect() is allowed
per socket; concurrent connect calls must be serialized by the caller), and
enumerate notable error conditions (std::system_error from open(),
std::errc::connection_refused, std::errc::no_such_file_or_directory,
operation_aborted on cancellation). Ensure the doc references the
functions/types connect(), connect_awaitable, local_endpoint, is_open(), and
open() so readers can locate the implementation.

In `@include/boost/corosio/native/detail/select/select_traits.hpp`:
- Around line 177-181: The setsockopt calls for SO_NOSIGPIPE and IPV6_V6ONLY are
currently ignored; check the return value of ::setsockopt where these options
are set (the blocks that set SO_NOSIGPIPE and IPV6_V6ONLY) and propagate
failures instead of swallowing them: if ::setsockopt returns -1, return or throw
an appropriate error from the surrounding open() / socket-creation routine (or
convert errno to the function's error return) so socket configuration failures
abort socket setup and surface to the caller; apply the same change to both
occurrences around SO_NOSIGPIPE and IPV6_V6ONLY.

In `@include/boost/corosio/tcp_socket.hpp`:
- Around line 398-400: The docstring incorrectly references a non-existent
overload shutdown(shutdown_type,std::error_code&); fix by adding a matching
overload declaration for tcp_socket::shutdown(shutdown_type, std::error_code&)
to the class (and implement/forward it to the existing shutdown(shutdown_type)
behavior while populating the std::error_code on failure), or alternatively
change the documentation text to point to the actual error-reporting API that
exists; update the doc/comment at the same spot (around the existing shutdown
documentation) to reflect whichever approach you take so the reference and the
code stay consistent.

In `@src/corosio/src/local_stream_acceptor.cpp`:
- Around line 53-64: The code currently unconditionally calls ::unlink on
ep.path() when bind_option::unlink_existing is set, which can delete arbitrary
filesystem entries; instead, null-terminate the copied path buffer and call
::lstat on that buffer, verify the existing file is a socket (S_ISSOCK /
S_IFSOCK) before calling ::unlink, treat lstat ENOENT as fine and skip unlink on
any non-socket result; apply this change in the block handling
bind_option::unlink_existing that uses ep.path(), char
buf[local_endpoint::max_path_length + 1], and ::unlink so bind() only removes
stale socket nodes.

---

Outside diff comments:
In `@include/boost/corosio/udp_socket.hpp`:
- Around line 505-510: The documentation for send_to incorrectly references
message_flags::dont_route; update the doc comment for the send_to function (in
udp_socket.hpp) to use the correct enum name message_flags::do_not_route as
exported by include/boost/corosio/message_flags.hpp, ensuring any mention of the
flag in the parameter description and examples is replaced with
message_flags::do_not_route.

---

Duplicate comments:
In `@include/boost/corosio/io/io_read_stream.hpp`:
- Around line 97-113: Update the read_some documentation in io_read_stream.hpp
to explicitly state that the operation supports cancellation via the stop_token
propagated through the IoAwaitable protocol and via the stream's cancel() member
(or cancel()), and clarify that when cancelled the awaitable resumes with an
error_code that compares equal to capy::cond::canceled as the first element of
the returned (error_code, std::size_t) tuple; reference the template function
read_some (template<capy::MutableBufferSequence MB>) so readers can find the
documented behavior.

In `@include/boost/corosio/local_endpoint.hpp`:
- Around line 78-85: The documentation comment in
include/boost/corosio/local_endpoint.hpp displays the null-character example as
'\\0' instead of the intended '\0'; update the docstring to render the character
literal correctly by replacing the escaped form with a single-quoted null char
`'\0'` (i.e., change the `\\0` instance in that comment block to `\0` inside
quotes/backticks) so the generated docs show '\0' as intended.

In `@include/boost/corosio/udp_socket.hpp`:
- Around line 505-533: Update the documentation for the new message-flags
overloads (e.g., the template send_to(Buffers const& buf, endpoint dest,
corosio::message_flags flags) and its two-argument overload calling it) to state
that these async operations support cancellation via a propagated stop_token
(IoAwaitable protocol) and via the socket's cancel()/i/o object cancel() method,
and that when cancelled the awaitable completes with an error that compares
equal to capy::cond::canceled; apply the same documentation wording to the other
newly added message_flags overloads referenced (the similar overloads around the
send_to_awaitable/receive_from_awaitable functions at the other ranges).

---

Nitpick comments:
In `@include/boost/corosio/local_endpoint.hpp`:
- Around line 26-42: Add a proper API docstring for the public class
local_endpoint documenting its purpose as a Unix domain socket endpoint, the
constructor(s) parameters and behavior (including the portable pathname length
limit and how abstract Linux paths starting with '\0' are handled), the
semantics of path() (that it returns a non-owning view into an internal
fixed-size buffer and the lifetime is tied to the local_endpoint object), the
fact the class avoids heap allocation and is trivially copyable, and the cleanup
responsibility (library does NOT unlink filesystem socket paths); update
docstrings for the constructors and path() accessor to state preconditions (path
length limits), postconditions, and platform-specific notes for abstract paths.

In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp`:
- Around line 13-28: Add a file-level overview block comment immediately after
the includes in reactor_acceptor.hpp that briefly describes ownership of the
acceptor file descriptor, how descriptor registration/unregistration is handled,
cancellation/close/release paths, and the synchronization model used to protect
the FD and internal state (e.g., which mutex(es) guard what and whether
operations may be called concurrently). Reference reactor_acceptor.hpp and the
key responsibilities (acceptor fd lifecycle, descriptor registration,
cancellation, close, release) so readers can quickly understand the module
boundaries and threading assumptions before reading class/struct declarations
and functions that implement those behaviors.
- Around line 252-344: Both do_close_socket() and do_release_socket() duplicate
the same lock/claim/post/reset sequence; extract that shared teardown into a
single helper (e.g., teardown_descriptor() or release_descriptor_resources())
and call it from both functions. The helper should capture the weak_from_this()
lock, call acc_.request_cancel(), take the desc_state_.mutex, exchange
desc_state_.read_op to nullptr, set read_ready/write_ready false, set
desc_state_.impl_ref_ if is_enqueued_.load(...), and if a claimed op exists set
acc_.impl_ptr = self then svc_.post(&acc_) and svc_.work_finished(); after
calling the helper each caller should continue its remaining socket-specific
logic (closing/deregistering fd_, resetting desc_state_.fd and
registered_events, and clearing local_endpoint_). Ensure the helper references
acc_, desc_state_, svc_, and weak_from_this() to preserve the exact existing
behavior.

In `@include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp`:
- Around line 21-38: The header reactor_socket_finals.hpp uses standard library
types (std::conditional_t, std::is_same_v, std::coroutine_handle,
std::stop_token, std::error_code) but doesn't include the corresponding standard
headers; add the minimal required includes (e.g. <type_traits>, <coroutine> or
<coroutine> shim used in this project, <stop_token>, and <system_error>) at the
top of the file so these symbols are always defined without relying on
transitive includes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 92a35d76-28f6-4ac1-acf9-c7fb1f4c2151

📥 Commits

Reviewing files that changed from the base of the PR and between 1e6c449 and 25f6507.

⛔ Files ignored due to path filters (20)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
  • test/unit/tcp_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (75)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
✅ Files skipped from review due to trivial changes (14)
  • include/boost/corosio.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • src/corosio/src/local_stream.cpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
🚧 Files skipped from review as they are similar to previous changes (18)
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/io_context.cpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • src/corosio/src/local_endpoint.cpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • src/corosio/src/local_stream_socket.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp

@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from 25f6507 to 85079b1 Compare April 10, 2026 18:46
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (2)
src/corosio/src/local_stream_acceptor.cpp (1)

14-20: Add the file-level implementation overview while this logic is fresh.

This new .cpp has non-trivial open/bind/listen behavior and a subtle unlink_existing safety path, but it still lacks the high-level /* */ maintainer note required for implementation files.

As per coding guidelines: "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/corosio/src/local_stream_acceptor.cpp` around lines 14 - 20, Add a
file-level /* */ block comment immediately after the includes that summarizes
the implementation of boost::corosio::local_stream_acceptor: describe the
open/bind/listen sequence, how errors are handled (referencing detail::except),
the role of detail::local_stream_acceptor_service in performing operations, and
clearly explain the unlink_existing safety path (when it unlinks, why, and any
race/permission caveats) so maintainers can quickly grasp the high-level
behavior without reading the code.
src/corosio/src/local_datagram_socket.cpp (1)

14-20: Add a file-level overview block here.

This new source file contains non-trivial lifecycle and state-management logic, but it goes straight from the includes into the implementation. Please add a short /* */ overview after the includes describing how local_datagram_socket delegates to detail::local_datagram_service and what the open/close/assign/query state model is.

♻️ Suggested addition
 `#include` <boost/corosio/detail/local_datagram_service.hpp>
 
 `#include` <sys/ioctl.h>
 
+/* Implements the POSIX local_datagram_socket facade by delegating socket
+   creation, binding, assignment, closure, and cancellation to
+   detail::local_datagram_service. The implementation keeps the public state
+   machine simple: open/close/cancel are idempotent, invalid state transitions
+   raise logic_error, and endpoint / availability queries degrade safely when
+   the socket is not open.
+*/
+
 namespace boost::corosio {

As per coding guidelines, "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/corosio/src/local_datagram_socket.cpp` around lines 14 - 20, Add a
file-level block comment after the includes that summarizes the purpose and
high-level design of this translation unit: explain that class
local_datagram_socket delegates operations (open/close/assign/query) to
detail::local_datagram_service, describe the socket lifecycle/state model (how
open/close transitions work, what assign does, and how query/readable state is
reported), and call out any important invariants or thread/coroutine-safety
expectations for methods like local_datagram_socket::open, ::close, ::assign and
the service helpers in detail::local_datagram_service so readers can quickly
understand ownership and state transitions without diving into implementation
details.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/local_datagram_socket.hpp`:
- Around line 40-66: The comment block describing the public contract for
local_datagram_socket is currently a C-style /* ... */ comment and will be
omitted from generated docs; replace it with a public Doxygen-style doc comment
/** ... */ placed immediately above the local_datagram_socket class declaration
so the thread-safety, overlap rules (recv/recv_from and send/send_to sharing
slots), supported modes (connected vs connectionless), and usage notes are
included in generated documentation; ensure the text remains intact and follows
the coding guideline that public classes in non-detail headers have docstrings.

In `@include/boost/corosio/local_endpoint.hpp`:
- Around line 26-41: Convert the leading block comment for the local_endpoint
class into a public docstring so it appears in generated docs: replace the plain
/* ... */ comment with a Doxygen-style /** ... */ comment immediately preceding
the local_endpoint class declaration, preserving the text about path storage,
abstract-socket semantics, no-auto-unlink, and thread-safety; mirror the style
used for local_datagram_socket to ensure it meets the project's public-header
docstring guideline.

In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 237-272: Update the documentation to match the implementation:
change the is_open() summary to state it only indicates the native acceptor
handle exists (not that it is listening), and update the `@throws` clauses on both
overloads accept(local_stream_socket& peer) and accept() to say they only throw
std::logic_error when the native acceptor handle is absent (i.e., !is_open()),
and that calling accept on an open-but-not-listening acceptor will not throw but
will complete with a normal kernel error (e.g., EINVAL) from the backend.

In `@include/boost/corosio/native/detail/endpoint_convert.hpp`:
- Around line 295-316: The code computes path_len from the incoming len even
though only up to sizeof(sockaddr_un) bytes were copied into sockaddr_un sa;
clamp the derived path_len to the actual bytes copied to avoid reading past
sa.sun_path. Change the logic around path_offset/path_len so you first compute
bytes_copied = std::min<std::size_t>(static_cast<std::size_t>(len), sizeof(sa)),
then set path_len = (bytes_copied > path_offset) ? bytes_copied - path_offset :
0 before doing the memchr and constructing local_endpoint
ep(std::string_view(sa.sun_path, path_len), ec). This ensures memchr and the
string_view only examine valid bytes in sa.sun_path.

In `@include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp`:
- Around line 72-113: Before calling socket_impl->init_and_register(fd) validate
the FD's address family and socket type and return an error so ownership stays
with the caller: use ::getsockname(fd, ...) to read sockaddr.sa_family and
::getsockopt(fd, SOL_SOCKET, SO_TYPE, ...) to get the socket type, then check
that the family == AF_UNIX and the SO_TYPE matches the expected type for this
SocketFinal (stream vs datagram); if either check fails, convert the failure
into an appropriate std::error_code and return it (do this after
Traits::configure_local_socket(fd) but before
socket_impl->init_and_register(fd)). Ensure the checks reference do_assign_fd,
socket_impl and init_and_register so the wrong-protocol FD is rejected before
adoption.

---

Nitpick comments:
In `@src/corosio/src/local_datagram_socket.cpp`:
- Around line 14-20: Add a file-level block comment after the includes that
summarizes the purpose and high-level design of this translation unit: explain
that class local_datagram_socket delegates operations (open/close/assign/query)
to detail::local_datagram_service, describe the socket lifecycle/state model
(how open/close transitions work, what assign does, and how query/readable state
is reported), and call out any important invariants or thread/coroutine-safety
expectations for methods like local_datagram_socket::open, ::close, ::assign and
the service helpers in detail::local_datagram_service so readers can quickly
understand ownership and state transitions without diving into implementation
details.

In `@src/corosio/src/local_stream_acceptor.cpp`:
- Around line 14-20: Add a file-level /* */ block comment immediately after the
includes that summarizes the implementation of
boost::corosio::local_stream_acceptor: describe the open/bind/listen sequence,
how errors are handled (referencing detail::except), the role of
detail::local_stream_acceptor_service in performing operations, and clearly
explain the unlink_existing safety path (when it unlinks, why, and any
race/permission caveats) so maintainers can quickly grasp the high-level
behavior without reading the code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c2deee44-3bd7-40de-bad7-46a07995380d

📥 Commits

Reviewing files that changed from the base of the PR and between 25f6507 and 85079b1.

⛔ Files ignored due to path filters (20)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
  • test/unit/tcp_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (76)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
  • src/corosio/src/tcp_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
✅ Files skipped from review due to trivial changes (16)
  • include/boost/corosio.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/shutdown_type.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • src/corosio/src/local_stream.cpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
🚧 Files skipped from review as they are similar to previous changes (14)
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/io_context.cpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • src/corosio/src/local_stream_socket.cpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp

@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from 85079b1 to 733f64d Compare April 10, 2026 19:16
@mvandeberg
Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

✅ Actions performed

Reviews resumed.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
include/boost/corosio/native/native_udp_socket.hpp (1)

73-155: ⚠️ Potential issue | 🟠 Major

Add flag overloads to native_udp_socket::send_to() and native_udp_socket::recv_from().

The base udp_socket now exposes send_to(buffers, dest, message_flags) and recv_from(buffers, source, message_flags) overloads, allowing callers to use message_flags::peek, dont_route, and other flag values. However, native_udp_socket only exposes the 2-argument forms, hiding the base overload set. Users of the native wrapper cannot access message flags unless they upcast to udp_socket, which defeats the purpose of using the native interface.

Add public send_to and recv_from overloads that accept message_flags, update both awaitables to store the flags parameter, and delegate the no-flags overloads to the flagged versions (matching the pattern in udp_socket.hpp lines 537 and 573).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/native_udp_socket.hpp` around lines 73 - 155,
The native wrapper is missing message_flags overloads, so add public overloads
native_udp_socket::send_to(ConstBufferSequence, endpoint, capy::message_flags)
and native_udp_socket::recv_from(MutableBufferSequence, endpoint&,
capy::message_flags) that forward to get_impl().send_to/get_impl().recv_from
with the flags; update native_send_to_awaitable and native_recv_from_awaitable
to store a capy::message_flags member (add to their constructors) and have
await_suspend pass that flags value into self_.get_impl().send_to(..., flags,
&ec_, &bytes_transferred_) and recv_from(..., flags, &ec_, &bytes_transferred_);
finally make the existing two-argument native_udp_socket::send_to/recv_from
delegate to the new three-argument overloads (matching the udp_socket pattern).
🧹 Nitpick comments (3)
include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp (1)

27-35: Use the enum values here instead of hard-coded bits.

Replace the raw bit patterns (1, 2, 4) with static_cast<int>(message_flags::peek), static_cast<int>(message_flags::out_of_band), and static_cast<int>(message_flags::do_not_route) to make the mapping explicit and keep it in sync if the enum values change.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp`
around lines 27 - 35, Replace the hard-coded mask literals in
to_native_msg_flags with the corresponding message_flags enum values: use
static_cast<int>(message_flags::peek) instead of 1,
static_cast<int>(message_flags::out_of_band) instead of 2, and
static_cast<int>(message_flags::do_not_route) instead of 4; update the three if
checks in to_native_msg_flags to test against those enum-derived ints so the
mapping to native MSG_PEEK, MSG_OOB and MSG_DONTROUTE remains explicit and
resilient to enum value changes.
include/boost/corosio/local_stream_acceptor.hpp (1)

189-199: Move assignment assertion could be stronger.

The assert at line 191-192 validates same context, but this is a debug-only check. Consider whether a release-mode check with a more informative error would help users diagnose cross-context moves in production.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_acceptor.hpp` around lines 189 - 199, The
move-assignment for local_stream_acceptor currently only asserts the contexts
match (assert(&ctx_ == &other.ctx_)) which disappears in release builds; change
operator=(local_stream_acceptor&& other) to perform a runtime check of ctx_ vs
other.ctx_ and handle mismatch deterministically (e.g., throw
std::invalid_argument or call std::terminate with a clear diagnostic) before
calling close() and io_object::operator=(std::move(other)); keep the assert for
debug builds but add the release-safe check and an explanatory error message
referencing ctx_ and the operation (local_stream_acceptor::operator=).
include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp (1)

254-291: Consider extracting shared cancellation logic.

do_close_socket() and do_release_socket() share nearly identical cancellation and cleanup logic (lines 258-276 vs 308-326). The only difference is that do_close_socket() calls ::close(fd_) while do_release_socket() returns the fd. This duplication increases maintenance burden.

♻️ Possible extraction
// Extract shared logic into a helper:
void prepare_for_close_or_release() noexcept
{
    auto self = this->weak_from_this().lock();
    if (self)
    {
        acc_.request_cancel();
        reactor_op_base* claimed = nullptr;
        {
            std::lock_guard lock(desc_state_.mutex);
            claimed = std::exchange(desc_state_.read_op, nullptr);
            desc_state_.read_ready  = false;
            desc_state_.write_ready = false;
            if (desc_state_.is_enqueued_.load(std::memory_order_acquire))
                desc_state_.impl_ref_ = self;
        }
        if (claimed)
        {
            acc_.impl_ptr = self;
            svc_.post(&acc_);
            svc_.work_finished();
        }
    }
}

Also applies to: 293-344

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp` around
lines 254 - 291, do_close_socket() and do_release_socket() duplicate the
cancellation/cleanup sequence (the acc_.request_cancel, claiming/exchanging
desc_state_.read_op, resetting read_ready/write_ready, setting impl_ref_, and
posting acc_) — extract that shared logic into a noexcept helper (e.g.,
prepare_for_close_or_release()) and have both do_close_socket() and
do_release_socket() call it; keep the helper using
this->weak_from_this().lock(), acc_, desc_state_.mutex, std::exchange on
desc_state_.read_op, desc_state_.is_enqueued_.load, svc_.post(&acc_) and
svc_.work_finished(), and leave only the fd-specific behavior (::close(fd_) vs
returning fd) in the two original functions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp`:
- Around line 57-99: stream_socket_hook's user_set_linger_ remains sticky and
can affect unrelated fds later; ensure the flag is cleared when the fd lifecycle
ends by resetting user_set_linger_ to false after clearing SO_LINGER (update
reset_linger to set user_set_linger_ = false after calling ::setsockopt), and
also ensure any code path that bypasses these hooks (e.g. release_socket)
explicitly clears the hook state on the stream_socket_hook instance so a reused
socket won't inherit the previous linger setting.

In `@include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp`:
- Around line 66-104: reactor_dgram_recv_op currently inherits
reactor_dgram_base_op::operator() which calls complete_io_op and treats zero
bytes as EOF; override operator() in reactor_dgram_recv_op to call
complete_datagram_op instead (e.g. implement reactor_dgram_recv_op::operator()
that invokes complete_datagram_op(*this)) so connected recv() completions treat
zero-length datagrams as successful datagrams rather than EOF; keep references
to reactor_dgram_recv_op, reactor_dgram_base_op::operator(),
complete_datagram_op, and complete_io_op to locate the change.

In `@include/boost/corosio/native/detail/select/select_traits.hpp`:
- Around line 174-175: The check that returns make_err(EMFILE) when fd >=
FD_SETSIZE should return make_err(EINVAL) instead so the backend consistently
reports "invalid argument / unsupported fd" (same as
accept_policy::do_accept()); locate the branch using FD_SETSIZE and replace the
EMFILE error with EINVAL by changing the call to make_err(...) accordingly,
ensuring select_traits.hpp's overflow path uses EINVAL.

---

Outside diff comments:
In `@include/boost/corosio/native/native_udp_socket.hpp`:
- Around line 73-155: The native wrapper is missing message_flags overloads, so
add public overloads native_udp_socket::send_to(ConstBufferSequence, endpoint,
capy::message_flags) and native_udp_socket::recv_from(MutableBufferSequence,
endpoint&, capy::message_flags) that forward to
get_impl().send_to/get_impl().recv_from with the flags; update
native_send_to_awaitable and native_recv_from_awaitable to store a
capy::message_flags member (add to their constructors) and have await_suspend
pass that flags value into self_.get_impl().send_to(..., flags, &ec_,
&bytes_transferred_) and recv_from(..., flags, &ec_, &bytes_transferred_);
finally make the existing two-argument native_udp_socket::send_to/recv_from
delegate to the new three-argument overloads (matching the udp_socket pattern).

---

Nitpick comments:
In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 189-199: The move-assignment for local_stream_acceptor currently
only asserts the contexts match (assert(&ctx_ == &other.ctx_)) which disappears
in release builds; change operator=(local_stream_acceptor&& other) to perform a
runtime check of ctx_ vs other.ctx_ and handle mismatch deterministically (e.g.,
throw std::invalid_argument or call std::terminate with a clear diagnostic)
before calling close() and io_object::operator=(std::move(other)); keep the
assert for debug builds but add the release-safe check and an explanatory error
message referencing ctx_ and the operation (local_stream_acceptor::operator=).

In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp`:
- Around line 254-291: do_close_socket() and do_release_socket() duplicate the
cancellation/cleanup sequence (the acc_.request_cancel, claiming/exchanging
desc_state_.read_op, resetting read_ready/write_ready, setting impl_ref_, and
posting acc_) — extract that shared logic into a noexcept helper (e.g.,
prepare_for_close_or_release()) and have both do_close_socket() and
do_release_socket() call it; keep the helper using
this->weak_from_this().lock(), acc_, desc_state_.mutex, std::exchange on
desc_state_.read_op, desc_state_.is_enqueued_.load, svc_.post(&acc_) and
svc_.work_finished(), and leave only the fd-specific behavior (::close(fd_) vs
returning fd) in the two original functions.

In `@include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp`:
- Around line 27-35: Replace the hard-coded mask literals in to_native_msg_flags
with the corresponding message_flags enum values: use
static_cast<int>(message_flags::peek) instead of 1,
static_cast<int>(message_flags::out_of_band) instead of 2, and
static_cast<int>(message_flags::do_not_route) instead of 4; update the three if
checks in to_native_msg_flags to test against those enum-derived ints so the
mapping to native MSG_PEEK, MSG_OOB and MSG_DONTROUTE remains explicit and
resilient to enum value changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e0cb93f7-a33c-48fa-9786-8e3548cc7e10

📥 Commits

Reviewing files that changed from the base of the PR and between 25f6507 and 733f64d.

⛔ Files ignored due to path filters (20)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
  • test/unit/tcp_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (76)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
  • src/corosio/src/tcp_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
✅ Files skipped from review due to trivial changes (12)
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio.hpp
  • include/boost/corosio/shutdown_type.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/io/io_write_stream.hpp
🚧 Files skipped from review as they are similar to previous changes (13)
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • src/corosio/src/tcp_socket.cpp
  • include/boost/corosio/io/io_object.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_socket_pair.cpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/udp_socket.hpp

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

✅ Actions performed

Reviews resumed.

@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from 733f64d to b968d3c Compare April 10, 2026 21:16
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
include/boost/corosio/native/native_udp_socket.hpp (1)

187-222: Consider adding message_flags overloads to match udp_socket API.

The base udp_socket now provides overloads accepting message_flags for send_to, recv_from, send, and recv. The native_udp_socket methods shadow these without offering the flags variants, so users of native_udp_socket cannot specify message flags.

For API consistency, consider adding:

template<capy::ConstBufferSequence CB>
auto send_to(CB const& buffers, endpoint dest, message_flags flags) { ... }

This is not blocking since the default (no flags) still works.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/native_udp_socket.hpp` around lines 187 - 222,
native_udp_socket currently lacks the message_flags overloads that udp_socket
exposes, so add new overloads for send_to, recv_from, send and recv that accept
a message_flags parameter; each overload should mirror the existing checks (call
is_open and throw_logic_error) and then forward to the corresponding backend
awaitable (native_send_to_awaitable, native_recv_from_awaitable,
native_send_awaitable, native_recv_awaitable) passing the flags along, using the
same template constraints (capy::ConstBufferSequence for send/send_to and
capy::MutableBufferSequence for recv/recv_from) and returning the same awaitable
type as the no-flags versions.
src/corosio/src/local_socket_pair.cpp (1)

10-24: Add the missing file-level implementation overview.

This file now owns the socketpair creation path, the nonblocking/CLOEXEC fallback, and the exception-safe FD handoff logic, so it qualifies as non-trivial implementation code and should have the required post-include /* */ summary block. As per coding guidelines, "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/corosio/src/local_socket_pair.cpp` around lines 10 - 24, Add a file-level
block comment immediately after the include section in local_socket_pair.cpp
that briefly summarizes the implementation: explain that this file implements
the POSIX socketpair creation path, attempts SOCK_NONBLOCK|SOCK_CLOEXEC
atomically and falls back to setting O_NONBLOCK and FD_CLOEXEC if not supported,
and describes the exception-safe file-descriptor handoff logic used to ensure no
FD leaks on errors; reference the socketpair creation/fallback and the
exception-safe handoff so reviewers can quickly understand functions handling
those concerns.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/detail/local_stream_acceptor_service.hpp`:
- Around line 35-41: The documentation comment in
local_stream_acceptor_service.hpp exposes POSIX macros AF_UNIX and SOCK_STREAM;
update the comment for the acceptor creation (the block describing the
parameters for the acceptor/open operation) to use Corosio-local semantics
instead of platform constants: describe the address family as "local (domain)
socket", the type as "stream socket semantics", and the protocol as "protocol
number (default 0)"/or "implementation-defined", removing any direct reference
to AF_UNIX or SOCK_STREAM so the header no longer contains platform-specific
macro names.

In `@include/boost/corosio/local_datagram_socket.hpp`:
- Around line 691-700: Update the assign(int fd) docblock to document the
precondition that the socket must not already be open and that violating this
precondition results in a std::logic_error; keep the existing note that
std::system_error is thrown on other failures. Reference the assign(int)
declaration and ensure the docstring mentions the parameter, the precondition
("socket must not already be open"), and both exception types (std::logic_error
for already-open sockets and std::system_error for other errors).

In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 124-130: The await_suspend implementation in local_stream_acceptor
should short-circuit if the provided env->stop_token is already requested:
assign token_ = env->stop_token, check token_.stop_requested(), and if true set
ec_ to an operation-cancelled error (e.g. std::errc::operation_canceled or
boost::asio::error::operation_aborted equivalent) and return the incoming
coroutine handle (h) to resume immediately instead of calling
implementation::accept(); otherwise call acc_.get().accept(...) as before. Apply
this same pre-cancellation guard to both accept_awaitable and
move_accept_awaitable await_suspend implementations, and ensure peer_impl_ is
not consumed when short-circuiting.

In `@include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp`:
- Around line 128-140: init_and_register() now always calls
svc_.scheduler().register_descriptor(fd, &desc_state_), so make the
close/release paths symmetric by always calling
svc_.scheduler().deregister_descriptor(fd_, &desc_state_) for any descriptor
that was registered (e.g., whenever fd_ or desc_state_.fd is valid), instead of
only when registered_events != 0; after deregistering clear fd_/desc_state_.fd
and reset descriptor pointers under the same mutex to avoid races. Apply the
same change to both existing close/release paths that currently check
registered_events (the other two deregistration sites) so every path that undoes
init_and_register performs an unconditional deregister followed by proper
cleanup.

In `@src/corosio/src/local_socket_pair.cpp`:
- Around line 28-55: The fallback make_nonblock_cloexec currently ignores
failures and returns partially-configured sockets; modify it to check the return
values of each ::fcntl call (F_GETFL, F_SETFL, F_SETFD) and propagate failures
back to create_pair (e.g., by returning an errno or throwing std::system_error).
In create_pair, after socketpair succeeds but before returning, call
make_nonblock_cloexec for both fds and if either call fails, close any opened
descriptors (close fds[0] and fds[1] if valid) and throw a std::system_error
using the failing errno so callers never receive blocking or CLOEXEC-missing
sockets; reference functions make_nonblock_cloexec and create_pair for locating
changes.

In `@src/corosio/src/local_stream_acceptor.cpp`:
- Around line 18-19: This translation unit calls std::memcpy (the usage around
the memcpy call) but doesn't include the <cstring> header; add `#include`
<cstring> to the includes at the top of local_stream_acceptor.cpp so std::memcpy
is declared reliably (keep the existing `#include` <sys/stat.h> and `#include`
<unistd.h> and insert <cstring> alongside them).

---

Nitpick comments:
In `@include/boost/corosio/native/native_udp_socket.hpp`:
- Around line 187-222: native_udp_socket currently lacks the message_flags
overloads that udp_socket exposes, so add new overloads for send_to, recv_from,
send and recv that accept a message_flags parameter; each overload should mirror
the existing checks (call is_open and throw_logic_error) and then forward to the
corresponding backend awaitable (native_send_to_awaitable,
native_recv_from_awaitable, native_send_awaitable, native_recv_awaitable)
passing the flags along, using the same template constraints
(capy::ConstBufferSequence for send/send_to and capy::MutableBufferSequence for
recv/recv_from) and returning the same awaitable type as the no-flags versions.

In `@src/corosio/src/local_socket_pair.cpp`:
- Around line 10-24: Add a file-level block comment immediately after the
include section in local_socket_pair.cpp that briefly summarizes the
implementation: explain that this file implements the POSIX socketpair creation
path, attempts SOCK_NONBLOCK|SOCK_CLOEXEC atomically and falls back to setting
O_NONBLOCK and FD_CLOEXEC if not supported, and describes the exception-safe
file-descriptor handoff logic used to ensure no FD leaks on errors; reference
the socketpair creation/fallback and the exception-safe handoff so reviewers can
quickly understand functions handling those concerns.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 882cae7a-a017-488d-b5b6-01a69b2f5ed4

📥 Commits

Reviewing files that changed from the base of the PR and between 733f64d and b968d3c.

⛔ Files ignored due to path filters (21)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
  • test/unit/tcp_socket.cpp is excluded by !**/test/**
  • test/unit/udp_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (76)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
  • src/corosio/src/tcp_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
✅ Files skipped from review due to trivial changes (12)
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/shutdown_type.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/message_flags.hpp
  • src/corosio/src/local_stream.cpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/op_base.hpp
🚧 Files skipped from review as they are similar to previous changes (10)
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • src/corosio/src/tcp_socket.cpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp

Add local_stream_socket, local_stream_acceptor, local_datagram_socket,
local_endpoint, and local_socket_pair for Unix domain socket I/O.
The public API mirrors TCP/UDP with protocol-appropriate differences
(path-based endpoints, socketpair, release_socket for fd passing).

Replace 42 per-backend reactor files (14 each for epoll, kqueue,
select) with parameterized templates instantiated from per-backend
traits structs. Each backend provides a traits type capturing its
platform-specific socket creation, write policy, and accept policy.

The reactor_types<Traits> template in reactor_backend.hpp generates
all concrete socket, service, acceptor, and op types. Virtual method
overrides move into the CRTP bases, and select's notify_reactor()
moves into register_op() via a compile-time trait, eliminating all
select-specific method overrides.

New files:
  - {epoll,kqueue,select}_traits.hpp: per-backend policies
  - reactor_{stream,datagram}_ops.hpp: parameterized op types
  - reactor_socket_finals.hpp: final socket/acceptor types
  - reactor_service_finals.hpp: per-protocol service types
  - reactor_backend.hpp: accept impl and reactor_types bundle
@mvandeberg mvandeberg force-pushed the pr/122-unix-sockets-2 branch from b968d3c to 64cbfc7 Compare April 10, 2026 22:28
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp (1)

279-289: ⚠️ Potential issue | 🟠 Major

Deregister the acceptor even before the first accept op arms events.

do_listen() registers the fd immediately, but both teardown paths still use registered_events != 0 as a proxy for “registered”. If the acceptor is closed or released right after listen() and before any accept() starts, the descriptor stays in the scheduler registry with a dead fd.

💡 Suggested fix
 protected:
     Service& svc_;
     int fd_ = -1;
     Endpoint local_endpoint_;
+    bool descriptor_registered_ = false;
@@
     std::error_code do_listen(int backlog);
@@
 std::error_code
 reactor_acceptor<Derived, Service, Op, AcceptOp, DescState, ImplBase, Endpoint>::
     do_listen(int backlog)
 {
     if (::listen(fd_, backlog) < 0)
         return make_err(errno);

     svc_.scheduler().register_descriptor(fd_, &desc_state_);
+    descriptor_registered_ = true;
     return {};
 }
@@
     if (fd_ >= 0)
     {
-        if (desc_state_.registered_events != 0)
+        if (descriptor_registered_)
             svc_.scheduler().deregister_descriptor(fd_);
         ::close(fd_);
         fd_ = -1;
     }

     desc_state_.fd                = -1;
     desc_state_.registered_events = 0;
+    descriptor_registered_        = false;
@@
     if (fd_ >= 0)
     {
-        if (desc_state_.registered_events != 0)
+        if (descriptor_registered_)
             svc_.scheduler().deregister_descriptor(fd_);
         fd_ = -1;
     }

     desc_state_.fd                = -1;
     desc_state_.registered_events = 0;
+    descriptor_registered_        = false;

Also applies to: 331-341, 385-389

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp` around
lines 279 - 289, When tearing down the acceptor, don't rely on
desc_state_.registered_events to decide whether to call
svc_.scheduler().deregister_descriptor because do_listen() registers the fd
immediately; instead, deregister whenever the descriptor was registered (e.g.,
check desc_state_.fd >= 0 or fd_ >= 0) before closing the fd. Update the
teardown blocks that currently check desc_state_.registered_events (the block
using fd_, desc_state_.registered_events and ::close, and the similar blocks at
the other noted sites) to call svc_.scheduler().deregister_descriptor when the
descriptor exists (fd/desc_state_.fd >= 0), then clear fd_ and desc_state_ as
before so the descriptor is removed from the scheduler even if no accept() had
yet armed events.
♻️ Duplicate comments (2)
include/boost/corosio/io/io_read_stream.hpp (1)

109-112: ⚠️ Potential issue | 🟡 Minor

Use capy::cond::canceled in the cancellation contract.

These docs still say cancellation yields errc::operation_canceled. The public contract should describe the propagated stop_token / cancel() behavior in terms of the library’s error condition and tell callers to compare conditions, not exact values.

📝 Suggested wording
-        Supports cancellation via the awaitable's stop_token or by
-        calling the owning stream's `cancel()` member. On cancellation,
-        yields `errc::operation_canceled`.
+        Supports cancellation via the stop_token propagated through the
+        IoAwaitable protocol or by calling the owning stream's
+        `cancel()` member. On cancellation, the first result compares
+        equal to `capy::cond::canceled`; compare error codes to error
+        conditions rather than specific values.

As per coding guidelines, "Cancellation — State that the operation supports cancellation via stop_token propagated through the IoAwaitable protocol, or via the i/o object's cancel() member; state that the resulting error compares equal to capy::cond::canceled."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/io/io_read_stream.hpp` around lines 109 - 112, Update
the cancellation paragraph in io_read_stream.hpp to reference
capy::cond::canceled instead of errc::operation_canceled and state that
cancellation is propagated via the IoAwaitable stop_token or the stream's
cancel() member and that callers should compare the resulting error with
capy::cond::canceled (i.e., use condition comparison, not exact value). Locate
the text around the IO read stream documentation block that currently mentions
"yields `errc::operation_canceled`" and replace that phrase and surrounding
wording to match the coding guideline wording describing stop_token propagation
and comparison to capy::cond::canceled.
include/boost/corosio/local_stream_socket.hpp (1)

39-57: ⚠️ Potential issue | 🟡 Minor

Finish the async contract for connect().

The new docs are better, but they still don't spell out the completion conditions, the caller-side serialization rule for initiating operations, or the portable cancellation contract (capy::cond::canceled rather than a specific error value). That leaves the public awaitable contract incomplete.

As per coding guidelines, "Completion conditions — Bulleted @li list of conditions under which the operation completes and the coroutine resumes" and "Cancellation — State that the resulting error compares equal to capy::cond::canceled."

Also applies to: 169-190

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 39 - 57, Update
the documentation for local_stream_socket::connect() to fully specify the async
awaitable contract: list explicit completion conditions (success on connected
peer, failure with corresponding system error on connect failure, and aborted
with capy::cond::canceled for cancellation), state the caller-side serialization
rule (no concurrent connect() calls; operations of the same type must be
serialized; one read and one write may be in flight), and declare the portable
cancellation result compares equal to capy::cond::canceled rather than a
platform-specific errno; apply the same additions to the duplicate doc block at
lines ~169-190 to keep both docs consistent.
🧹 Nitpick comments (1)
include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp (1)

26-42: Add a file-level overview for the consolidated reactor core.

This header now owns the shared speculative-I/O and reactor-registration flow for every backend, but the only prose here is the CRTP type comment. A short /* */ overview after the includes would make the backend/trait invariants much easier to audit and maintain.

As per coding guidelines, "Files containing non-trivial implementation logic should include a /* */ block comment after the includes that provides a high-level overview of how the implementation works."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp` around
lines 26 - 42, Add a file-level /* ... */ overview comment immediately after the
`#include` section in reactor_stream_socket.hpp that summarizes the consolidated
reactor core responsibilities: ownership of speculative I/O,
reactor-registration/cancellation flow, relationship with reactor_basic_socket,
and invariants expected by CRTP types (Derived, Service, ConnOp, ReadOp,
WriteOp, DescState, ImplBase, Endpoint). Keep it short (5–8 lines) and describe
how connect/read/write/shutdown dispatch and descriptor_state management are
coordinated so reviewers can quickly audit backend/trait expectations without
diving into implementation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@include/boost/corosio/backend.hpp`:
- Around line 16-30: The public header backend.hpp is including
reactor_backend.hpp and platform-specific *_traits.hpp which pull in
POSIX/native headers; to fix, remove those direct includes from
include/boost/corosio/backend.hpp and instead create a lightweight non-native
shim (e.g., a new header like
include/boost/corosio/detail/reactor_types_shim.hpp) that only contains the
alias-only mapping (reactor_types) or forward declarations without including
native headers, then have reactor_backend.hpp and the platform-specific
*_traits.hpp include the real native headers and the shim include the alias
mapping; update backend.hpp to include only the shim (or forward declaration) so
it no longer transitively pulls in <sys/socket.h> etc., and ensure symbols
referenced in backend.hpp (reactor_types) are resolved via the shim in
compilation units that need the real traits.

In `@include/boost/corosio/local_stream_acceptor.hpp`:
- Around line 110-121: The current await_resume() can turn a completed accept
into cancellation by checking token_.stop_requested() before verifying ec_ and
peer_impl_; change the logic so a successful accept (ec_ indicates success and
peer_impl_ is non-null) is honored even if stop_requested() became true
afterward: first test if (ec_ || !peer_impl_) and only if that indicates failure
consider returning the operation_canceled when token_.stop_requested();
otherwise construct the local_stream_socket via reset_peer_impl(peer,
peer_impl_) and return the successful result. Apply the same fix to the other
await_resume() variant around lines 158–165.

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 64-99: Document the public backend hook struct implementation and
each pure virtual method (connect, shutdown, native_handle, release_socket,
cancel, set_option, get_option, local_endpoint, remote_endpoint): add a brief
docstring for the struct describing its role as the platform backend interface,
then for each method document parameters and return values, ownership and
lifetime rules (who owns/relinquishes sockets or handles), error-reporting
semantics (how std::error_code is used and when it must be set), cancellation
behavior and thread-safety guarantees for cancel and connect
(preconditions/postconditions around stop tokens and coroutine handles), and any
platform-specific expectations for option calls (valid levels/optnames, how size
is used/updated); ensure the docs are placed in this public header near struct
implementation so backend implementers follow the same contract.

In `@include/boost/corosio/native/detail/reactor/reactor_backend.hpp`:
- Around line 67-104: The inline-accept fast path in reactor_backend.hpp skips
complete_accept_op(), leaving op.stop_cb set and allowing a stale stop callback
to fire against this->acc_ later; fix by clearing the stop callback before
returning from the inline branch—e.g., reset op.stop_cb (or call the op/accept
stop-clear helper) after setting *impl_out and before op.cont_op.cont.h = h /
return dispatch_coro(...), ensuring the accept object's stop state is cleared
for this accept.

---

Outside diff comments:
In `@include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp`:
- Around line 279-289: When tearing down the acceptor, don't rely on
desc_state_.registered_events to decide whether to call
svc_.scheduler().deregister_descriptor because do_listen() registers the fd
immediately; instead, deregister whenever the descriptor was registered (e.g.,
check desc_state_.fd >= 0 or fd_ >= 0) before closing the fd. Update the
teardown blocks that currently check desc_state_.registered_events (the block
using fd_, desc_state_.registered_events and ::close, and the similar blocks at
the other noted sites) to call svc_.scheduler().deregister_descriptor when the
descriptor exists (fd/desc_state_.fd >= 0), then clear fd_ and desc_state_ as
before so the descriptor is removed from the scheduler even if no accept() had
yet armed events.

---

Duplicate comments:
In `@include/boost/corosio/io/io_read_stream.hpp`:
- Around line 109-112: Update the cancellation paragraph in io_read_stream.hpp
to reference capy::cond::canceled instead of errc::operation_canceled and state
that cancellation is propagated via the IoAwaitable stop_token or the stream's
cancel() member and that callers should compare the resulting error with
capy::cond::canceled (i.e., use condition comparison, not exact value). Locate
the text around the IO read stream documentation block that currently mentions
"yields `errc::operation_canceled`" and replace that phrase and surrounding
wording to match the coding guideline wording describing stop_token propagation
and comparison to capy::cond::canceled.

In `@include/boost/corosio/local_stream_socket.hpp`:
- Around line 39-57: Update the documentation for local_stream_socket::connect()
to fully specify the async awaitable contract: list explicit completion
conditions (success on connected peer, failure with corresponding system error
on connect failure, and aborted with capy::cond::canceled for cancellation),
state the caller-side serialization rule (no concurrent connect() calls;
operations of the same type must be serialized; one read and one write may be in
flight), and declare the portable cancellation result compares equal to
capy::cond::canceled rather than a platform-specific errno; apply the same
additions to the duplicate doc block at lines ~169-190 to keep both docs
consistent.

---

Nitpick comments:
In `@include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp`:
- Around line 26-42: Add a file-level /* ... */ overview comment immediately
after the `#include` section in reactor_stream_socket.hpp that summarizes the
consolidated reactor core responsibilities: ownership of speculative I/O,
reactor-registration/cancellation flow, relationship with reactor_basic_socket,
and invariants expected by CRTP types (Derived, Service, ConnOp, ReadOp,
WriteOp, DescState, ImplBase, Endpoint). Keep it short (5–8 lines) and describe
how connect/read/write/shutdown dispatch and descriptor_state management are
coordinated so reviewers can quickly audit backend/trait expectations without
diving into implementation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f1b8d525-9117-449c-8dd0-9e405a04f41f

📥 Commits

Reviewing files that changed from the base of the PR and between b968d3c and 64cbfc7.

⛔ Files ignored due to path filters (21)
  • doc/modules/ROOT/nav.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4a.tcp-networking.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/4.guide/4p.unix-sockets.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/glossary.adoc is excluded by !**/doc/**
  • doc/modules/ROOT/pages/index.adoc is excluded by !**/doc/**
  • perf/bench/CMakeLists.txt is excluded by !**/bench/**
  • perf/bench/asio/callback/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/callback/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/coroutine/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/asio/unix_socket_utils.hpp is excluded by !**/bench/**
  • perf/bench/corosio/benchmarks.hpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_latency_bench.cpp is excluded by !**/bench/**
  • perf/bench/corosio/unix_socket_throughput_bench.cpp is excluded by !**/bench/**
  • perf/bench/main.cpp is excluded by !**/bench/**
  • test/unit/local_datagram_socket.cpp is excluded by !**/test/**
  • test/unit/local_stream_socket.cpp is excluded by !**/test/**
  • test/unit/tcp_socket.cpp is excluded by !**/test/**
  • test/unit/udp_socket.cpp is excluded by !**/test/**
📒 Files selected for processing (82)
  • include/boost/corosio.hpp
  • include/boost/corosio/backend.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/detail/tcp_acceptor_service.hpp
  • include/boost/corosio/detail/tcp_service.hpp
  • include/boost/corosio/detail/udp_service.hpp
  • include/boost/corosio/io/io_object.hpp
  • include/boost/corosio/io/io_read_stream.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_datagram_socket.hpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_stream_acceptor.hpp
  • include/boost/corosio/local_stream_socket.hpp
  • include/boost/corosio/message_flags.hpp
  • include/boost/corosio/native/detail/endpoint_convert.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_traits.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_traits.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor.hpp
  • include/boost/corosio/native/detail/reactor/reactor_acceptor_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_backend.hpp
  • include/boost/corosio/native/detail/reactor/reactor_basic_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op.hpp
  • include/boost/corosio/native/detail/reactor/reactor_op_complete.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_service_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_finals.hpp
  • include/boost/corosio/native/detail/reactor/reactor_socket_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_ops.hpp
  • include/boost/corosio/native/detail/reactor/reactor_stream_socket.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_traits.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/native_udp_socket.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/socket_option.hpp
  • include/boost/corosio/tcp.hpp
  • include/boost/corosio/tcp_socket.hpp
  • include/boost/corosio/udp.hpp
  • include/boost/corosio/udp_socket.hpp
  • perf/common/native_includes.hpp
  • src/corosio/src/io_context.cpp
  • src/corosio/src/local_datagram.cpp
  • src/corosio/src/local_datagram_socket.cpp
  • src/corosio/src/local_endpoint.cpp
  • src/corosio/src/local_socket_pair.cpp
  • src/corosio/src/local_stream.cpp
  • src/corosio/src/local_stream_acceptor.cpp
  • src/corosio/src/local_stream_socket.cpp
  • src/corosio/src/tcp_socket.cpp
💤 Files with no reviewable changes (23)
  • include/boost/corosio/native/native_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_op.hpp
  • include/boost/corosio/native/native_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_tcp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_op.hpp
  • include/boost/corosio/native/detail/epoll/epoll_op.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_udp_socket.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_socket.hpp
  • include/boost/corosio/native/detail/select/select_udp_service.hpp
  • include/boost/corosio/native/detail/select/select_udp_socket.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_service.hpp
  • include/boost/corosio/native/detail/kqueue/kqueue_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/select/select_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_tcp_acceptor_service.hpp
  • include/boost/corosio/native/detail/epoll/epoll_udp_socket.hpp
✅ Files skipped from review due to trivial changes (22)
  • include/boost/corosio/socket_option.hpp
  • include/boost/corosio/tcp.hpp
  • include/boost/corosio.hpp
  • include/boost/corosio/detail/config.hpp
  • include/boost/corosio/detail/udp_service.hpp
  • include/boost/corosio/udp.hpp
  • include/boost/corosio/detail/tcp_service.hpp
  • include/boost/corosio/shutdown_type.hpp
  • include/boost/corosio/detail/tcp_acceptor_service.hpp
  • include/boost/corosio/local_stream.hpp
  • include/boost/corosio/local_datagram.hpp
  • include/boost/corosio/local_socket_pair.hpp
  • include/boost/corosio/detail/local_stream_service.hpp
  • src/corosio/src/local_datagram.cpp
  • include/boost/corosio/detail/local_stream_acceptor_service.hpp
  • include/boost/corosio/message_flags.hpp
  • src/corosio/src/local_stream.cpp
  • include/boost/corosio/detail/local_datagram_service.hpp
  • include/boost/corosio/udp_socket.hpp
  • include/boost/corosio/detail/op_base.hpp
  • include/boost/corosio/io/io_write_stream.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_socket.hpp
🚧 Files skipped from review as they are similar to previous changes (9)
  • include/boost/corosio/native/detail/select/select_scheduler.hpp
  • include/boost/corosio/native/detail/reactor/reactor_scheduler.hpp
  • src/corosio/src/tcp_socket.cpp
  • src/corosio/src/io_context.cpp
  • include/boost/corosio/local_endpoint.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_socket.hpp
  • include/boost/corosio/native/detail/iocp/win_udp_service.hpp
  • include/boost/corosio/native/detail/reactor/reactor_datagram_ops.hpp
  • include/boost/corosio/local_datagram_socket.hpp

Comment on lines +16 to +30
#if BOOST_COROSIO_HAS_EPOLL || BOOST_COROSIO_HAS_SELECT || BOOST_COROSIO_HAS_KQUEUE
#include <boost/corosio/native/detail/reactor/reactor_backend.hpp>
#endif

#if BOOST_COROSIO_HAS_EPOLL
#include <boost/corosio/native/detail/epoll/epoll_traits.hpp>
#endif

#if BOOST_COROSIO_HAS_SELECT
#include <boost/corosio/native/detail/select/select_traits.hpp>
#endif

#if BOOST_COROSIO_HAS_KQUEUE
#include <boost/corosio/native/detail/kqueue/kqueue_traits.hpp>
#endif
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep backend.hpp free of native POSIX headers.

This refactor makes the top-level public header depend on reactor_backend.hpp and the backend *_traits.hpp files, which transitively pull in native headers like <sys/socket.h> and <netinet/in.h>. That breaks the portable-header boundary for include/boost/corosio/backend.hpp. Please move the alias-only reactor_types mapping behind a lightweight shim, or otherwise keep the native traits out of this header.

As per coding guidelines "Headers in include/boost/corosio/, include/boost/corosio/detail/, and include/boost/corosio/concept/ MUST NOT include Unix/POSIX-specific headers such as <sys/socket.h>, <netinet/in.h>, <arpa/inet.h>, <unistd.h>, <sys/types.h>, or platform-specific <errno.h> constants".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/backend.hpp` around lines 16 - 30, The public header
backend.hpp is including reactor_backend.hpp and platform-specific *_traits.hpp
which pull in POSIX/native headers; to fix, remove those direct includes from
include/boost/corosio/backend.hpp and instead create a lightweight non-native
shim (e.g., a new header like
include/boost/corosio/detail/reactor_types_shim.hpp) that only contains the
alias-only mapping (reactor_types) or forward declarations without including
native headers, then have reactor_backend.hpp and the platform-specific
*_traits.hpp include the real native headers and the shim include the alias
mapping; update backend.hpp to include only the shim (or forward declaration) so
it no longer transitively pulls in <sys/socket.h> etc., and ensure symbols
referenced in backend.hpp (reactor_types) are resolved via the shim in
compilation units that need the real traits.

Comment on lines +110 to +121
capy::io_result<local_stream_socket> await_resume() const noexcept
{
if (token_.stop_requested())
return {make_error_code(std::errc::operation_canceled),
local_stream_socket()};

if (ec_ || !peer_impl_)
return {ec_, local_stream_socket()};

local_stream_socket peer(acc_.ctx_);
reset_peer_impl(peer, peer_impl_);
return {ec_, std::move(peer)};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t let a late stop request overwrite a completed accept.

await_suspend() already records pre-cancel into ec_, and the backend completion path records in-flight cancellation there too. Re-checking token_.stop_requested() in await_resume() means a stop request that arrives after a successful accept but before resumption turns success into cancellation and drops peer_impl_.

💡 Suggested fix
         capy::io_result<local_stream_socket> await_resume() const noexcept
         {
-            if (token_.stop_requested())
-                return {make_error_code(std::errc::operation_canceled),
-                        local_stream_socket()};
-
             if (ec_ || !peer_impl_)
                 return {ec_, local_stream_socket()};

             local_stream_socket peer(acc_.ctx_);
             reset_peer_impl(peer, peer_impl_);
             return {ec_, std::move(peer)};
         }
@@
         capy::io_result<> await_resume() const noexcept
         {
-            if (token_.stop_requested())
-                return {make_error_code(std::errc::operation_canceled)};
-
             if (!ec_ && peer_impl_)
                 peer_.h_.reset(peer_impl_);
             return {ec_};
         }

Also applies to: 158-165

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_acceptor.hpp` around lines 110 - 121, The
current await_resume() can turn a completed accept into cancellation by checking
token_.stop_requested() before verifying ec_ and peer_impl_; change the logic so
a successful accept (ec_ indicates success and peer_impl_ is non-null) is
honored even if stop_requested() became true afterward: first test if (ec_ ||
!peer_impl_) and only if that indicates failure consider returning the
operation_canceled when token_.stop_requested(); otherwise construct the
local_stream_socket via reset_peer_impl(peer, peer_impl_) and return the
successful result. Apply the same fix to the other await_resume() variant around
lines 158–165.

Comment on lines +64 to +99
/** Define backend hooks for local stream socket operations.

Platform backends (epoll, kqueue, select) derive from this
to implement socket I/O, connection, and option management.
*/
struct implementation : io_stream::implementation
{
virtual std::coroutine_handle<> connect(
std::coroutine_handle<> h,
capy::executor_ref ex,
corosio::local_endpoint ep,
std::stop_token token,
std::error_code* ec) = 0;

virtual std::error_code shutdown(shutdown_type what) noexcept = 0;

virtual native_handle_type native_handle() const noexcept = 0;

virtual native_handle_type release_socket() noexcept = 0;

virtual void cancel() noexcept = 0;

virtual std::error_code set_option(
int level,
int optname,
void const* data,
std::size_t size) noexcept = 0;

virtual std::error_code
get_option(int level, int optname, void* data, std::size_t* size)
const noexcept = 0;

virtual corosio::local_endpoint local_endpoint() const noexcept = 0;

virtual corosio::local_endpoint remote_endpoint() const noexcept = 0;
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Document the implementation hook contract.

These pure virtuals are a public extension surface, but their ownership, error-reporting, and cancellation semantics are still implicit. Please add brief docs for each method so backend implementations agree on what connect, release_socket, endpoint accessors, and option calls must guarantee.

As per coding guidelines, "Docstrings are required for all classes and functions in public headers in non-detail namespaces. Docstrings should include a brief description of purpose, document all parameters, return values, and any preconditions, postconditions, or exceptions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/local_stream_socket.hpp` around lines 64 - 99, Document
the public backend hook struct implementation and each pure virtual method
(connect, shutdown, native_handle, release_socket, cancel, set_option,
get_option, local_endpoint, remote_endpoint): add a brief docstring for the
struct describing its role as the platform backend interface, then for each
method document parameters and return values, ownership and lifetime rules (who
owns/relinquishes sockets or handles), error-reporting semantics (how
std::error_code is used and when it must be set), cancellation behavior and
thread-safety guarantees for cancel and connect (preconditions/postconditions
around stop tokens and coroutine handles), and any platform-specific
expectations for option calls (valid levels/optnames, how size is used/updated);
ensure the docs are placed in this public header near struct implementation so
backend implementers follow the same contract.

Comment on lines +67 to +104
if (this->svc_.scheduler().try_consume_inline_budget())
{
auto* socket_svc = this->svc_.stream_service();
if (socket_svc)
{
auto& impl =
static_cast<socket_final&>(*socket_svc->construct());
impl.set_socket(accepted);

impl.desc_state_.fd = accepted;
{
std::lock_guard lock(impl.desc_state_.mutex);
impl.desc_state_.read_op = nullptr;
impl.desc_state_.write_op = nullptr;
impl.desc_state_.connect_op = nullptr;
}
socket_svc->scheduler().register_descriptor(
accepted, &impl.desc_state_);

impl.set_endpoints(
this->local_endpoint_,
from_sockaddr_as(
peer_storage, peer_addrlen, Endpoint{}));

*ec = {};
if (impl_out)
*impl_out = &impl;
}
else
{
::close(accepted);
*ec = make_err(ENOENT);
if (impl_out)
*impl_out = nullptr;
}
op.cont_op.cont.h = h;
return dispatch_coro(ex, op.cont_op.cont);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Reset the stop callback on the inline accept fast path.

This branch resumes directly instead of going through complete_accept_op(), so op.stop_cb never gets cleared. A later stop request can still fire the stale callback against this->acc_ after the accept has already completed, which can cancel the next accept on the same object.

💡 Suggested fix
         if (this->svc_.scheduler().try_consume_inline_budget())
         {
+            op.stop_cb.reset();
             auto* socket_svc = this->svc_.stream_service();
             if (socket_svc)
             {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (this->svc_.scheduler().try_consume_inline_budget())
{
auto* socket_svc = this->svc_.stream_service();
if (socket_svc)
{
auto& impl =
static_cast<socket_final&>(*socket_svc->construct());
impl.set_socket(accepted);
impl.desc_state_.fd = accepted;
{
std::lock_guard lock(impl.desc_state_.mutex);
impl.desc_state_.read_op = nullptr;
impl.desc_state_.write_op = nullptr;
impl.desc_state_.connect_op = nullptr;
}
socket_svc->scheduler().register_descriptor(
accepted, &impl.desc_state_);
impl.set_endpoints(
this->local_endpoint_,
from_sockaddr_as(
peer_storage, peer_addrlen, Endpoint{}));
*ec = {};
if (impl_out)
*impl_out = &impl;
}
else
{
::close(accepted);
*ec = make_err(ENOENT);
if (impl_out)
*impl_out = nullptr;
}
op.cont_op.cont.h = h;
return dispatch_coro(ex, op.cont_op.cont);
}
if (this->svc_.scheduler().try_consume_inline_budget())
{
op.stop_cb.reset();
auto* socket_svc = this->svc_.stream_service();
if (socket_svc)
{
auto& impl =
static_cast<socket_final&>(*socket_svc->construct());
impl.set_socket(accepted);
impl.desc_state_.fd = accepted;
{
std::lock_guard lock(impl.desc_state_.mutex);
impl.desc_state_.read_op = nullptr;
impl.desc_state_.write_op = nullptr;
impl.desc_state_.connect_op = nullptr;
}
socket_svc->scheduler().register_descriptor(
accepted, &impl.desc_state_);
impl.set_endpoints(
this->local_endpoint_,
from_sockaddr_as(
peer_storage, peer_addrlen, Endpoint{}));
*ec = {};
if (impl_out)
*impl_out = &impl;
}
else
{
::close(accepted);
*ec = make_err(ENOENT);
if (impl_out)
*impl_out = nullptr;
}
op.cont_op.cont.h = h;
return dispatch_coro(ex, op.cont_op.cont);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@include/boost/corosio/native/detail/reactor/reactor_backend.hpp` around lines
67 - 104, The inline-accept fast path in reactor_backend.hpp skips
complete_accept_op(), leaving op.stop_cb set and allowing a stale stop callback
to fire against this->acc_ later; fix by clearing the stop callback before
returning from the inline branch—e.g., reset op.stop_cb (or call the op/accept
stop-clear helper) after setting *impl_out and before op.cont_op.cont.h = h /
return dispatch_coro(...), ensuring the accept object's stop state is cleared
for this accept.

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