Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:35

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/bind_handler.hpp>
0015 #include <boost/beast/core/stream_traits.hpp>
0016 #include <boost/beast/core/detail/bind_continuation.hpp>
0017 #include <boost/beast/core/detail/is_invocable.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, bind_front_handler(
0133                         std::move(*this), ec));
0134                 }
0135             }
0136             {
0137                 error_code ignored;
0138                 s_.non_blocking(nb_, ignored);
0139             }
0140             this->complete_now(ec);
0141         }
0142     }
0143 };
0144 
0145 } // detail
0146 
0147 //------------------------------------------------------------------------------
0148 
0149 template<class Protocol, class Executor>
0150 void
0151 teardown(
0152     role_type role,
0153     net::basic_stream_socket<
0154         Protocol, Executor>& socket,
0155     error_code& ec)
0156 {
0157     if(role == role_type::server)
0158         socket.shutdown(
0159             net::socket_base::shutdown_send, ec);
0160     if(ec)
0161         return;
0162     for(;;)
0163     {
0164         char buf[2048];
0165         auto const bytes_transferred =
0166             socket.read_some(net::buffer(buf), ec);
0167         if(ec)
0168         {
0169             if(ec != net::error::eof)
0170                 return;
0171             ec = {};
0172             break;
0173         }
0174         if(bytes_transferred == 0)
0175         {
0176             // happens sometimes
0177             // https://github.com/boostorg/beast/issues/1373
0178             break;
0179         }
0180     }
0181     if(role == role_type::client)
0182         socket.shutdown(
0183             net::socket_base::shutdown_send, ec);
0184     if(ec)
0185         return;
0186     socket.close(ec);
0187 }
0188 
0189 template<
0190     class Protocol, class Executor,
0191     class TeardownHandler>
0192 void
0193 async_teardown(
0194     role_type role,
0195     net::basic_stream_socket<
0196         Protocol, Executor>& socket,
0197     TeardownHandler&& handler)
0198 {
0199     static_assert(beast::detail::is_invocable<
0200         TeardownHandler, void(error_code)>::value,
0201             "TeardownHandler type requirements not met");
0202     detail::teardown_tcp_op<
0203         Protocol,
0204         Executor,
0205         typename std::decay<TeardownHandler>::type>(
0206             std::forward<TeardownHandler>(handler),
0207             socket,
0208             role);
0209 }
0210 
0211 } // websocket
0212 } // beast
0213 } // boost
0214 
0215 #endif