Skip to content

Migrate QuicCommunication onto shared ba-quic-lib transport - #69

Open
danprudky wants to merge 12 commits into
masterfrom
BAF-1723/Migrate-onto-the-QUIC-lib
Open

Migrate QuicCommunication onto shared ba-quic-lib transport#69
danprudky wants to merge 12 commits into
masterfrom
BAF-1723/Migrate-onto-the-QUIC-lib

Conversation

@danprudky

@danprudky danprudky commented Jul 19, 2026

Copy link
Copy Markdown
Contributor
  • Replace the hand-rolled MsQuic client wrapper in QuicCommunication (registration/configuration/connection/stream callbacks, manual send buffers, per-stream reassembly) with bringauto::quic::QuicClient from the new ba-quic-lib dependency, eliminating ~300 lines of manual msquic plumbing.
  • Preserve existing connection-recovery behavior on top of the new transport: initializeConnection() still clears stale inbound/outbound queues before a fresh attempt and blocks until the handshake completes (or times out) so callers get the same synchronous "connected on return" contract as MQTT; peer-initiated shutdown still transitions to CLOSING before the final disconnect.
  • Drop QuicSettingsParser entirely — the quic-settings JSON is now passed straight through to bringauto::quic::QuicSettings::fromJson, which also warns on unrecognized keys instead of silently ignoring them. - Swap BA_PACKAGE_LIBRARY(msquic) / FIND_PACKAGE(msquic CONFIG REQUIRED) for a new cmake/FindBAQuicLib.cmake + FIND_PACKAGE(BAQuicLib REQUIRED), resolving in-scope target → system package → FetchContent from quic-lib.
  • Initialize bringauto::quic::Logger alongside the app's own logger in main.cpp, otherwise the library's internal logs are silently dropped.

Breaking change: the QUIC transport now always uses one unidirectional stream per message — the "stream-mode" config key (and bidirectional streams) is no longer supported and is ignored with a warning if present.

Dependency: requires the ba-quic-lib branch project-migration-features to be merged first — this MR's FetchContent currently tracks the master branch head and will not build until those changes land there.

Summary by CodeRabbit

  • New Features

    • Upgraded QUIC connectivity and messaging with improved connection lifecycle behavior, including “connected on return,” and revised shutdown/disconnect handling.
    • Added QUIC configuration keys for client certificate, private key, and ALPN (replacing the previous stream-mode setting).
    • Enabled QUIC internal logging to follow the app’s console/file logging configuration when enabled.
    • Switched the QUIC backend used for runtime connectivity.
  • Documentation

    • Updated QUIC configuration docs and the example JSON to remove the obsolete stream-mode setting and reflect the new keys/behavior.

@danprudky
danprudky requested a review from jiriskuta July 19, 2026 15:50
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Changes

The QUIC integration now uses BAQuicLib and QuicClient instead of direct MsQuic APIs. Build discovery, connection lifecycle, message transport, settings keys, logging, and configuration documentation are updated accordingly.

QUIC transport migration

