]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/libs/beast/test/beast/core/basic_stream.cpp
import quincy beta 17.1.0
[ceph.git] / ceph / src / boost / libs / beast / test / beast / core / basic_stream.cpp
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 // Test that header file is self-contained.
11 #include <boost/beast/core/basic_stream.hpp>
12
13 #include "stream_tests.hpp"
14
15 #include <boost/beast/_experimental/unit_test/suite.hpp>
16 #include <boost/beast/core/flat_buffer.hpp>
17 #include <boost/beast/core/stream_traits.hpp>
18 #include <boost/beast/core/string.hpp>
19 #include <boost/beast/core/tcp_stream.hpp>
20 #include <boost/beast/http/message.hpp>
21 #include <boost/beast/http/empty_body.hpp>
22 #include <boost/beast/http/read.hpp>
23 #include <boost/beast/http/string_body.hpp>
24 #include <boost/beast/http/write.hpp>
25 #include <boost/asio/ip/tcp.hpp>
26 #include <boost/asio/spawn.hpp>
27 #include <boost/asio/strand.hpp>
28 #include <boost/asio/write.hpp>
29 #include <boost/optional.hpp>
30 #include <array>
31 #include <thread>
32
33 #if BOOST_ASIO_HAS_CO_AWAIT
34 #include <boost/asio/awaitable.hpp>
35 #include <boost/asio/co_spawn.hpp>
36 #include <boost/asio/use_awaitable.hpp>
37 #endif
38
39
40 namespace boost {
41 namespace beast {
42
43 namespace {
44
45 template<class Executor = net::io_context::executor_type>
46 class test_executor
47 {
48 public:
49 // VFALCO These need to be atomic or something
50 struct info
51 {
52 int dispatch = 0;
53 int post = 0;
54 int defer = 0;
55 int work = 0;
56 int total = 0;
57 };
58
59 private:
60 struct state
61 {
62 Executor ex;
63 info info_;
64
65 state(Executor const& ex_)
66 : ex(ex_)
67 {
68 }
69 };
70
71 std::shared_ptr<state> sp_;
72
73 public:
74 test_executor(test_executor const&) = default;
75 test_executor& operator=(test_executor const&) = default;
76
77 explicit
78 test_executor(Executor const& ex)
79 : sp_(std::make_shared<state>(ex))
80 {
81 }
82
83 decltype(sp_->ex.context())
84 context() const noexcept
85 {
86 return sp_->ex.context();
87 }
88
89 info&
90 operator*() noexcept
91 {
92 return sp_->info_;
93 }
94
95 info*
96 operator->() noexcept
97 {
98 return &sp_->info_;
99 }
100
101 void
102 on_work_started() const noexcept
103 {
104 ++sp_->info_.work;
105 }
106
107 void
108 on_work_finished() const noexcept
109 {
110 }
111
112 template<class F, class A>
113 void
114 dispatch(F&& f, A const& a)
115 {
116 ++sp_->info_.dispatch;
117 ++sp_->info_.total;
118 sp_->ex.dispatch(
119 std::forward<F>(f), a);
120 }
121
122 template<class F, class A>
123 void
124 post(F&& f, A const& a)
125 {
126 ++sp_->info_.post;
127 ++sp_->info_.total;
128 sp_->ex.post(
129 std::forward<F>(f), a);
130 }
131
132 template<class F, class A>
133 void
134 defer(F&& f, A const& a)
135 {
136 ++sp_->info_.defer;
137 ++sp_->info_.total;
138 sp_->ex.defer(
139 std::forward<F>(f), a);
140 }
141 };
142
143 struct test_acceptor
144 {
145 net::io_context ioc;
146 net::ip::tcp::acceptor a;
147 net::ip::tcp::endpoint ep;
148
149 test_acceptor()
150 : a(ioc)
151 , ep(net::ip::make_address_v4("127.0.0.1"), 0)
152 {
153 a.open(ep.protocol());
154 a.set_option(
155 net::socket_base::reuse_address(true));
156 a.bind(ep);
157 a.listen(net::socket_base::max_listen_connections);
158 ep = a.local_endpoint();
159 a.async_accept(
160 [](error_code, net::ip::tcp::socket)
161 {
162 });
163 }
164 };
165
166 class test_server
167 {
168 string_view s_;
169 std::ostream& log_;
170 net::io_context ioc_;
171 net::ip::tcp::acceptor acceptor_;
172 net::ip::tcp::socket socket_;
173 std::thread t_;
174
175 void
176 fail(error_code const& ec, string_view what)
177 {
178 if(ec != net::error::operation_aborted)
179 log_ << what << ": " << ec.message() << "\n";
180 }
181
182 public:
183 test_server(
184 string_view s,
185 net::ip::tcp::endpoint ep,
186 std::ostream& log)
187 : s_(s)
188 , log_(log)
189 , ioc_(1)
190 , acceptor_(ioc_)
191 , socket_(ioc_)
192 {
193 boost::system::error_code ec;
194
195 acceptor_.open(ep.protocol(), ec);
196 if(ec)
197 {
198 fail(ec, "open");
199 return;
200 }
201
202 acceptor_.set_option(
203 net::socket_base::reuse_address(true), ec);
204 if(ec)
205 {
206 fail(ec, "set_option");
207 return;
208 }
209
210 acceptor_.bind(ep, ec);
211 if(ec)
212 {
213 fail(ec, "bind");
214 return;
215 }
216
217 acceptor_.listen(
218 net::socket_base::max_listen_connections, ec);
219 if(ec)
220 {
221 fail(ec, "listen");
222 return;
223 }
224
225 acceptor_.async_accept(socket_,
226 [this](error_code ec)
227 {
228 this->on_accept(ec);
229 });
230
231 t_ = std::thread(
232 [this]
233 {
234 ioc_.run();
235 });
236 }
237
238 ~test_server()
239 {
240 ioc_.stop();
241 t_.join();
242 }
243
244 net::ip::tcp::endpoint
245 local_endpoint() const noexcept
246 {
247 return acceptor_.local_endpoint();
248 }
249
250 private:
251 class session
252 : public std::enable_shared_from_this<session>
253 {
254 string_view s_;
255 net::ip::tcp::socket socket_;
256
257 public:
258 session(
259 string_view s,
260 net::ip::tcp::socket sock,
261 std::ostream&)
262 : s_(s)
263 , socket_(std::move(sock))
264 {
265 }
266
267 void
268 run()
269 {
270 if(s_.empty())
271 socket_.async_wait(
272 net::socket_base::wait_read,
273 bind_front_handler(
274 &session::on_read,
275 shared_from_this()));
276 else
277 net::async_write(
278 socket_,
279 net::const_buffer(s_.data(), s_.size()),
280 bind_front_handler(
281 &session::on_write,
282 shared_from_this()));
283 }
284
285 protected:
286 void
287 on_read(error_code const&)
288 {
289 }
290
291 void
292 on_write(error_code const&, std::size_t)
293 {
294 }
295 };
296
297 void
298 on_accept(error_code const& ec)
299 {
300 if(! acceptor_.is_open())
301 return;
302 if(ec)
303 fail(ec, "accept");
304 else
305 std::make_shared<session>(
306 s_, std::move(socket_), log_)->run();
307 acceptor_.async_accept(socket_,
308 [this](error_code ec)
309 {
310 this->on_accept(ec);
311 });
312 }
313 };
314
315 } // (anon)
316
317 class basic_stream_test
318 : public beast::unit_test::suite
319 {
320 public:
321 using tcp = net::ip::tcp;
322 using executor = net::io_context::executor_type;
323 using strand = net::strand<executor>;
324
325 //--------------------------------------------------------------------------
326
327 void
328 testSpecialMembers()
329 {
330 net::io_context ioc;
331
332 // net::io_context::executor_type
333
334 {
335 auto ex = ioc.get_executor();
336 basic_stream<tcp, executor> s1(ioc);
337 basic_stream<tcp, executor> s2(ex);
338 basic_stream<tcp, executor> s3(ioc, tcp::v4());
339 basic_stream<tcp, executor> s4(std::move(s1));
340 s2.socket() =
341 net::basic_stream_socket<tcp, executor>(ioc);
342 BEAST_EXPECT(s1.get_executor() == ex);
343 BEAST_EXPECT(s2.get_executor() == ex);
344 BEAST_EXPECT(s3.get_executor() == ex);
345 BEAST_EXPECT(s4.get_executor() == ex);
346
347 BEAST_EXPECT((! static_cast<
348 basic_stream<tcp, executor> const&>(
349 s2).socket().is_open()));
350
351 test_sync_stream<
352 basic_stream<
353 tcp, net::io_context::executor_type>>();
354
355 test_async_stream<
356 basic_stream<
357 tcp, net::io_context::executor_type>>();
358 }
359
360 // net::io_context::strand
361
362 {
363 auto ex = net::make_strand(ioc);
364 basic_stream<tcp, strand> s1(ex);
365 basic_stream<tcp, strand> s2(ex, tcp::v4());
366 basic_stream<tcp, strand> s3(std::move(s1));
367 BEAST_EXPECT(s1.get_executor() == ex);
368 BEAST_EXPECT(s2.get_executor() == ex);
369 BEAST_EXPECT(s3.get_executor() == ex);
370
371 test_sync_stream<
372 basic_stream<
373 tcp, strand>>();
374
375 test_async_stream<
376 basic_stream<
377 tcp, strand>>();
378 }
379
380 // layers
381
382 {
383 net::socket_base::keep_alive opt;
384 tcp_stream s(ioc);
385 s.socket().open(tcp::v4());
386 s.socket().get_option(opt);
387 BEAST_EXPECT(! opt.value());
388 opt = true;
389 s.socket().set_option(opt);
390 opt = false;
391 BEAST_EXPECT(! opt.value());
392 }
393
394 // rate policies
395
396 {
397 basic_stream<tcp,
398 net::io_context::executor_type,
399 simple_rate_policy> s(ioc);
400 }
401
402 {
403 basic_stream<tcp,
404 net::io_context::executor_type,
405 simple_rate_policy> s(
406 simple_rate_policy{}, ioc);
407 }
408
409 {
410 basic_stream<tcp,
411 net::io_context::executor_type,
412 unlimited_rate_policy> s(ioc);
413 }
414
415 {
416 basic_stream<tcp,
417 net::io_context::executor_type,
418 unlimited_rate_policy> s(
419 unlimited_rate_policy{}, ioc);
420 }
421 }
422
423 class handler
424 {
425 boost::optional<error_code> ec_;
426 std::size_t n_;
427
428 public:
429 handler(error_code ec, std::size_t n)
430 : ec_(ec)
431 , n_(n)
432 {
433 }
434
435 handler(handler&& other)
436 : ec_(other.ec_)
437 , n_(boost::exchange(other.n_,
438 (std::numeric_limits<std::size_t>::max)()))
439 {
440 }
441
442 ~handler()
443 {
444 BEAST_EXPECT(
445 n_ == (std::numeric_limits<std::size_t>::max)());
446 }
447
448 void
449 operator()(error_code const& ec, std::size_t n)
450 {
451 BEAST_EXPECTS(ec == ec_, ec.message());
452 BEAST_EXPECT(n == n_);
453 n_ = (std::numeric_limits<std::size_t>::max)();
454 }
455 };
456
457 void
458 testRead()
459 {
460 using stream_type = basic_stream<tcp,
461 net::io_context::executor_type>;
462
463 char buf[4];
464 net::io_context ioc;
465 std::memset(buf, 0, sizeof(buf));
466 net::mutable_buffer mb(buf, sizeof(buf));
467 auto const ep = net::ip::tcp::endpoint(
468 net::ip::make_address("127.0.0.1"), 0);
469
470 // read_some
471
472 {
473 error_code ec;
474 stream_type s(ioc, tcp::v4());
475 BEAST_EXPECT(s.read_some(net::mutable_buffer{}) == 0);
476 BEAST_EXPECT(s.read_some(net::mutable_buffer{}, ec) == 0);
477 BEAST_EXPECTS(! ec, ec.message());
478 }
479
480 // async_read_some
481
482 {
483 // success
484 test_server srv("*", ep, log);
485 stream_type s(ioc);
486 s.socket().connect(srv.local_endpoint());
487 s.expires_never();
488 s.async_read_some(mb, handler({}, 1));
489 ioc.run();
490 ioc.restart();
491 }
492
493 {
494 // success, with timeout
495 test_server srv("*", ep, log);
496 stream_type s(ioc);
497 s.socket().connect(srv.local_endpoint());
498 s.expires_after(std::chrono::seconds(30));
499 s.async_read_some(mb, handler({}, 1));
500 ioc.run();
501 ioc.restart();
502 }
503
504 {
505 // empty buffer
506 test_server srv("*", ep, log);
507 stream_type s(ioc);
508 s.socket().connect(srv.local_endpoint());
509 s.expires_never();
510 s.async_read_some(
511 net::mutable_buffer{}, handler({}, 0));
512 ioc.run();
513 ioc.restart();
514 }
515
516 {
517 // empty buffer, timeout
518 test_server srv("*", ep, log);
519 stream_type s(ioc);
520 s.socket().connect(srv.local_endpoint());
521 s.expires_after(std::chrono::seconds(0));
522 s.async_read_some(net::mutable_buffer{},
523 handler(error::timeout, 0));
524 ioc.run();
525 ioc.restart();
526 }
527
528 {
529 // expires_after
530 test_server srv("", ep, log);
531 stream_type s(ioc);
532 s.socket().connect(srv.local_endpoint());
533 s.expires_after(std::chrono::seconds(0));
534 s.async_read_some(mb, handler(error::timeout, 0));
535 ioc.run();
536 ioc.restart();
537 }
538
539 {
540 // expires_at
541 test_server srv("", ep, log);
542 stream_type s(ioc);
543 s.socket().connect(srv.local_endpoint());
544 s.expires_at(std::chrono::steady_clock::now());
545 s.async_read_some(mb, handler(error::timeout, 0));
546 ioc.run();
547 ioc.restart();
548 }
549
550 {
551 // stream destroyed
552 test_server srv("", ep, log);
553 {
554 stream_type s(ioc);
555 s.socket().connect(srv.local_endpoint());
556 s.expires_after(std::chrono::seconds(0));
557 s.async_read_some(mb,
558 [](error_code, std::size_t)
559 {
560 });
561 }
562 ioc.run();
563 ioc.restart();
564 }
565
566 {
567 // stale timer
568 test_acceptor a;
569 stream_type s(ioc);
570 s.expires_after(std::chrono::milliseconds(50));
571 s.async_read_some(mb,
572 [](error_code, std::size_t)
573 {
574 });
575 std::this_thread::sleep_for(
576 std::chrono::milliseconds(100));
577 ioc.run();
578 ioc.restart();
579 }
580
581 // abandoned operation
582 {
583 stream_type s(ioc);
584 s.async_read_some(net::mutable_buffer{},
585 [](error_code, std::size_t)
586 {
587 BEAST_FAIL();
588 });
589 }
590 }
591
592 void
593 testWrite()
594 {
595 using stream_type = basic_stream<tcp,
596 net::io_context::executor_type>;
597
598 char buf[4];
599 net::io_context ioc;
600 std::memset(buf, 0, sizeof(buf));
601 net::const_buffer cb(buf, sizeof(buf));
602 auto const ep = net::ip::tcp::endpoint(
603 net::ip::make_address("127.0.0.1"), 0);
604
605 // write_some
606
607 {
608 error_code ec;
609 stream_type s(ioc, tcp::v4());
610 BEAST_EXPECT(s.write_some(net::const_buffer{}) == 0);
611 BEAST_EXPECT(s.write_some(net::const_buffer{}, ec) == 0);
612 BEAST_EXPECTS(! ec, ec.message());
613 }
614
615 // async_write_some
616
617 {
618 // success
619 test_server srv("*", ep, log);
620 stream_type s(ioc);
621 s.socket().connect(srv.local_endpoint());
622 s.expires_never();
623 s.async_write_some(cb, handler({}, 4));
624 ioc.run();
625 ioc.restart();
626 }
627
628 {
629 // success, with timeout
630 test_server srv("*", ep, log);
631 stream_type s(ioc);
632 s.socket().connect(srv.local_endpoint());
633 s.expires_after(std::chrono::seconds(30));
634 s.async_write_some(cb, handler({}, 4));
635 ioc.run();
636 ioc.restart();
637 }
638
639 {
640 // empty buffer
641 test_server srv("*", ep, log);
642 stream_type s(ioc);
643 s.socket().connect(srv.local_endpoint());
644 s.expires_never();
645 s.async_write_some(
646 net::const_buffer{}, handler({}, 0));
647 ioc.run();
648 ioc.restart();
649 }
650
651 {
652 // empty buffer, timeout
653 test_server srv("*", ep, log);
654 stream_type s(ioc);
655 s.socket().connect(srv.local_endpoint());
656 s.expires_after(std::chrono::seconds(0));
657 s.async_write_some(net::const_buffer{},
658 handler(error::timeout, 0));
659 ioc.run();
660 ioc.restart();
661 }
662
663 // abandoned operation
664 {
665 stream_type s(ioc);
666 s.async_write_some(cb,
667 [](error_code, std::size_t)
668 {
669 BEAST_FAIL();
670 });
671 }
672 }
673
674 void
675 testConnect()
676 {
677 using stream_type = basic_stream<tcp,
678 net::io_context::executor_type>;
679
680 struct range
681 {
682 tcp::endpoint ep;
683
684 using iterator =
685 tcp::endpoint const*;
686
687 // VFALCO This is here because asio mistakenly requires it
688 using const_iterator =
689 tcp::endpoint const*;
690
691 iterator begin() const noexcept
692 {
693 return &ep;
694 }
695
696 // VFALCO need to use const_iterator to silence
697 // warning about unused types
698 const_iterator end() const noexcept
699 {
700 return begin() + 1;
701 }
702 };
703
704 class connect_handler
705 {
706 bool pass_ = false;
707 boost::optional<error_code> expected_ = {};
708
709 public:
710 ~connect_handler()
711 {
712 BEAST_EXPECT(pass_);
713 }
714
715 connect_handler()
716 : expected_(error_code{})
717 {
718 }
719
720 explicit
721 connect_handler(error_code expected)
722 : expected_(expected)
723 {
724 }
725
726 explicit
727 connect_handler(boost::none_t)
728 {
729 }
730
731 connect_handler(connect_handler&& other)
732 : pass_(boost::exchange(other.pass_, true))
733 , expected_(other.expected_)
734 {
735 }
736
737 void operator()(error_code ec)
738 {
739 pass_ = true;
740 if(expected_)
741 BEAST_EXPECTS(
742 ec == expected_, ec.message());
743 }
744 };
745
746 struct range_handler
747 {
748 bool pass = false;
749
750 range_handler() = default;
751
752 range_handler(range_handler&& other)
753 : pass(boost::exchange(other.pass, true))
754 {
755 }
756
757 ~range_handler()
758 {
759 BEAST_EXPECT(pass);
760 }
761
762 void operator()(error_code ec, tcp::endpoint)
763 {
764 pass = true;
765 BEAST_EXPECTS(! ec, ec.message());
766 }
767 };
768
769 struct iterator_handler
770 {
771 bool pass = false;
772
773 iterator_handler() = default;
774
775 iterator_handler(iterator_handler&& other)
776 : pass(boost::exchange(other.pass, true))
777 {
778 }
779
780 ~iterator_handler()
781 {
782 BEAST_EXPECT(pass);
783 }
784
785 void operator()(error_code ec, tcp::endpoint const*)
786 {
787 pass = true;
788 BEAST_EXPECTS(! ec, ec.message());
789 }
790 };
791
792 struct connect_condition
793 {
794 bool operator()(error_code, tcp::endpoint) const
795 {
796 return true;
797 };
798 };
799
800 range r;
801 net::io_context ioc;
802 connect_condition cond;
803
804 // connect (member)
805
806 {
807 test_acceptor a;
808 stream_type s(ioc);
809 error_code ec;
810 s.connect(a.ep);
811 s.socket().close();
812 s.connect(a.ep, ec);
813 BEAST_EXPECTS(! ec, ec.message());
814 }
815
816 // connect
817
818 {
819 test_acceptor a;
820 stream_type s(ioc);
821 error_code ec;
822 r.ep = a.ep;
823 s.connect(r);
824 s.socket().close();
825 s.connect(r, ec);
826 BEAST_EXPECTS(! ec, ec.message());
827 }
828
829 {
830 test_acceptor a;
831 stream_type s(ioc);
832 error_code ec;
833 r.ep = a.ep;
834 s.connect(r, cond);
835 s.socket().close();
836 s.connect(r, cond, ec);
837 BEAST_EXPECTS(! ec, ec.message());
838 }
839
840 {
841 test_acceptor a;
842 stream_type s(ioc);
843 error_code ec;
844 r.ep = a.ep;
845 s.connect(r.begin(), r.end());
846 s.socket().close();
847 s.connect(r.begin(), r.end(), ec);
848 BEAST_EXPECTS(! ec, ec.message());
849 }
850
851 {
852 test_acceptor a;
853 stream_type s(ioc);
854 error_code ec;
855 r.ep = a.ep;
856 s.connect(r.begin(), r.end(), cond);
857 s.socket().close();
858 s.connect(r.begin(), r.end(), cond, ec);
859 BEAST_EXPECTS(! ec, ec.message());
860 }
861
862 // async_connect (member)
863
864 {
865 test_acceptor a;
866 stream_type s(ioc);
867 s.expires_never();
868 s.async_connect(a.ep, connect_handler{});
869 ioc.run();
870 ioc.restart();
871 s.socket().close();
872 s.expires_after(std::chrono::seconds(30));
873 s.async_connect(a.ep, connect_handler{});
874 ioc.run();
875 ioc.restart();
876 }
877
878 // async_connect
879
880 {
881 test_acceptor a;
882 stream_type s(ioc);
883 r.ep = a.ep;
884 s.expires_never();
885 s.async_connect(r, range_handler{});
886 ioc.run();
887 ioc.restart();
888 s.socket().close();
889 s.expires_after(std::chrono::seconds(30));
890 s.async_connect(r, range_handler{});
891 ioc.run();
892 ioc.restart();
893 }
894
895 {
896 test_acceptor a;
897 stream_type s(ioc);
898 r.ep = a.ep;
899 s.expires_never();
900 s.async_connect(r, cond, range_handler{});
901 ioc.run();
902 ioc.restart();
903 s.socket().close();
904 s.expires_after(std::chrono::seconds(30));
905 s.async_connect(r, cond, range_handler{});
906 ioc.run();
907 ioc.restart();
908 }
909
910 {
911 test_acceptor a;
912 stream_type s(ioc);
913 r.ep = a.ep;
914 s.expires_never();
915 s.async_connect(r.begin(), r.end(),
916 iterator_handler{});
917 ioc.run();
918 ioc.restart();
919 s.socket().close();
920 s.expires_after(std::chrono::seconds(30));
921 s.async_connect(r.begin(), r.end(),
922 iterator_handler{});
923 ioc.run();
924 ioc.restart();
925 }
926
927 {
928 test_acceptor a;
929 stream_type s(ioc);
930 r.ep = a.ep;
931 s.expires_never();
932 s.async_connect(r.begin(), r.end(), cond,
933 iterator_handler{});
934 ioc.run();
935 ioc.restart();
936 s.socket().close();
937 s.expires_after(std::chrono::seconds(30));
938 s.async_connect(r.begin(), r.end(), cond,
939 iterator_handler{});
940 ioc.run();
941 ioc.restart();
942 }
943 #if 0
944 // use_future
945
946 BEAST_EXPECT(static_cast<std::future<
947 tcp::endpoint>(*)(stream_type&,
948 std::array<tcp::endpoint, 2> const&,
949 net::use_future_t<>&&)>(
950 &beast::async_connect));
951
952 BEAST_EXPECT(static_cast<std::future<
953 tcp::endpoint>(*)(stream_type&,
954 std::array<tcp::endpoint, 2> const&,
955 connect_condition const&,
956 net::use_future_t<>&&)>(
957 &beast::async_connect));
958
959 BEAST_EXPECT(static_cast<std::future<
960 tcp::endpoint const*>(*)(stream_type&,
961 tcp::endpoint const*,
962 tcp::endpoint const*,
963 net::use_future_t<>&&)>(
964 &beast::async_connect));
965
966 BEAST_EXPECT(static_cast<std::future<
967 tcp::endpoint const*>(*)(stream_type&,
968 tcp::endpoint const*,
969 tcp::endpoint const*,
970 connect_condition const&,
971 net::use_future_t<>&&)>(
972 &beast::async_connect));
973
974 // yield_context
975
976 BEAST_EXPECT(static_cast<
977 tcp::endpoint(*)(stream_type&,
978 std::array<tcp::endpoint, 2> const&,
979 net::yield_context&&)>(
980 &beast::async_connect));
981
982 BEAST_EXPECT(static_cast<
983 tcp::endpoint(*)(stream_type&,
984 std::array<tcp::endpoint, 2> const&,
985 connect_condition const&,
986 net::yield_context&&)>(
987 &beast::async_connect));
988
989 BEAST_EXPECT(static_cast<
990 tcp::endpoint const*(*)(stream_type&,
991 tcp::endpoint const*,
992 tcp::endpoint const*,
993 net::yield_context&&)>(
994 &beast::async_connect));
995
996 BEAST_EXPECT(static_cast<
997 tcp::endpoint const*(*)(stream_type&,
998 tcp::endpoint const*,
999 tcp::endpoint const*,
1000 connect_condition const&,
1001 net::yield_context&&)>(
1002 &beast::async_connect));
1003 #endif
1004
1005 //
1006 // async_connect timeout
1007 //
1008
1009 {
1010 // normal timeout
1011 // Requires timeout happen before ECONNREFUSED
1012 stream_type s(ioc);
1013 auto const ep = net::ip::tcp::endpoint(
1014 #if 1
1015 // This address _should_ be unconnectible
1016 net::ip::make_address("72.5.65.111"), 1);
1017 #else
1018 // On Travis ECONNREFUSED happens before the timeout
1019 net::ip::make_address("127.0.0.1"), 1);
1020 #endif
1021 s.expires_after(std::chrono::seconds(0));
1022 s.async_connect(ep, connect_handler{error::timeout});
1023 ioc.run_for(std::chrono::seconds(1));
1024 ioc.restart();
1025 }
1026
1027 {
1028 // stream destroyed
1029 {
1030 stream_type s(ioc);
1031 auto const ep = net::ip::tcp::endpoint(
1032 net::ip::make_address("127.0.0.1"), 1);
1033 s.expires_after(std::chrono::seconds(0));
1034 s.async_connect(ep, connect_handler{boost::none});
1035 }
1036 ioc.run();
1037 ioc.restart();
1038 }
1039
1040 {
1041 // stale timer
1042 test_acceptor a;
1043 stream_type s(ioc);
1044 s.expires_after(std::chrono::milliseconds(50));
1045 s.async_connect(a.ep, connect_handler{});
1046 std::this_thread::sleep_for(
1047 std::chrono::milliseconds(100));
1048 ioc.run();
1049 ioc.restart();
1050 }
1051
1052 // abandoned operation
1053 {
1054 stream_type s(ioc);
1055 net::ip::tcp::endpoint ep(
1056 net::ip::make_address_v4("127.0.0.1"), 1);
1057 s.async_connect(ep,
1058 [](error_code)
1059 {
1060 BEAST_FAIL();
1061 });
1062 }
1063 }
1064
1065 void
1066 testMembers()
1067 {
1068 using stream_type = basic_stream<tcp,
1069 net::io_context::executor_type>;
1070
1071 class handler
1072 {
1073 bool pass_ = false;
1074 boost::optional<error_code> expected_ = {};
1075
1076 public:
1077 ~handler()
1078 {
1079 BEAST_EXPECT(pass_);
1080 }
1081
1082 handler()
1083 : expected_(error_code{})
1084 {
1085 }
1086
1087 explicit
1088 handler(error_code expected)
1089 : expected_(expected)
1090 {
1091 }
1092
1093 explicit
1094 handler(boost::none_t)
1095 {
1096 }
1097
1098 handler(handler&& other)
1099 : pass_(boost::exchange(other.pass_, true))
1100 , expected_(other.expected_)
1101 {
1102 }
1103
1104 void operator()(error_code ec, std::size_t)
1105 {
1106 pass_ = true;
1107 if(expected_)
1108 BEAST_EXPECTS(
1109 ec == expected_, ec.message());
1110 }
1111 };
1112
1113 auto const ep = net::ip::tcp::endpoint(
1114 net::ip::make_address("127.0.0.1"), 0);
1115
1116 char buf[4];
1117 net::io_context ioc;
1118 auto mb = net::buffer(buf);
1119 std::memset(buf, 0, sizeof(buf));
1120
1121 // cancel
1122
1123 {
1124 test_server srv("", ep, log);
1125 stream_type s(ioc);
1126 s.connect(srv.local_endpoint());
1127 s.expires_never();
1128 s.socket().async_read_some(mb, handler(
1129 net::error::operation_aborted));
1130 s.cancel();
1131 ioc.run();
1132 ioc.restart();
1133 }
1134
1135 // close
1136
1137 {
1138 test_server srv("", ep, log);
1139 stream_type s(ioc);
1140 s.connect(srv.local_endpoint());
1141 s.expires_never();
1142 s.socket().async_read_some(mb,
1143 handler(boost::none));
1144 s.close();
1145 ioc.run();
1146 ioc.restart();
1147 }
1148
1149 // destructor
1150
1151 {
1152 test_server srv("", ep, log);
1153 {
1154 stream_type s(ioc);
1155 s.connect(srv.local_endpoint());
1156 s.expires_never();
1157 s.socket().async_read_some(mb,
1158 handler(boost::none));
1159 }
1160 ioc.run();
1161 ioc.restart();
1162 }
1163
1164 // customization points
1165
1166 {
1167 stream_type s(ioc);
1168 beast::close_socket(s);
1169 }
1170
1171 {
1172 error_code ec;
1173 stream_type s(ioc);
1174 teardown(role_type::client, s, ec);
1175 }
1176
1177 {
1178 stream_type s(ioc);
1179 async_teardown(role_type::server, s,
1180 [](error_code)
1181 {
1182 });
1183 }
1184 }
1185
1186 //--------------------------------------------------------------------------
1187
1188 http::response<http::string_body>
1189 make_response(http::request<http::empty_body>)
1190 {
1191 return {};
1192 }
1193
1194 void process_http_1 (tcp_stream& stream, net::yield_context yield)
1195 {
1196 flat_buffer buffer;
1197 http::request<http::empty_body> req;
1198
1199 // Read the request, with a 15 second timeout
1200 stream.expires_after(std::chrono::seconds(15));
1201 http::async_read(stream, buffer, req, yield);
1202
1203 // Calculate the response
1204 http::response<http::string_body> res = make_response(req);
1205
1206 // Send the response, with a 30 second timeout.
1207 stream.expires_after (std::chrono::seconds(30));
1208 http::async_write (stream, res, yield);
1209 }
1210
1211 void process_http_2 (tcp_stream& stream, net::yield_context yield)
1212 {
1213 flat_buffer buffer;
1214 http::request<http::empty_body> req;
1215
1216 // Require that the read and write combined take no longer than 30 seconds
1217 stream.expires_after(std::chrono::seconds(30));
1218
1219 http::async_read(stream, buffer, req, yield);
1220
1221 http::response<http::string_body> res = make_response(req);
1222 http::async_write (stream, res, yield);
1223 }
1224
1225 void
1226 testJavadocs()
1227 {
1228 BEAST_EXPECT(&basic_stream_test::process_http_1);
1229 BEAST_EXPECT(&basic_stream_test::process_http_2);
1230 }
1231
1232 //--------------------------------------------------------------------------
1233
1234 void
1235 testIssue1589()
1236 {
1237 net::io_context ioc;
1238
1239 // the timer needlessly used polymorphic executor
1240 basic_stream<
1241 net::ip::tcp,
1242 net::io_context::executor_type>{ioc};
1243
1244 // make sure strands work
1245 basic_stream<
1246 net::ip::tcp,
1247 net::strand<
1248 net::io_context::executor_type>>{
1249 net::make_strand(ioc)};
1250
1251 // address the problem in the issue
1252 {
1253 net::basic_stream_socket<
1254 net::ip::tcp,
1255 net::strand<
1256 net::io_context::executor_type>
1257 > sock(net::make_strand(ioc));
1258 basic_stream<
1259 net::ip::tcp,
1260 net::strand<
1261 net::io_context::executor_type>,
1262 unlimited_rate_policy> stream(std::move(sock));
1263 BOOST_STATIC_ASSERT(
1264 std::is_convertible<
1265 decltype(sock)::executor_type,
1266 decltype(stream)::executor_type>::value);
1267 }
1268 }
1269
1270 //--------------------------------------------------------------------------
1271
1272 #if BOOST_ASIO_HAS_CO_AWAIT
1273 void testAwaitableCompilation(
1274 basic_stream<net::ip::tcp>& stream,
1275 net::mutable_buffer outbuf,
1276 net::const_buffer inbuf,
1277 net::ip::tcp::resolver::results_type resolve_results)
1278 {
1279 static_assert(std::is_same_v<
1280 net::awaitable<std::size_t>, decltype(
1281 stream.async_read_some(outbuf, net::use_awaitable))>);
1282
1283 static_assert(std::is_same_v<
1284 net::awaitable<std::size_t>, decltype(
1285 stream.async_write_some(inbuf, net::use_awaitable))>);
1286
1287 static_assert(std::is_same_v<
1288 net::awaitable<net::ip::tcp::resolver::results_type::const_iterator>, decltype(
1289 stream.async_connect(
1290 resolve_results.begin(),
1291 resolve_results.end(),
1292 net::use_awaitable))>);
1293
1294 static_assert(std::is_same_v<
1295 net::awaitable<net::ip::tcp::endpoint>, decltype(
1296 stream.async_connect(
1297 resolve_results,
1298 net::use_awaitable))>);
1299
1300 static_assert(std::is_same_v<
1301 net::awaitable<void>, decltype(
1302 stream.async_connect(
1303 resolve_results.begin()->endpoint(),
1304 net::use_awaitable))>);
1305
1306 auto comparison_function = [](error_code&, net::ip::tcp::endpoint) { return true; };
1307
1308 static_assert(std::is_same_v<
1309 net::awaitable<net::ip::tcp::resolver::results_type::const_iterator>, decltype(
1310 stream.async_connect(
1311 resolve_results.begin(),
1312 resolve_results.end(),
1313 comparison_function,
1314 net::use_awaitable))>);
1315
1316 static_assert(std::is_same_v<
1317 net::awaitable<net::ip::tcp::endpoint>, decltype(
1318 stream.async_connect(
1319 resolve_results,
1320 comparison_function,
1321 net::use_awaitable))>);
1322 }
1323 #endif
1324
1325 void
1326 testConnectionConditionArgs(
1327 basic_stream<net::ip::tcp> &stream,
1328 net::ip::tcp::resolver::results_type const &results)
1329 {
1330 struct condition
1331 {
1332 bool
1333 operator()(const error_code &,
1334 net::ip::tcp::endpoint const &) const;
1335 };
1336
1337 {
1338 struct handler
1339 {
1340 void
1341 operator()(error_code const &,
1342 net::ip::tcp::resolver::results_type::const_iterator) const;
1343 };
1344
1345 static_assert(std::is_void<decltype(
1346 stream.async_connect(
1347 results.begin(),
1348 results.end(),
1349 condition(),
1350 handler()))>::value, "");
1351 }
1352
1353 {
1354 struct handler
1355 {
1356 void
1357 operator()(error_code const &,
1358 net::ip::tcp::endpoint const &);
1359 };
1360
1361 static_assert(std::is_void<decltype(
1362 stream.async_connect(
1363 results,
1364 condition(),
1365 handler()))>::value, "");
1366 };
1367 }
1368
1369 void
1370 testIssue2065()
1371 {
1372 using stream_type = basic_stream<tcp,
1373 net::io_context::executor_type>;
1374
1375 char buf[4];
1376 net::io_context ioc;
1377 std::memset(buf, 0, sizeof(buf));
1378 net::mutable_buffer mb(buf, sizeof(buf));
1379 auto const ep = net::ip::tcp::endpoint(
1380 net::ip::make_address("127.0.0.1"), 0);
1381
1382 // async_read_some
1383
1384 {
1385 // success
1386 test_server srv("*", ep, log);
1387 stream_type s(ioc);
1388 s.socket().connect(srv.local_endpoint());
1389 s.expires_never();
1390 s.async_read_some(mb, handler({}, 1));
1391 s.async_read_some(net::buffer(buf, 0), handler({}, 0));
1392 ioc.run();
1393 ioc.restart();
1394 }
1395 }
1396
1397 void
1398 run()
1399 {
1400 testSpecialMembers();
1401 testRead();
1402 testWrite();
1403 testConnect();
1404 testMembers();
1405 testJavadocs();
1406 testIssue1589();
1407
1408 #if BOOST_ASIO_HAS_CO_AWAIT
1409 // test for compilation success only
1410 boost::ignore_unused(&basic_stream_test::testAwaitableCompilation);
1411 #endif
1412 boost::ignore_unused(&basic_stream_test::testConnectionConditionArgs);
1413 testIssue2065();
1414 }
1415 };
1416
1417 BEAST_DEFINE_TESTSUITE(beast,core,basic_stream);
1418
1419 } // beast
1420 } // boost