Using ASIO to wait on a foreign socket being readable, with a timeout
Hi, I'm trying to use ASIO to wait until a socket is ready to read, or timeout. This is a blocking wait. But the socket is not "owned" by ASIO, but is from the libpq PostgreSQL connection. So ASIO should NOT consume any of the input on the socket, just notify me when that socket is "read-ready". I've cobbled together the following test code: ``` const int socket2 = PQsocket(conn2.handle()); BOOST_CHECK(socket2 > 0); int timr_err_code = 0; int sock_err_code = 0; bool timr_aborted = false; bool sock_aborted = false; std::string timr_err_msg; std::string sock_err_msg; bool timed_out = true; auto c1 = "C# 1"sv; conn2.listen(c1); conn1->notify(c1, "wake up!"sv); { boost::asio::io_context io_ctx; boost::asio::ip::tcp::socket io_sock(io_ctx); io_sock.assign(boost::asio::ip::tcp::v4(), socket2); boost::asio::steady_timer io_timer(io_ctx); io_timer.expires_from_now(std::chrono::milliseconds(100)); io_sock.async_wait( io_sock.wait_read, [&](const boost::system::error_code& errc) { if (errc) { sock_err_code = errc.value(); sock_err_msg = errc.message(); sock_aborted = (errc == boost::asio::error::operation_aborted); } timed_out = false; //io_timer.cancel(); io_ctx.stop(); } ); io_timer.async_wait( [&](const boost::system::error_code& errc) { if (errc) { timr_err_code = errc.value(); timr_err_msg = errc.message(); timr_aborted = (errc == boost::asio::error::operation_aborted); } io_sock.cancel(); io_ctx.stop(); } ); io_ctx.run(); // blocks until either async op above runs } // there's a notif to read, so io_sock.async_wait should have completed BOOST_CHECK_EQUAL(timr_err_code, 0); BOOST_CHECK_EQUAL(sock_err_code, 0); BOOST_CHECK_EQUAL(timr_err_msg, ""); BOOST_CHECK_EQUAL(sock_err_msg, ""); BOOST_CHECK_EQUAL(timr_aborted, false); BOOST_CHECK_EQUAL(sock_aborted, false); BOOST_CHECK_EQUAL(timed_out, false); auto notif = conn2.notification(); BOOST_REQUIRE(notif); BOOST_CHECK_EQUAL(notif.backend_pid(), pid1); BOOST_CHECK_EQUAL(notif.channel(), c1); BOOST_CHECK_EQUAL(notif.payload(), "wake up!"sv); ``` The io_sock.async_wait(io_sock.wait_read, ...) succeeds, the IO loop stops as expected, but when I try to PQconsumeInput() from the LIBPQ connection next (as shown in the code below) ``` Notification Connection::notification() { auto [lock, hndl] = ensure_handle(); if (1 != PQconsumeInput(hndl)) { throw std::runtime_error(error_msg()); // <<<<<< THROWS } PGnotify_uptr notif{ PQnotifies(hndl) }; return Notification(std::move(notif)); // may be null } ``` that calls fail with this error message: fatal error: in "NotificationTests/test_across_backends": class std::runtime_error: could not receive data from server: Socket operation on non-socket (0x00002736/10038) LIBPQ didn't like what ASIO somehow did on the socket descriptor. The LIBPQ doc says to select() the descriptor, but I thought ASIO would be cleaner, more C++, and perhaps more cross-platform. Can somehow help, telling me if I'm using ASIO incorrectly here? Thanks, --DD
On Thu, Jan 18, 2024, at 7:18 PM, Dominique Devienne via Boost wrote:
Hi,
I'm trying to use ASIO to wait until a socket is ready to read, or timeout. This is a blocking wait. But the socket is not "owned" by ASIO, but is from the libpq PostgreSQL connection. So ASIO should NOT consume any of the input on the socket, just notify me when that socket is "read-ready".
I've cobbled together the following test code:
``` ... boost::asio::ip::tcp::socket io_sock(io_ctx); io_sock.assign(boost::asio::ip::tcp::v4(), socket2);
You `assign()`ed the fd, but never `release()` it, so the socket desctructor closed it.
On Wed, 31 Jan 2024 at 21:46, Seth via Boost
On Thu, Jan 18, 2024, at 7:18 PM, Dominique Devienne via Boost wrote:
Hi,
I'm trying to use ASIO to wait until a socket is ready to read, or timeout. This is a blocking wait. But the socket is not "owned" by ASIO, but is from the libpq PostgreSQL connection. So ASIO should NOT consume any of the input on the socket, just notify me when that socket is "read-ready".
I've cobbled together the following test code:
``` ... boost::asio::ip::tcp::socket io_sock(io_ctx); io_sock.assign(boost::asio::ip::tcp::v4(), socket2);
You `assign()`ed the fd, but never `release()` it, so the socket desctructor closed it.
Another way that supports RAII (at least with a unix-like OS): boost::asio::ip::tcp::socket io_sock(io_ctx); io_sock.assign(boost::asio::ip::tcp::v4(), *::dup(*socket2*)*);
_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
participants (3)
-
Dominique Devienne
-
Richard Hodges
-
Seth