Wyverex
Wyverex

Reputation: 15

boost::asio completion handler on async_connect never called again after first failure

I'm writing a small client class that uses boost asio to connect to a remote socket. It should be able to try to reconnect if the initial connection failed.

When testing for that scenario, i.e. there is no open remote socket, the completion handler of async_connect got called correctly the first time. But my completion handler will never be called again for the second attempt when m_state goes into State_Connect again. What am I doing wrong?

class Test
{
    public:
        Test() : m_socket(m_io)
        {
        }

        void update()
        {
            switch (m_state)
            {
                case State_Connect:
                    std::cout << "Start connect\n";
                    m_socket.async_connect(tcp::endpoint(tcp::v4(), 33000),
                        boost::bind(&Test::onCompleted, this, asio::placeholders::error));
                    m_state = State_Connecting;
                    break;

                case State_Connecting:
                    if (m_error)
                    {
                        m_error.clear();
                        std::cout << "Could not connect\n";
                        m_state = State_Connect;
                    }
                    break;
            }

            m_io.poll_one();
        }

    private:
        void onCompleted(const bs::error_code& error)
        {
            if (error)
            {
                m_error = error;
                m_socket.close();
            }
        }

        enum State
        {
            State_Connect,
            State_Connecting,
        };
        State           m_state = State_Connect;

        asio::io_service    m_io;
        tcp::socket         m_socket;
        bs::error_code      m_error;
};

int main(int argc, char* argv[])
{
    Test test;
    for (;;)
    {
        test.update();
        boost::this_thread::sleep(boost::posix_time::milliseconds(20));
    }
    return 0;
}

Output is: Start connect Could not connect Start connect

But I expect it to repeat indefinitely.

Upvotes: 1

Views: 781

Answers (1)

rafix07
rafix07

Reputation: 20936

Reference

When an io_context object is stopped, calls to run(), run_one(), poll() or poll_one() will return immediately without invoking any handlers.

When you call poll_one() and no handler is ready, poll_one() function marks io_service as stopped. poll_one() has nothing to do when m_state is State_Connecting and in this moment io_service is marked as stopped due to the empty queue of handlers.

You can test if io_service is stopped, if so call reset:

if (m_io.stopped())
   m_io.reset();
m_io.poll_one();

Upvotes: 2

Related Questions