From a9da358e22a8bcda7c2e99625ecc48a536e87b4e Mon Sep 17 00:00:00 2001 From: Noah Roberts Date: Thu, 25 Apr 2024 13:16:38 -0700 Subject: [PATCH] fix: avoids deadlock when requesting info on disconnected inlet * Adds test to for calling info on a disconnected stream_inlet to testing/ext/discovery.cpp * Fixes deadlock that occurred by checking return value of buffer.connect and throwing a system_error based on the error_code in buffer if the check fails. issue: sccn/liblsl#201 --- src/info_receiver.cpp | 5 ++++- testing/ext/discovery.cpp | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/info_receiver.cpp b/src/info_receiver.cpp index 2f26daab..36e1355f 100644 --- a/src/info_receiver.cpp +++ b/src/info_receiver.cpp @@ -52,7 +52,10 @@ void lsl::info_receiver::info_thread() { buffer.register_at(&conn_); std::iostream server_stream(&buffer); // connect... - buffer.connect(conn_.get_tcp_endpoint()); + if (nullptr == buffer.connect(conn_.get_tcp_endpoint())) + { + throw asio::system_error(buffer.error()); + } // send the query server_stream << "LSL:fullinfo\r\n" << std::flush; // receive and parse the response diff --git a/testing/ext/discovery.cpp b/testing/ext/discovery.cpp index 7d66e6e3..4523a1fe 100644 --- a/testing/ext/discovery.cpp +++ b/testing/ext/discovery.cpp @@ -43,5 +43,21 @@ TEST_CASE("fullinfo", "[inlet][fullinfo][basic]") { CHECK(fullinfo.desc().child_value("info") == extinfo); } +TEST_CASE("downed outlet deadlock", "[inlet][streaminfo]") +{ + // This test verifies that calling info on a resolved inlet that has become disconnected + // does not get locked waiting on a response. + auto outlet = std::make_unique(lsl::stream_info("deadtest", "type")); + + auto resolved = lsl::resolve_streams(); + REQUIRE(!resolved.empty()); + lsl::stream_inlet inlet(resolved[0]); + + outlet.reset(); + + // this would previously deadlock + CHECK_THROWS(inlet.info()); +} + } // namespace