2

I am using the asio library and I am trying to connect to a socket. Sometimes, the socket may take a very long time to connect. In that case, i just want to cancel the connection.

I am attempting to use std::future and asio::use_future with asynchronous operations to do that. My idea is that i will call the asio::ip::tcp::socket's member function async_connect() with asio::use_future() and then the wait_for() to wait for the std::future and check if it is ready or timed out.

If it is timed out I will cancel (return false) and if it is ready, I will continue the work. However, if I attempt to use wait_for() and wait for the operation it will never be ready (it almost seems as if it is never run, but not sure how to verify that). Running the same code without using the std::future seems to work fine, but I won't be able to enforce a timeout.

This is the code I tried.

asio::ip::tcp::endpoint endpoint(asio::ip::make_address(peer.address, ec), peer.port);

        if (ec)
        {
            std::cout << ec.message() << std::endl;
            return false;
        }

        asio::io_context context;

        asio::ip::tcp::socket socket{context};

        std::chrono::milliseconds span(100);

        std::future<void> connect_status = socket.async_connect(endpoint, asio::use_future);

        if (connect_status.wait_for(span) == std::future_status::timeout)
            return false;

        connect_status.get();
Milan Š.
  • 1,353
  • 1
  • 2
  • 11
ILutRf7
  • 39
  • 2
  • Your `io_context` isn't running so no asynchronous processing will happen. See http://think-async.com/Asio/boost_asio_1_10_6/doc/html/boost_asio/example/cpp11/futures/daytime_client.cpp for an example – Alan Birtles Jan 07 '23 at 09:26
  • If I run the context before the wait_for, it blocks, if I do it after, then I can't tell if it times out or not. The example they use doesn't have a wait_for, which is why I couldn't figure it out. – ILutRf7 Jan 07 '23 at 10:50
  • you'll need to run it in a thread, see the example – Alan Birtles Jan 07 '23 at 10:52

1 Answers1

1

The asio::io_context is responsible for performing any asynchronous work. In order for it to do that you must run context.run().

For example see: https://www.boost.org/doc/libs/1_81_0/doc/html/boost_asio/example/cpp11/futures/daytime_client.cpp.

The fixed version of your code would be:

asio::ip::tcp::endpoint endpoint(asio::ip::make_address(peer.address, ec), peer.port);

if (ec)
{
    std::cout << ec.message() << std::endl;
    return false;
}

asio::io_context context;
auto work = boost::asio::make_work_guard(context);
std::thread thread([&context](){ context.run(); });

asio::ip::tcp::socket socket{context};

std::chrono::milliseconds span(100);

std::future<void> connect_status = socket.async_connect(endpoint, asio::use_future);

if (connect_status.wait_for(span) == std::future_status::timeout)
    return false;

connect_status.get();
Alan Birtles
  • 32,622
  • 4
  • 31
  • 60
  • True, though I'd probably simplify this http://coliru.stacked-crooked.com/a/5e9444fa2b56e6d0 - of course with c++20 I'd suggest coroutines (something like this https://compiler-explorer.com/z/M6afavnM5) – sehe Jan 07 '23 at 18:31
  • @sehe I went with your solution since it seemed the shortest. It works mostly but I occasionally get seg faults. I narrowed it down to happen between two lines of code. My code is here: https://compiler-explorer.com/z/xozWfdjhT it seems between checkpoint 3 and 4 a segfault occurs. Do you have any idea what would cause that or if there is any fault in my logic? – ILutRf7 Jan 09 '23 at 10:22
  • @ILutRf7 you should ask a new question if you have a new problem. Note that `std::move(std::make_shared` is just weird (but not related to your problem). Looks like you have an unhandled exception, that's not unexpected, you need to catch and handle exceptions – Alan Birtles Jan 09 '23 at 10:26
  • Sure thing. I asked a new question here [link](https://stackoverflow.com/questions/75056039/segfault-on-async-boost-asio-with-use-future), but for your response, I am wrapping the entire method with a try-catch block in my actual code. Would this not avoid the unhandled exception? Also my understanding is that segfault is different from uncaught exception. – ILutRf7 Jan 09 '23 at 10:42