Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |
Launch files
Messages
Services
Plugins
Recent questions tagged wirestead at Robotics Stack Exchange
Package Summary
| Version | 0.10.0 |
| License | Apache-2.0 |
| Build type | CMAKE |
| Use | RECOMMENDED |
Repository Summary
| Checkout URI | https://github.com/wirestead/wirestead.git |
| VCS Type | git |
| VCS Version | main |
| Last Updated | 2026-10-06 |
| Dev Status | DEVELOPED |
| Released | RELEASED |
| Contributing |
Help Wanted (-)
Good First Issues (-) Pull Requests to Review (-) |
Package Description
Additional Links
Maintainers
- Jinwoo Sung
Authors
Wirestead™
Robust, simple async communication for modern C++20.
Serial · TCP · UDP · UDS — one API for all four, on Linux, macOS and Windows, x64 and arm64.
Description
wirestead provides a unified interface for asynchronous communication across different transports, allowing applications to switch between Serial, TCP, UDP, and UDS with minimal code changes. The public C++ API exposes builders and wrappers for all four transport families.
The project prioritizes API clarity, predictable runtime behavior, and stability over rapid feature expansion.
#include <iostream>
#include <wirestead/wirestead.hpp>
auto client = wirestead::tcp_client("127.0.0.1", 8080)
.max_retries(3)
.on_data([](const wirestead::MessageContext& ctx) {
std::cout << "received " << ctx.data().size() << " bytes\n";
})
.build();
client->start_sync();
client->send("hello");
The same shape builds a serial port, a UDP socket or a UDS endpoint — see Quick Start.
Security note: transports send data in plaintext by default. TCP can do TLS in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON- server and client, with the client verifying the server; UDP, Serial and UDS cannot, and DTLS is not supported. See Security and Threat Model before usingwiresteadover an untrusted network.
How Wirestead compares
Wirestead is a multi-transport async library. Most alternatives are either a single-transport library or a set of ready-to-run ROS nodes, so the useful question is usually which shape you need rather than which has more features.
| Transports | Async | Platforms | Install | |
|---|---|---|---|---|
| Wirestead | Serial, TCP, UDP, UDS | yes, one io_context model across all four |
Linux, macOS, Windows — x64 and arm64 | vcpkg, FetchContent, PyPI |
| transport_drivers | Serial, UDP | yes (standalone Asio) | Linux (ROS 2) | rosdep / apt |
| libserial | Serial | no | Linux only | apt install libserial-dev |
| serialib | Serial | no | Linux, Windows | copy two files |
| Boost.Asio directly | everything | yes | everywhere | you already have it |
Wirestead fits best when one application speaks over more than one transport — a serial sensor, a TCP command server, a UDP telemetry feed — and you would otherwise write reconnect, buffering and framing three times against three different APIs. The four transports share one API, so switching between them is a builder change rather than a rewrite. It runs on Linux, macOS and Windows alike, which the serial-only libraries above do not, and latency is published per release on real hardware: see the benchmark releases. The Feature Highlights below cover what it adds on top of Asio.
When to use something else
-
You only need serial, on Linux.
apt install libserial-devand you are done. Wirestead pulls in Boost and asks you to build it; that is a poor trade for one serial port. - You want the smallest possible dependency. serialib is two files with no dependencies at all.
-
You are on ROS 2 and want a bridge, not a library.
transport_driversshipsserial_bridgeandudp_bridge_node_exe— running executables that move bytes between a device and a topic. Wirestead gives you a library to write your own node against;wirestead_rosprovides a lifecycle shutdown gate,RuntimeStatsreporting ontodiagnostic_updater, and a reference lifecycle driver, but no drop-in bridge node. If a bridge is all you need,transport_driversis less work. - You know Asio well and want direct control. Any wrapper is in your way. Wirestead is a wrapper.
Feature Highlights
- Unified transport surface: Consistent builders and wrappers for TCP client/server, UDP, Serial, and UDS.
- Callback-scoped data views: Avoid unnecessary copies during callbacks, with explicit ownership-copy helpers for stored data. Each payload carries the time it arrived, so a timestamp does not have to be taken after the fact.
-
Message framing: Line-delimited, start/end pattern, and length-prefixed framers, or your own
IFramer. -
Optional TLS: TCP client and server in a build configured with
-DWIRESTEAD_ENABLE_TLS=ON, with the client verifying the server. - Fluent API with CRTP Builders: Type-safe configuration with improved method chaining.
- Built for devices: Serial low-latency mode and RS-485, UDP multicast, a per-channel silence age for spotting a sensor that stopped talking, and a hook for putting the io threads on a real-time policy. See Tuning.
-
Tested runtime behavior: Unit, integration, and end-to-end test suites are part of the repository and documented in
test/.
Requirements
- C++20 compiler: GCC 10+, Clang 14+, or MSVC 2022. CMake enforces these and fails the configure step below them. CI builds GCC on Ubuntu 22.04 and 24.04, Clang on Ubuntu 24.04 and macOS, and MSVC on Windows, each on x64 and arm64.
- CMake 3.12 or later for plain builds; CMake 3.21 or later for the repository presets
- Boost 1.74.0 or later, which covers the system packages on Ubuntu 22.04 (1.74), RHEL 9 (1.75) and Ubuntu 24.04 (1.83). vcpkg remains the recommended dependency supplier; CI builds against the 1.74 floor as well as current Boost.
📦 Installation
vcpkg (recommended)
vcpkg install wirestead
CMake FetchContent
include(FetchContent)
FetchContent_Declare(wirestead
GIT_REPOSITORY https://github.com/wirestead/wirestead.git
GIT_TAG v0.10.0)
FetchContent_MakeAvailable(wirestead)
target_link_libraries(your_target PRIVATE wirestead::wirestead)
Python
pip install wirestead
File truncated at 100 lines see the full file
Changelog
All notable changes to Wirestead are documented in this file.
This project follows the Keep a Changelog section names where practical. The
core C++ API is still pre-1.0; see docs/api_stability.md for compatibility
and ABI policy.
Unreleased
Fixed
- Destroying a running wrapper now completes its shutdown on the destroying thread. A callback in flight could otherwise hold the last reference, so the transport was torn down on its own io thread, detached it and destroyed the io_context it was still running - an intermittent segfault at process exit (#613).
- Move-assigning over a running wrapper completes the previous object’s shutdown on the assigning thread, as destruction does.
- Correct the serial DTR documentation:
dtr(false)does not stop an Arduino from rebooting when the port opens, since Linux asserts DTR before the setting applies, and every reopen reboots it again.docs/tuning.mdnow also says to setrx_idle_timeoutabove such a board’s reboot time (#710).
v0.10.0 - 2026-10-02
Changed
- Amortize Serial and TCP/UDS server-session send-accounting locks over each gather batch, preserving request boundaries, reset epochs and stop/loss causes.
-
Clarify that callback/executor stop is request-only; outside concurrent stop callers wait for completion before destruction, restart or stopped-only settings.
-
Reduce TCP/UDS client send-accounting lock acquisitions to once per gather batch at handoff and completion, preserving partial-prefix, reset-epoch and stop/loss accounting.
-
Restore send throughput lost since v0.9.6 without changing send or accounting policies. No transport holds its admission lock across a write system call, and TCP/UDS client write handoff and successful completion no longer take it at all: the send-accounting ledger fences handoff against stop and connection loss. The ledger’s per-request bookkeeping is O(1) and briefly spins instead of sleeping under contention. Unpressured wrapper sends avoid redundant capacity-wait preparation and channel reference-count updates.
-
Index send-accounting entries by request identity in a reusable ring instead of a hashed node map. Steady traffic no longer allocates or hashes per request; accounting semantics are unchanged. Sparse retention bounds metadata when rollback or UDP expiry retires later requests behind an older pending write.
-
Cache TCP client write-submission executor properties instead of adapting the strand on every send. Enqueue handlers remain asynchronous, serialized on the same strand and owning the transport.
-
Defer TCP/UDS client blocking-send executor checks and owning connection references to the capacity-wait path. Rejection reasons and the connection pinned at entry are unchanged.
-
Breaking behavior: invalid configuration is rejected before application; native construction no longer silently clamps it. Settings outside the explicit runtime allowlist require completed stop. Native callback exceptions are logged and contained without recursive error events; opt-in Serial/UDP callback stop remains quiet. See docs/configuration_and_callbacks.md.
-
Breaking behavior: established client loss emits one disconnect even when retry succeeds; start failure or retry exhaustion emits one terminal error. UDP virtual-session idle expiry now uses the concrete on_session_expired callback instead of on_disconnect. See docs/lifecycle_events.md.
-
Breaking behavior: built-in wrappers enforce configurable aggregate receive storage, framing-buffer and server session limits. TCP/UDS end only the affected connection; Serial follows its reopen policy; UDP drops the new input while preserving prior built-in framing/batch state. Concrete receive_stats exposes cause-separated receive counters without changing RuntimeStats or IFramer. Receive-limit changes require completed stop. See docs/receive_memory_limits.md for defaults, costs and excluded storage.
-
Breaking behavior: built-in plain native writes preserve accepted work under BestEffort instead of implicitly dropping older queued data. Ordinary BestEffort wrapper sends still reject new requests under pressure. Blocking wrapper sends retry capacity races without a five-attempt limit, with a brief wait between retries; callbacks still never wait. Plain/try reservations and pending transfers share hard-limit accounting. See docs/blocking_queue_policy.md.
-
Breaking ABI: SendAccounting gains session_expiry, changing RuntimeStats and embedded ledger layouts; rebuild C++ consumers. UDP server client_stats now exposes virtual-session totals. Expiry discards accepted waiting work, lets active datagrams retain their completion outcome, and leaves other peers untouched. Socket totals retain expired/stopped contributors exactly once; reset and wrapper restart isolate statistics epochs. Shared-socket pressure remains shared in peer snapshots. See docs/udp_send_accounting.md.
- Breaking ABI: TCP/UDS server sessions now expose logical-request send accounting and change their exported class layouts; rebuild C++ consumers. Server aggregates retain closed and stopping sessions exactly once, including legacy totals previously lost at explicit stop. Reset includes retiring contributors. TCP handshake/read state changes and TCP/UDS write completions explicitly return to the session strand; short writes/initiation exceptions terminate outstanding requests. Queue completion preserves concurrent send reservations. See docs/tcp_send_accounting.md.
File truncated at 100 lines see the full file
Package Dependencies
System Dependencies
Dependant Packages
| Name | Deps |
|---|---|
| wirestead_ros |