Stable Release
Major release: build system migration, extensive security hardening, and disconnect diagnostics.
Build and CI
- Build system migrated from premake to CMake (3.16+).
cmake -B build && cmake --build build -j, executables inbin/. See BUILDING.md. - Full CI: Linux/macOS/Windows debug + release, ASan+UBSan+LSan, MemorySanitizer, bounded fuzzing and a sanitized soak on every PR, plus a nightly extended-fuzzing workflow with a persistent corpus.
Security hardening
- The vendored libsodium is pruned to the used subset, aligned to upstream 1.0.20, and amalgamated into a single header/source pair, with AEAD known-answer tests.
- Five libFuzzer targets cover every untrusted parser, including stateful and structure-aware targets over the connection deserializer. Fuzzing found and fixed: a remote heap overflow in block reassembly, a
ChannelPacketDataunion misread, an uninitialized read ofblock.messageType, debug-build asserts reachable from the wire, allocation-failure crashes, a network-simulator packet leak, a block fragment-count overflow, and undefined behavior from unaligned bit-reader reads. Regression tests cover each. - New SECURITY.md with private vulnerability reporting.
New features
- Client/server configuration is validated at startup in debug builds: invalid configs fail loudly with the field name and required value, and compile away entirely in release.
- The server tracks why each client slot was last disconnected:
Server::GetClientDisconnectReason(clientIndex)distinguishes kicked, clean disconnect, timed out (via netcode v1.3.2), and specific connection errors (serialize failure, desync, out of memory, …), recorded beforeOnServerClientDisconnectedfires. - The client reports why it ended up disconnected:
Client::GetDisconnectReason()preserves the detailed netcode failure states — connection denied (server full), connect token expired/invalid, request/response/connection timed out, disconnected by server — so games can tell the player what actually happened. - Insecure connect tokens now use a longer expiry than their timeout, so a failed insecure connect reports "connection request timed out" like a matcher token would.
Vendored libraries
- serialize v1.3.1, reliable v1.3.0, netcode v1.3.2.
Documentation
- USAGE.md: message ownership rules, disconnect reason handling, config validation. README: design assumptions (single-threaded, ~100 players or less, identical client/server config). CONTRIBUTING.md added; BUILDING.md covers CMake and Windows header notes.
Validated with the full CI matrix plus a 5.5-million-iteration soak under AddressSanitizer and UndefinedBehaviorSanitizer at high packet loss, run clean before tagging.
What's Changed
- Fix unaligned dword reads (UB) in BitReader on the packet receive path by @gafferongames in #251
- sodium: prune to used subset, align to 1.0.20, keep all optimized impls, harden, bundle by default by @gafferongames in #252
- sodium: amalgamate bundled libsodium to a single sodium.h + sodium.c (and re-land SIMD/bundle work) by @gafferongames in #253
- Fix network-simulator duplicate-packet leak and block fragment-count overflow by @gafferongames in #254
- Add GitHub Actions CI (Linux, macOS, Windows, sanitizers) by @gafferongames in #255
- README: add CI build status badge by @gafferongames in #256
- Fix minor audit findings (bounds assert, unchecked reassembly alloc, init leak) by @gafferongames in #257
- Remove vestigial SODIUM_STATIC define in yojimbo.cpp by @gafferongames in #258
- Fix return type in hand-declared netcode_enable_packet_tagging prototype by @gafferongames in #259
- yojimbo.cpp: include netcode.h/reliable.h instead of hand-declared prototypes by @gafferongames in #260
- matcher: fix always-true expiry check; safer error/key defaults by @gafferongames in #261
- Add CLAUDE.md working notes and in-progress fuzz harnesses by @gafferongames in #262
- Fuzz the untrusted-input parsers; fix three bugs they found by @gafferongames in #263
- Add time-boxed sanitized soak to CI by @gafferongames in #264
- Add seed corpora for the fuzz targets by @gafferongames in #265
- Add SECURITY.md disclosure policy by @gafferongames in #266
- Add .clang-format encoding the existing house style by @gafferongames in #267
- Add netcode connect-token fuzz target by @gafferongames in #268
- Add richer fuzz seeds: connection-request packet and multi-fragment block by @gafferongames in #269
- USAGE.md: document the mandatory InitializeYojimbo/ShutdownYojimbo by @gafferongames in #270
- Add CONTRIBUTING.md, fix build-doc drift, record a library assessment by @gafferongames in #271
- Fix uninitialized block.message deref on a disabled-blocks channel by @gafferongames in #272
- Make fuzz_connection stateful with config + full-serialize message coverage by @gafferongames in #273
- Add structure-aware fuzz_connection_structured target by @gafferongames in #274
- Add MemorySanitizer CI job (and fix the uninitialized read it found) by @gafferongames in #275
- Add a nightly extended-fuzzing workflow with dictionaries by @gafferongames in #276
- test: print the random seed and allow passing it to reproduce failures by @gafferongames in #278
- Replace premake with CMake by @gafferongames in #277
- CLAUDE.md: the libsodium amalgamation is an agent task, not a missing script by @gafferongames in #279
- Make ChannelPacketData safe by construction: de-union message/block by @gafferongames in #280
- Don't assert on an over-budget packet on the read path (remote DoS) by @gafferongames in #281
- CLAUDE.md: record paused work + public-header encapsulation invariant by @gafferongames in #282
- Fix remote heap overflow in block reassembly and bracketed IPv6 parse by @gafferongames in #283
- Harden read-path message-array allocs and fix network-sim ring draining by @gafferongames in #284
- Harden send-path allocator-exhaustion handling; stop tracking build artifacts by @gafferongames in #285
- Fuzz allocation failures + adversarial block fragments; fix two OOM crashes by @gafferongames in #286
- Fix NULL-client crash in Client::Connect / ConnectLoopback on socket failure by @gafferongames in #287
- Fix NULL-client crash in Client::IsLoopback when disconnected by @gafferongames in #288
- Validate config at startup, document design assumptions, harden .gitignore by @gafferongames in #289
- Add per-client slot disconnect reason to the server by @gafferongames in #290
- Add disconnect reason to the client by @gafferongames in #291
- Document disconnect reasons and config validation by @gafferongames in #292
- Make insecure connect tokens expire like matcher tokens by @gafferongames in #293
- Split server disconnect reason: timed out vs clean disconnect by @gafferongames in #294
- Pre-release cleanups: leak check via assert, no config-sized allocas, loopback kick reason, Windows docs by @gafferongames in #295
- Remove the remaining config-sized allocas from message serialization by @gafferongames in #296
- CLAUDE.md: remove the concerns section — all concerns fully addressed by @gafferongames in #297
- Bump version to 1.5.0 by @gafferongames in #298
Full Changelog: v1.4.0...v1.5.0