// // Copyright (c) 2013-2016 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // #ifndef BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED #define BEAST_WEBSOCKET_IMPL_SSL_IPP_INCLUDED #include #include namespace beast { namespace websocket { namespace detail { /* See http://stackoverflow.com/questions/32046034/what-is-the-proper-way-to-securely-disconnect-an-asio-ssl-socket/32054476#32054476 Behavior of ssl::stream regarding close_ If the remote host calls async_shutdown then the local host's async_read will complete with eof. If both hosts call async_shutdown then the calls to async_shutdown will complete with eof. */ template class teardown_ssl_op { using stream_type = boost::asio::ssl::stream; struct data { stream_type& stream; Handler h; bool cont; int state = 0; template data(DeducedHandler&& h_, stream_type& stream_) : stream(stream_) , h(std::forward(h_)) , cont(boost_asio_handler_cont_helpers:: is_continuation(h)) { } }; std::shared_ptr d_; public: template explicit teardown_ssl_op( DeducedHandler&& h, stream_type& stream) : d_(std::make_shared( std::forward(h), stream)) { (*this)(error_code{}, false); } void operator()(error_code ec, bool again = true); friend void* asio_handler_allocate(std::size_t size, teardown_ssl_op* op) { return boost_asio_handler_alloc_helpers:: allocate(size, op->d_->h); } friend void asio_handler_deallocate(void* p, std::size_t size, teardown_ssl_op* op) { return boost_asio_handler_alloc_helpers:: deallocate(p, size, op->d_->h); } friend bool asio_handler_is_continuation( teardown_ssl_op* op) { return op->d_->cont; } template friend void asio_handler_invoke(Function&& f, teardown_ssl_op* op) { return boost_asio_handler_invoke_helpers:: invoke(f, op->d_->h); } }; template void teardown_ssl_op:: operator()(error_code ec, bool again) { auto& d = *d_; d.cont = d.cont || again; while(!ec && d.state != 99) { switch(d.state) { case 0: d.state = 99; d.stream.async_shutdown(*this); return; } } d.h(ec); } } // detail //------------------------------------------------------------------------------ template void teardown( boost::asio::ssl::stream& stream, error_code& ec) { stream.shutdown(ec); } template void async_teardown( boost::asio::ssl::stream& stream, TeardownHandler&& handler) { static_assert(beast::is_CompletionHandler< TeardownHandler, void(error_code)>::value, "TeardownHandler requirements not met"); detail::teardown_ssl_op::type>{std::forward( handler), stream}; } } // websocket } // beast #endif