简体   繁体   中英

Boost.Asio async_handshake cannot be canceled

When initiating an async_handshake with a Boost Asio SSL stream, and then implementing a deadline timer to cancel/close the stream before the handshake completes, the program will crash with a buffer overflow exception (on Windows, I haven't tried Linux yet). The crash is somewhere after the socket is close d, and external handlers finish executing, but before the run() command completes.

Is there a reason why the socket cannot be closed when an SSL handshake is in progress? Or is this a bug in Boost Asio?

class Connection
{
    void connect_handler(const boost::system::error_code &err)
    {
        ...
        ssock->async_handshake(boost::asio::ssl::stream_base::client,
                   boost::bind(&Connection::handle_handshake, this, _1));
        ...
    }

    void handle_handshake(const boost::system::error_code &err)
    {
        // CONNECTED SECURELY
    }

    void handle_timeout()
    {
        // HANDLE SSL SHUTDOWN IF ALREADY CONNECTED...
        ...
        ssock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
        ssock->close();
        delete ssock;
    }

    ...

    boost::asio::ssl::stream<boost::asio::ip::tcp::socket> *ssock;
};

To clarify, calling handle_timeout() before handle_handshake() is called by the IO service will crash in the io_service::run() method.

The problem is the socket object is being destroyed before the asynchronous handlers complete. To cancel the pending/queued handlers, use io_service::stop() like this:

io_service.stop(); // Stop the IO service to prevent handlers from executing
ssock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
ssock->close();
delete ssock;

So no, it is not a bug in Boost.Asio itself.

We've ran into that one as well. My colleague (AW) found that culprit. Handshake uses read and write operations behind the scene, those need to be cancelled, and the handshake operation needs to properly finish (with operation_aborted error) before the ssock can be safely closed. Tested solution for this is below:

void handle_timeout() {
  ...

  // cancel pending read/write operations
  ssock->lowest_layer().cancel();

  // finish shutdown on next tick of event loop
  boost::asio::post([=] {
    ssock->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
    ssock->close();
    delete ssock;
  });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM