Using boost's SSL asio code, async_write_some hangs
boost-asio, multithreading, ssl
Solution
This is the result of a multi-threading issue.
For most Boost.Asio objects, it is safe to have multiple asynchronous operations pending on an object; it is just specified that concurrent calls on the object are unsafe. Nevertheless, it normally does not present a problem on some types, such as `ip::tcp::socket`. However, `ssl::stream` accentuates that:
The application must also ensure that all asynchronous operations are performed within the same implicit or explicit strand.
In your case, the solution is to `wrap()` each composed operation's completion handler by the same strand. This will result in all intermediate operations being invoked within the strand. For more details about thread safety and nuance details of strands, considering reading this answer.
Problem
I have some multi-threaded code that uses Boost's SSL ASIO library. The code is multi-threaded, but there's a mutex associated with each SSL connection and calls to `async_*` functions are done holding the mutex. I sometimes see my code grind to a halt. There's a stuck thread. The thread is stuck in `bio_write`. The stack trace looks this: ``` #0 0x00000000010a974f in bio_write () #1 0x00000000010a3529 in BIO_write () #2 0x000000000105fe72 in ssl3_write_pending () #3 0x0000000001060b02 in ssl3_write_bytes () #4 0x0000000000cce43a in boost::asio::ssl::detail::engine::do_write (this=0x1e618a0, data=0x234c7b0, length=189) at /usr/include/boost/asio/ssl/detail/impl/engine.ipp:294 #5 0x0000000000cce109 in boost::asio::ssl::detail::engine::perform(this=0x1e618a0, op=(int (boost::asio::ssl::detail::engine::*)(boost::asio::ssl::detail::engine * const, void *, std::size_t)) 0xcce3fc<boost::asio::ssl::detail::engine::do_write(void*, unsigned long)>, data=0x234c7b0, length=189, ec=..., bytes_transferred=0x7fff8ad74d48) at /usr/include/boost/asio/ssl/detail/impl/engine.ipp:219 #6 0x0000000000ccdd23 in boost::asio::ssl::detail::engine::write (this=0x1e618a0, data=..., ec=..., bytes_transferred=@0x7fff8ad74d48: 0) at /usr/include/boost/asio/ssl/detail/impl/engine.ipp:137 #7 0x0000000000dac504 in boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>::operator() (this=0x7fff8ad74d20, eng=..., ec=..., bytes_transferred=@0x7fff8ad74d48: 0) at /usr/include/boost/asio/ssl/detail/write_op.hpp:51 #8 0x0000000000da9d8a in boost::asio::ssl::detail::io_op<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > >::operator() (this=0x7fff8ad74d10, ec=..., bytes_transferred=0, start=1) at /usr/include/boost/asio/ssl/detail/io.hpp:136 #9 0x0000000000da7f42 in boost::asio::ssl::detail::async_io<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> >, boost::asio::ssl::detail::write_op<boost::asio::mutable_buffers_1>, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > > (next_layer=..., core=..., op=..., handler=...) at /usr/include/boost/asio/ssl/detail/io.hpp:322 #10 0x0000000000da634d in boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >::async_write_some<boost::asio::mutable_buffers_1, boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > > (this=0x1e61880, buffers=..., handler=...) at /usr/include/boost/asio/ssl/stream.hpp:502 #11 0x0000000000da3032 in boost::asio::detail::write_op<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::mutable_buffers_1, boost::asio::detail::transfer_all_t, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > >::operator() (this=0x7fff8ad74f00, ec=..., bytes_transferred=0, start=1) at /usr/include/boost/asio/impl/write.hpp:250 #12 0x0000000000d9ffbb in boost::asio::async_write<boost::asio::ssl::stream<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::stream_socket_service<boost::asio::ip::tcp> > >, boost::asio::mutable_buffers_1, boost::_bi::bind_t<void, boost::_mfi::mf2<void, Peer, boost::system::error_code const&, unsigned long>, boost::_bi::list3<boost::_bi::value<boost::shared_ptr<Peer> >, boost::arg<1> (*)(), boost::arg<2> (*)()> > > (s=..., buffers=..., handler=...) at /usr/include/boost/asio/impl/write.hpp:585 ``` Any ideas?