C++ multipurpose networking library for linux
  • C++ 94.6%
  • JavaScript 5.4%
Find a file
2026-05-19 02:53:50 +02:00
additional browser wasm 2026-05-19 02:53:50 +02:00
examples/SimpleClient browser wasm 2026-05-19 02:53:50 +02:00
implementations browser wasm 2026-05-19 02:53:50 +02:00
interfaces browser wasm 2026-05-19 02:53:50 +02:00
tests browser wasm 2026-05-19 02:53:50 +02:00
.gitignore initial commit 2025-11-02 15:00:53 +01:00
LICENSE initial commit 2025-11-02 15:00:53 +01:00
project.cpp browser wasm 2026-05-19 02:53:50 +02:00
README.md browser wasm 2026-05-19 02:53:50 +02:00

Crafter.Network

A cross-platform C++ networking library providing TCP, QUIC, HTTP/3, and WebTransport client/server functionality with modern C++ features. Builds for native Linux and for the browser (wasm32-wasip1).

Overview

Crafter.Network is a C++ networking library designed for modern C++ applications. It provides TCP, QUIC, HTTP/3, and WebTransport-over-HTTP/3 capabilities with support for synchronous and asynchronous operations, making it suitable for a wide range of networking tasks including real-time multiplayer games. The same source compiles for native Linux (via msquic + POSIX sockets) and for the browser (via fetch() + WebTransport JS APIs); see Browser build.

Features

  • TCP Networking: Client and server implementations for raw TCP connections (native only).
  • QUIC Networking: Encrypted, multi-stream transport via msquic — reliable streams for control plane, unreliable datagrams for low-latency state sync.
  • HTTP/3: Client and server implementations on top of QUIC. Uses ALPN h3, QUIC bidi streams for requests/responses, the mandatory unidirectional control stream + SETTINGS frame (RFC 9114 §6.2.1), the (empty) QPACK encoder + decoder unidi streams required by stricter peers like Chromium, and a built-in QPACK codec (RFC 9204) with the full static table, Huffman decoding (RFC 7541), and literal-only emission. The QPACK dynamic table is unused. The client is interoperable with mainstream public h3 endpoints (cloudflare, nghttp3-based servers, etc.).
  • WebTransport (server): ListenerHTTP accepts extended-CONNECT sessions (:method=CONNECT, :protocol=webtransport) negotiated on the existing h3 listener — no separate port or alternate stack. Both draft-02 and draft-07+ identifier sets are advertised in SETTINGS so current Chrome/Edge browsers connect out of the box. Per-route handlers receive a WebTransportSession& and can multiplex bidirectional streams over the session.
  • Browser client: Same C++ API compiled to wasm32-wasip1 and routed through fetch() (for ClientHTTP) and WebTransport (for ClientQUIC). Listeners and raw TCP are not compiled in the browser build — the browser is client-only.
  • Asynchronous Operations: Thread poolbased async operations on native; the same *Async API on the browser side, where it's required (no synchronous I/O in the browser event loop).
  • Cross-Platform: Native Linux (POSIX sockets + msquic) and browser (wasm32-wasip1).
  • Modern C++: Uses C++20 modules, STL containers, and modern C++ features.

Architecture

The library follows a modular design using C++20 modules:

Core Modules

  • Crafter.Network: Main module that exports all components
  • Crafter.Network:ClientTCP: TCP client implementation (native only)
  • Crafter.Network:ListenerTCP: TCP server implementation (native only)
  • Crafter.Network:ClientHTTP: HTTP/3 client (ALPN h3). On browser builds this maps to fetch().
  • Crafter.Network:ListenerHTTP: HTTP/3 + WebTransport server (ALPN h3, native only)
  • Crafter.Network:HTTP: HTTP request/response types and constructors
  • Crafter.Network:ClientQUIC: QUIC connection (client + accepted-server side) with reliable streams and unreliable datagrams. On browser builds this maps to the WebTransport JS API.
  • Crafter.Network:ListenerQUIC: QUIC listener accepting incoming connections (native only). Also exports ComputeCertificateHashSHA256() and GetSelfSignedCertificatePath() for browser-peer cert pinning.
  • Crafter.Network:WebTransport: WebTransportSession type — the per-session handle handed to ListenerHTTP WT route handlers.
  • Crafter.Network:HTTP3: HTTP/3 wire-format helpers (QUIC varint, frame layer, QPACK static-table codec, WT frame/setting constants). Re-exported on native, excluded on browser (it uses throw and the wasm build is -fno-exceptions).

Components

TCP Components

ClientTCP

// Create a TCP client
Crafter::ClientTCP client("localhost", 8080);
client.Send("Hello World", 11);

