Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:27:55

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_CORE_IMPL_BASIC_STREAM_HPP
0011 #define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
0012 
0013 #include <boost/beast/core/async_base.hpp>
0014 #include <boost/beast/core/buffer_traits.hpp>
0015 #include <boost/beast/core/buffers_prefix.hpp>
0016 #include <boost/beast/websocket/teardown.hpp>
0017 #include <boost/asio/append.hpp>
0018 #include <boost/asio/coroutine.hpp>
0019 #include <boost/assert.hpp>
0020 #include <boost/make_shared.hpp>
0021 #include <boost/core/exchange.hpp>
0022 #include <cstdlib>
0023 #include <type_traits>
0024 #include <utility>
0025 
0026 namespace boost {
0027 namespace beast {
0028 
0029 //------------------------------------------------------------------------------
0030 
0031 template<class Protocol, class Executor, class RatePolicy>
0032 template<class... Args>
0033 basic_stream<Protocol, Executor, RatePolicy>::
0034 impl_type::
0035 impl_type(std::false_type, Args&&... args)
0036     : socket(std::forward<Args>(args)...)
0037     , read(ex())
0038     , write(ex())
0039     , timer(ex())
0040 {
0041     reset();
0042 }
0043 
0044 template<class Protocol, class Executor, class RatePolicy>
0045 template<class RatePolicy_, class... Args>
0046 basic_stream<Protocol, Executor, RatePolicy>::
0047 impl_type::
0048 impl_type(std::true_type,
0049     RatePolicy_&& policy, Args&&... args)
0050     : boost::empty_value<RatePolicy>(
0051         boost::empty_init_t{},
0052         std::forward<RatePolicy_>(policy))
0053     , socket(std::forward<Args>(args)...)
0054     , read(ex())
0055     , write(ex())
0056     , timer(ex())
0057 {
0058     reset();
0059 }
0060 
0061 template<class Protocol, class Executor, class RatePolicy>
0062 template<class Executor2>
0063 void
0064 basic_stream<Protocol, Executor, RatePolicy>::
0065 impl_type::
0066 on_timer(Executor2 const& ex2)
0067 {
0068     BOOST_ASSERT(waiting > 0);
0069 
0070     // the last waiter starts the new slice
0071     if(--waiting > 0)
0072         return;
0073 
0074     // update the expiration time
0075     BOOST_VERIFY(timer.expires_after(
0076         std::chrono::seconds(1)) == 0);
0077 
0078     rate_policy_access::on_timer(policy());
0079 
0080     struct handler : boost::empty_value<Executor2>
0081     {
0082         boost::weak_ptr<impl_type> wp;
0083 
0084         using executor_type = Executor2;
0085 
0086         executor_type
0087         get_executor() const noexcept
0088         {
0089             return this->get();
0090         }
0091 
0092         handler(
0093             Executor2 const& ex2,
0094             boost::shared_ptr<impl_type> const& sp)
0095             : boost::empty_value<Executor2>(
0096                 boost::empty_init_t{}, ex2)
0097             , wp(sp)
0098         {
0099         }
0100 
0101         void
0102         operator()(error_code ec)
0103         {
0104             auto sp = wp.lock();
0105             if(! sp)
0106                 return;
0107             if(ec == net::error::operation_aborted)
0108                 return;
0109             BOOST_ASSERT(! ec);
0110             if(ec)
0111                 return;
0112             sp->on_timer(this->get());
0113         }
0114     };
0115 
0116     // wait on the timer again
0117     ++waiting;
0118     timer.async_wait(handler(ex2, this->shared_from_this()));
0119 }
0120 
0121 template<class Protocol, class Executor, class RatePolicy>
0122 void
0123 basic_stream<Protocol, Executor, RatePolicy>::
0124 impl_type::
0125 reset()
0126 {
0127     // If assert goes off, it means that there are
0128     // already read or write (or connect) operations
0129     // outstanding, so there is nothing to apply
0130     // the expiration time to!
0131     //
0132     BOOST_ASSERT(! read.pending || ! write.pending);
0133 
0134     if(! read.pending)
0135         BOOST_VERIFY(
0136             read.timer.expires_at(never()) == 0);
0137 
0138     if(! write.pending)
0139         BOOST_VERIFY(
0140             write.timer.expires_at(never()) == 0);
0141 }
0142 
0143 template<class Protocol, class Executor, class RatePolicy>
0144 void
0145 basic_stream<Protocol, Executor, RatePolicy>::
0146 impl_type::
0147 close() noexcept
0148 {
0149     {
0150         error_code ec;
0151         socket.close(ec);
0152     }
0153 #if !defined(BOOST_NO_EXCEPTIONS)
0154     try
0155     {
0156         timer.cancel();
0157     }
0158     catch(...)
0159     {
0160     }
0161 #else
0162     timer.cancel();
0163 #endif
0164 }
0165 
0166 //------------------------------------------------------------------------------
0167 
0168 template<class Protocol, class Executor, class RatePolicy>
0169 template<class Executor2>
0170 struct basic_stream<Protocol, Executor, RatePolicy>::
0171     timeout_handler
0172 {
0173     using executor_type = Executor2;
0174 
0175     op_state& state;
0176     boost::weak_ptr<impl_type> wp;
0177     tick_type tick;
0178     executor_type ex;
0179 
0180     executor_type get_executor() const noexcept
0181     {
0182         return ex;
0183     }
0184 
0185     void
0186     operator()(error_code ec)
0187     {
0188         // timer canceled
0189         if(ec == net::error::operation_aborted)
0190             return;
0191         BOOST_ASSERT(! ec);
0192 
0193         auto sp = wp.lock();
0194 
0195         // stream destroyed
0196         if(! sp)
0197             return;
0198 
0199         // stale timer
0200         if(tick < state.tick)
0201             return;
0202         BOOST_ASSERT(tick == state.tick);
0203 
0204         // timeout
0205         BOOST_ASSERT(! state.timeout);
0206         sp->close();
0207         state.timeout = true;
0208     }
0209 };
0210 
0211 //------------------------------------------------------------------------------
0212 
0213 template<class Protocol, class Executor, class RatePolicy>
0214 struct basic_stream<Protocol, Executor, RatePolicy>::ops
0215 {
0216 
0217 template<bool isRead, class Buffers, class Handler>
0218 class transfer_op
0219     : public async_base<Handler, Executor>
0220     , public boost::asio::coroutine
0221 {
0222     boost::shared_ptr<impl_type> impl_;
0223     pending_guard pg_;
0224     Buffers b_;
0225 
0226     using is_read = std::integral_constant<bool, isRead>;
0227 
0228     op_state&
0229     state()
0230     {
0231         if (isRead)
0232             return impl_->read;
0233         else
0234             return impl_->write;
0235     }
0236 
0237     std::size_t
0238     available_bytes()
0239     {
0240         if (isRead)
0241             return rate_policy_access::
0242                 available_read_bytes(impl_->policy());
0243         else
0244             return rate_policy_access::
0245                 available_write_bytes(impl_->policy());
0246     }
0247 
0248     void
0249     transfer_bytes(std::size_t n)
0250     {
0251         if (isRead)
0252             rate_policy_access::
0253                 transfer_read_bytes(impl_->policy(), n);
0254         else
0255             rate_policy_access::
0256                 transfer_write_bytes(impl_->policy(), n);
0257     }
0258 
0259     void
0260     async_perform(
0261         std::size_t amount, std::true_type)
0262     {
0263         impl_->socket.async_read_some(
0264             beast::buffers_prefix(amount, b_),
0265                 std::move(*this));
0266     }
0267 
0268     void
0269     async_perform(
0270         std::size_t amount, std::false_type)
0271     {
0272         impl_->socket.async_write_some(
0273             beast::buffers_prefix(amount, b_),
0274                 std::move(*this));
0275     }
0276 
0277     static bool never_pending_;
0278 
0279 public:
0280     template<class Handler_>
0281     transfer_op(
0282         Handler_&& h,
0283         basic_stream& s,
0284         Buffers const& b)
0285         : async_base<Handler, Executor>(
0286             std::forward<Handler_>(h), s.get_executor())
0287         , impl_(s.impl_)
0288         , pg_()
0289         , b_(b)
0290     {
0291         this->set_allowed_cancellation(net::cancellation_type::all);
0292         if (buffer_bytes(b_) == 0 && state().pending)
0293         {
0294             // Workaround:
0295             // Corner case discovered in https://github.com/boostorg/beast/issues/2065
0296             // Enclosing SSL stream wishes to complete a 0-length write early by
0297             // executing a 0-length read against the underlying stream.
0298             // This can occur even if an existing async_read is in progress.
0299             // In this specific case, we will complete the async op with no error
0300             // in order to prevent assertions and/or internal corruption of the basic_stream
0301             this->complete(false, error_code(), std::size_t{0});
0302         }
0303         else
0304         {
0305             pg_.assign(state().pending);
0306             (*this)({});
0307         }
0308     }
0309 
0310     void
0311     operator()(
0312         error_code ec,
0313         std::size_t bytes_transferred = 0)
0314     {
0315         BOOST_ASIO_CORO_REENTER(*this)
0316         {
0317             // apply the timeout manually, otherwise
0318             // behavior varies across platforms.
0319             if(state().timer.expiry() <= now())
0320             {
0321                 BOOST_ASIO_CORO_YIELD
0322                 {
0323                     BOOST_ASIO_HANDLER_LOCATION((
0324                         __FILE__, __LINE__,
0325                         (isRead ? "basic_stream::async_read_some"
0326                             : "basic_stream::async_write_some")));
0327 
0328                     net::dispatch(this->get_immediate_executor(),
0329                         net::append(std::move(*this), ec, 0));
0330                 }
0331 
0332                 impl_->close();
0333                 BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
0334                 goto upcall;
0335             }
0336 
0337             // handle empty buffers
0338             if(detail::buffers_empty(b_))
0339             {
0340                 // make sure we perform the no-op
0341                 BOOST_ASIO_CORO_YIELD
0342                 {
0343                     BOOST_ASIO_HANDLER_LOCATION((
0344                         __FILE__, __LINE__,
0345                         (isRead ? "basic_stream::async_read_some"
0346                             : "basic_stream::async_write_some")));
0347 
0348                     async_perform(0, is_read{});
0349                 }
0350                 goto upcall;
0351             }
0352 
0353             // if a timeout is active, wait on the timer
0354             if(state().timer.expiry() != never())
0355             {
0356                 BOOST_ASIO_HANDLER_LOCATION((
0357                     __FILE__, __LINE__,
0358                     (isRead ? "basic_stream::async_read_some"
0359                         : "basic_stream::async_write_some")));
0360 
0361                 state().timer.async_wait(
0362                     timeout_handler<decltype(this->get_executor())>{
0363                         state(),
0364                         impl_,
0365                         state().tick,
0366                         this->get_executor()});
0367             }
0368 
0369             // check rate limit, maybe wait
0370             std::size_t amount;
0371             amount = available_bytes();
0372             if(amount == 0)
0373             {
0374                 ++impl_->waiting;
0375                 BOOST_ASIO_CORO_YIELD
0376                 {
0377                     BOOST_ASIO_HANDLER_LOCATION((
0378                         __FILE__, __LINE__,
0379                         (isRead ? "basic_stream::async_read_some"
0380                             : "basic_stream::async_write_some")));
0381 
0382                     impl_->timer.async_wait(std::move(*this));
0383                 }
0384                 if(ec)
0385                 {
0386                     // socket was closed, or a timeout
0387                     BOOST_ASSERT(ec ==
0388                         net::error::operation_aborted);
0389                     // timeout handler invoked?
0390                     if(state().timeout)
0391                     {
0392                         // yes, socket already closed
0393                         BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
0394                         state().timeout = false;
0395                     }
0396                     goto upcall;
0397                 }
0398                 impl_->on_timer(this->get_executor());
0399 
0400                 // Allow at least one byte, otherwise
0401                 // bytes_transferred could be 0.
0402                 amount = std::max<std::size_t>(
0403                     available_bytes(), 1);
0404             }
0405 
0406             BOOST_ASIO_CORO_YIELD
0407             {
0408                 BOOST_ASIO_HANDLER_LOCATION((
0409                     __FILE__, __LINE__,
0410                     (isRead ? "basic_stream::async_read_some"
0411                         : "basic_stream::async_write_some")));
0412 
0413                 async_perform(amount, is_read{});
0414             }
0415 
0416             if(state().timer.expiry() != never())
0417             {
0418                 ++state().tick;
0419 
0420                 // try cancelling timer
0421                 auto const n =
0422                     state().timer.cancel();
0423                 if(n == 0)
0424                 {
0425                     // timeout handler invoked?
0426                     if(state().timeout)
0427                     {
0428                         // yes, socket already closed
0429                         BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
0430                         state().timeout = false;
0431                     }
0432                 }
0433                 else
0434                 {
0435                     BOOST_ASSERT(n == 1);
0436                     BOOST_ASSERT(! state().timeout);
0437                 }
0438             }
0439 
0440         upcall:
0441             pg_.reset();
0442             transfer_bytes(bytes_transferred);
0443             this->complete_now(ec, bytes_transferred);
0444         }
0445     }
0446 };
0447 
0448 template<class Handler>
0449 class connect_op
0450     : public async_base<Handler, Executor>
0451 {
0452     boost::shared_ptr<impl_type> impl_;
0453     pending_guard pg0_;
0454     pending_guard pg1_;
0455 
0456     op_state&
0457     state() noexcept
0458     {
0459         return impl_->write;
0460     }
0461 
0462 public:
0463     template<class Handler_>
0464     connect_op(
0465         Handler_&& h,
0466         basic_stream& s,
0467         endpoint_type ep)
0468         : async_base<Handler, Executor>(
0469             std::forward<Handler_>(h), s.get_executor())
0470         , impl_(s.impl_)
0471         , pg0_(impl_->read.pending)
0472         , pg1_(impl_->write.pending)
0473     {
0474         this->set_allowed_cancellation(net::cancellation_type::all);
0475         if(state().timer.expiry() != stream_base::never())
0476         {
0477             BOOST_ASIO_HANDLER_LOCATION((
0478                 __FILE__, __LINE__,
0479                 "basic_stream::async_connect"));
0480 
0481             impl_->write.timer.async_wait(
0482                 timeout_handler<decltype(this->get_executor())>{
0483                     state(),
0484                     impl_,
0485                     state().tick,
0486                     this->get_executor()});
0487         }
0488 
0489         BOOST_ASIO_HANDLER_LOCATION((
0490             __FILE__, __LINE__,
0491             "basic_stream::async_connect"));
0492 
0493         impl_->socket.async_connect(
0494             ep, std::move(*this));
0495         // *this is now moved-from
0496     }
0497 
0498     template<
0499         class Endpoints, class Condition,
0500         class Handler_>
0501     connect_op(
0502         Handler_&& h,
0503         basic_stream& s,
0504         Endpoints const& eps,
0505         Condition const& cond)
0506         : async_base<Handler, Executor>(
0507             std::forward<Handler_>(h), s.get_executor())
0508         , impl_(s.impl_)
0509         , pg0_(impl_->read.pending)
0510         , pg1_(impl_->write.pending)
0511     {
0512         this->set_allowed_cancellation(net::cancellation_type::all);
0513         if(state().timer.expiry() != stream_base::never())
0514         {
0515             BOOST_ASIO_HANDLER_LOCATION((
0516                 __FILE__, __LINE__,
0517                 "basic_stream::async_connect"));
0518 
0519             impl_->write.timer.async_wait(
0520                 timeout_handler<decltype(this->get_executor())>{
0521                     state(),
0522                     impl_,
0523                     state().tick,
0524                     this->get_executor()});
0525         }
0526 
0527         BOOST_ASIO_HANDLER_LOCATION((
0528             __FILE__, __LINE__,
0529             "basic_stream::async_connect"));
0530 
0531         net::async_connect(impl_->socket,
0532             eps, cond, std::move(*this));
0533         // *this is now moved-from
0534     }
0535 
0536     template<
0537         class Iterator, class Condition,
0538         class Handler_>
0539     connect_op(
0540         Handler_&& h,
0541         basic_stream& s,
0542         Iterator begin, Iterator end,
0543         Condition const& cond)
0544         : async_base<Handler, Executor>(
0545             std::forward<Handler_>(h), s.get_executor())
0546         , impl_(s.impl_)
0547         , pg0_(impl_->read.pending)
0548         , pg1_(impl_->write.pending)
0549     {
0550         this->set_allowed_cancellation(net::cancellation_type::all);
0551         if(state().timer.expiry() != stream_base::never())
0552         {
0553             BOOST_ASIO_HANDLER_LOCATION((
0554                 __FILE__, __LINE__,
0555                 "basic_stream::async_connect"));
0556 
0557             impl_->write.timer.async_wait(
0558                 timeout_handler<decltype(this->get_executor())>{
0559                     state(),
0560                     impl_,
0561                     state().tick,
0562                     this->get_executor()});
0563         }
0564 
0565         BOOST_ASIO_HANDLER_LOCATION((
0566             __FILE__, __LINE__,
0567             "basic_stream::async_connect"));
0568 
0569         net::async_connect(impl_->socket,
0570             begin, end, cond, std::move(*this));
0571         // *this is now moved-from
0572     }
0573 
0574     template<class... Args>
0575     void
0576     operator()(error_code ec, Args&&... args)
0577     {
0578         if(state().timer.expiry() != stream_base::never())
0579         {
0580             ++state().tick;
0581 
0582             // try cancelling timer
0583             auto const n =
0584                 impl_->write.timer.cancel();
0585             if(n == 0)
0586             {
0587                 // timeout handler invoked?
0588                 if(state().timeout)
0589                 {
0590                     // yes, socket already closed
0591                     BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
0592                     state().timeout = false;
0593                 }
0594             }
0595             else
0596             {
0597                 BOOST_ASSERT(n == 1);
0598                 BOOST_ASSERT(! state().timeout);
0599             }
0600         }
0601 
0602         pg0_.reset();
0603         pg1_.reset();
0604         this->complete_now(ec, std::forward<Args>(args)...);
0605     }
0606 };
0607 
0608 struct run_read_op
0609 {
0610     basic_stream* self;
0611 
0612     using executor_type = typename basic_stream::executor_type;
0613 
0614     executor_type
0615     get_executor() const noexcept
0616     {
0617         return self->get_executor();
0618     }
0619 
0620     template<class ReadHandler, class Buffers>
0621     void
0622     operator()(
0623         ReadHandler&& h,
0624         Buffers const& b)
0625     {
0626         // If you get an error on the following line it means
0627         // that your handler does not meet the documented type
0628         // requirements for the handler.
0629 
0630         static_assert(
0631             detail::is_invocable<ReadHandler,
0632                 void(error_code, std::size_t)>::value,
0633             "ReadHandler type requirements not met");
0634 
0635         transfer_op<
0636             true,
0637             Buffers,
0638             typename std::decay<ReadHandler>::type>(
0639                 std::forward<ReadHandler>(h), *self, b);
0640     }
0641 };
0642 
0643 struct run_write_op
0644 {
0645     basic_stream* self;
0646 
0647     using executor_type = typename basic_stream::executor_type;
0648 
0649     executor_type
0650     get_executor() const noexcept
0651     {
0652         return self->get_executor();
0653     }
0654 
0655     template<class WriteHandler, class Buffers>
0656     void
0657     operator()(
0658         WriteHandler&& h,
0659         Buffers const& b)
0660     {
0661         // If you get an error on the following line it means
0662         // that your handler does not meet the documented type
0663         // requirements for the handler.
0664 
0665         static_assert(
0666             detail::is_invocable<WriteHandler,
0667                 void(error_code, std::size_t)>::value,
0668             "WriteHandler type requirements not met");
0669 
0670         transfer_op<
0671             false,
0672             Buffers,
0673             typename std::decay<WriteHandler>::type>(
0674                 std::forward<WriteHandler>(h), *self, b);
0675     }
0676 };
0677 
0678 struct run_connect_op
0679 {
0680     basic_stream* self;
0681 
0682     using executor_type = typename basic_stream::executor_type;
0683 
0684     executor_type
0685     get_executor() const noexcept
0686     {
0687         return self->get_executor();
0688     }
0689 
0690     template<class ConnectHandler>
0691     void
0692     operator()(
0693         ConnectHandler&& h,
0694         endpoint_type const& ep)
0695     {
0696         // If you get an error on the following line it means
0697         // that your handler does not meet the documented type
0698         // requirements for the handler.
0699 
0700         static_assert(
0701             detail::is_invocable<ConnectHandler,
0702                 void(error_code)>::value,
0703             "ConnectHandler type requirements not met");
0704 
0705         connect_op<typename std::decay<ConnectHandler>::type>(
0706             std::forward<ConnectHandler>(h), *self, ep);
0707     }
0708 };
0709 
0710 struct run_connect_range_op
0711 {
0712     basic_stream* self;
0713 
0714     using executor_type = typename basic_stream::executor_type;
0715 
0716     executor_type
0717     get_executor() const noexcept
0718     {
0719         return self->get_executor();
0720     }
0721 
0722     template<
0723         class RangeConnectHandler,
0724         class EndpointSequence,
0725         class Condition>
0726     void
0727     operator()(
0728         RangeConnectHandler&& h,
0729         EndpointSequence const& eps,
0730         Condition const& cond)
0731     {
0732         // If you get an error on the following line it means
0733         // that your handler does not meet the documented type
0734         // requirements for the handler.
0735 
0736         static_assert(
0737             detail::is_invocable<RangeConnectHandler,
0738                 void(error_code, typename Protocol::endpoint)>::value,
0739             "RangeConnectHandler type requirements not met");
0740 
0741         connect_op<typename std::decay<RangeConnectHandler>::type>(
0742             std::forward<RangeConnectHandler>(h), *self, eps, cond);
0743     }
0744 };
0745 
0746 struct run_connect_iter_op
0747 {
0748     basic_stream* self;
0749 
0750     using executor_type = typename basic_stream::executor_type;
0751 
0752     executor_type
0753     get_executor() const noexcept
0754     {
0755         return self->get_executor();
0756     }
0757 
0758     template<
0759         class IteratorConnectHandler,
0760         class Iterator,
0761         class Condition>
0762     void
0763     operator()(
0764         IteratorConnectHandler&& h,
0765         Iterator begin, Iterator end,
0766         Condition const& cond)
0767     {
0768         // If you get an error on the following line it means
0769         // that your handler does not meet the documented type
0770         // requirements for the handler.
0771 
0772         static_assert(
0773             detail::is_invocable<IteratorConnectHandler,
0774                 void(error_code, Iterator)>::value,
0775             "IteratorConnectHandler type requirements not met");
0776 
0777         connect_op<typename std::decay<IteratorConnectHandler>::type>(
0778             std::forward<IteratorConnectHandler>(h), *self, begin, end, cond);
0779     }
0780 };
0781 
0782 };
0783 
0784 //------------------------------------------------------------------------------
0785 
0786 template<class Protocol, class Executor, class RatePolicy>
0787 basic_stream<Protocol, Executor, RatePolicy>::
0788 ~basic_stream()
0789 {
0790     // the shared object can outlive *this,
0791     // cancel any operations so the shared
0792     // object is destroyed as soon as possible.
0793     impl_->close();
0794 }
0795 
0796 template<class Protocol, class Executor, class RatePolicy>
0797 template<class Arg0, class... Args, class>
0798 basic_stream<Protocol, Executor, RatePolicy>::
0799 basic_stream(Arg0&& arg0, Args&&... args)
0800     : impl_(boost::make_shared<impl_type>(
0801         std::false_type{},
0802         std::forward<Arg0>(arg0),
0803         std::forward<Args>(args)...))
0804 {
0805 }
0806 
0807 template<class Protocol, class Executor, class RatePolicy>
0808 template<class RatePolicy_, class Arg0, class... Args, class>
0809 basic_stream<Protocol, Executor, RatePolicy>::
0810 basic_stream(
0811     RatePolicy_&& policy, Arg0&& arg0, Args&&... args)
0812     : impl_(boost::make_shared<impl_type>(
0813         std::true_type{},
0814         std::forward<RatePolicy_>(policy),
0815         std::forward<Arg0>(arg0),
0816         std::forward<Args>(args)...))
0817 {
0818 }
0819 
0820 template<class Protocol, class Executor, class RatePolicy>
0821 basic_stream<Protocol, Executor, RatePolicy>::
0822 basic_stream(basic_stream&& other)
0823     : impl_(boost::make_shared<impl_type>(
0824         std::move(*other.impl_)))
0825 {
0826     // Explainer: Asio's sockets provide the guarantee that a moved-from socket
0827     // will be in a state as-if newly created. i.e.:
0828     // * having the same (valid) executor
0829     // * the socket shall not be open
0830     // We provide the same guarantee by moving the impl rather than the pointer
0831     // controlling its lifetime.
0832 }
0833 
0834 template<class Protocol, class Executor, class RatePolicy>
0835 template<class Executor_>
0836 basic_stream<Protocol, Executor, RatePolicy>::
0837 basic_stream(basic_stream<Protocol, Executor_, RatePolicy> && other)
0838     : impl_(boost::make_shared<impl_type>(std::false_type{}, std::move(other.impl_->socket)))
0839 {
0840 }
0841 
0842 //------------------------------------------------------------------------------
0843 
0844 template<class Protocol, class Executor, class RatePolicy>
0845 auto
0846 basic_stream<Protocol, Executor, RatePolicy>::
0847 release_socket() ->
0848     socket_type
0849 {
0850     this->cancel();
0851     return std::move(impl_->socket);
0852 }
0853 
0854 template<class Protocol, class Executor, class RatePolicy>
0855 void
0856 basic_stream<Protocol, Executor, RatePolicy>::
0857 expires_after(net::steady_timer::duration expiry_time)
0858 {
0859     // If assert goes off, it means that there are
0860     // already read or write (or connect) operations
0861     // outstanding, so there is nothing to apply
0862     // the expiration time to!
0863     //
0864     BOOST_ASSERT(
0865         ! impl_->read.pending ||
0866         ! impl_->write.pending);
0867 
0868     if(! impl_->read.pending)
0869         BOOST_VERIFY(
0870             impl_->read.timer.expires_after(
0871                 expiry_time) == 0);
0872 
0873     if(! impl_->write.pending)
0874         BOOST_VERIFY(
0875             impl_->write.timer.expires_after(
0876                 expiry_time) == 0);
0877 }
0878 
0879 template<class Protocol, class Executor, class RatePolicy>
0880 void
0881 basic_stream<Protocol, Executor, RatePolicy>::
0882 expires_at(
0883     net::steady_timer::time_point expiry_time)
0884 {
0885     // If assert goes off, it means that there are
0886     // already read or write (or connect) operations
0887     // outstanding, so there is nothing to apply
0888     // the expiration time to!
0889     //
0890     BOOST_ASSERT(
0891         ! impl_->read.pending ||
0892         ! impl_->write.pending);
0893 
0894     if(! impl_->read.pending)
0895         BOOST_VERIFY(
0896             impl_->read.timer.expires_at(
0897                 expiry_time) == 0);
0898 
0899     if(! impl_->write.pending)
0900         BOOST_VERIFY(
0901             impl_->write.timer.expires_at(
0902                 expiry_time) == 0);
0903 }
0904 
0905 template<class Protocol, class Executor, class RatePolicy>
0906 void
0907 basic_stream<Protocol, Executor, RatePolicy>::
0908 expires_never()
0909 {
0910     impl_->reset();
0911 }
0912 
0913 template<class Protocol, class Executor, class RatePolicy>
0914 void
0915 basic_stream<Protocol, Executor, RatePolicy>::
0916 cancel()
0917 {
0918     error_code ec;
0919     impl_->socket.cancel(ec);
0920     impl_->timer.cancel();
0921 }
0922 
0923 template<class Protocol, class Executor, class RatePolicy>
0924 void
0925 basic_stream<Protocol, Executor, RatePolicy>::
0926 close()
0927 {
0928     impl_->close();
0929 }
0930 
0931 //------------------------------------------------------------------------------
0932 
0933 template<class Protocol, class Executor, class RatePolicy>
0934 template<BOOST_BEAST_ASYNC_TPARAM1 ConnectHandler>
0935 BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
0936 basic_stream<Protocol, Executor, RatePolicy>::
0937 async_connect(
0938     endpoint_type const& ep,
0939     ConnectHandler&& handler)
0940 {
0941     return net::async_initiate<
0942         ConnectHandler,
0943         void(error_code)>(
0944             typename ops::run_connect_op{this},
0945             handler,
0946             ep);
0947 }
0948 
0949 template<class Protocol, class Executor, class RatePolicy>
0950 template<
0951     class EndpointSequence,
0952     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
0953     class,
0954     class>
0955 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
0956 basic_stream<Protocol, Executor, RatePolicy>::
0957 async_connect(
0958     EndpointSequence const& endpoints,
0959     RangeConnectHandler&& handler)
0960 {
0961     return net::async_initiate<
0962         RangeConnectHandler,
0963         void(error_code, typename Protocol::endpoint)>(
0964             typename ops::run_connect_range_op{this},
0965             handler,
0966             endpoints,
0967             detail::any_endpoint{});
0968 }
0969 
0970 template<class Protocol, class Executor, class RatePolicy>
0971 template<
0972     class EndpointSequence,
0973     class ConnectCondition,
0974     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
0975     class,
0976     class>
0977 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
0978 basic_stream<Protocol, Executor, RatePolicy>::
0979 async_connect(
0980     EndpointSequence const& endpoints,
0981     ConnectCondition connect_condition,
0982     RangeConnectHandler&& handler)
0983 {
0984     return net::async_initiate<
0985         RangeConnectHandler,
0986         void(error_code, typename Protocol::endpoint)>(
0987             typename ops::run_connect_range_op{this},
0988             handler,
0989             endpoints,
0990             connect_condition);
0991 }
0992 
0993 template<class Protocol, class Executor, class RatePolicy>
0994 template<
0995     class Iterator,
0996     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler,
0997     class>
0998 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
0999 basic_stream<Protocol, Executor, RatePolicy>::
1000 async_connect(
1001     Iterator begin, Iterator end,
1002     IteratorConnectHandler&& handler)
1003 {
1004     return net::async_initiate<
1005         IteratorConnectHandler,
1006         void(error_code, Iterator)>(
1007             typename ops::run_connect_iter_op{this},
1008             handler,
1009             begin, end,
1010             detail::any_endpoint{});
1011 }
1012 
1013 template<class Protocol, class Executor, class RatePolicy>
1014 template<
1015     class Iterator,
1016     class ConnectCondition,
1017     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler,
1018     class>
1019 BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
1020 basic_stream<Protocol, Executor, RatePolicy>::
1021 async_connect(
1022     Iterator begin, Iterator end,
1023     ConnectCondition connect_condition,
1024     IteratorConnectHandler&& handler)
1025 {
1026     return net::async_initiate<
1027         IteratorConnectHandler,
1028         void(error_code, Iterator)>(
1029             typename ops::run_connect_iter_op{this},
1030             handler,
1031             begin, end,
1032             connect_condition);
1033 }
1034 
1035 //------------------------------------------------------------------------------
1036 
1037 template<class Protocol, class Executor, class RatePolicy>
1038 template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
1039 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
1040 basic_stream<Protocol, Executor, RatePolicy>::
1041 async_read_some(
1042     MutableBufferSequence const& buffers,
1043     ReadHandler&& handler)
1044 {
1045     static_assert(net::is_mutable_buffer_sequence<
1046         MutableBufferSequence>::value,
1047         "MutableBufferSequence type requirements not met");
1048     return net::async_initiate<
1049         ReadHandler,
1050         void(error_code, std::size_t)>(
1051             typename ops::run_read_op{this},
1052             handler,
1053             buffers);
1054 }
1055 
1056 template<class Protocol, class Executor, class RatePolicy>
1057 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
1058 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
1059 basic_stream<Protocol, Executor, RatePolicy>::
1060 async_write_some(
1061     ConstBufferSequence const& buffers,
1062     WriteHandler&& handler)
1063 {
1064     static_assert(net::is_const_buffer_sequence<
1065         ConstBufferSequence>::value,
1066         "ConstBufferSequence type requirements not met");
1067     return net::async_initiate<
1068         WriteHandler,
1069         void(error_code, std::size_t)>(
1070             typename ops::run_write_op{this},
1071             handler,
1072             buffers);
1073 }
1074 
1075 //------------------------------------------------------------------------------
1076 //
1077 // Customization points
1078 //
1079 
1080 #if ! BOOST_BEAST_DOXYGEN
1081 
1082 template<
1083     class Protocol, class Executor, class RatePolicy>
1084 void
1085 beast_close_socket(
1086     basic_stream<Protocol, Executor, RatePolicy>& stream)
1087 {
1088     error_code ec;
1089     stream.socket().close(ec);
1090 }
1091 
1092 template<
1093     class Protocol, class Executor, class RatePolicy>
1094 void
1095 teardown(
1096     role_type role,
1097     basic_stream<Protocol, Executor, RatePolicy>& stream,
1098     error_code& ec)
1099 {
1100     using beast::websocket::teardown;
1101     teardown(role, stream.socket(), ec);
1102 }
1103 
1104 template<
1105     class Protocol, class Executor, class RatePolicy,
1106     class TeardownHandler>
1107 void
1108 async_teardown(
1109     role_type role,
1110     basic_stream<Protocol, Executor, RatePolicy>& stream,
1111     TeardownHandler&& handler)
1112 {
1113     using beast::websocket::async_teardown;
1114     async_teardown(role, stream.socket(),
1115         std::forward<TeardownHandler>(handler));
1116 }
1117 
1118 #endif
1119 
1120 } // beast
1121 } // boost
1122 
1123 #endif