• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
3 //
4 // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 //
7 // Official repository: https://github.com/boostorg/beast
8 //
9 
10 #ifndef BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
11 #define BOOST_BEAST_CORE_IMPL_BASIC_STREAM_HPP
12 
13 #include <boost/beast/core/async_base.hpp>
14 #include <boost/beast/core/buffer_traits.hpp>
15 #include <boost/beast/core/buffers_prefix.hpp>
16 #include <boost/beast/websocket/teardown.hpp>
17 #include <boost/asio/coroutine.hpp>
18 #include <boost/assert.hpp>
19 #include <boost/make_shared.hpp>
20 #include <boost/core/exchange.hpp>
21 #include <cstdlib>
22 #include <type_traits>
23 #include <utility>
24 
25 namespace boost {
26 namespace beast {
27 
28 //------------------------------------------------------------------------------
29 
30 template<class Protocol, class Executor, class RatePolicy>
31 template<class... Args>
32 basic_stream<Protocol, Executor, RatePolicy>::
33 impl_type::
impl_type(std::false_type,Args &&...args)34 impl_type(std::false_type, Args&&... args)
35     : socket(std::forward<Args>(args)...)
36     , read(ex())
37     , write(ex())
38     , timer(ex())
39 {
40     reset();
41 }
42 
43 template<class Protocol, class Executor, class RatePolicy>
44 template<class RatePolicy_, class... Args>
45 basic_stream<Protocol, Executor, RatePolicy>::
46 impl_type::
impl_type(std::true_type,RatePolicy_ && policy,Args &&...args)47 impl_type(std::true_type,
48     RatePolicy_&& policy, Args&&... args)
49     : boost::empty_value<RatePolicy>(
50         boost::empty_init_t{},
51         std::forward<RatePolicy_>(policy))
52     , socket(std::forward<Args>(args)...)
53     , read(ex())
54     , write(ex())
55     , timer(ex())
56 {
57     reset();
58 }
59 
60 template<class Protocol, class Executor, class RatePolicy>
61 template<class Executor2>
62 void
63 basic_stream<Protocol, Executor, RatePolicy>::
64 impl_type::
on_timer(Executor2 const & ex2)65 on_timer(Executor2 const& ex2)
66 {
67     BOOST_ASSERT(waiting > 0);
68 
69     // the last waiter starts the new slice
70     if(--waiting > 0)
71         return;
72 
73     // update the expiration time
74     BOOST_VERIFY(timer.expires_after(
75         std::chrono::seconds(1)) == 0);
76 
77     rate_policy_access::on_timer(policy());
78 
79     struct handler : boost::empty_value<Executor2>
80     {
81         boost::weak_ptr<impl_type> wp;
82 
83         using executor_type = Executor2;
84 
85         executor_type
86         get_executor() const noexcept
87         {
88             return this->get();
89         }
90 
91         handler(
92             Executor2 const& ex2,
93             boost::shared_ptr<impl_type> const& sp)
94             : boost::empty_value<Executor2>(
95                 boost::empty_init_t{}, ex2)
96             , wp(sp)
97         {
98         }
99 
100         void
101         operator()(error_code ec)
102         {
103             auto sp = wp.lock();
104             if(! sp)
105                 return;
106             if(ec == net::error::operation_aborted)
107                 return;
108             BOOST_ASSERT(! ec);
109             if(ec)
110                 return;
111             sp->on_timer(this->get());
112         }
113     };
114 
115     // wait on the timer again
116     ++waiting;
117     timer.async_wait(handler(ex2, this->shared_from_this()));
118 }
119 
120 template<class Protocol, class Executor, class RatePolicy>
121 void
122 basic_stream<Protocol, Executor, RatePolicy>::
123 impl_type::
reset()124 reset()
125 {
126     // If assert goes off, it means that there are
127     // already read or write (or connect) operations
128     // outstanding, so there is nothing to apply
129     // the expiration time to!
130     //
131     BOOST_ASSERT(! read.pending || ! write.pending);
132 
133     if(! read.pending)
134         BOOST_VERIFY(
135             read.timer.expires_at(never()) == 0);
136 
137     if(! write.pending)
138         BOOST_VERIFY(
139             write.timer.expires_at(never()) == 0);
140 }
141 
142 template<class Protocol, class Executor, class RatePolicy>
143 void
144 basic_stream<Protocol, Executor, RatePolicy>::
145 impl_type::
close()146 close() noexcept
147 {
148     {
149         error_code ec;
150         socket.close(ec);
151     }
152     try
153     {
154         timer.cancel();
155     }
156     catch(...)
157     {
158     }
159 }
160 
161 //------------------------------------------------------------------------------
162 
163 template<class Protocol, class Executor, class RatePolicy>
164 template<class Executor2>
165 struct basic_stream<Protocol, Executor, RatePolicy>::
166     timeout_handler
167 {
168     using executor_type = Executor2;
169 
170     op_state& state;
171     boost::weak_ptr<impl_type> wp;
172     tick_type tick;
173     executor_type ex;
174 
get_executorboost::beast::basic_stream::timeout_handler175     executor_type get_executor() const noexcept
176     {
177         return ex;
178     }
179 
180     void
operator ()boost::beast::basic_stream::timeout_handler181     operator()(error_code ec)
182     {
183         // timer canceled
184         if(ec == net::error::operation_aborted)
185             return;
186         BOOST_ASSERT(! ec);
187 
188         auto sp = wp.lock();
189 
190         // stream destroyed
191         if(! sp)
192             return;
193 
194         // stale timer
195         if(tick < state.tick)
196             return;
197         BOOST_ASSERT(tick == state.tick);
198 
199         // timeout
200         BOOST_ASSERT(! state.timeout);
201         sp->close();
202         state.timeout = true;
203     }
204 };
205 
206 //------------------------------------------------------------------------------
207 
208 template<class Protocol, class Executor, class RatePolicy>
209 struct basic_stream<Protocol, Executor, RatePolicy>::ops
210 {
211 
212 template<bool isRead, class Buffers, class Handler>
213 class transfer_op
214     : public async_base<Handler, Executor>
215     , public boost::asio::coroutine
216 {
217     boost::shared_ptr<impl_type> impl_;
218     pending_guard pg_;
219     Buffers b_;
220 
221     using is_read = std::integral_constant<bool, isRead>;
222 
223     op_state&
state()224     state()
225     {
226         if (isRead)
227             return impl_->read;
228         else
229             return impl_->write;
230     }
231 
232     std::size_t
available_bytes()233     available_bytes()
234     {
235         if (isRead)
236             return rate_policy_access::
237                 available_read_bytes(impl_->policy());
238         else
239             return rate_policy_access::
240                 available_write_bytes(impl_->policy());
241     }
242 
243     void
transfer_bytes(std::size_t n)244     transfer_bytes(std::size_t n)
245     {
246         if (isRead)
247             rate_policy_access::
248                 transfer_read_bytes(impl_->policy(), n);
249         else
250             rate_policy_access::
251                 transfer_write_bytes(impl_->policy(), n);
252     }
253 
254     void
async_perform(std::size_t amount,std::true_type)255     async_perform(
256         std::size_t amount, std::true_type)
257     {
258         impl_->socket.async_read_some(
259             beast::buffers_prefix(amount, b_),
260                 std::move(*this));
261     }
262 
263     void
async_perform(std::size_t amount,std::false_type)264     async_perform(
265         std::size_t amount, std::false_type)
266     {
267         impl_->socket.async_write_some(
268             beast::buffers_prefix(amount, b_),
269                 std::move(*this));
270     }
271 
272 public:
273     template<class Handler_>
transfer_op(Handler_ && h,basic_stream & s,Buffers const & b)274     transfer_op(
275         Handler_&& h,
276         basic_stream& s,
277         Buffers const& b)
278         : async_base<Handler, Executor>(
279             std::forward<Handler_>(h), s.get_executor())
280         , impl_(s.impl_)
281         , pg_(state().pending)
282         , b_(b)
283     {
284         (*this)({});
285     }
286 
287     void
operator ()(error_code ec,std::size_t bytes_transferred=0)288     operator()(
289         error_code ec,
290         std::size_t bytes_transferred = 0)
291     {
292         BOOST_ASIO_CORO_REENTER(*this)
293         {
294             // handle empty buffers
295             if(detail::buffers_empty(b_))
296             {
297                 // make sure we perform the no-op
298                 BOOST_ASIO_CORO_YIELD
299                 async_perform(0, is_read{});
300                 // apply the timeout manually, otherwise
301                 // behavior varies across platforms.
302                 if(state().timer.expiry() <= clock_type::now())
303                 {
304                     impl_->close();
305                     ec = beast::error::timeout;
306                 }
307                 goto upcall;
308             }
309 
310             // if a timeout is active, wait on the timer
311             if(state().timer.expiry() != never())
312                 state().timer.async_wait(
313                     timeout_handler<decltype(this->get_executor())>{
314                         state(),
315                         impl_,
316                         state().tick,
317                         this->get_executor()});
318 
319             // check rate limit, maybe wait
320             std::size_t amount;
321             amount = available_bytes();
322             if(amount == 0)
323             {
324                 ++impl_->waiting;
325                 BOOST_ASIO_CORO_YIELD
326                 impl_->timer.async_wait(std::move(*this));
327                 if(ec)
328                 {
329                     // socket was closed, or a timeout
330                     BOOST_ASSERT(ec ==
331                         net::error::operation_aborted);
332                     // timeout handler invoked?
333                     if(state().timeout)
334                     {
335                         // yes, socket already closed
336                         ec = beast::error::timeout;
337                         state().timeout = false;
338                     }
339                     goto upcall;
340                 }
341                 impl_->on_timer(this->get_executor());
342 
343                 // Allow at least one byte, otherwise
344                 // bytes_transferred could be 0.
345                 amount = std::max<std::size_t>(
346                     available_bytes(), 1);
347             }
348 
349             BOOST_ASIO_CORO_YIELD
350             async_perform(amount, is_read{});
351 
352             if(state().timer.expiry() != never())
353             {
354                 ++state().tick;
355 
356                 // try cancelling timer
357                 auto const n =
358                     state().timer.cancel();
359                 if(n == 0)
360                 {
361                     // timeout handler invoked?
362                     if(state().timeout)
363                     {
364                         // yes, socket already closed
365                         ec = beast::error::timeout;
366                         state().timeout = false;
367                     }
368                 }
369                 else
370                 {
371                     BOOST_ASSERT(n == 1);
372                     BOOST_ASSERT(! state().timeout);
373                 }
374             }
375 
376         upcall:
377             pg_.reset();
378             transfer_bytes(bytes_transferred);
379             this->complete_now(ec, bytes_transferred);
380         }
381     }
382 };
383 
384 template<class Handler>
385 class connect_op
386     : public async_base<Handler, Executor>
387 {
388     boost::shared_ptr<impl_type> impl_;
389     pending_guard pg0_;
390     pending_guard pg1_;
391 
392     op_state&
state()393     state() noexcept
394     {
395         return impl_->write;
396     }
397 
398 public:
399     template<class Handler_>
connect_op(Handler_ && h,basic_stream & s,endpoint_type ep)400     connect_op(
401         Handler_&& h,
402         basic_stream& s,
403         endpoint_type ep)
404         : async_base<Handler, Executor>(
405             std::forward<Handler_>(h), s.get_executor())
406         , impl_(s.impl_)
407         , pg0_(impl_->read.pending)
408         , pg1_(impl_->write.pending)
409     {
410         if(state().timer.expiry() != stream_base::never())
411             impl_->write.timer.async_wait(
412                 timeout_handler<decltype(this->get_executor())>{
413                     state(),
414                     impl_,
415                     state().tick,
416                     this->get_executor()});
417 
418         impl_->socket.async_connect(
419             ep, std::move(*this));
420         // *this is now moved-from
421     }
422 
423     template<
424         class Endpoints, class Condition,
425         class Handler_>
connect_op(Handler_ && h,basic_stream & s,Endpoints const & eps,Condition const & cond)426     connect_op(
427         Handler_&& h,
428         basic_stream& s,
429         Endpoints const& eps,
430         Condition const& cond)
431         : async_base<Handler, Executor>(
432             std::forward<Handler_>(h), s.get_executor())
433         , impl_(s.impl_)
434         , pg0_(impl_->read.pending)
435         , pg1_(impl_->write.pending)
436     {
437         if(state().timer.expiry() != stream_base::never())
438             impl_->write.timer.async_wait(
439                 timeout_handler<decltype(this->get_executor())>{
440                     state(),
441                     impl_,
442                     state().tick,
443                     this->get_executor()});
444 
445         net::async_connect(impl_->socket,
446             eps, cond, std::move(*this));
447         // *this is now moved-from
448     }
449 
450     template<
451         class Iterator, class Condition,
452         class Handler_>
connect_op(Handler_ && h,basic_stream & s,Iterator begin,Iterator end,Condition const & cond)453     connect_op(
454         Handler_&& h,
455         basic_stream& s,
456         Iterator begin, Iterator end,
457         Condition const& cond)
458         : async_base<Handler, Executor>(
459             std::forward<Handler_>(h), s.get_executor())
460         , impl_(s.impl_)
461         , pg0_(impl_->read.pending)
462         , pg1_(impl_->write.pending)
463     {
464         if(state().timer.expiry() != stream_base::never())
465             impl_->write.timer.async_wait(
466                 timeout_handler<decltype(this->get_executor())>{
467                     state(),
468                     impl_,
469                     state().tick,
470                     this->get_executor()});
471 
472         net::async_connect(impl_->socket,
473             begin, end, cond, std::move(*this));
474         // *this is now moved-from
475     }
476 
477     template<class... Args>
478     void
operator ()(error_code ec,Args &&...args)479     operator()(error_code ec, Args&&... args)
480     {
481         if(state().timer.expiry() != stream_base::never())
482         {
483             ++state().tick;
484 
485             // try cancelling timer
486             auto const n =
487                 impl_->write.timer.cancel();
488             if(n == 0)
489             {
490                 // timeout handler invoked?
491                 if(state().timeout)
492                 {
493                     // yes, socket already closed
494                     ec = beast::error::timeout;
495                     state().timeout = false;
496                 }
497             }
498             else
499             {
500                 BOOST_ASSERT(n == 1);
501                 BOOST_ASSERT(! state().timeout);
502             }
503         }
504 
505         pg0_.reset();
506         pg1_.reset();
507         this->complete_now(ec, std::forward<Args>(args)...);
508     }
509 };
510 
511 struct run_read_op
512 {
513     template<class ReadHandler, class Buffers>
514     void
operator ()boost::beast::basic_stream::ops::run_read_op515     operator()(
516         ReadHandler&& h,
517         basic_stream* s,
518         Buffers const& b)
519     {
520         // If you get an error on the following line it means
521         // that your handler does not meet the documented type
522         // requirements for the handler.
523 
524         static_assert(
525             detail::is_invocable<ReadHandler,
526                 void(error_code, std::size_t)>::value,
527             "ReadHandler type requirements not met");
528 
529         transfer_op<
530             true,
531             Buffers,
532             typename std::decay<ReadHandler>::type>(
533                 std::forward<ReadHandler>(h), *s, b);
534     }
535 };
536 
537 struct run_write_op
538 {
539     template<class WriteHandler, class Buffers>
540     void
operator ()boost::beast::basic_stream::ops::run_write_op541     operator()(
542         WriteHandler&& h,
543         basic_stream* s,
544         Buffers const& b)
545     {
546         // If you get an error on the following line it means
547         // that your handler does not meet the documented type
548         // requirements for the handler.
549 
550         static_assert(
551             detail::is_invocable<WriteHandler,
552                 void(error_code, std::size_t)>::value,
553             "WriteHandler type requirements not met");
554 
555         transfer_op<
556             false,
557             Buffers,
558             typename std::decay<WriteHandler>::type>(
559                 std::forward<WriteHandler>(h), *s, b);
560     }
561 };
562 
563 struct run_connect_op
564 {
565     template<class ConnectHandler>
566     void
operator ()boost::beast::basic_stream::ops::run_connect_op567     operator()(
568         ConnectHandler&& h,
569         basic_stream* s,
570         endpoint_type const& ep)
571     {
572         // If you get an error on the following line it means
573         // that your handler does not meet the documented type
574         // requirements for the handler.
575 
576         static_assert(
577             detail::is_invocable<ConnectHandler,
578                 void(error_code)>::value,
579             "ConnectHandler type requirements not met");
580 
581         connect_op<typename std::decay<ConnectHandler>::type>(
582             std::forward<ConnectHandler>(h), *s, ep);
583     }
584 };
585 
586 struct run_connect_range_op
587 {
588     template<
589         class RangeConnectHandler,
590         class EndpointSequence,
591         class Condition>
592     void
operator ()boost::beast::basic_stream::ops::run_connect_range_op593     operator()(
594         RangeConnectHandler&& h,
595         basic_stream* s,
596         EndpointSequence const& eps,
597         Condition const& cond)
598     {
599         // If you get an error on the following line it means
600         // that your handler does not meet the documented type
601         // requirements for the handler.
602 
603         static_assert(
604             detail::is_invocable<RangeConnectHandler,
605                 void(error_code, typename Protocol::endpoint)>::value,
606             "RangeConnectHandler type requirements not met");
607 
608         connect_op<typename std::decay<RangeConnectHandler>::type>(
609             std::forward<RangeConnectHandler>(h), *s, eps, cond);
610     }
611 };
612 
613 struct run_connect_iter_op
614 {
615     template<
616         class IteratorConnectHandler,
617         class Iterator,
618         class Condition>
619     void
operator ()boost::beast::basic_stream::ops::run_connect_iter_op620     operator()(
621         IteratorConnectHandler&& h,
622         basic_stream* s,
623         Iterator begin, Iterator end,
624         Condition const& cond)
625     {
626         // If you get an error on the following line it means
627         // that your handler does not meet the documented type
628         // requirements for the handler.
629 
630         static_assert(
631             detail::is_invocable<IteratorConnectHandler,
632                 void(error_code, Iterator)>::value,
633             "IteratorConnectHandler type requirements not met");
634 
635         connect_op<typename std::decay<IteratorConnectHandler>::type>(
636             std::forward<IteratorConnectHandler>(h), *s, begin, end, cond);
637     }
638 };
639 
640 };
641 
642 //------------------------------------------------------------------------------
643 
644 template<class Protocol, class Executor, class RatePolicy>
645 basic_stream<Protocol, Executor, RatePolicy>::
~basic_stream()646 ~basic_stream()
647 {
648     // the shared object can outlive *this,
649     // cancel any operations so the shared
650     // object is destroyed as soon as possible.
651     impl_->close();
652 }
653 
654 template<class Protocol, class Executor, class RatePolicy>
655 template<class Arg0, class... Args, class>
656 basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(Arg0 && arg0,Args &&...args)657 basic_stream(Arg0&& arg0, Args&&... args)
658     : impl_(boost::make_shared<impl_type>(
659         std::false_type{},
660         std::forward<Arg0>(arg0),
661         std::forward<Args>(args)...))
662 {
663 }
664 
665 template<class Protocol, class Executor, class RatePolicy>
666 template<class RatePolicy_, class Arg0, class... Args, class>
667 basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(RatePolicy_ && policy,Arg0 && arg0,Args &&...args)668 basic_stream(
669     RatePolicy_&& policy, Arg0&& arg0, Args&&... args)
670     : impl_(boost::make_shared<impl_type>(
671         std::true_type{},
672         std::forward<RatePolicy_>(policy),
673         std::forward<Arg0>(arg0),
674         std::forward<Args>(args)...))
675 {
676 }
677 
678 template<class Protocol, class Executor, class RatePolicy>
679 basic_stream<Protocol, Executor, RatePolicy>::
basic_stream(basic_stream && other)680 basic_stream(basic_stream&& other)
681     : impl_(boost::make_shared<impl_type>(
682         std::move(*other.impl_)))
683 {
684     // Explainer: Asio's sockets provide the guarantee that a moved-from socket
685     // will be in a state as-if newly created. i.e.:
686     // * having the same (valid) executor
687     // * the socket shall not be open
688     // We provide the same guarantee by moving the impl rather than the pointer
689     // controlling its lifetime.
690 }
691 
692 //------------------------------------------------------------------------------
693 
694 template<class Protocol, class Executor, class RatePolicy>
695 auto
696 basic_stream<Protocol, Executor, RatePolicy>::
release_socket()697 release_socket() ->
698     socket_type
699 {
700     this->cancel();
701     return std::move(impl_->socket);
702 }
703 
704 template<class Protocol, class Executor, class RatePolicy>
705 void
706 basic_stream<Protocol, Executor, RatePolicy>::
expires_after(net::steady_timer::duration expiry_time)707 expires_after(net::steady_timer::duration expiry_time)
708 {
709     // If assert goes off, it means that there are
710     // already read or write (or connect) operations
711     // outstanding, so there is nothing to apply
712     // the expiration time to!
713     //
714     BOOST_ASSERT(
715         ! impl_->read.pending ||
716         ! impl_->write.pending);
717 
718     if(! impl_->read.pending)
719         BOOST_VERIFY(
720             impl_->read.timer.expires_after(
721                 expiry_time) == 0);
722 
723     if(! impl_->write.pending)
724         BOOST_VERIFY(
725             impl_->write.timer.expires_after(
726                 expiry_time) == 0);
727 }
728 
729 template<class Protocol, class Executor, class RatePolicy>
730 void
731 basic_stream<Protocol, Executor, RatePolicy>::
expires_at(net::steady_timer::time_point expiry_time)732 expires_at(
733     net::steady_timer::time_point expiry_time)
734 {
735     // If assert goes off, it means that there are
736     // already read or write (or connect) operations
737     // outstanding, so there is nothing to apply
738     // the expiration time to!
739     //
740     BOOST_ASSERT(
741         ! impl_->read.pending ||
742         ! impl_->write.pending);
743 
744     if(! impl_->read.pending)
745         BOOST_VERIFY(
746             impl_->read.timer.expires_at(
747                 expiry_time) == 0);
748 
749     if(! impl_->write.pending)
750         BOOST_VERIFY(
751             impl_->write.timer.expires_at(
752                 expiry_time) == 0);
753 }
754 
755 template<class Protocol, class Executor, class RatePolicy>
756 void
757 basic_stream<Protocol, Executor, RatePolicy>::
expires_never()758 expires_never()
759 {
760     impl_->reset();
761 }
762 
763 template<class Protocol, class Executor, class RatePolicy>
764 void
765 basic_stream<Protocol, Executor, RatePolicy>::
cancel()766 cancel()
767 {
768     error_code ec;
769     impl_->socket.cancel(ec);
770     impl_->timer.cancel();
771 }
772 
773 template<class Protocol, class Executor, class RatePolicy>
774 void
775 basic_stream<Protocol, Executor, RatePolicy>::
close()776 close()
777 {
778     impl_->close();
779 }
780 
781 //------------------------------------------------------------------------------
782 
783 template<class Protocol, class Executor, class RatePolicy>
784 template<BOOST_BEAST_ASYNC_TPARAM1 ConnectHandler>
BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)785 BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
786 basic_stream<Protocol, Executor, RatePolicy>::
787 async_connect(
788     endpoint_type const& ep,
789     ConnectHandler&& handler)
790 {
791     return net::async_initiate<
792         ConnectHandler,
793         void(error_code)>(
794             typename ops::run_connect_op{},
795             handler,
796             this,
797             ep);
798 }
799 
800 template<class Protocol, class Executor, class RatePolicy>
801 template<
802     class EndpointSequence,
803     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
804     class>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code,typename Protocol::endpoint))805 BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
806 basic_stream<Protocol, Executor, RatePolicy>::
807 async_connect(
808     EndpointSequence const& endpoints,
809     RangeConnectHandler&& handler)
810 {
811     return net::async_initiate<
812         RangeConnectHandler,
813         void(error_code, typename Protocol::endpoint)>(
814             typename ops::run_connect_range_op{},
815             handler,
816             this,
817             endpoints,
818             detail::any_endpoint{});
819 }
820 
821 template<class Protocol, class Executor, class RatePolicy>
822 template<
823     class EndpointSequence,
824     class ConnectCondition,
825     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
826     class>
BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code,typename Protocol::endpoint))827 BOOST_ASIO_INITFN_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
828 basic_stream<Protocol, Executor, RatePolicy>::
829 async_connect(
830     EndpointSequence const& endpoints,
831     ConnectCondition connect_condition,
832     RangeConnectHandler&& handler)
833 {
834     return net::async_initiate<
835         RangeConnectHandler,
836         void(error_code, typename Protocol::endpoint)>(
837             typename ops::run_connect_range_op{},
838             handler,
839             this,
840             endpoints,
841             connect_condition);
842 }
843 
844 template<class Protocol, class Executor, class RatePolicy>
845 template<
846     class Iterator,
847     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code,Iterator))848 BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
849 basic_stream<Protocol, Executor, RatePolicy>::
850 async_connect(
851     Iterator begin, Iterator end,
852     IteratorConnectHandler&& handler)
853 {
854     return net::async_initiate<
855         IteratorConnectHandler,
856         void(error_code, Iterator)>(
857             typename ops::run_connect_iter_op{},
858             handler,
859             this,
860             begin, end,
861             detail::any_endpoint{});
862 }
863 
864 template<class Protocol, class Executor, class RatePolicy>
865 template<
866     class Iterator,
867     class ConnectCondition,
868     BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code,Iterator))869 BOOST_ASIO_INITFN_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
870 basic_stream<Protocol, Executor, RatePolicy>::
871 async_connect(
872     Iterator begin, Iterator end,
873     ConnectCondition connect_condition,
874     IteratorConnectHandler&& handler)
875 {
876     return net::async_initiate<
877         IteratorConnectHandler,
878         void(error_code, Iterator)>(
879             typename ops::run_connect_iter_op{},
880             handler,
881             this,
882             begin, end,
883             connect_condition);
884 }
885 
886 //------------------------------------------------------------------------------
887 
888 template<class Protocol, class Executor, class RatePolicy>
889 template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
BOOST_BEAST_ASYNC_RESULT2(ReadHandler)890 BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
891 basic_stream<Protocol, Executor, RatePolicy>::
892 async_read_some(
893     MutableBufferSequence const& buffers,
894     ReadHandler&& handler)
895 {
896     static_assert(net::is_mutable_buffer_sequence<
897         MutableBufferSequence>::value,
898         "MutableBufferSequence type requirements not met");
899     return net::async_initiate<
900         ReadHandler,
901         void(error_code, std::size_t)>(
902             typename ops::run_read_op{},
903             handler,
904             this,
905             buffers);
906 }
907 
908 template<class Protocol, class Executor, class RatePolicy>
909 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
BOOST_BEAST_ASYNC_RESULT2(WriteHandler)910 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
911 basic_stream<Protocol, Executor, RatePolicy>::
912 async_write_some(
913     ConstBufferSequence const& buffers,
914     WriteHandler&& handler)
915 {
916     static_assert(net::is_const_buffer_sequence<
917         ConstBufferSequence>::value,
918         "ConstBufferSequence type requirements not met");
919     return net::async_initiate<
920         WriteHandler,
921         void(error_code, std::size_t)>(
922             typename ops::run_write_op{},
923             handler,
924             this,
925             buffers);
926 }
927 
928 //------------------------------------------------------------------------------
929 //
930 // Customization points
931 //
932 
933 #if ! BOOST_BEAST_DOXYGEN
934 
935 template<
936     class Protocol, class Executor, class RatePolicy>
937 void
beast_close_socket(basic_stream<Protocol,Executor,RatePolicy> & stream)938 beast_close_socket(
939     basic_stream<Protocol, Executor, RatePolicy>& stream)
940 {
941     error_code ec;
942     stream.socket().close(ec);
943 }
944 
945 template<
946     class Protocol, class Executor, class RatePolicy>
947 void
teardown(role_type role,basic_stream<Protocol,Executor,RatePolicy> & stream,error_code & ec)948 teardown(
949     role_type role,
950     basic_stream<Protocol, Executor, RatePolicy>& stream,
951     error_code& ec)
952 {
953     using beast::websocket::teardown;
954     teardown(role, stream.socket(), ec);
955 }
956 
957 template<
958     class Protocol, class Executor, class RatePolicy,
959     class TeardownHandler>
960 void
async_teardown(role_type role,basic_stream<Protocol,Executor,RatePolicy> & stream,TeardownHandler && handler)961 async_teardown(
962     role_type role,
963     basic_stream<Protocol, Executor, RatePolicy>& stream,
964     TeardownHandler&& handler)
965 {
966     using beast::websocket::async_teardown;
967     async_teardown(role, stream.socket(),
968         std::forward<TeardownHandler>(handler));
969 }
970 
971 #endif
972 
973 } // beast
974 } // boost
975 
976 #endif
977