C++ SDK
Integrate rstream in native C++ services, gateways, and embedded software.
The C++ SDK targets native environments where performance, runtime control, and deep integration with existing networking stacks matter.
github.com/rstreamlabs/rstream-cppNative C++ SDK for Boost.Asio, Boost.Beast, bytestream tunnel workflows, and embedded agents.This page focuses on the C++ SDK surface. For raw HTTP routes, see APIs. For event-stream semantics, see Signaling.
The Go SDK remains the reference SDK and covers the broadest surface today. The C++ SDK is built for native integration inside an existing process, with Boost.Asio and Boost.Beast friendly async APIs, long-lived bytestream tunnel workflows, and compatibility with the same config and project model as the CLI.
Interface Model
The C++ SDK exposes two complementary interfaces.
Use the generic io_rstrm networking interface when existing code already expects Boost.Asio-style sockets, acceptors, endpoints, and resolvers. The main types are rstream::io_rstrm::socket, rstream::io_rstrm::acceptor, rstream::io_rstrm::endpoint, and rstream::io_rstrm::resolver. This path feels close to TCP code because socket behaves as an asynchronous stream socket and can be passed to Boost.Beast reads and writes.
Use the tunnel-specific interface when the process should explicitly connect to the engine, create tunnel properties, inspect forwarding addresses, and own tunnel lifecycle. The main types are rstream::io_rstrm::client, rstream::io_rstrm::tunnel, and rstream::io_rstrm::tunnel_properties.
The two interfaces are designed to work together. client.async_create_tunnel() returns a tunnel, tunnel.async_accept() fills an io_rstrm::socket, and an io_rstrm::socket can also dial an io_rstrm::endpoint directly.
Published and Private Tunnels
The SDK supports the two main tunnel patterns used by rstream. Published tunnels expose a forwarding address through the edge. Private tunnels are consumed by tunnel id or name through rstream-native dialing. Tunnel properties still carry policy-related configuration such as labels and publication mode, while enforcement remains the responsibility of the rstream edge.
Async Model
The SDK follows the Boost.Asio asynchronous model. Core objects use executors, strands, and async_initiate, which makes integration natural in codebases that already use Asio.
Codebases that already use Beast, Asio coroutines, or executor-based networking components can integrate rstream-cpp directly.
Build Prerequisites
A typical source build uses a C++20 compiler, CMake, Conan 2.x, Python 3.x, and usually Ninja as the build generator. Dependencies are resolved through Conan/CMake integration and include Boost, OpenSSL or LibreSSL, yaml-cpp, nlohmann_json, and spdlog.
Install with Conan
Applications can consume the SDK from the rstream Conan remote without cloning rstream-cpp.
conan profile detect --force
conan remote add rstream https://nexus.rstream.io/repository/conan -fUse rstream/[>=1.9.0 <2] for current C++ tunnel integrations. Application recipes should disable SDK utility binaries when they only need the libraries, sockets, acceptors, and tunnel client APIs.
requires = (
"boost/[>=1.83 <2]",
"rstream/[>=1.9.0 <2]",
)
default_options = {
"rstream/*:build_bins": False,
"rstream/*:enable_testing": False,
"rstream/*:with_maxminddb": False,
"rstream/*:with_ncurses": False,
}build_bins defaults to True in the SDK package so release builds still publish the complete toolset. Application samples set it to False because they link the SDK as a library and do not need to build utilities such as the SDK netcat or benchmark binaries during a Conan source fallback.
Build From Source
Local CMake build:
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release
cmake --build build
cmake --build build --target check
cmake --install build --prefix ./build/releaseConan package build:
conan profile detect --force
conan config install conan/config
conan create . -u --build=missing -pr:b default -pr:h defaultThe repository also provides packaging helpers such as build-conan-cross.sh, build-docker-conan.sh, and deploy.py for producing distributable artifacts.
Using the SDK in CMake
After installation or Conan consumption, integrate through find_package and link rstream::rstream.
find_package(rstream CONFIG REQUIRED)
add_executable(my_app main.cpp)
target_link_libraries(my_app PRIVATE rstream::rstream)Authentication and Project Setup
The C++ SDK uses the same runtime config model as the rstream CLI.
Typical developer-machine setup:
rstream login
rstream project use <project-endpoint> --defaultThe SDK then reads the same ~/.rstream/config.yaml file and context selection model as the CLI.
Token authentication and mTLS agent authentication are mutually exclusive for the control-channel connection. When both mTLS variables are set, the SDK authenticates that connection with the client certificate and does not use a stored context token; setting RSTREAM_AUTHENTICATION_TOKEN at the same time is an error. Engine HTTP API requests use token authentication.
The shared config schema also includes transport.proxy for SDKs that can proxy the engine connection. The C++ SDK parses that block so the same YAML file shape can be shared across SDKs, but it does not implement HTTP CONNECT, SOCKS5, or environment-derived proxying for io-rstrm engine connections today. If the selected context or environment requests a proxy, configuration resolution fails instead of silently opening a direct connection.
PKCS#11 mTLS
The C++ SDK supports PKCS#11-backed mTLS agent authentication when it is built with PKCS#11 support and an OpenSSL PKCS#11 provider is available at runtime. The configuration uses the same auth.mtls.storage.kind: pkcs11 shape as the Go SDK: the SDK loads the provider, selects the token and private key, and asks the module to sign TLS handshake data without exporting the private key.
Use this model for embedded devices, smart cards, YubiKeys, HSMs, and SoftHSM validation tokens. See Credential Storage for the portable config fields, provider naming, PIN handling, and unsupported-mode behavior.
Published HTTP Server with the Tunnel Interface
The example below creates a published HTTP tunnel with client.async_create_tunnel(), accepts incoming rstream streams with tunnel.async_accept(), and serves a simple Beast response through an io_rstrm::socket.
#include <csignal>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/beast/core.hpp>
#include <boost/beast/http.hpp>
#include <rstream/io-rstrm/client.hpp>
#include <rstream/io-rstrm/io-rstrm.hpp>
#include <rstream/io-rstrm/socket.hpp>
namespace asio = boost::asio;
namespace http = boost::beast::http;
namespace rstrm = rstream::io_rstrm;
asio::awaitable<void> session(rstrm::socket socket) {
http::request<http::string_body> req;
boost::beast::flat_buffer buffer;
co_await http::async_read(socket, buffer, req, asio::use_awaitable);
http::response<http::string_body> res{http::status::ok, req.version()};
res.set(http::field::content_type, "text/plain");
res.body() = "Hello from rstream-cpp";
res.prepare_payload();
co_await http::async_write(socket, res, asio::use_awaitable);
}
asio::awaitable<void> listener() {
auto executor = co_await asio::this_coro::executor;
rstrm::client client(executor);
co_await client.async_connect(asio::use_awaitable);
rstrm::tunnel_properties properties = {
.m_publish = true,
.m_protocol = rstrm::protocol::http,
};
auto tunnel = co_await client.async_create_tunnel(
properties,
asio::use_awaitable
);
while (true) {
rstrm::socket socket(executor);
rstrm::endpoint peer;
co_await tunnel.async_accept(socket, peer, asio::use_awaitable);
asio::co_spawn(executor, session(std::move(socket)), asio::detached);
}
}Private Tunnel Pattern
Private tunnels are dialed through an io_rstrm::endpoint. The endpoint carries the tunnel id or name and the engine address that the SDK should use for the rstream control path.
rstrm::client client(executor);
co_await client.async_connect(asio::use_awaitable);
boost::system::error_code ec;
auto server = client.address(ec);
if (ec) {
throw boost::system::system_error(ec);
}
rstrm::endpoint endpoint = {
.m_id_name = std::string("private-api"),
.m_server_address = server,
};
rstrm::socket socket(executor);
co_await socket.async_connect(endpoint, asio::use_awaitable);
co_await asio::async_write(socket, asio::buffer("ping", 4), asio::use_awaitable);This is the native C++ equivalent of dialing a private rstream tunnel by name. The application receives an asynchronous stream socket and can continue with the same framing or protocol code it would use on another Boost.Asio socket.
Generic Acceptor Interface
For code that prefers an acceptor-shaped API, configure settings_acceptor, bind an endpoint, and accept io_rstrm::socket instances.
#include <rstream/io-rstrm/acceptor.hpp>
rstrm::settings_acceptor settings;
settings.m_tunnel_properties.m_name = std::string("beast-http");
settings.m_tunnel_properties.m_publish = true;
settings.m_tunnel_properties.m_protocol = rstrm::protocol::http;
rstrm::acceptor acceptor(executor, settings);
auto endpoint = rstrm::make_endpoint(
boost::optional<std::string>{"beast-http"},
boost::optional<std::string>{}
).value();
acceptor.open(endpoint, ec);
if (ec) {
throw boost::system::system_error(ec);
}
acceptor.bind(endpoint, ec);
if (ec) {
throw boost::system::system_error(ec);
}
acceptor.listen(boost::asio::socket_base::max_listen_connections, ec);
if (ec) {
throw boost::system::system_error(ec);
}
rstrm::socket peer(executor);
rstrm::endpoint remote;
co_await acceptor.async_accept(peer, remote, asio::use_awaitable);Use this interface when adapting code that already abstracts over TCP acceptors and stream sockets. Use client and tunnel directly when the application needs tighter control over tunnel creation, labels, forwarding addresses, or reconnect behavior.
Examples
The main repository includes examples for published HTTP servers, private bytestream tunnels, Boost/Asio integration patterns, and packaging and Conan usage.
Environment variables
The C++ SDK follows the runtime resolution model used by the CLI. Explicit SDK options are read first, then environment variables, then the selected context from RSTREAM_CONFIG or the default ~/.rstream/config.yaml file.
| Variable | Purpose |
|---|---|
RSTREAM_CONFIG | Path to the rstream configuration file. If unset, the SDK falls back to ~/.rstream/config.yaml. |
RSTREAM_CONTEXT | Name of the context to select during config-based resolution. |
RSTREAM_ENGINE_ADDRESS | Highest-priority C++ runtime engine address override. |
RSTREAM_ENGINE | Secondary engine override. When provided as host:port, the C++ SDK expands it to the default TCP/TLS runtime address form. |
RSTREAM_AUTHENTICATION_TOKEN | Authentication token override when token behavior is not fixed in SDK options. |
RSTREAM_MTLS_CERT_FILE | Client certificate file for mTLS agent authentication. |
RSTREAM_MTLS_KEY_FILE | Client private key file for mTLS agent authentication. |
RSTREAM_AUTHENTICATION_TOKEN and the mTLS certificate/key pair are mutually exclusive for the agent control-channel connection. When both mTLS variables are set, config-derived tokens are not used for that connection. Engine HTTP API requests still require token authentication.