Skip to content

Multicast receive + complete the realtime story + cleanups#22

Open
tap wants to merge 4 commits into
mainfrom
claude/phase2-multicast-rt
Open

Multicast receive + complete the realtime story + cleanups#22
tap wants to merge 4 commits into
mainfrom
claude/phase2-multicast-rt

Conversation

@tap

@tap tap commented Jun 28, 2026

Copy link
Copy Markdown
Owner

Three focused commits picking up loose ends after the last merge. Each independently green; please Rebase and merge (keep the commits).

Multicast receive (issue #19 — the last open Phase 2 feature)

  • UdpSocket::JoinMulticastGroup() / LeaveMulticastGroup() (IP_ADD/DROP_MEMBERSHIP) on both posix and win32, available on any UDP receive socket once bound.
  • tests/OscMulticastTest.cpp — real loopback (join 239.7.7.7, send 3 OSC messages to the group, assert receipt), skip-resilient like the other socket tests. Wired into the win32-wine CI job too.
  • Verified: passes on POSIX (ASan/UBSan-clean) and on win32 under Wine; aarch64 cross-build clean.

Complete the realtime story (the RTSan deferral)

  • AsBlobUnchecked() and AsBoolUnchecked() are now throw-free and OSCTAP_REALTIME — they trust the validation done at construction, like the other *Unchecked accessors. Every *Unchecked read accessor is now on the realtime contract.
  • OscRealtimeTest reads the blob payload + bool on the [[clang::nonblocking]] hot path; verified under Clang-20 with -Wfunction-effects -Werror (static) and -fsanitize=realtime (runtime).
  • tests/OscLatencyBench.cpp — worst-case parse/serialize latency (min/median/p99/max ns), the secondary signal the strategy calls for; run informationally in the rtsan CI job.
  • Fuzzer still ASan/UBSan-clean (200k mutations) after the accessor change.

Cleanups

  • win32/UdpSocket.h: GetCurrentTimeMs() now uses std::chrono::steady_clock (matches posix; no ~49-day timeGetTime() wrap) — resolves the FIXME.
  • Refreshed now-stale "Deferred" notes in ROADMAP/STATUS (guard rename, strcpy/gethostbyname, uncompiled backends — all done).

Full hosted suite 9/9.

Closes #19.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MMR6tmM7H3obaL7SX14bkJ


Generated by Claude Code

claude added 4 commits June 28, 2026 14:40
- win32/UdpSocket.h: GetCurrentTimeMs() now uses std::chrono::steady_clock
  (matching the posix backend) instead of timeGetTime(), which wrapped after
  ~49 days. Resolves the FIXME. Verified: win32 smoke compiles clean (MinGW
  -Wshadow -Werror) and OscUdpTest passes under Wine.
- ROADMAP.md: the INCLUDED_OSCPACK_* guard rename and the strcpy/gethostbyname /
  uncompiled-ip-backend deferrals are done -- updated those stale "Deferred" notes;
  refreshed the top status line.
- STATUS.md: Phase 1/2 issues exist (#3-#8, #14-#19); only the "Phase 2 - Reach"
  milestone object remains an owner action.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMR6tmM7H3obaL7SX14bkJ
…cy benchmark

The RTSan deferral was a non-throwing realtime blob accessor and a worst-case
latency benchmark. Both done, plus the analogous bool accessor.

- AsBlobUnchecked() and AsBoolUnchecked() are now throw-free and marked
  OSCTAP_REALTIME. Like the other *Unchecked accessors they trust the validation
  done at construction (ReceivedMessage::TryInit bounds-checks every blob), so the
  redundant re-validation/throw is dropped. Every *Unchecked read accessor is now
  on the realtime contract -- no exceptions.
- OscRealtimeTest reads the blob payload and bool through these accessors inside
  the [[clang::nonblocking]] hot path. Verified under Clang-20: -Wfunction-effects
  -Werror (static) and -fsanitize=realtime (runtime) both pass.
- tests/OscLatencyBench.cpp: worst-case parse/serialize latency (min/median/p99/max
  ns), the secondary signal the sanitizer strategy calls for. Built as a target;
  the rtsan CI job runs it (informational, non-gating).
- ROADMAP/STATUS/test comments updated; fuzzer still ASan/UBSan-clean (200k
  mutations) after the blob-accessor change; full suite 8/8.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMR6tmM7H3obaL7SX14bkJ
…n32)

Closes the last open Phase 2 feature box (issue #19).

- UdpSocket<Impl_T>::JoinMulticastGroup() / LeaveMulticastGroup() forward to the
  impl; posix and win32 UdpSocketImplementation implement them via setsockopt
  IP_ADD_MEMBERSHIP / IP_DROP_MEMBERSHIP (default interface). Available on any UDP
  receive socket once bound; closing the socket leaves joined groups automatically.
- tests/OscMulticastTest.cpp: real loopback -- bind, join 239.7.7.7, send 3 OSC
  messages to the group, assert receipt. Skip-resilient (like the unicast socket
  tests). Wired into CMake (POSIX) and the win32-wine CI job.
- Docs: API.md, ROADMAP.md (multicast now done), STATUS.md.

Verified: OscMulticastTest passes on POSIX (ASan/UBSan-clean) and on win32 under
Wine; full hosted suite 9/9; aarch64 cross-build clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMR6tmM7H3obaL7SX14bkJ
OscMulticastTest died with SIGPIPE on the macOS runners: a connected-UDP send()
to an unrouted multicast group raises SIGPIPE on macOS/BSD (the CI hosts have no
multicast route), killing the process before the test could SKIP.

- posix UdpSocketImplementation now sets SO_NOSIGPIPE (where defined: macOS/BSD)
  so send() returns an error instead of raising SIGPIPE -- mirroring the TCP
  backend. The library should never SIGPIPE the host process.
- OscMulticastTest also installs SIG_IGN for SIGPIPE (non-Windows) as a
  belt-and-suspenders guard, so an unsupported-multicast environment SKIPs cleanly.

Linux + Wine multicast still deliver and pass; full suite 9/9. SO_NOSIGPIPE is
macOS/BSD-only (the #ifdef is skipped on Linux).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MMR6tmM7H3obaL7SX14bkJ
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Phase 2: Multicast receive (cherry-pick from stephram/oscpack)

2 participants