PLAN.md keeps MVP traffic to one Ethernet frame per QUIC datagram with no
fragmentation. The relay already negotiates a datagram budget, but the client
and gateway send paths still relied on Quinn to reject oversized encoded
Ethernet datagrams.
Add a shared protocol validation helper for encoded datagram length versus the
negotiated QUIC budget. Thread the negotiated budget into client and gateway
send boundaries, reject oversized datagrams before send, and count those valid
but unsent frames as local drops.
Document the budget check in the workspace decomposition and gateway behavior.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-proto -p lanparty-client-core -p lanparty-gateway
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
PLAN.md calls out "Broadcast traffic flowing" as a user-facing diagnostic.
The tunnel stats only reported total Ethernet frame counts, so the client
could not distinguish whether broadcast traffic was actually crossing the
tunnel.
Add defaulted broadcast tx/rx counters to TunnelStats while preserving the
existing constructor and old JSON compatibility. Client and gateway accounting
now increments those counters from validated Ethernet frames, and the client
diagnostics line reports the broadcast flow next to total frame counts.
Relay peer stats logs include the new counters so operators can see broadcast
activity from forwarded stats snapshots too.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-obs -p lanparty-client-core -p lanparty-gateway \
-p lanparty-client-win -p lanparty-relay
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
The relay already accepts post-handshake Disconnect control messages, but the
client and gateway shutdown paths only sent a QUIC application close. That made
normal shutdown indistinguishable from transport closure until the relay
inferred a generic Normal leave.
Client and gateway shutdown now send a best-effort Disconnect message with the
human-readable shutdown reason before closing QUIC. The client-core drain uses
Quinn's runtime timer instead of taking a Tokio runtime dependency. The gateway
uses its existing Tokio runtime and applies the same short drain window on both
explicit shutdown and Ctrl-C in the Linux bridge loop.
The endpoint integration tests now assert that the server receives Disconnect
after the stats stream, which also protects against closing too quickly and
aborting the control stream.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core \
connects_to_relay_control_stream_as_client -- --nocapture
- cargo test -p lanparty-gateway \
connects_to_relay_control_stream_as_gateway -- --nocapture
- cargo test -p lanparty-client-core
- cargo test -p lanparty-gateway
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo clippy -p lanparty-gateway --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
Client counters were only local diagnostics even though the control protocol and
relay now understand Stats messages. Add a client-core sender that opens a
peer-to-relay unidirectional stream with the current TunnelStats snapshot.
The Windows client reports stats whenever it prints its diagnostics snapshot.
Failures are logged instead of stopping the frame pump because stats reporting
is diagnostic and should not be the reason a live tunnel goes down.
The client-core integration test now has the server decode the stats stream
before shutdown so the send path is covered without a timing race.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core \
connects_to_relay_control_stream_as_client -- --nocapture
- cargo test -p lanparty-client-core
- cargo test -p lanparty-client-win
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo clippy -p lanparty-client-win --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
ClientSession can now accept one-frame relay control events sent on reliable
unidirectional QUIC streams. This gives the Windows client a core API for the
PeerJoined and PeerLeft lifecycle messages that the relay now emits.
The implementation stays in client-core because it shares the relay connection
and control codec with the handshake. Client UI/status handling remains a
separate slice so this commit only establishes the tested transport boundary.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core connects_to_relay_control_stream_as_client \
-- --nocapture
- cargo test -p lanparty-client-core
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
ServerWelcome now carries an initial gateway_connected flag with serde defaulting
for older welcome payloads. The relay sets it from room admission state so a
gateway sees itself as connected, clients joining behind an existing gateway see
yes, and clients that arrive first see no.
The Windows client prints that handshake fact at startup. This does not replace
the later peer-event stream; it gives phase-1 diagnostics an immediate answer
for whether the relay already has a LAN gateway in the room.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \
-p lanparty-client-win
- cargo clippy -p lanparty-ctrl -p lanparty-relay -p lanparty-client-core \
-p lanparty-client-win --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
Client connection setup already fails when QUIC DATAGRAM is unavailable and
clamps the advertised datagram budget before sending hello. Keep that clamped
value on ClientSession and expose it through QuicDiagnostics so the Windows
client can report the negotiated budget without recomputing handshake details.
The value remains owned by client-core because it is derived from the live
quinn connection and the configured client budget during handshake. TAP and UI
code can sample the snapshot later alongside tunnel counters.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
Client relay I/O now shares atomic tunnel counters across cloned
ClientRelayIo handles and the owning ClientSession. The counters cover
successful Ethernet frame rx/tx, relay datagram rx/tx, and dropped or
malformed frames so client diagnostics have the traffic totals called
out in PLAN.md.
The counters live in client-core because that crate owns relay datagram
classification and Ethernet payload validation. The Windows TAP runner can
later sample this snapshot without duplicating protocol decisions.
Test Plan:
- cargo fmt --check
- cargo test -p lanparty-client-core
- cargo clippy -p lanparty-client-core --all-targets -- -D warnings
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md
The Windows client frame pump needs one side reading TAP frames and sending them
to the relay while another side receives relay datagrams and writes them to TAP.
That should not require the binary to reach into `ClientSession` internals.
Introduce `ClientRelayIo`, a cloneable handle around the accepted QUIC
connection and server welcome. It owns the Ethernet datagram send/receive logic
that previously lived directly on `ClientSession`, while `ClientSession` keeps
convenience forwarding methods for existing callers.
This is an enabling slice only. TAP frame pumping can now hold independent relay
I/O handles without broadening the platform-specific TAP crate.
Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- Windows-target cargo clippy for lanparty-client-tap with -D warnings
- git diff --check
Refs: PLAN.md Windows TAP frame pump
Remote clients need a stable locally administered MAC address so the relay,
gateway, DHCP lease, and LAN peers keep seeing the same tunnel identity across
runs. Requiring users to pass `--virtual-mac` made that responsibility manual.
Add a platform-neutral client identity store that loads a JSON identity file or
generates a new valid virtual MAC with OS randomness and persists it. The file
stores the MAC in the same string form shown by the CLI. The Windows client now
uses `lanparty-client-identity.json` by default while keeping `--virtual-mac` as
a manual test override.
TAP binding still remains future work; this slice only owns the client identity
that will be assigned to the TAP adapter.
Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- git diff --check
Refs: PLAN.md MAC identity
lanparty-client-core now owns the platform-neutral remote client relay session.
It validates relay trust input, room, virtual MAC identity, and datagram budget,
then connects to the relay, sends a client hello, and stores the assigned
welcome metadata.
The session exposes Ethernet datagram send and receive helpers that stamp
outgoing frames with the relay-assigned room and peer ids, ignore frames for
other rooms or from itself, and reject malformed Ethernet payloads before
handing them to the future TAP bridge.
The loopback Quinn test verifies the full client-side control and datagram path
without requiring Windows TAP access: pinned certificate trust, role = client
hello, announced virtual MAC, welcome parsing, and Ethernet datagrams in both
directions.
Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
Refs: PLAN.md Windows client relay connection and QUIC datagrams