Files
udpscope/docs/superpowers/specs/2026-11-06-tcp-streamer-source-design.md
T

2.7 KiB

TCPStreamer source kind

A new source kind tcps ("TCPStreamer") that receives a MARTe2 TCPStreamer DataSource, either standalone or through a shared TCPStreamService.

Wire and scope

  • Both transports are plain UDPS framing over TCP. A standalone TCPStreamer (TCPSServer) sends CONFIG then DATA on connect. A TCPStreamService additionally requires a first client frame, SUBSCRIBE (type 5, payload = stream name, 1..255 bytes).
  • A plain server ignores SUBSCRIBE, so the client sends it only when a stream name is set.
  • One connection carries one stream. Multiplexed lists ("a,b,c", stream index in fragmentIdx) are out of scope: a udpscope source is single-timebase. Several streams are merged server-side with TCPStreamJoin, which publishes an ordinary named stream.

deps/udpsclient: a TCP transport mode

  • udps_client_config_t gains use_tcp and stream_name.
  • New connect_tcp(): open the TCP socket, send SUBSCRIBE if a stream name is set, send no CONNECT. No UDP socket, no keepalive ACK.
  • udps_client_poll reuses read_tcp_frame / handle_packet.
  • reorder_window_s is forced to 0 in TCP mode: TCP is ordered, so a counter gap is a server-side drop and is reported at once.
  • Silence timeout and reconnect delay behave as in UDP (dead server, or a stalled client the server evicted, reconnects).
  • The datagram tap does not fire; the packet capture stays UDP-only (has_datagrams() false).
  • Additive. Recorded in docs/claude/build-and-run.md as a sixth intentional upstream change.

Source adapter and kind

  • UdpsSource takes a transport argument (UdpsSource(cfg, Transport::Tcp)) instead of being copied: its callbacks are identical. The TCP variant reads server, port (default 44500) and stream.
  • src/source/tcps_kind.cpp: kind tcps, display name "TCPStreamer". Form rows: Server, Port, Stream name (optional). Description: "Leave empty for a standalone TCPStreamer; name the stream for a TCPStreamService".
  • Identity: host:port or host:port/stream. Session naming follows the existing non-UDPS rule (tcps-<identity>, port 1, source_kind=tcps, source_opt_*).
  • Registered in register_builtin_sources() and CMakeLists.txt.

Verification

No unit suite. Extend the self-check in src/ui_probe.cpp with an in-process fake TCP server that sends CONFIG then DATA, and requires SUBSCRIBE in one mode. Probe lines assert the signals, the frame count, and the reconnect after the server closes. Baselines: exactly one build warning, no Gtk-CRITICAL. A smoke test against a real MARTe TCPStreamer if one is runnable.

Docs

README and docs/claude/architecture.md (Sources) describe the kind; docs/claude/probe-readings.md gets the new probe lines.