A cross-platform LAN multicast file transfer tool. A trusted sender broadcasts a file once over IP multicast; any number of receivers on the network pick it up simultaneously, verify it via a signed, chunk-hashed manifest, decrypt it (chunk payloads are encrypted end-to-end with ChaCha20-Poly1305, not just signed — see below), and repair any lost chunks by requesting them from peer receivers rather than re-asking the sender.
Runs on Windows, macOS, and Linux with full IP multicast; iOS and Android join the same swarm as unicast clients over LAN-discovered peers, since neither OS allows apps to reliably join true multicast groups.
One sender, any number of receivers, one broadcast — a LAN party mod pack push, a sysadmin scripting a fleet config rollout, a test lab loading the same dataset onto every bench machine at once. See all three, with GIFs of the CLI, the colorful TUI dashboard, and the desktop GUI →
Interested in how the performance work was actually done — including the fix we shipped
first and had to reverse, and why we read UFTP's source and then declined to copy its
congestion control? METHODOLOGY.md covers the approaches and the
reasoning; docs/benchmarks/throughput-runs.md keeps
every raw measurement behind it.
M0 (scaffolding) through M8 are complete. M5 shipped the showcase docs
below; M6 root-caused and fixed a receiver-side throughput bottleneck
(wiki/synthesis/m6-throughput-pipelining.md); M7 removed a self-inflicted
repair storm that was sending the file roughly twice, cutting wire
amplification from 2.39× to 1.13× and eliminating a burst/stall delivery
pattern (wiki/synthesis/m7-repair-amplification.md); M8 raised the default
chunk size to the 256 KB that Castr.Core and the wire protocol had
specified all along. Throughput work is not finished — per-datagram syscall
cost currently caps transfers near ~37 MB/s, and raising the datagram budget
is the tracked next step. Formal release automation (tag-triggered releases,
checksums/signatures) also remains open. Both are in
wiki/synthesis/roadmap.md, and every measurement behind these claims is in
docs/benchmarks/throughput-runs.md. Chunk payloads are ChaCha20-Poly1305-encrypted end-to-end and
travel over MTU-safe wire packets (chunks split/reassembled below the
crypto layer) — see wiki/synthesis/m1.5-encryption-summary.md and
wiki/synthesis/m3-test-ci-hardening-summary.md.
castr send/castr receive/castr trust, a live Spectre.Console dashboard
(--tui), and an Avalonia desktop GUI are all working — see
wiki/synthesis/m2-ui-summary.md. Mobile (iOS/Android) joins as a unicast
swarm client over LAN-discovered peers (native NsdManager/NWBrowser
discovery, TCP pull, the same signed-manifest/Merkle/AEAD verification the
desktop multicast tier uses) — Castr.Gui.Android produces a real
debug-signed sideloadable APK; Castr.Gui.iOS builds and links its native
discovery bindings against real Xcode, though the full app-level Simulator
link is currently blocked by an upstream libsodium packaging gap — see
wiki/synthesis/m4-mobile-summary.md. CI runs a real 3-OS build+test matrix,
a Docker-gated multi-container E2E fan-out job with real induced packet
loss, and dedicated Android/iOS mobile-build workflows on real
SDK/Xcode-provisioned runners — see wiki/synthesis/m3-test-ci-hardening-summary.md
and wiki/synthesis/m4-mobile-summary.md. See wiki/synthesis/roadmap.md for milestone status and
wiki/ generally for the accumulated design decisions (ADRs, spike results). The
full architecture — wire protocol, repair algorithm, security model, and milestone
plan — lives in the project plan; a synthesis of it is ingested into wiki/ as the
project's first source so it survives session restarts.
src/Castr.Core— protocol state machines, chunker, Merkle/manifest, trust store, transport abstractions (no UI, no platform-specific code)src/Castr.Core.Discovery— peer discovery abstraction + platform mDNS impls (used by the mobile unicast tier)src/Castr.Cli— command-line entrypoint (System.CommandLine):send,receive,trust list|add|block|removesrc/Castr.Tui— colorful live transfer dashboard (Spectre.Console), consumed byCastr.Cli --tuisrc/Castr.Gui,src/Castr.Gui.Desktop— Avalonia GUI: shared views/viewmodels and the Windows/macOS/Linux desktop headsrc/Castr.Gui.Android,src/Castr.Gui.iOS— Avalonia mobile GUI heads (unicast swarm client), built on top ofCastr.Core.Discovery+ the TCP swarm-pull tier inCastr.Core; each opt-in-multitargeted so a defaultdotnet build/CI matrix never requires mobile workloadstests/— unit, loopback-multicast integration, CLI, TUI, GUI, and discovery test projects, one per correspondingsrc/project's concerns, plusCastr.Core.E2ETests: a Testcontainers-driven multi-container fan-out suite (real Docker bridge multicast + kernel-leveltc netemloss), opt-in viaCASTR_E2E=1and gated on Docker being reachablewiki/,raw/— the project's persistent knowledge base (llm-wiki), the durable memory across sessionsgraphify-out/— generated codebase knowledge graph (query this instead of re-reading the whole tree when resuming work)
dotnet build
dotnet test
Requires the .NET 10 SDK (LTS, pinned via global.json).
Every push to main also builds self-contained, per-platform zips of castr (CLI) and the desktop GUI for
win-x64, win-arm64, osx-x64, osx-arm64, and linux-x64, uploaded as downloadable artifacts on that CI run's
Actions page (see the package job in .github/workflows/ci.yml). These are unsigned CI convenience builds,
not versioned/checksummed releases — that's tracked for M5.
Apache-2.0 — see LICENSE.
