apple / swift (push) Successful in 1m24s
release / apple (push) Successful in 10m3s
android / android (push) Successful in 13m31s
arch / build-publish (push) Successful in 13m39s
ci / web (push) Successful in 1m4s
ci / docs-site (push) Successful in 1m12s
windows-host / package (push) Successful in 16m40s
apple / screenshots (push) Successful in 6m38s
ci / bench (push) Successful in 5m26s
windows-msix / package (arm64, C:\Users\Public\ffmpeg-arm64, --no-default-features, aarch64-pc-windows-msvc, C:\t-a64) (push) Successful in 3m9s
ci / rust (push) Successful in 20m46s
decky / build-publish (push) Successful in 30s
windows-msix / package (x64, C:\Users\Public\ffmpeg, , x86_64-pc-windows-msvc, C:\t) (push) Successful in 3m15s
deb / build-publish (push) Successful in 8m50s
docker / build-push (., web/Dockerfile, punktfunk-web) (push) Successful in 45s
docker / build-push (ci, ci/rust-ci-noble.Dockerfile, punktfunk-rust-ci-noble) (push) Successful in 12s
docker / build-push (ci, ci/rust-ci.Dockerfile, punktfunk-rust-ci) (push) Successful in 12s
docker / build-push (docs-site, docs-site/Dockerfile, punktfunk-docs) (push) Successful in 12s
windows / build (aarch64-pc-windows-msvc) (push) Successful in 4m31s
docker / build-push (--build-arg FEDORA_VERSION=44, ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora44-rpm) (push) Successful in 7m6s
deb / build-publish-host (push) Successful in 9m52s
docker / build-push (ci, ci/fedora-rpm.Dockerfile, punktfunk-fedora-rpm) (push) Successful in 6m44s
docker / deploy-docs (push) Successful in 28s
windows / build (x86_64-pc-windows-msvc) (push) Successful in 7m4s
rpm / build-publish (44, fedora-44, punktfunk-fedora44-rpm) (push) Successful in 16m35s
rpm / build-publish (43, bazzite, punktfunk-fedora-rpm) (push) Successful in 16m45s
flatpak / build-publish (push) Failing after 8m6s
The pen plane from design/pen-tablet-input.md, protocol side only (the P1 uinput tablet injector will consume it): 0xCC kind 0x05 carries batches of state-full PenSamples (pressure, polar tilt + azimuth, barrel roll, hover distance, eraser tool, barrel buttons); PenTracker diffs samples into injector transitions so a lost datagram self-heals; HOST_CAP_PEN (0x10) gates sending and stays unadvertised until a real backend exists. C ABI: PunktfunkPenSample + punktfunk_connection_send_pen, documented in docs/embedding-the-c-abi.md §8. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
86 lines
4.0 KiB
Rust
86 lines
4.0 KiB
Rust
//! `punktfunk/1` — the native control plane, gated behind the `quic` feature.
|
||
//!
|
||
//! GameStream is punktfunk's compatibility layer; this is the start of its own protocol. A QUIC
|
||
//! connection (quinn, tokio — control plane only, never the per-frame path) carries a
|
||
//! length-prefixed binary handshake on one bidirectional stream:
|
||
//!
|
||
//! ```text
|
||
//! client → host Hello { abi_version }
|
||
//! host → client Welcome { abi_version, session: full data-plane Config + mode + UDP port }
|
||
//! client → host Start { client_udp_port }
|
||
//! ```
|
||
//!
|
||
//! after which both sides bring up a [`crate::session::Session`] over a plain
|
||
//! [`UdpTransport`](crate::transport::udp) (native threads, no async) and the host streams.
|
||
//! The Welcome carries everything the core negotiates — FEC scheme (including GF(2¹⁶)
|
||
//! Leopard, which GameStream can't express), shard sizing, crypto key/salt — so the data
|
||
//! plane is exactly the hardened core `Session`.
|
||
//!
|
||
//! Transport security: the host presents a long-lived self-signed certificate
|
||
//! ([`endpoint::server_with_identity`]) and the client pins its SHA-256 fingerprint
|
||
//! ([`endpoint::client_pinned`]; no pin = trust-on-first-use, with the observed fingerprint
|
||
//! reported back for persisting). The data plane adds AES-GCM on top.
|
||
//! All integers little-endian; every message is `u16 length || payload`.
|
||
//!
|
||
//! Split by concern (networking-audit deferred plan §3 — a pure move): `handshake` the
|
||
//! positional Hello/Welcome/Start codecs, `caps` the capability/codec-negotiation
|
||
//! vocabulary, `control` the typed control + clipboard messages, `pairing` the pairing
|
||
//! message codecs with [`pake`] the SPAKE2 itself, `datagram` the 0xC9–0xCF plane codecs,
|
||
//! `pen` the stylus batch (0xCC kind 0x05) + host stroke tracker,
|
||
//! [`io`] framed stream IO, `clock` skew estimation + mid-stream re-sync, [`endpoint`] the
|
||
//! quinn constructors, [`clipstream`] the per-transfer clipboard fetch streams. Every item
|
||
//! is re-exported here, so all existing `crate::quic::X` paths compile unchanged; each
|
||
//! module's tests sit at its own foot.
|
||
|
||
/// Protocol magic + version, first bytes of the positional handshake (Hello/Welcome/Start).
|
||
pub const MAGIC: &[u8; 4] = b"PKF1";
|
||
|
||
/// Magic for typed post-handshake / pairing control messages. A distinct magic keeps the
|
||
/// typed namespace disjoint from the positional handshake: a `Hello` (whose abi_version
|
||
/// byte sits where a type byte would) can never be misparsed as a control message, and
|
||
/// vice-versa, regardless of field values.
|
||
pub const CTL_MAGIC: &[u8; 4] = b"PKFc";
|
||
|
||
mod caps;
|
||
mod clock;
|
||
mod control;
|
||
mod datagram;
|
||
mod handshake;
|
||
mod pairing;
|
||
mod pen;
|
||
|
||
/// quinn endpoint constructors. Host: self-signed identity (fresh, or persisted PEMs via
|
||
/// [`endpoint::server_with_identity`]). Client: fingerprint pinning / TOFU via
|
||
/// [`endpoint::client_pinned`] ([`endpoint::client_insecure`] is the no-pin special case).
|
||
pub mod endpoint;
|
||
|
||
/// Async framed-message IO over a quinn stream (`u16 LE length || payload`).
|
||
pub mod io;
|
||
|
||
/// Per-transfer clipboard fetch bi-streams (`PKFs` magic + kind byte, then request/response). The
|
||
/// transport half of the shared clipboard; wire codecs are in [`control`], state lives per side.
|
||
pub mod clipstream;
|
||
|
||
/// SPAKE2 over Ed25519 for the pairing ceremony. The two roles use the asymmetric flow so
|
||
/// the identities are ordered; each side binds **both** certificate fingerprints as the
|
||
/// SPAKE2 identities, so the derived key only matches when client and host agree on the PIN
|
||
/// *and* saw the same two certificates (a MITM, presenting different certs to each leg,
|
||
/// cannot reach a shared key).
|
||
pub mod pake;
|
||
|
||
pub use caps::*;
|
||
pub use clock::*;
|
||
pub use control::*;
|
||
pub use datagram::*;
|
||
pub use handshake::*;
|
||
pub use pairing::*;
|
||
pub use pen::*;
|
||
|
||
// Typed rejection close codes + [`RejectReason`] live in `crate::reject` (ungated — the
|
||
// error enum references them even in `quic`-less builds) and are re-exported here so the
|
||
// wire vocabulary stays browsable next to QUIT/APP_EXITED.
|
||
pub use crate::reject::*;
|
||
|
||
#[cfg(test)]
|
||
pub(crate) mod test_util;
|