Layer / File(s) Summary
BAQuicLib dependency resolution
CMakeLists.txt, cmake/...
Adds existing-target, installed-package, and FetchContent discovery paths, removes the explicit MsQuic package dependency, and links module-gateway-lib to ba-quic-lib::ba-quic-lib.
QuicClient transport contract
include/bringauto/external_client/connection/communication/QuicCommunication.hpp, include/bringauto/settings/Constants.hpp
Replaces MsQuic-specific state, callbacks, stream buffering, and STREAM_MODE with QuicClient lifecycle helpers and certificate, key, and ALPN settings.
Connection and message flow
source/bringauto/external_client/connection/communication/QuicCommunication.cpp
Builds endpoint and QUIC settings, initializes QuicClient, handles connection and shutdown callbacks, serializes outbound messages, parses inbound bytes, and runs the sender loop.
Logging and configuration updates
main.cpp, resources/config/*
Initializes QUIC console and file logging and updates QUIC documentation and examples to remove stream-mode configuration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant QuicCommunication
  participant QuicClient
  participant ExternalPeer
  QuicCommunication->>QuicClient: initialize()
  QuicCommunication->>QuicClient: connect()
  QuicClient->>ExternalPeer: QUIC handshake
  ExternalPeer-->>QuicClient: connection established
  QuicClient-->>QuicCommunication: onConnected()
  QuicCommunication->>QuicClient: send(serialized ExternalClient)
  QuicClient-->>QuicCommunication: onBytesReceived()
  QuicCommunication->>QuicClient: disconnect()
  QuicClient-->>QuicCommunication: onDisconnected()
Loading

Possibly related PRs

Suggested reviewers: jiriskuta, koudis

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: refactoring QuicCommunication to use the shared ba-quic-lib transport.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch BAF-1723/Migrate-onto-the-QUIC-lib

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jiriskuta
jiriskuta force-pushed the BAF-1723/Migrate-onto-the-QUIC-lib branch from 4b133fb to 4626ff1 Compare July 23, 2026 09:33
…nsport

- replace the hand-rolled MsQuic client wrapper (registration/configuration/connection/stream callbacks) with bringauto::quic::QuicClient from the new ba-quic-lib dependency, removing ~250 lines of manual msquic plumbing from QuicCommunication
- keep the existing ConnectionState state machine and the outbound queue/dedicated sender thread, since ExternalConnection enqueues the Fleet-protocol Connect message before the QUIC handshake completes and relies on the queue to defer the send until CONNECTED
- delete QuicSettingsParser; quic-settings JSON is now passed straight through to bringauto::quic::QuicSettings::fromJson, which also warns on unrecognized keys instead of silently ignoring them
- swap BA_PACKAGE_LIBRARY(msquic)/FIND_PACKAGE(msquic CONFIG REQUIRED) for cmake/FindBAQuicLib.cmake + FIND_PACKAGE(BAQuicLib REQUIRED), matching the module-mode resolution convention (in-scope target -> system package -> FetchContent)
- init bringauto::quic::Logger alongside the app's own logger in main.cpp, otherwise the library's internal logs are silently dropped
- reorder QuicCommunication's members so quicClient_ outlives the condvars/atomics it can still call back into during ~QuicClient()'s blocking RegistrationClose

BREAKING CHANGE: the QUIC transport now always uses one unidirectional stream per message; the "stream-mode" config key (and bidirectional streams) is no longer supported and is ignored with a warning if present.
@jiriskuta
jiriskuta force-pushed the BAF-1723/Migrate-onto-the-QUIC-lib branch from 4626ff1 to ac348ba Compare July 23, 2026 09:53
jiriskuta and others added 6 commits July 23, 2026 12:26
The v0.1.0 tag now exists on quic-lib, so pin the FetchContent GIT_TAG
to it instead of tracking the master branch head, making the build
reproducible. Removes the now-obsolete TODO.
…chContent

When module-gateway configures with BRINGAUTO_INSTALL=ON (its CMDEF packaging),
FetchContent pulls ba-quic-lib in via add_subdirectory, so it inherits the flag
and runs its own install(EXPORT ba-quic-lib-targets). That fails at generate
time: the exported ba-quic-lib target links msquic PUBLIC, but msquic (also a
FetchContent subdir target) is in no export set, and CMake forbids exporting a
target whose public dependency isn't exported too.

module-gateway links ba-quic-lib statically in-tree and never consumes its
install/export, so shadow BRINGAUTO_INSTALL=OFF around the fetch, mirroring the
existing BRINGAUTO_TESTS shadow.
… via ba-quic-lib

PR #69 removed BA_PACKAGE_LIBRARY(msquic v2.5.6) + FIND_PACKAGE(msquic CONFIG),
which left ba-quic-lib to resolve msquic itself -- its FindBAMsquic falls through
to FetchContent and builds msquic + vendored quictls/OpenSSL from source. That
source build needs Perl FindBin.pm (absent on the fedora44 CI image) and
libatomic/libnuma, none of which the prebuilt-package path ever required.

Restore the prebuilt msquic and resolve it BEFORE FIND_PACKAGE(BAQuicLib):
ba-quic-lib's FindBAMsquic returns early on an already-defined 'msquic' target
(if(TARGET msquic) return()), so it now reuses the prebuilt package -- no source
build, matching how this repo (and every other msquic consumer) always did it.
…t-msquic wiring)

Reverts 8b05090. Per direction, msquic is owned by ba-quic-lib (the new shared
transport lib) and consumed transitively; module-gateway no longer declares its
own msquic package or FIND_PACKAGE(msquic). This is consistent with PR #69, which
moved QuicCommunication off direct msquic.h onto ba-quic-lib's QuicClient, so MG
has no direct msquic dependency of its own. Everything else in MG's CMLIB-based
build is unchanged.
v0.1.1 resolves msquic from the prebuilt bacpack package instead of building it from source, so
the fedora44 CI build no longer needs the msquic source-build toolchain (Perl/FindBin, libnuma).
- Replace the hardcoded "ModuleGateway" string with bringauto::quic::kLoggerId.id when initializing the ba-quic-lib logger instance
- The literal id didn't match the id ba-quic-lib actually registers under, so its logs could go uninitialized/swallowed despite the init() call
@danprudky
danprudky requested a review from vbartak July 27, 2026 12:01

@vbartak vbartak left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review

Direction is right — the msquic plumbing does not belong in QuicCommunication, and −473 net lines is a real win. Comment quality in the new code is unusually good.

Two things I'd want resolved before merge, marked 🔴 inline:

  1. senderThread_ threading regression — it's written from an msquic worker thread with no synchronization, and onDisconnected() dropped the old request_stop(), so the next onConnected() implicitly joins the previous session's thread from the transport's own worker.
  2. Dependency resolution bypasses the BA_PACKAGE_LIBRARY conventionFetchContent from private GitLab at configure time, and msquic no longer flows through BA_PACKAGE_DEPS_IMPORTED.

Severity legend: 🔴 major · 🟠 mid · 🔵 minor · ⚪ nit

Not anchorable to a diff line

  • 🔵 CLAUDE.md:77 is stale — still states config is parsed by "SettingsParser (and QuicSettingsParser for QUIC-specific fields)". This PR deletes QuicSettingsParser.
  • 🟠 Zero test coverage. buildEndpointConfig and buildQuicSettings are pure static functions over a std::unordered_map<std::string, std::string> — the cheapest possible unit tests, and buildQuicSettings is exactly where config-parsing behavior changed (widened key set, new warning path, JSON re-interpretation). The gtest suite gained nothing from a 743-line deletion.

Done well

  • resources/config/README.md documents both the removed stream-mode and the new pass-through contract, and quic_example.json was updated to match.
  • Unrecognized keys now warn instead of vanishing — strictly better than the old four-key parser.
  • The reconnect queue-drain and the notify-under-guarding-mutex fixes survived the refactor intact.
  • The main.cpp note explaining why bringauto::quic::Logger::init() is required is the comment that saves the next reader an hour.

Comment thread source/bringauto/external_client/connection/communication/QuicCommunication.cpp Outdated
Comment thread CMakeLists.txt Outdated
Comment thread cmake/Dependencies.cmake
Comment thread cmake/FindBAQuicLib.cmake Outdated
Comment thread source/bringauto/external_client/connection/communication/QuicCommunication.cpp Outdated
Comment thread source/bringauto/external_client/connection/communication/QuicCommunication.cpp Outdated
Daniel Prudky and others added 5 commits July 28, 2026 14:27
…ency, CMake robustness, test coverage

- #3664157558/#3664157568 senderThread_: guard with senderThreadMutex_, explicitly
  stop+join from onDisconnected()/stop() instead of relying on implicit jthread
  destruction racing an msquic worker callback
- #3664157621 initializeConnection(): bounded wait for onDisconnected() + CAS instead
  of a hard NOT_CONNECTED store on handshake timeout
- #3664157629 sendViaQuicClient(): null-check quicClient_ before dereferencing
- #3664157632 constructor: widen catch to std::exception (QuicSettings::fromJson is
  third-party)
- #3664157646 onShutdownInitiatedByPeer(): notify outboundCv_ so senderLoop unwinds
  without waiting for onDisconnected()
- #3664157649 buildEndpointConfig(): drop no-op static_cast<uint16_t> on settings.port
- #3664157641 buildQuicSettings(): document the string-vs-numeric re-typing caveat
  (no functional change, matches existing serializeToJson shape)
- #3664157587 FindBAQuicLib.cmake: use string(FIND) instead of MATCHES (regex) for the
  build-dir cache-entry check
- #3664157592 FindBAQuicLib.cmake: FORCE-write the BRINGAUTO_TESTS/BRINGAUTO_INSTALL
  cache entries instead of relying on CMP0077=NEW in ba-quic-lib's own scope
- #3664157614 FindBAQuicLib.cmake: drop include_guard(GLOBAL), redundant with the
  existing TARGET check and unsafe across scopes
- #3664157581 CMakeLists.txt: resolve BAQuicLib before the BRINGAUTO_GET_PACKAGES_ONLY
  early-return, and copy FindBAQuicLib.cmake into the Dockerfile's cache-builder stage,
  so ba-quic-lib is pre-fetched during Docker cache warming
- #3664157625 add QuicCommunicationTests covering buildQuicSettings/buildEndpointConfig
  (known key, unknown key, non-numeric value, endpoint-key exclusion, empty settings)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ceptions and lookups

- Catch nlohmann::json::exception instead of std::exception in
  QuicCommunication's constructor, since buildQuicSettings only ever
  throws JSON-related errors
- Reuse the outer `expected` variable in initializeConnection instead of
  redeclaring it, fixing a shadowing warning
- Give ExternalConnectionSettings::protocolSettings a transparent hash/
  equality (TransparentStringHash + std::equal_to<>) so lookups by
  std::string_view avoid an allocation; update getProtocolSettingsString
  and the ConfigMock/QuicCommunicationTests mocks to match the new map type

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…t CMake error

- FindBAQuicLib.cmake now builds the FetchContent GIT_REPOSITORY URL with
  $ENV{BA_GITLAB_TOKEN_URI}, matching transparent-module's PR #11 fix, so
  CI can clone the private quic-lib GitLab repo
- Resolve libbringauto_logger before FIND_PACKAGE(BAQuicLib REQUIRED) in
  CMakeLists.txt: ba-quic-lib vendors its own FindBALogger.cmake that
  defines a partial bringauto_logger::bringauto_logger shim if the target
  doesn't exist yet, which made the later real libbringauto_logger CONFIG
  import fail with "Some (but not all) targets in this export set were
  already defined"

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…scope

An unqualified `friend class QuicCommunicationTests;` inside a namespace either
refers to (or, if undeclared, silently introduces) that name in the enclosing
namespace, not the global-scope test fixture the friend declaration was meant
to grant access to. clang++-17 (the tested test-suite compiler) and this build's
g++ both rejected the private buildQuicSettings/buildEndpointConfig calls from
QuicCommunicationTests as a result. Forward-declare the fixture at global scope
and qualify the friend declaration with `::` so it resolves there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
InternalServerTests.FiftyClients occasionally crashed the entire test binary
("Subprocess aborted") instead of just failing, whenever the module handler
missed its response timeout for one of the 50 simulated devices under CI load.
The server closes that device's connection, but ClientForTesting::sendMessage
used the throwing write_some() overload; a subsequent write to the now-closed
socket threw an uncaught boost::system::system_error ("Broken pipe"), which
terminate()d the process. Switch both sendMessage overloads to the non-throwing
error_code overload + ASSERT_FALSE(er), matching the pattern already used by
receiveMessage/connectSocket in this same file, so this now fails the one
assertion instead of killing the whole suite.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants