Hi Vinnie,

Am Di., 3. Sept. 2019 um 16:23 Uhr schrieb Vinnie Falco <vinnie.falco@gmail.com>:
On Tue, Sep 3, 2019 at 7:22 AM Stephan Menzel via Boost-users
<boost-users@lists.boost.org> wrote:
> I'm trying to realize an old dream in asio. A function that will take a socket
> and asynchronously...connect to the result while having a timeout around
> the operation.

Like this?

<https://www.boost.org/doc/libs/1_71_0/libs/beast/doc/html/beast/ref/boost__beast__basic_stream/async_connect/overload1.html>

Well, not exactly. I wanted to do the resolve and connect in one go. This one has a timeout though, which already is a huge step in the right direction. Didn't know this existed.

Anyway, your implementation did bring me to beast::bind_handler, which eventually led me to a working implementation:
as it enabled me to adopt the handler to async ops with different handler requirements.

However, since I'm here ;-) may I ask a followup in this regard:

I have had success with beast::bind_handler using it in timed_connect like this:

    template <typename Self>
    void operator()(Self &n_self, const boost::system::error_code &n_error = boost::system::error_code(),
            boost::asio::ip::tcp::resolver::results_type n_results = boost::asio::ip::tcp::resolver::results_type(),
            boost::asio::ip::tcp::endpoint n_connected_ep = boost::asio::ip::tcp::endpoint()) {

    reenter(m_coro) {
        ....
        yield boost::asio::async_connect(m_socket, n_results, 
            boost::beast::bind_handler(std::forward<Self>(n_self), boost::placeholders::_1,
                boost::asio::ip::tcp::resolver::results_type(), boost::placeholders::_2));
        ....
    }}

Now, this is great as it was key to have placeholders and therefore combine async ops with incompatible handler types. However, I tried to adopt the exact same thing in my next operation, which shall wrap up a socks4 handshake. Like this
     
      template <typename Self>
      void operator()(Self &n_self, boost::system::error_code n_error = boost::system::error_code(),
          std::size_t = 0,
          boost::asio::ip::tcp::resolver::results_type n_results = boost::asio::ip::tcp::resolver::results_type()) {

     reenter(m_coro) {
        ....
        yield m_resolver.async_resolve(tcp::v4(), *m_target_hostname, *m_target_servicename,
                tcp::resolver::query::numeric_service,
                boost::beast::bind_handler(std::move(n_self), boost::placeholders::_1, 0, boost::placeholders::_2));
        ....
    }}

and in this context, it fails. I have tried many different variations and all I'm getting is crashes in the async_resolve operation that look like moving the handler fails at runtime. Or strange errors at runtime when the op returns with 995, which I suppose means a similar thing, e.g. m_resolver being destroyed

Strangely it doesn't seem to matter which op I use the bind_handler with. There is a reolve, a write and a read. Each one will fail weirdly at runtime when I use the bind_handler to adapt the handler type. Of course, I change the signature for operator() for those trials.

I strongly suspect it's got something to do with the moving that fails but there's no difference between this object and the one I use in TimedConnect which works great. Here's the data members:

    boost::asio::ip::tcp::socket    &m_socket;
    boost::asio::ip::tcp::resolver   m_resolver;
    std::unique_ptr<std::string>     m_target_hostname;
    boost::uint16_t                  m_target_port;
    boost::asio::coroutine           m_coro;

Nothing that can't be moved....

Anyway, maybe change move errors when using bind_handler rings a bell.

Thanks for your suggestions,
Stephan