From 5dc28890f0f9366f534ce9b5ad093f36abb3f6a6 Mon Sep 17 00:00:00 2001 From: mikael-lovqvists-claude-agent Date: Wed, 25 Mar 2026 22:28:56 +0000 Subject: [PATCH] Document custom mDNS-inspired discovery in architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reuse UDP multicast transport (224.0.0.251:5353) with our own binary wire format — no Avahi, no Bonjour, no daemon dependency. Co-Authored-By: Claude Sonnet 4.6 --- architecture.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/architecture.md b/architecture.md index 992b400..355e471 100644 --- a/architecture.md +++ b/architecture.md @@ -298,6 +298,48 @@ The preprocessor is the same tool planned for generating error location codes (s --- +## Node Discovery + +Standard mDNS (RFC 6762) uses UDP multicast over `224.0.0.251:5353` with DNS-SD service records. The wire protocol is well-defined and the multicast group is already in active use on most LANs. The standard service discovery stack (Avahi, Bonjour, `nss-mdns`) provides that transport but brings significant overhead: persistent daemons, D-Bus dependencies, complex configuration surface, and substantial resident memory. None of that is needed here. + +The approach: **reuse the multicast transport, define our own wire format**. + +Rather than DNS wire format, node announcements are encoded as binary frames using the same serialization layer (`serial`) and frame header used for video transport. A node joins the multicast group, broadcasts periodic announcements, and listens for announcements from peers. + +### Announcement Frame + +| Field | Size | Purpose | +|---|---|---| +| `message_type` | 2 bytes | Discovery message type (e.g. `0x0010` for node announcement) | +| `channel_id` | 2 bytes | Reserved / zero | +| `payload_length` | 4 bytes | Byte length of payload | +| Payload | variable | Encoded node identity and capabilities | + +Payload fields: + +| Field | Type | Purpose | +|---|---|---| +| `protocol_version` | u8 | Wire format version | +| `tcp_port` | u16 | Port where this node accepts transport connections | +| `name_len` | u8 | Length of name string | +| `name` | bytes | Node name (`namespace:instance`, e.g. `v4l2:microscope`) | +| `function_len` | u8 | Length of function string | +| `function` | bytes | Node function identifier (`source`, `relay`, `sink`, ...) | + +### Behaviour + +- Nodes send announcements periodically (e.g. every 5 s) and immediately on startup +- No daemon — the node process itself sends and listens; no background service required +- On receiving an announcement, the control plane records the peer (address, port, name, function) and can initiate a transport connection if needed +- A node going silent for a configured number of announcement intervals is considered offline +- Announcements are informational only — the hub validates identity at connection time + +### No Avahi/Bonjour Dependency + +The system does not link against, depend on, or interact with Avahi or Bonjour. It opens a raw UDP multicast socket directly, which requires only standard POSIX socket APIs. This keeps the runtime dependency footprint minimal and the behaviour predictable. + +--- + ## Open Questions - What is the graph's representation format — in-memory object graph, serialized config, or both? @@ -305,5 +347,4 @@ The preprocessor is the same tool planned for generating error location codes (s - Drop policy for completeness queues: drop oldest (recency) or drop newest (continuity)? Should be per-output configurable. - When a relay has multiple inputs on an encapsulated transport, how are streams tagged on the outbound side — same stream_id passthrough, or remapped? - What transport is used for relay edges — TCP, UDP, shared memory for local hops? -- How are nodes discovered — static config, mDNS, manual registration? - Should per-output byte budgets be hard limits or soft limits with hysteresis?