Improve network stack#876
Conversation
|
@x37v if you want to review / test this version with your stack. I need to do a bit more testing but we now have:
|
|
@jcelerier I managed to build this branch into my score dev environment. However, I had to comment out all calls to I tested OSCQuery device, gives the same results under this branch or with release 3.8.1 :
I confirm that user agent is different in the websocket setup header : 3.8.1 : Is there a way to test socket.io from Score at the moment ? |
|
@jcelerier sorry for the slow response, pretty busy with the latest release and various tasks around that but I will get to this. |
|
thanks for the review @ogauthiersat ! and no worries @x37v, the branch still needs a fair bit of polishing ::) |
a63d9c4 to
1d3fe70
Compare
4337901 to
450ea74
Compare
…removal - websocket_simple_beast: the duck-typed simple client stored its member as unique_ptr<websocket_client_beast>, but make_websocket_client() returns the websocket_client_interface base (and the beast header is not included here). This broke every libossia build that compiles osc_factory.cpp (i.e. all platforms). Store the interface type instead. - http_client_request: a response to a HEAD request never carries a body even when it advertises Content-Length. Tell the beast parser to skip the body for HEAD, otherwise it waits for bytes that never arrive and fails with "partial message". Fixes the http_client_head test. - HttpClientRequestTest: include the boost.asio headers it uses directly (streambuf, read, read_until, buffers_iterator, write) instead of relying on transitive includes that no longer pull them in. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRveXCy9GX7Kt7xD2ydd7v
The websocketpp->beast port performed synchronous beast writes from the producer (device/score) thread while an async_read was in flight on the io thread. A beast websocket::stream is not thread-safe; the old websocketpp send() was. ThreadSanitizer confirms the data race; this commit makes every send marshal onto the connection strand through an async write queue (one write in flight, payload copied so it outlives the op), restoring the thread-safe-send semantics. Server (websocket_server_beast): - per-connection async write queue dispatched on the strand; close() also dispatched (it shares the stream with the in-flight read). - find_connection() returns a shared_ptr (was a raw pointer freed under a TOCTOU window by the io thread). - on_accept() re-arms on transient errors instead of killing the listener. Client (websocket_client_beast): - same strand-dispatched async write queue. - remote_endpoint() now uses the non-throwing overload (a throw here ran inside io_context::run and would stop all networking). - wss:// is rejected loudly instead of silently connecting in plaintext (TLS is not implemented in the beast backend yet); factory docs fixed. OSCQuery: - open_osc_sender() sets up client.sender under m_clientsMutex; it was written by the io thread while push() read it under the lock (TSAN race). - query_parser query-string slice off-by-one (read one byte past the end). Socket.IO: - do_accept_ws() passed the request by value; async_accept borrowed the destroyed local -> use the member (use-after-free). - same strand write queue; ping/probe go through it; close() on the strand; parse_* use the non-throwing boost::json::parse; Emscripten build guards. websocket_simple_beast: guard the listener list with a mutex. examples/Web: usleep -> std::this_thread::sleep_for (Windows build). New: tests/Network/NetworkThreadSafetyTest validates the WS send race, the teardown path, and concurrent OSCQuery pushes over both transports. Verified under TSAN (0 races), ASAN/UBSAN (0 errors), and the full suite (59/59) on gcc-14 and clang-20. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRveXCy9GX7Kt7xD2ydd7v
…build A parent project that embeds libossia with CMAKE_INCLUDE_CURRENT_DIR ON (score does, globally) leaks that setting into the vendored Abseil add_subdirectory. Each Abseil target then gets its own source/binary dir on the include path, so `absl/time/time.h` shadows the system <time.h>, which breaks libstdc++'s <ctime>/<chrono> and fails the abseil build under clang. Force the flag off inside the existing block() (scoped, so the parent's setting is restored afterwards). No-op for standalone libossia, where the flag is already off. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRveXCy9GX7Kt7xD2ydd7v
websocket_client_beast derives from the OSSIA_EXPORT websocket_client_interface whose vtable lives in a .cpp, so any use of it (or the make_websocket_client factory) requires linking libossia. Tiny standalone tools that consume ossia headers only — e.g. score's vst/vst3/clap puppets, which link $<COMPILE_ONLY:ossia> and must not depend on libossia.so — therefore can't use it. Add websocket_simple_header_client: a fully inline beast-based client (reusing parse_websocket_uri and the common ws types) that connects, fires on_open/on_fail/on_close, sends text/binary frames and closes. Driven by a single-threaded io_context, so sends are synchronous. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRveXCy9GX7Kt7xD2ydd7v
score builds with CMAKE_UNITY_BUILD ON, which leaks into the vendored Abseil add_subdirectory. Abseil's cctz sources are not unity-safe: time_zone_posix.cc and time_zone_fixed.cc each define a namespace-scope `kDigits`, so the merged unity TU fails with "redefinition of 'kDigits'". Force unity off for Abseil inside the existing scoped block(); the parent setting is unchanged. No-op for standalone libossia (unity already off). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WRveXCy9GX7Kt7xD2ydd7v
OSCQuery publication / exploration examples seem to work fine and are compatible with the previous version.