TLS

Introduction

xpp::net::TlsConfig and TlsContext provide RAII TLS configuration. Pass a TlsContext to TcpStream::connect() to enable TLS — the handshake is transparent.

Example — .await()

#include <xpp/net/tls.h>

xpp::EventLoop loop;
xpp::WaitScope scope(loop);

xpp::net::TlsContext ctx(xpp::net::TlsConfig::client());
auto conn = xpp::net::TcpStream::connect("example.com:443", ctx).await();

Example — co_await (C++20)

xpp::net::TlsContext ctx(xpp::net::TlsConfig::client());
auto conn = co_await xpp::net::TcpStream::connect("example.com:443", ctx);

API Reference

TlsConfig

MethodReturnsDescription
client()TlsConfigClient defaults (system CA, verify on)
client_insecure()TlsConfigClient that skips peer verification
server(cert, key)TlsConfigServer config with cert + key paths
server(cert, key, ca)TlsConfigServer config with CA (for mTLS)
with_cert(path)TlsConfig&Builder: set cert path
with_key(path)TlsConfig&Builder: set key path
with_ca(path)TlsConfig&Builder: set CA path
with_key_password(pw)TlsConfig&Builder: set key password
with_alpn(protocols)TlsConfig&Builder: set ALPN list
with_skip_verify(bool)TlsConfig&Builder: toggle verification
raw()const xTlsConf*Underlying libx config

Each with_* builder has two overloads, selected by ref-qualifier:

  • with_*(...) & → returns TlsConfig&, modifies in-place (lvalue chain)
  • with_*(...) && → returns TlsConfig&&, enables move (rvalue chain)
// Rvalue chain: temporary factory → && overloads → move at end
auto conf = TlsConfig::client().with_cert(...).with_key(...);

// Lvalue chain: named variable → & overloads → modify in-place
TlsConfig conf = TlsConfig::client();
conf.with_ca("/custom/ca.pem").with_alpn({"h2", "http/1.1"});

TlsContext

MethodReturnsDescription
TlsContext(conf)TlsContextCreate context from TlsConfig
TlsContext(xTlsConf*)TlsContextCreate from raw libx config
reload(conf)intHot-reload certificates (0 = success)
raw()xTlsCtxUnderlying libx context
is_valid()boolConstruction succeeded
operator bool()boolSame as is_valid()

How it works

TlsConfig is a builder that owns the string storage (cert path, key path, CA path, key password, ALPN protocols). It wraps xTlsConf (a POD of pointers).

TlsContext calls xTlsCtxCreate in its constructor and xTlsCtxDestroy in its destructor. The mode (client or server) is determined automatically by libx: if both cert and key are set, server mode; otherwise client mode.

When passed to TcpStream::connect(), the xTlsCtx handle is set in xTcpConnectConf::tls_ctx. libx's xTcpConnect does the TLS handshake transparently.

Usage Examples

Client with system CA — .await()

xpp::net::TlsContext tls(xpp::net::TlsConfig::client());
auto conn = xpp::net::TcpStream::connect("example.com:443", tls).await();
conn.write("GET / HTTP/1.0\r\n\r\n", 18).await();

Client with system CA — co_await (C++20)

xpp::Promise<void> https_fetch() {
    xpp::net::TlsContext tls(xpp::net::TlsConfig::client());
    auto conn = co_await xpp::net::TcpStream::connect("example.com:443", tls);
    co_await conn.write("GET / HTTP/1.0\r\nHost: example.com\r\n\r\n", 40);
    char buf[4096];
    ssize_t n = co_await conn.read(buf, sizeof(buf));
    printf("%.*s\n", (int)n, buf);
}

Server with certificate

xpp::net::TlsContext tls(xpp::net::TlsConfig::server("cert.pem", "key.pem"));

Builder pattern

xpp::net::TlsConfig conf = xpp::net::TlsConfig::client()
    .with_ca("/custom/ca.pem")
    .with_alpn({"h2", "http/1.1"});
xpp::net::TlsContext ctx(conf);

mTLS (mutual TLS)

xpp::net::TlsContext server_tls(
    xpp::net::TlsConfig::server("server.pem", "server.key", "ca.pem"));

xpp::net::TlsConfig client_conf = xpp::net::TlsConfig::client()
    .with_cert("client.pem").with_key("client.key");
xpp::net::TlsContext client_tls(client_conf);

Connect with error handling — .await()

xpp::net::TlsContext tls(xpp::net::TlsConfig::client());
auto conn = xpp::net::TcpStream::connect("example.com:443", tls).await();
if (!conn.is_open()) { /* handle failure */ }
conn.write("hello", 5).await();

Connect with error handling — co_await (C++20)

xpp::Promise<void> connect_or_fallback() {
    xpp::net::TlsContext tls(xpp::net::TlsConfig::client());
    auto conn = co_await xpp::net::TcpStream::connect("example.com:443", tls);
    if (!conn.is_open()) { co_return; }
    co_await conn.write("hello", 5);
}