// Receive data
std::vector<char> data = client.RecieveSync();

ListenerTCP

// Create a TCP listener
auto callback = [](Crafter::ClientTCP* client) {
    // Handle new connection
};
Crafter::ListenerTCP listener(8080, callback);
listener.ListenSyncSync(); // Synchronous listening

HTTP/3 Components

HTTP/3 runs over QUIC, which always requires TLS. Pass server credentials when constructing the listener (or set selfSigned = true for a development-only ephemeral cert) and matching client credentials when constructing the client (insecureNoServerValidation = true for self-signed servers).

ClientHTTP

Crafter::QUICClientCredentials creds;
creds.insecureNoServerValidation = true; // dev-only
Crafter::ClientHTTP client("localhost", 8082, creds);

Crafter::HTTPResponse response = client.Send(
    Crafter::CreateRequestHTTP("GET", "/", "localhost")
);
// response.status is the numeric status as a string, e.g. "200"

ListenerHTTP

std::unordered_map<std::string,
    std::function<Crafter::HTTPResponse(const Crafter::HTTPRequest&)>> routes;
routes["/hello"] = [](const Crafter::HTTPRequest&) {
    return Crafter::CreateResponseHTTP("200", "Hello World!");
};

Crafter::QUICServerCredentials creds;
creds.selfSigned = true; // dev-only
Crafter::ListenerHTTP listener(8082, creds, routes);
listener.Listen();

The HTTPRequest exposes the four HTTP/3 pseudo-headers (method, scheme, authority, path) as named struct fields rather than mixing them into the regular headers map. Routes are dispatched by exact match on path; unmatched paths return a synthetic 404.

WebTransport Components

ListenerHTTP has a WT-aware constructor overload that takes a second route map keyed by :path. When the map is non-empty the listener advertises both draft-02 (SETTINGS_ENABLE_WEBTRANSPORT = 0x2b603742) and draft-07+ (SETTINGS_WT_MAX_SESSIONS = 0xc671706a) identifiers in its SETTINGS frame so current browsers connect. An extended-CONNECT request (:method=CONNECT, :protocol=webtransport) whose :path matches a registered route is accepted with a 200 (no FIN), upgraded into a WebTransportSession, and dispatched on the ThreadPool. Plain HTTP/3 routes and WT routes coexist on the same listener and port.

std::unordered_map<std::string,
    std::function<Crafter::HTTPResponse(const Crafter::HTTPRequest&)>> httpRoutes;
std::unordered_map<std::string,
    std::function<void(Crafter::WebTransportSession&)>> wtRoutes;

wtRoutes["/echo"] = [](Crafter::WebTransportSession& session) {
    session.OnStream([](Crafter::QUICStream peerStream) {
        auto bytes = peerStream.RecieveUntilCloseSync();
        peerStream.SendSync(bytes.data(),
                            static_cast<std::uint32_t>(bytes.size()),
                            /*finish=*/true);
    });
};

Crafter::QUICServerCredentials creds;
creds.selfSigned = true; // dev-only, see "Self-signed certs & browser peers"
Crafter::ListenerAsyncHTTP listener(4443, creds, std::move(httpRoutes), std::move(wtRoutes));

Browser-initiated bidi/unidi WebTransport streams arrive via session.OnStream(...). The WT_BIDI (0x41) / WT_UNIDI (0x54) stream-type prefix and session-id varint are stripped before the user handler sees the stream; what the handler reads is pure session payload. Phase 1 covers session establishment + bidirectional streams; WebTransport datagrams and capsule-protocol control are stubbed for a follow-up.

Self-signed certs & browser peers

Passing QUICServerCredentials{selfSigned = true} makes the listener generate (and cache) an ephemeral cert at /tmp/crafter-network-quic-cert/{cert,key}.pem and reuse it across server restarts while it's still valid. The cert is shaped to satisfy Chromium's WebTransport.serverCertificateHashes rules: ECDSA P-256, signed with ECDSA-SHA256, validity ≤14 days (10 in practice), BasicConstraints CA:FALSE, KeyUsage digitalSignature, EKU serverAuth, SAN=DNS:localhost,IP:127.0.0.1,IP:::1. To let a browser peer pin this cert without trusting a CA:

auto certPath = Crafter::GetSelfSignedCertificatePath();
auto hash     = Crafter::ComputeCertificateHashSHA256(certPath); // 32-byte SHA-256 of cert DER
// Publish hash to the browser (e.g. write hex to a file the page can fetch);
// on the browser side feed it into QUICClientCredentials::serverCertificateHash.

For production use a real cert (certPath + keyPath on QUICServerCredentials).

