Boost logo

Boost Users :

From: Martijn Otto (boost_at_[hidden])
Date: 2024-01-18 19:19:19


ASIO will assume ownership of the socket, which means it'll close the
socket when it's destructed. If you don't want this, you have to call
`release()` on it before destructing.

That _might_ help, or it might not, ASIO might do different things to
the socket as well. Depending on the platform, it'll use different
techniques for waiting on the socket, might be epoll on linux, kqueue
on BSD (including mac), etc... In my experience, if it's a pipe, it'll
work with epoll on linux, but it might fail on BSD. YMMV.

On Thu, 2024-01-18 at 19:44 +0100, Dominique Devienne via Boost-users
wrote:
> Sorry, sent originally to the wrong list.
> And this is on Windows 10 too, BTW.
> Haven't tried Linux with that code yet. --DD
>
> ---------- Forwarded message ---------
> From: Dominique Devienne <ddevienne_at_[hidden]>
> Date: Thu, Jan 18, 2024 at 7:18 PM
> Subject: Using ASIO to wait on a foreign socket being readable, with
> a timeout
> To: <boost_at_[hidden]>
>
>
> 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
>
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> https://lists.boost.org/mailman/listinfo.cgi/boost-users


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net