Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-12 08:08:50

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_TEARDOWN_HPP
0012 
0013 #include <boost/beast/core/async_base.hpp>
0014 #include <boost/beast/core/stream_traits.hpp>
0015 #include <boost/beast/core/detail/bind_continuation.hpp>
0016 #include <boost/beast/core/detail/is_invocable.hpp>
0017 #include <boost/asio/append.hpp>
0018 #include <boost/asio/coroutine.hpp>
0019 #include <boost/asio/dispatch.hpp>
0020 #include <memory>
0021 
0022 namespace boost {
0023 namespace beast {
0024 namespace websocket {
0025 
0026 namespace detail {
0027 
0028 template<
0029     class Protocol, class Executor,
0030     class Handler>
0031 class teardown_tcp_op
0032     : public beast::async_base<
0033         Handler, beast::executor_type<
0034             net::basic_stream_socket<
0035                 Protocol, Executor>>>
0036     , public asio::coroutine
0037 {
0038     using socket_type =
0039         net::basic_stream_socket<Protocol, Executor>;
0040 
0041     socket_type& s_;
0042     role_type role_;
0043     bool nb_;
0044 
0045 public:
0046     template<class Handler_>
0047     teardown_tcp_op(
0048         Handler_&& h,
0049         socket_type& s,
0050         role_type role)
0051         : async_base<Handler,
0052             beast::executor_type<
0053                 net::basic_stream_socket<
0054                     Protocol, Executor>>>(
0055             std::forward<Handler_>(h),
0056             s.get_executor())
0057         , s_(s)
0058         , role_(role)
0059         , nb_(false)
0060     {
0061         (*this)({}, 0, false);
0062         this->set_allowed_cancellation(net::cancellation_type::all);
0063     }
0064 
0065     void
0066     operator()(
0067         error_code ec = {},
0068         std::size_t bytes_transferred = 0,
0069         bool cont = true)
0070     {
0071         BOOST_ASIO_CORO_REENTER(*this)
0072         {
0073             nb_ = s_.non_blocking();
0074             s_.non_blocking(true, ec);
0075             if(ec)
0076                 goto upcall;
0077             if(role_ == role_type::server)
0078                 s_.shutdown(net::socket_base::shutdown_send, ec);
0079             if(ec)
0080                 goto upcall;
0081             for(;;)
0082             {
0083                 {
0084                     char buf[2048];
0085                     s_.read_some(net::buffer(buf), ec);
0086                 }
0087                 if(ec == net::error::would_block)
0088                 {
0089                     BOOST_ASIO_CORO_YIELD
0090                     {
0091                         BOOST_ASIO_HANDLER_LOCATION((
0092                             __FILE__, __LINE__,
0093                             "websocket::tcp::async_teardown"
0094                         ));
0095 
0096                         s_.async_wait(
0097                             net::socket_base::wait_read,
0098                                 beast::detail::bind_continuation(std::move(*this)));
0099                     }
0100                     continue;
0101                 }
0102                 if(ec)
0103                 {
0104                     if(ec != net::error::eof)
0105                         goto upcall;
0106                     ec = {};
0107                     break;
0108                 }
0109                 if(bytes_transferred == 0)
0110                 {
0111                     // happens sometimes
0112                     // https://github.com/boostorg/beast/issues/1373
0113                     break;
0114                 }
0115             }
0116             if(role_ == role_type::client)
0117                 s_.shutdown(net::socket_base::shutdown_send, ec);
0118             if(ec)
0119                 goto upcall;
0120             s_.close(ec);
0121         upcall:
0122             if(! cont)
0123             {
0124                 BOOST_ASIO_CORO_YIELD
0125                 {
0126                     BOOST_ASIO_HANDLER_LOCATION((
0127                         __FILE__, __LINE__,
0128                         "websocket::tcp::async_teardown"
0129                         ));
0130 
0131                     const auto ex = this->get_immediate_executor();
0132                     net::dispatch(ex, net::append(std::move(*this), ec));
0133                 }
0134             }
0135             {
0136                 error_code ignored;
0137                 s_.non_blocking(nb_, ignored);
0138             }
0139             this->complete_now(ec);
0140         }
0141     }
0142 };
0143 
0144 } // detail
0145 
0146 //------------------------------------------------------------------------------
0147 
0148 template<class Protocol, class Executor>
0149 void
0150 teardown(
0151     role_type role,
0152     net::basic_stream_socket<
0153         Protocol, Executor>& socket,
0154     error_code& ec)
0155 {
0156     if(role == role_type::server)
0157         socket.shutdown(
0158             net::socket_base::shutdown_send, ec);
0159     if(ec)
0160         return;
0161     for(;;)
0162     {
0163         char buf[2048];
0164         auto const bytes_transferred =
0165             socket.read_some(net::buffer(buf), ec);
0166         if(ec)
0167         {
0168             if(ec != net::error::eof)
0169                 return;
0170             ec = {};
0171             break;
0172         }
0173         if(bytes_transferred == 0)
0174         {
0175             // happens sometimes
0176             // https://github.com/boostorg/beast/issues/1373
0177             break;
0178         }
0179     }
0180     if(role == role_type::client)
0181         socket.shutdown(
0182             net::socket_base::shutdown_send, ec);
0183     if(ec)
0184         return;
0185     socket.close(ec);
0186 }
0187 
0188 template<
0189     class Protocol, class Executor,
0190     class TeardownHandler>
0191 void
0192 async_teardown(
0193     role_type role,
0194     net::basic_stream_socket<
0195         Protocol, Executor>& socket,
0196     TeardownHandler&& handler)
0197 {
0198     static_assert(beast::detail::is_invocable<
0199         TeardownHandler, void(error_code)>::value,
0200             "TeardownHandler type requirements not met");
0201     detail::teardown_tcp_op<
0202         Protocol,
0203         Executor,
0204         typename std::decay<TeardownHandler>::type>(
0205             std::forward<TeardownHandler>(handler),
0206             socket,
0207             role);
0208 }
0209 
0210 } // websocket
0211 } // beast
0212 } // boost
0213 
0214 #endif