Browser build

Crafter.Network compiles for wasm32-wasip1 via Crafter.Build; the build path is selected automatically when cfg.target.find("wasm") != npos. On that target:

  • CRAFTER_NETWORK_BROWSER is defined. Synchronous methods on ClientHTTP / QUICStream / ClientQUIC are not compiled — only the *Async variants are available.
  • ClientHTTP calls into crafterNetworkFetch (JS) which delegates to fetch(). An empty host is a same-origin sentinel: the path is passed through as the URL, so ClientHTTP("", 0).SendAsync({.path="/data.json"}, ...) fetches from the page origin.
  • ClientQUIC calls into crafterNetworkWtConnect which constructs a WebTransport(url, opts) against https://{host}:{port}/{alpn} (i.e. alpn is the WebTransport URL path on this target). QUICClientCredentials::serverCertificateHash is forwarded as serverCertificateHashes; leaving it zeroed makes the browser fall back to its normal trust store.
  • ListenerTCP, ListenerHTTP, ListenerQUIC, ClientTCP, and the sync receive/send paths are excluded — the browser is client-only.
  • additional/network-env.js is shipped alongside the produced .wasm and merged into the runtime's env import object by EnableWasiBrowserRuntime.

A worked example pairing a wasm browser client with a native server lives in examples/SimpleClient/. Build the server with crafter-build --target=x86_64-pc-linux-gnu, run it, then run crafter-build (no --target) to produce the wasm and serve it over HTTPS.

Build Configuration

The project is a single Crafter.Build configuration (crafter-network, ConfigurationType::LibraryStatic). Target selection and debug flags are handled by ApplyStandardArgs:

  • crafter-build — host native (x86_64-pc-linux-gnu by default), msquic + listeners + sync APIs.
  • crafter-build --target=wasm32-wasip1 — browser build, fetch + WebTransport, async-only API; defines CRAFTER_NETWORK_BROWSER, drops msquic.
  • crafter-build test [globs] — build and run tests under tests/.

Testing

The library includes tests covering:

  • HTTP/3 round-trip (ShouldSendRecieveHTTP) — canonical local client/server round-trip
  • HTTP/3 connection multiplexing (ShouldSendRecieveKeepaliveHTTP) — two requests share one QUIC connection
  • HTTP/3 large body transfer (ShouldSendRecieveLargeHTTP) — 10 MiB POST
  • HTTP/3 external interop (ShouldSend) — live fetch from cloudflare-quic.com:443, exercises real TLS chain validation, mandatory control stream, peer-initiated unidi streams, and QPACK Huffman decoding
  • QUIC reliable streams (ShouldSendRecieveQUICStream)
  • QUIC unreliable datagrams (ShouldSendRecieveQUICDatagram)
  • WebTransport echo (ShouldEchoWebTransport) — extended-CONNECT acceptance, draft-02 SETTINGS, bidi data stream framing (WT_STREAM 0x41 + session-id varint), and byte-for-byte echo

The external-interop test requires outbound UDP/443; if your network blocks it the test will fail.

Dependencies

  • Crafter.Thread: Thread pool management for asynchronous operations.
  • msquic (native target only) — fetched and built automatically as a Crafter ExternalDependency (no system install required). The build clones microsoft/msquic recursively into the per-project external cache, configures it via CMake (QUIC_TLS_LIB=quictls, tests/tools/perf disabled), and links the produced libmsquic into the QUIC and HTTP/3 modules. Skipped entirely on browser builds.
    • On Linux msquic links against libnuma (provided by the numactl package on most distros).
  • The self-signed-cert path used by tests/dev shells out to the openssl CLI; install openssl if you intend to use QUICServerCredentials{selfSigned = true}. The same path also produces the cert hash that browser peers need for serverCertificateHashes.
  • Browser build has no extra dependencies beyond Crafter.Build's wasi-browser runtime: HTTP delegates to the browser's fetch(), QUIC to its WebTransport. The JS glue lives in additional/network-env.js and is shipped alongside the produced .wasm.

Usage Example

#include <Crafter.Network>
#include <iostream>

int main() {
    Crafter::QUICClientCredentials creds;
    creds.insecureNoServerValidation = true;
    Crafter::ClientHTTP client("localhost", 8443, creds);

    auto response = client.Send(Crafter::CreateRequestHTTP("GET", "/", "localhost"));

    std::cout << "Status: " << response.status << std::endl;
    std::cout << "Body: " << response.body << std::endl;
    return 0;
}

License

This library is licensed under the GNU Lesser General Public License version 3.0. See LICENSE for more information.

Copyright (C) 2026 Catcrafts® Catcrafts.net