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