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
25namespace boost {
26namespace beast {
27
28//------------------------------------------------------------------------------
29
30template<class Protocol, class Executor, class RatePolicy>
31template<class... Args>
32basic_stream<Protocol, Executor, RatePolicy>::
33impl_type::
34impl_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
43template<class Protocol, class Executor, class RatePolicy>
44template<class RatePolicy_, class... Args>
45basic_stream<Protocol, Executor, RatePolicy>::
46impl_type::
47impl_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
60template<class Protocol, class Executor, class RatePolicy>
61template<class Executor2>
62void
63basic_stream<Protocol, Executor, RatePolicy>::
64impl_type::
65on_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
120template<class Protocol, class Executor, class RatePolicy>
121void
122basic_stream<Protocol, Executor, RatePolicy>::
123impl_type::
124reset()
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
142template<class Protocol, class Executor, class RatePolicy>
143void
144basic_stream<Protocol, Executor, RatePolicy>::
145impl_type::
146close() noexcept
147{
148 {
149 error_code ec;
150 socket.close(ec);
151 }
152#if !defined(BOOST_NO_EXCEPTIONS)
153 try
154 {
155 timer.cancel();
156 }
157 catch(...)
158 {
159 }
160#else
161 timer.cancel();
162#endif
163}
164
165//------------------------------------------------------------------------------
166
167template<class Protocol, class Executor, class RatePolicy>
168template<class Executor2>
169struct basic_stream<Protocol, Executor, RatePolicy>::
170 timeout_handler
171{
172 using executor_type = Executor2;
173
174 op_state& state;
175 boost::weak_ptr<impl_type> wp;
176 tick_type tick;
177 executor_type ex;
178
179 executor_type get_executor() const noexcept
180 {
181 return ex;
182 }
183
184 void
185 operator()(error_code ec)
186 {
187 // timer canceled
188 if(ec == net::error::operation_aborted)
189 return;
190 BOOST_ASSERT(! ec);
191
192 auto sp = wp.lock();
193
194 // stream destroyed
195 if(! sp)
196 return;
197
198 // stale timer
199 if(tick < state.tick)
200 return;
201 BOOST_ASSERT(tick == state.tick);
202
203 // timeout
204 BOOST_ASSERT(! state.timeout);
205 sp->close();
206 state.timeout = true;
207 }
208};
209
210//------------------------------------------------------------------------------
211
212template<class Protocol, class Executor, class RatePolicy>
213struct basic_stream<Protocol, Executor, RatePolicy>::ops
214{
215
216template<bool isRead, class Buffers, class Handler>
217class transfer_op
218 : public async_base<Handler, Executor>
219 , public boost::asio::coroutine
220{
221 boost::shared_ptr<impl_type> impl_;
222 pending_guard pg_;
223 Buffers b_;
224
225 using is_read = std::integral_constant<bool, isRead>;
226
227 op_state&
228 state()
229 {
230 if (isRead)
231 return impl_->read;
232 else
233 return impl_->write;
234 }
235
236 std::size_t
237 available_bytes()
238 {
239 if (isRead)
240 return rate_policy_access::
241 available_read_bytes(impl_->policy());
242 else
243 return rate_policy_access::
244 available_write_bytes(impl_->policy());
245 }
246
247 void
248 transfer_bytes(std::size_t n)
249 {
250 if (isRead)
251 rate_policy_access::
252 transfer_read_bytes(impl_->policy(), n);
253 else
254 rate_policy_access::
255 transfer_write_bytes(impl_->policy(), n);
256 }
257
258 void
259 async_perform(
260 std::size_t amount, std::true_type)
261 {
262 impl_->socket.async_read_some(
263 beast::buffers_prefix(amount, b_),
264 std::move(*this));
265 }
266
267 void
268 async_perform(
269 std::size_t amount, std::false_type)
270 {
271 impl_->socket.async_write_some(
272 beast::buffers_prefix(amount, b_),
273 std::move(*this));
274 }
275
276 static bool never_pending_;
277
278public:
279 template<class Handler_>
280 transfer_op(
281 Handler_&& h,
282 basic_stream& s,
283 Buffers const& b)
284 : async_base<Handler, Executor>(
285 std::forward<Handler_>(h), s.get_executor())
286 , impl_(s.impl_)
287 , pg_()
288 , b_(b)
289 {
290 this->set_allowed_cancellation(net::cancellation_type::all);
291 if (buffer_bytes(b_) == 0 && state().pending)
292 {
293 // Workaround:
294 // Corner case discovered in https://github.com/boostorg/beast/issues/2065
295 // Enclosing SSL stream wishes to complete a 0-length write early by
296 // executing a 0-length read against the underlying stream.
297 // This can occur even if an existing async_read is in progress.
298 // In this specific case, we will complete the async op with no error
299 // in order to prevent assertions and/or internal corruption of the basic_stream
300 this->complete(false, error_code(), std::size_t{0});
301 }
302 else
303 {
304 pg_.assign(b&: state().pending);
305 (*this)({});
306 }
307 }
308
309 void
310 operator()(
311 error_code ec,
312 std::size_t bytes_transferred = 0)
313 {
314 BOOST_ASIO_CORO_REENTER(*this)
315 {
316 // handle empty buffers
317 if(detail::buffers_empty(b_))
318 {
319 // make sure we perform the no-op
320 BOOST_ASIO_CORO_YIELD
321 {
322 BOOST_ASIO_HANDLER_LOCATION((
323 __FILE__, __LINE__,
324 (isRead ? "basic_stream::async_read_some"
325 : "basic_stream::async_write_some")));
326
327 async_perform(0, is_read{});
328 }
329 // apply the timeout manually, otherwise
330 // behavior varies across platforms.
331 if(state().timer.expiry() <= clock_type::now())
332 {
333 impl_->close();
334 BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
335 }
336 goto upcall;
337 }
338
339 // if a timeout is active, wait on the timer
340 if(state().timer.expiry() != never())
341 {
342 BOOST_ASIO_HANDLER_LOCATION((
343 __FILE__, __LINE__,
344 (isRead ? "basic_stream::async_read_some"
345 : "basic_stream::async_write_some")));
346
347 state().timer.async_wait(
348 timeout_handler<decltype(this->get_executor())>{
349 state(),
350 impl_,
351 state().tick,
352 this->get_executor()});
353 }
354
355 // check rate limit, maybe wait
356 std::size_t amount;
357 amount = available_bytes();
358 if(amount == 0)
359 {
360 ++impl_->waiting;
361 BOOST_ASIO_CORO_YIELD
362 {
363 BOOST_ASIO_HANDLER_LOCATION((
364 __FILE__, __LINE__,
365 (isRead ? "basic_stream::async_read_some"
366 : "basic_stream::async_write_some")));
367
368 impl_->timer.async_wait(std::move(*this));
369 }
370 if(ec)
371 {
372 // socket was closed, or a timeout
373 BOOST_ASSERT(ec ==
374 net::error::operation_aborted);
375 // timeout handler invoked?
376 if(state().timeout)
377 {
378 // yes, socket already closed
379 BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
380 state().timeout = false;
381 }
382 goto upcall;
383 }
384 impl_->on_timer(this->get_executor());
385
386 // Allow at least one byte, otherwise
387 // bytes_transferred could be 0.
388 amount = std::max<std::size_t>(
389 available_bytes(), 1);
390 }
391
392 BOOST_ASIO_CORO_YIELD
393 {
394 BOOST_ASIO_HANDLER_LOCATION((
395 __FILE__, __LINE__,
396 (isRead ? "basic_stream::async_read_some"
397 : "basic_stream::async_write_some")));
398
399 async_perform(amount, is_read{});
400 }
401
402 if(state().timer.expiry() != never())
403 {
404 ++state().tick;
405
406 // try cancelling timer
407 auto const n =
408 state().timer.cancel();
409 if(n == 0)
410 {
411 // timeout handler invoked?
412 if(state().timeout)
413 {
414 // yes, socket already closed
415 BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
416 state().timeout = false;
417 }
418 }
419 else
420 {
421 BOOST_ASSERT(n == 1);
422 BOOST_ASSERT(! state().timeout);
423 }
424 }
425
426 upcall:
427 pg_.reset();
428 transfer_bytes(n: bytes_transferred);
429 this->complete_now(ec, bytes_transferred);
430 }
431 }
432};
433
434template<class Handler>
435class connect_op
436 : public async_base<Handler, Executor>
437{
438 boost::shared_ptr<impl_type> impl_;
439 pending_guard pg0_;
440 pending_guard pg1_;
441
442 op_state&
443 state() noexcept
444 {
445 return impl_->write;
446 }
447
448public:
449 template<class Handler_>
450 connect_op(
451 Handler_&& h,
452 basic_stream& s,
453 endpoint_type ep)
454 : async_base<Handler, Executor>(
455 std::forward<Handler_>(h), s.get_executor())
456 , impl_(s.impl_)
457 , pg0_(impl_->read.pending)
458 , pg1_(impl_->write.pending)
459 {
460 this->set_allowed_cancellation(net::cancellation_type::all);
461 if(state().timer.expiry() != stream_base::never())
462 {
463 BOOST_ASIO_HANDLER_LOCATION((
464 __FILE__, __LINE__,
465 "basic_stream::async_connect"));
466
467 impl_->write.timer.async_wait(
468 timeout_handler<decltype(this->get_executor())>{
469 state(),
470 impl_,
471 state().tick,
472 this->get_executor()});
473 }
474
475 BOOST_ASIO_HANDLER_LOCATION((
476 __FILE__, __LINE__,
477 "basic_stream::async_connect"));
478
479 impl_->socket.async_connect(
480 ep, std::move(*this));
481 // *this is now moved-from
482 }
483
484 template<
485 class Endpoints, class Condition,
486 class Handler_>
487 connect_op(
488 Handler_&& h,
489 basic_stream& s,
490 Endpoints const& eps,
491 Condition const& cond)
492 : async_base<Handler, Executor>(
493 std::forward<Handler_>(h), s.get_executor())
494 , impl_(s.impl_)
495 , pg0_(impl_->read.pending)
496 , pg1_(impl_->write.pending)
497 {
498 this->set_allowed_cancellation(net::cancellation_type::all);
499 if(state().timer.expiry() != stream_base::never())
500 {
501 BOOST_ASIO_HANDLER_LOCATION((
502 __FILE__, __LINE__,
503 "basic_stream::async_connect"));
504
505 impl_->write.timer.async_wait(
506 timeout_handler<decltype(this->get_executor())>{
507 state(),
508 impl_,
509 state().tick,
510 this->get_executor()});
511 }
512
513 BOOST_ASIO_HANDLER_LOCATION((
514 __FILE__, __LINE__,
515 "basic_stream::async_connect"));
516
517 net::async_connect(impl_->socket,
518 eps, cond, std::move(*this));
519 // *this is now moved-from
520 }
521
522 template<
523 class Iterator, class Condition,
524 class Handler_>
525 connect_op(
526 Handler_&& h,
527 basic_stream& s,
528 Iterator begin, Iterator end,
529 Condition const& cond)
530 : async_base<Handler, Executor>(
531 std::forward<Handler_>(h), s.get_executor())
532 , impl_(s.impl_)
533 , pg0_(impl_->read.pending)
534 , pg1_(impl_->write.pending)
535 {
536 this->set_allowed_cancellation(net::cancellation_type::all);
537 if(state().timer.expiry() != stream_base::never())
538 {
539 BOOST_ASIO_HANDLER_LOCATION((
540 __FILE__, __LINE__,
541 "basic_stream::async_connect"));
542
543 impl_->write.timer.async_wait(
544 timeout_handler<decltype(this->get_executor())>{
545 state(),
546 impl_,
547 state().tick,
548 this->get_executor()});
549 }
550
551 BOOST_ASIO_HANDLER_LOCATION((
552 __FILE__, __LINE__,
553 "basic_stream::async_connect"));
554
555 net::async_connect(impl_->socket,
556 begin, end, cond, std::move(*this));
557 // *this is now moved-from
558 }
559
560 template<class... Args>
561 void
562 operator()(error_code ec, Args&&... args)
563 {
564 if(state().timer.expiry() != stream_base::never())
565 {
566 ++state().tick;
567
568 // try cancelling timer
569 auto const n =
570 impl_->write.timer.cancel();
571 if(n == 0)
572 {
573 // timeout handler invoked?
574 if(state().timeout)
575 {
576 // yes, socket already closed
577 BOOST_BEAST_ASSIGN_EC(ec, beast::error::timeout);
578 state().timeout = false;
579 }
580 }
581 else
582 {
583 BOOST_ASSERT(n == 1);
584 BOOST_ASSERT(! state().timeout);
585 }
586 }
587
588 pg0_.reset();
589 pg1_.reset();
590 this->complete_now(ec, std::forward<Args>(args)...);
591 }
592};
593
594struct run_read_op
595{
596 template<class ReadHandler, class Buffers>
597 void
598 operator()(
599 ReadHandler&& h,
600 basic_stream* s,
601 Buffers const& b)
602 {
603 // If you get an error on the following line it means
604 // that your handler does not meet the documented type
605 // requirements for the handler.
606
607 static_assert(
608 detail::is_invocable<ReadHandler,
609 void(error_code, std::size_t)>::value,
610 "ReadHandler type requirements not met");
611
612 transfer_op<
613 true,
614 Buffers,
615 typename std::decay<ReadHandler>::type>(
616 std::forward<ReadHandler>(h), *s, b);
617 }
618};
619
620struct run_write_op
621{
622 template<class WriteHandler, class Buffers>
623 void
624 operator()(
625 WriteHandler&& h,
626 basic_stream* s,
627 Buffers const& b)
628 {
629 // If you get an error on the following line it means
630 // that your handler does not meet the documented type
631 // requirements for the handler.
632
633 static_assert(
634 detail::is_invocable<WriteHandler,
635 void(error_code, std::size_t)>::value,
636 "WriteHandler type requirements not met");
637
638 transfer_op<
639 false,
640 Buffers,
641 typename std::decay<WriteHandler>::type>(
642 std::forward<WriteHandler>(h), *s, b);
643 }
644};
645
646struct run_connect_op
647{
648 template<class ConnectHandler>
649 void
650 operator()(
651 ConnectHandler&& h,
652 basic_stream* s,
653 endpoint_type const& ep)
654 {
655 // If you get an error on the following line it means
656 // that your handler does not meet the documented type
657 // requirements for the handler.
658
659 static_assert(
660 detail::is_invocable<ConnectHandler,
661 void(error_code)>::value,
662 "ConnectHandler type requirements not met");
663
664 connect_op<typename std::decay<ConnectHandler>::type>(
665 std::forward<ConnectHandler>(h), *s, ep);
666 }
667};
668
669struct run_connect_range_op
670{
671 template<
672 class RangeConnectHandler,
673 class EndpointSequence,
674 class Condition>
675 void
676 operator()(
677 RangeConnectHandler&& h,
678 basic_stream* s,
679 EndpointSequence const& eps,
680 Condition const& cond)
681 {
682 // If you get an error on the following line it means
683 // that your handler does not meet the documented type
684 // requirements for the handler.
685
686 static_assert(
687 detail::is_invocable<RangeConnectHandler,
688 void(error_code, typename Protocol::endpoint)>::value,
689 "RangeConnectHandler type requirements not met");
690
691 connect_op<typename std::decay<RangeConnectHandler>::type>(
692 std::forward<RangeConnectHandler>(h), *s, eps, cond);
693 }
694};
695
696struct run_connect_iter_op
697{
698 template<
699 class IteratorConnectHandler,
700 class Iterator,
701 class Condition>
702 void
703 operator()(
704 IteratorConnectHandler&& h,
705 basic_stream* s,
706 Iterator begin, Iterator end,
707 Condition const& cond)
708 {
709 // If you get an error on the following line it means
710 // that your handler does not meet the documented type
711 // requirements for the handler.
712
713 static_assert(
714 detail::is_invocable<IteratorConnectHandler,
715 void(error_code, Iterator)>::value,
716 "IteratorConnectHandler type requirements not met");
717
718 connect_op<typename std::decay<IteratorConnectHandler>::type>(
719 std::forward<IteratorConnectHandler>(h), *s, begin, end, cond);
720 }
721};
722
723};
724
725//------------------------------------------------------------------------------
726
727template<class Protocol, class Executor, class RatePolicy>
728basic_stream<Protocol, Executor, RatePolicy>::
729~basic_stream()
730{
731 // the shared object can outlive *this,
732 // cancel any operations so the shared
733 // object is destroyed as soon as possible.
734 impl_->close();
735}
736
737template<class Protocol, class Executor, class RatePolicy>
738template<class Arg0, class... Args, class>
739basic_stream<Protocol, Executor, RatePolicy>::
740basic_stream(Arg0&& arg0, Args&&... args)
741 : impl_(boost::make_shared<impl_type>(
742 std::false_type{},
743 std::forward<Arg0>(arg0),
744 std::forward<Args>(args)...))
745{
746}
747
748template<class Protocol, class Executor, class RatePolicy>
749template<class RatePolicy_, class Arg0, class... Args, class>
750basic_stream<Protocol, Executor, RatePolicy>::
751basic_stream(
752 RatePolicy_&& policy, Arg0&& arg0, Args&&... args)
753 : impl_(boost::make_shared<impl_type>(
754 std::true_type{},
755 std::forward<RatePolicy_>(policy),
756 std::forward<Arg0>(arg0),
757 std::forward<Args>(args)...))
758{
759}
760
761template<class Protocol, class Executor, class RatePolicy>
762basic_stream<Protocol, Executor, RatePolicy>::
763basic_stream(basic_stream&& other)
764 : impl_(boost::make_shared<impl_type>(
765 std::move(*other.impl_)))
766{
767 // Explainer: Asio's sockets provide the guarantee that a moved-from socket
768 // will be in a state as-if newly created. i.e.:
769 // * having the same (valid) executor
770 // * the socket shall not be open
771 // We provide the same guarantee by moving the impl rather than the pointer
772 // controlling its lifetime.
773}
774
775template<class Protocol, class Executor, class RatePolicy>
776template<class Executor_>
777basic_stream<Protocol, Executor, RatePolicy>::
778basic_stream(basic_stream<Protocol, Executor_, RatePolicy> && other)
779 : impl_(boost::make_shared<impl_type>(std::false_type{}, std::move(other.impl_->socket)))
780{
781}
782
783//------------------------------------------------------------------------------
784
785template<class Protocol, class Executor, class RatePolicy>
786auto
787basic_stream<Protocol, Executor, RatePolicy>::
788release_socket() ->
789 socket_type
790{
791 this->cancel();
792 return std::move(impl_->socket);
793}
794
795template<class Protocol, class Executor, class RatePolicy>
796void
797basic_stream<Protocol, Executor, RatePolicy>::
798expires_after(net::steady_timer::duration expiry_time)
799{
800 // If assert goes off, it means that there are
801 // already read or write (or connect) operations
802 // outstanding, so there is nothing to apply
803 // the expiration time to!
804 //
805 BOOST_ASSERT(
806 ! impl_->read.pending ||
807 ! impl_->write.pending);
808
809 if(! impl_->read.pending)
810 BOOST_VERIFY(
811 impl_->read.timer.expires_after(
812 expiry_time) == 0);
813
814 if(! impl_->write.pending)
815 BOOST_VERIFY(
816 impl_->write.timer.expires_after(
817 expiry_time) == 0);
818}
819
820template<class Protocol, class Executor, class RatePolicy>
821void
822basic_stream<Protocol, Executor, RatePolicy>::
823expires_at(
824 net::steady_timer::time_point expiry_time)
825{
826 // If assert goes off, it means that there are
827 // already read or write (or connect) operations
828 // outstanding, so there is nothing to apply
829 // the expiration time to!
830 //
831 BOOST_ASSERT(
832 ! impl_->read.pending ||
833 ! impl_->write.pending);
834
835 if(! impl_->read.pending)
836 BOOST_VERIFY(
837 impl_->read.timer.expires_at(
838 expiry_time) == 0);
839
840 if(! impl_->write.pending)
841 BOOST_VERIFY(
842 impl_->write.timer.expires_at(
843 expiry_time) == 0);
844}
845
846template<class Protocol, class Executor, class RatePolicy>
847void
848basic_stream<Protocol, Executor, RatePolicy>::
849expires_never()
850{
851 impl_->reset();
852}
853
854template<class Protocol, class Executor, class RatePolicy>
855void
856basic_stream<Protocol, Executor, RatePolicy>::
857cancel()
858{
859 error_code ec;
860 impl_->socket.cancel(ec);
861 impl_->timer.cancel();
862}
863
864template<class Protocol, class Executor, class RatePolicy>
865void
866basic_stream<Protocol, Executor, RatePolicy>::
867close()
868{
869 impl_->close();
870}
871
872//------------------------------------------------------------------------------
873
874template<class Protocol, class Executor, class RatePolicy>
875template<BOOST_BEAST_ASYNC_TPARAM1 ConnectHandler>
876BOOST_BEAST_ASYNC_RESULT1(ConnectHandler)
877basic_stream<Protocol, Executor, RatePolicy>::
878async_connect(
879 endpoint_type const& ep,
880 ConnectHandler&& handler)
881{
882 return net::async_initiate<
883 ConnectHandler,
884 void(error_code)>(
885 typename ops::run_connect_op{},
886 handler,
887 this,
888 ep);
889}
890
891template<class Protocol, class Executor, class RatePolicy>
892template<
893 class EndpointSequence,
894 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
895 class>
896BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,void(error_code, typename Protocol::endpoint))
897basic_stream<Protocol, Executor, RatePolicy>::
898async_connect(
899 EndpointSequence const& endpoints,
900 RangeConnectHandler&& handler)
901{
902 return net::async_initiate<
903 RangeConnectHandler,
904 void(error_code, typename Protocol::endpoint)>(
905 typename ops::run_connect_range_op{},
906 handler,
907 this,
908 endpoints,
909 detail::any_endpoint{});
910}
911
912template<class Protocol, class Executor, class RatePolicy>
913template<
914 class EndpointSequence,
915 class ConnectCondition,
916 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, typename Protocol::endpoint)) RangeConnectHandler,
917 class>
918BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(RangeConnectHandler,void (error_code, typename Protocol::endpoint))
919basic_stream<Protocol, Executor, RatePolicy>::
920async_connect(
921 EndpointSequence const& endpoints,
922 ConnectCondition connect_condition,
923 RangeConnectHandler&& handler)
924{
925 return net::async_initiate<
926 RangeConnectHandler,
927 void(error_code, typename Protocol::endpoint)>(
928 typename ops::run_connect_range_op{},
929 handler,
930 this,
931 endpoints,
932 connect_condition);
933}
934
935template<class Protocol, class Executor, class RatePolicy>
936template<
937 class Iterator,
938 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
939BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
940basic_stream<Protocol, Executor, RatePolicy>::
941async_connect(
942 Iterator begin, Iterator end,
943 IteratorConnectHandler&& handler)
944{
945 return net::async_initiate<
946 IteratorConnectHandler,
947 void(error_code, Iterator)>(
948 typename ops::run_connect_iter_op{},
949 handler,
950 this,
951 begin, end,
952 detail::any_endpoint{});
953}
954
955template<class Protocol, class Executor, class RatePolicy>
956template<
957 class Iterator,
958 class ConnectCondition,
959 BOOST_ASIO_COMPLETION_TOKEN_FOR(void(error_code, Iterator)) IteratorConnectHandler>
960BOOST_ASIO_INITFN_AUTO_RESULT_TYPE(IteratorConnectHandler,void (error_code, Iterator))
961basic_stream<Protocol, Executor, RatePolicy>::
962async_connect(
963 Iterator begin, Iterator end,
964 ConnectCondition connect_condition,
965 IteratorConnectHandler&& handler)
966{
967 return net::async_initiate<
968 IteratorConnectHandler,
969 void(error_code, Iterator)>(
970 typename ops::run_connect_iter_op{},
971 handler,
972 this,
973 begin, end,
974 connect_condition);
975}
976
977//------------------------------------------------------------------------------
978
979template<class Protocol, class Executor, class RatePolicy>
980template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler>
981BOOST_BEAST_ASYNC_RESULT2(ReadHandler)
982basic_stream<Protocol, Executor, RatePolicy>::
983async_read_some(
984 MutableBufferSequence const& buffers,
985 ReadHandler&& handler)
986{
987 static_assert(net::is_mutable_buffer_sequence<
988 MutableBufferSequence>::value,
989 "MutableBufferSequence type requirements not met");
990 return net::async_initiate<
991 ReadHandler,
992 void(error_code, std::size_t)>(
993 typename ops::run_read_op{},
994 handler,
995 this,
996 buffers);
997}
998
999template<class Protocol, class Executor, class RatePolicy>
1000template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
1001BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
1002basic_stream<Protocol, Executor, RatePolicy>::
1003async_write_some(
1004 ConstBufferSequence const& buffers,
1005 WriteHandler&& handler)
1006{
1007 static_assert(net::is_const_buffer_sequence<
1008 ConstBufferSequence>::value,
1009 "ConstBufferSequence type requirements not met");
1010 return net::async_initiate<
1011 WriteHandler,
1012 void(error_code, std::size_t)>(
1013 typename ops::run_write_op{},
1014 handler,
1015 this,
1016 buffers);
1017}
1018
1019//------------------------------------------------------------------------------
1020//
1021// Customization points
1022//
1023
1024#if ! BOOST_BEAST_DOXYGEN
1025
1026template<
1027 class Protocol, class Executor, class RatePolicy>
1028void
1029beast_close_socket(
1030 basic_stream<Protocol, Executor, RatePolicy>& stream)
1031{
1032 error_code ec;
1033 stream.socket().close(ec);
1034}
1035
1036template<
1037 class Protocol, class Executor, class RatePolicy>
1038void
1039teardown(
1040 role_type role,
1041 basic_stream<Protocol, Executor, RatePolicy>& stream,
1042 error_code& ec)
1043{
1044 using beast::websocket::teardown;
1045 teardown(role, stream.socket(), ec);
1046}
1047
1048template<
1049 class Protocol, class Executor, class RatePolicy,
1050 class TeardownHandler>
1051void
1052async_teardown(
1053 role_type role,
1054 basic_stream<Protocol, Executor, RatePolicy>& stream,
1055 TeardownHandler&& handler)
1056{
1057 using beast::websocket::async_teardown;
1058 async_teardown(role, stream.socket(),
1059 std::forward<TeardownHandler>(handler));
1060}
1061
1062#endif
1063
1064} // beast
1065} // boost
1066
1067#endif
1068

source code of boost/libs/beast/include/boost/beast/core/impl/basic_stream.hpp