Skip to content

Harden protocol runtime, configuration reloads, and regression testing - #157

Open
anzimber wants to merge 30 commits into
openv:masterfrom
anzimber:fix/robust-protocol-and-runtime
Open

Harden protocol runtime, configuration reloads, and regression testing#157
anzimber wants to merge 30 commits into
openv:masterfrom
anzimber:fix/robust-protocol-and-runtime

Conversation

@anzimber

@anzimber anzimber commented Jul 29, 2026

Copy link
Copy Markdown

Summary

This PR hardens vcontrold's protocol, parser, XML configuration, client, and
resource-lifecycle paths while adding a regression suite that exercises the
daemon, client, simulator, and supported configuration profiles end to end.

The primary goals are:

  • reject malformed or oversized input without corrupting memory;
  • keep the active configuration intact when a reload candidate is invalid;
  • make partial I/O, EOF, timeout, signal, and allocation failures explicit;
  • retain compatible CLI and XML behaviour for valid configurations;
  • make future regressions visible through strict builds, sanitizers, static
    analysis, CodeQL, and enforced coverage thresholds.

Root causes addressed

Several reusable paths mixed buffer length and capacity, assumed complete
reads/writes, or terminated the process from library code. XML parsing could
also expose partially constructed object graphs on allocation or semantic
failure. Those behaviours made malformed traffic, large command lists,
truncated P300 frames, and repeated reloads unnecessarily risky.

The changes introduce explicit capacities and checked conversions, transactional
configuration loading, consistent error propagation and cleanup, bounded
protocol framing, dynamic client/simulator buffers, and deterministic resource
ownership.

Main changes

Runtime and protocol safety

  • harden TCP command parsing, including empty lines and oversized input;
  • validate complete P300/KW frames, checksums, payload lengths, and truncation;
  • handle partial reads/writes, EOF, EINTR, and timeouts through checked I/O;
  • validate TTY, socket, semaphore, descriptor, and blocking-mode operations;
  • make signal handling and reload cleanup deterministic;
  • preserve the previous configuration when parsing, expansion, or compilation
    of a reload candidate fails.

Parser, units, XML, and client

  • carry buffer capacities through parser and unit-conversion APIs;
  • reject invalid numeric narrowing, malformed integer expressions, and
    unterminated/oversized command-file lines;
  • support both legacy 8-byte and extended 15-byte cycle-time formats;
  • fix enum resolution after integer expressions;
  • fully escape JSON and emit failed values as null with error information;
  • grow direct vclient command lists dynamically instead of imposing the old
    512-byte limit;
  • check all XML allocations and release partial command, unit, protocol,
    device, and enum graphs on failure;
  • keep useful version metadata in source mirrors that do not carry upstream
    tags by falling back to the abbreviated commit ID.

Build, CI, and documentation

  • split reusable code into testable library targets;
  • add unit and socket-pair integration tests for parser, framer, client, I/O,
    arithmetic, units, XML reloads, allocation failures, semaphore handling,
    vclient, vcontrold, and vsim;
  • add strict GCC/Clang builds, ASan/UBSan/LSan, GCC -fanalyzer,
    clang-tidy, cppcheck, Clang Static Analyzer, Valgrind, CodeQL, XML and shell
    validation, and a supported-option build matrix;
  • enforce at least 80% aggregate core and overall line coverage, with at least
    65% per core module and for the daemon;
  • document the trusted-LAN threat model, write-command exposure, reload
    boundaries, source installs, and a hardened systemd service;
  • add a hardware-validated Vitola 20C8 profile while keeping device-specific
    and alternative/frost addresses clearly separated.

Compatibility and operational notes

  • Valid existing XML, command names, and normal plain/CSV output remain
    compatible.
  • Invalid XML elements, missing mandatory values, malformed numbers, and
    oversized input now fail explicitly.
  • Empty TCP lines only return the prompt.
  • Failed reloads do not replace the active configuration.
  • JSON error output intentionally changes to strict JSON using null plus an
    error field.
  • Listener, port, user/group, and log-target changes still require a restart.
  • This does not add network authentication. Deployments that expose the
    listener beyond a trusted LAN must add their own network controls.
  • Set and raw-write commands remain available. Controlled hardware validation
    included reversible get-set-get round trips: each initial value was read and
    recorded before writing, the changed value was read back, and the original
    value was restored and verified. The final rollout smoke test itself remained
    read-only.

Existing PRs incorporated or superseded

This branch incorporates the intent of, and extends with regression coverage:

#135 directly addresses and fixes #134.

Related issue context

The hardening and tests cover failure modes discussed in #30, #53, #66, #70,
#91, #108, #116, #128, #141, #144, and #152. These references are contextual:
device-specific reports still need confirmation on the respective hardware and
are not automatically closed by this PR.

Fixes #134.

Validation

  • GCC and Clang strict builds with -Wall -Wextra -Wpedantic -Werror;
  • 13/13 CTest tests in Debug and Release builds;
  • 13/13 tests under ASan, UBSan, and LeakSanitizer;
  • GCC -fanalyzer, clang-tidy, cppcheck, Clang Static Analyzer, Valgrind,
    CodeQL, ShellCheck, xmllint, and git diff --check;
  • build matrix for minimal, vclient, vsim, full test, and manpage profiles;
  • line coverage:
    • core aggregate: 83.28%;
    • overall: 80.66%;
    • unit.c: 89.61%;
    • vcontrold.c: 68.57%;
  • Ubuntu hardware validation performed on a 2014 Viessmann Vitoladens 300-C
    (type J3RA), using the KW6B protocol and the Vitola 20C8 device profile:
    • 81/81 read commands successful;
    • configured set commands validated with controlled get-set-get round trips;
    • initial values recorded and successfully restored after each reversible
      write test;
    • system-time synchronization validated separately;
    • stable Home Assistant polling across repeated intervals;
    • daemon remained active with zero restarts;
    • no raw-write command was used, and the final deployment check was read-only.

Suggested review order

  1. src/io.c, src/framer.c, and src/parser.c for transport boundaries;
  2. src/xmlconfig.c for transactional ownership and rollback;
  3. src/unit.c, src/arithmetic.c, and src/vclient.c for conversion/output;
  4. tests and coverage enforcement;
  5. CMake/workflows, documentation, and the optional 20C8 profile.

anzimber added 30 commits July 28, 2026 19:02
@anzimber
anzimber marked this pull request as ready for review July 29, 2026 12:02
@anzimber

anzimber commented Aug 6, 2026

Copy link
Copy Markdown
Author

Hi @speters, @hmueller01, and @l3u — could you please take a look at this PR when you have a chance? Thanks!

@l3u

l3u commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Hi, thanks a lot for this extensive contribution!

I only formatted the code in a decent way and rewrote the build system back then to "rescue" the project. I actually lack the low-level C knowledge to decently review actual code changes.

That being said, this PR is too much at once IMHO. 30 commits and 63 changed files … we have documentation changes, corrected typos, CI corrections, and so on. You should really break this up into multiple PRs.

E.g. stuff like fixing "deamon" into "daemon" in some init script can easily be approved and merged. As well as the CI stuff can possibly be (although I'm not fit with Github's CI). But all that in combination with codebase changes … one simply can't grasp all at once.

I'm pretty sure if you break this up into several smaller logical units that can be grasped more easily, chances would be way, way higher your contribution can actually be reviewed and finally merged.

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.

vclient command limited to 512 characters

2 participants