From 7930d2f0f429f3802dc991cbb8efc733e1c9e9f6 Mon Sep 17 00:00:00 2001 From: enricobuehler Date: Sat, 4 Jul 2026 14:29:33 +0000 Subject: [PATCH] =?UTF-8?q?fix(core):=20split=20WIRE=5FVERSION=20from=20AB?= =?UTF-8?q?I=5FVERSION=20=E2=80=94=20new=20clients=20locked=20out=20of=20e?= =?UTF-8?q?very=20deployed=20host?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ABI_VERSION was doing double duty: the embeddable C surface AND the punktfunk/1 Hello/Welcome version that hosts equality-check. The WoL feature's v3 bump added a client-local FFI function without changing a single wire byte — and every new client started refusing against every deployed host ("ABI mismatch: client 3 host 2", observed live Deck → Bazzite). The wire now carries its own WIRE_VERSION (still 2); ABI_VERSION stays 3 for the C header and the mgmt API's informational field. Bump WIRE_VERSION only when the handshake/planes actually change incompatibly. Co-Authored-By: Claude Fable 5 --- clients/probe/src/main.rs | 2 +- crates/punktfunk-core/src/client.rs | 2 +- crates/punktfunk-core/src/lib.rs | 8 ++++++++ crates/punktfunk-host/src/punktfunk1.rs | 14 +++++++------- include/punktfunk_core.h | 8 ++++++++ 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/clients/probe/src/main.rs b/clients/probe/src/main.rs index 7bf17ff..99c47cf 100644 --- a/clients/probe/src/main.rs +++ b/clients/probe/src/main.rs @@ -412,7 +412,7 @@ async fn session(args: Args) -> Result<()> { io::write_msg( &mut send, &Hello { - abi_version: punktfunk_core::ABI_VERSION, + abi_version: punktfunk_core::WIRE_VERSION, mode: args.mode, compositor: args.compositor, gamepad: args.gamepad, diff --git a/crates/punktfunk-core/src/client.rs b/crates/punktfunk-core/src/client.rs index 8b43fd8..91bf531 100644 --- a/crates/punktfunk-core/src/client.rs +++ b/crates/punktfunk-core/src/client.rs @@ -876,7 +876,7 @@ async fn worker_main(args: WorkerArgs) { io::write_msg( &mut send, &Hello { - abi_version: crate::ABI_VERSION, + abi_version: crate::WIRE_VERSION, mode, compositor, gamepad, diff --git a/crates/punktfunk-core/src/lib.rs b/crates/punktfunk-core/src/lib.rs index ec991dc..cd77ffe 100644 --- a/crates/punktfunk-core/src/lib.rs +++ b/crates/punktfunk-core/src/lib.rs @@ -54,3 +54,11 @@ pub use stats::Stats; /// v3: added `punktfunk_wake_on_lan` (Wake-on-LAN magic packet; the host's wake MAC(s) reach /// clients out-of-band via the mDNS `mac` TXT record, so no connection is required to wake). pub const ABI_VERSION: u32 = 3; + +/// The punktfunk/1 **wire** version — what `Hello`/`Welcome` carry and hosts equality-check. +/// Deliberately its own constant: [`ABI_VERSION`] tracks the embeddable **C surface** +/// (functions a client links), which can grow without changing a single wire byte — v3's +/// `punktfunk_wake_on_lan` is client-local, and riding the C-ABI bump onto the wire locked +/// every new client out of every deployed host ("ABI mismatch: client 3 host 2", observed +/// live). Bump this ONLY when the handshake/planes actually change incompatibly. +pub const WIRE_VERSION: u32 = 2; diff --git a/crates/punktfunk-host/src/punktfunk1.rs b/crates/punktfunk-host/src/punktfunk1.rs index df1a8dc..b0b593f 100644 --- a/crates/punktfunk-host/src/punktfunk1.rs +++ b/crates/punktfunk-host/src/punktfunk1.rs @@ -585,10 +585,10 @@ async fn serve_session( // the `handshake` future re-decodes for the real session — a few dozen bytes, negligible. let gate_hello = Hello::decode(&first).map_err(|e| anyhow!("Hello decode: {e:?}"))?; anyhow::ensure!( - gate_hello.abi_version == punktfunk_core::ABI_VERSION, - "ABI mismatch: client {} host {}", + gate_hello.abi_version == punktfunk_core::WIRE_VERSION, + "wire version mismatch: client {} host {}", gate_hello.abi_version, - punktfunk_core::ABI_VERSION + punktfunk_core::WIRE_VERSION ); let fp = endpoint::peer_fingerprint(&conn); let known = fp @@ -654,10 +654,10 @@ async fn serve_session( let handshake = async { let hello = Hello::decode(&first).map_err(|e| anyhow!("Hello decode: {e:?}"))?; anyhow::ensure!( - hello.abi_version == punktfunk_core::ABI_VERSION, - "ABI mismatch: client {} host {}", + hello.abi_version == punktfunk_core::WIRE_VERSION, + "wire version mismatch: client {} host {}", hello.abi_version, - punktfunk_core::ABI_VERSION + punktfunk_core::WIRE_VERSION ); // The pairing gate (require_pairing → paired? else park for delegated approval) ran above, // before this future, so a client reaching here is paired (or the host is `--open`). @@ -805,7 +805,7 @@ async fn serve_session( let mut key = [0u8; 16]; rand::thread_rng().fill_bytes(&mut key); let welcome = Welcome { - abi_version: punktfunk_core::ABI_VERSION, + abi_version: punktfunk_core::WIRE_VERSION, udp_port, mode: hello.mode, // The post-GameStream point of punktfunk/1: Leopard GF(2¹⁶) FEC + real encryption. diff --git a/include/punktfunk_core.h b/include/punktfunk_core.h index 7f1b76f..4cbfc90 100644 --- a/include/punktfunk_core.h +++ b/include/punktfunk_core.h @@ -21,6 +21,14 @@ // clients out-of-band via the mDNS `mac` TXT record, so no connection is required to wake). #define ABI_VERSION 3 +// The punktfunk/1 **wire** version — what `Hello`/`Welcome` carry and hosts equality-check. +// Deliberately its own constant: [`ABI_VERSION`] tracks the embeddable **C surface** +// (functions a client links), which can grow without changing a single wire byte — v3's +// `punktfunk_wake_on_lan` is client-local, and riding the C-ABI bump onto the wire locked +// every new client out of every deployed host ("ABI mismatch: client 3 host 2", observed +// live). Bump this ONLY when the handshake/planes actually change incompatibly. +#define WIRE_VERSION 2 + // `PunktfunkHidOutput::kind` — lightbar RGB (`r`/`g`/`b` valid). #define PUNKTFUNK_HIDOUT_LED 1