// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // // Official repository: https://github.com/boostorg/beast // #ifndef BOOST_BEAST_TEST_IMPL_STREAM_IPP #define BOOST_BEAST_TEST_IMPL_STREAM_IPP #include #include #include #include #include #include namespace boost { namespace beast { namespace test { //------------------------------------------------------------------------------ template void basic_stream::initiate_read( boost::shared_ptr const& in_, std::unique_ptr&& op, std::size_t buf_size) { std::unique_lock lock(in_->m); ++in_->nread; if(in_->op != nullptr) BOOST_THROW_EXCEPTION( std::logic_error{"in_->op != nullptr"}); // test failure error_code ec; if(in_->fc && in_->fc->fail(ec)) { lock.unlock(); (*op)(ec); return; } // A request to read 0 bytes from a stream is a no-op. if(buf_size == 0 || buffer_bytes(in_->b.data()) > 0) { lock.unlock(); (*op)(ec); return; } // deliver error if(in_->code != detail::stream_status::ok) { lock.unlock(); (*op)(net::error::eof); return; } // complete when bytes available or closed in_->op = std::move(op); } //------------------------------------------------------------------------------ template basic_stream:: ~basic_stream() { close(); in_->remove(); } template basic_stream:: basic_stream(basic_stream&& other) { auto in = detail::stream_service::make_impl( other.in_->exec, other.in_->fc); in_ = std::move(other.in_); out_ = std::move(other.out_); other.in_ = in; } template basic_stream& basic_stream:: operator=(basic_stream&& other) { close(); auto in = detail::stream_service::make_impl( other.in_->exec, other.in_->fc); in_->remove(); in_ = std::move(other.in_); out_ = std::move(other.out_); other.in_ = in; return *this; } //------------------------------------------------------------------------------ template basic_stream:: basic_stream(executor_type exec) : in_(detail::stream_service::make_impl(std::move(exec), nullptr)) { } template basic_stream:: basic_stream( net::io_context& ioc, fail_count& fc) : in_(detail::stream_service::make_impl(ioc.get_executor(), &fc)) { } template basic_stream:: basic_stream( net::io_context& ioc, string_view s) : in_(detail::stream_service::make_impl(ioc.get_executor(), nullptr)) { in_->b.commit(net::buffer_copy( in_->b.prepare(s.size()), net::buffer(s.data(), s.size()))); } template basic_stream:: basic_stream( net::io_context& ioc, fail_count& fc, string_view s) : in_(detail::stream_service::make_impl(ioc.get_executor(), &fc)) { in_->b.commit(net::buffer_copy( in_->b.prepare(s.size()), net::buffer(s.data(), s.size()))); } template void basic_stream:: connect(basic_stream& remote) { BOOST_ASSERT(! out_.lock()); BOOST_ASSERT(! remote.out_.lock()); std::lock(in_->m, remote.in_->m); std::lock_guard guard1{in_->m, std::adopt_lock}; std::lock_guard guard2{remote.in_->m, std::adopt_lock}; out_ = remote.in_; remote.out_ = in_; in_->code = detail::stream_status::ok; remote.in_->code = detail::stream_status::ok; } template string_view basic_stream:: str() const { auto const bs = in_->b.data(); if(buffer_bytes(bs) == 0) return {}; net::const_buffer const b = *net::buffer_sequence_begin(bs); return {static_cast(b.data()), b.size()}; } template void basic_stream:: append(string_view s) { std::lock_guard lock{in_->m}; in_->b.commit(net::buffer_copy( in_->b.prepare(s.size()), net::buffer(s.data(), s.size()))); } template void basic_stream:: clear() { std::lock_guard lock{in_->m}; in_->b.consume(in_->b.size()); } template void basic_stream:: close() { in_->cancel_read(); // disconnect { auto out = out_.lock(); out_.reset(); // notify peer if(out) { std::lock_guard lock(out->m); if(out->code == detail::stream_status::ok) { out->code = detail::stream_status::eof; out->notify_read(); } } } } template void basic_stream:: close_remote() { std::lock_guard lock{in_->m}; if(in_->code == detail::stream_status::ok) { in_->code = detail::stream_status::eof; in_->notify_read(); } } template void teardown( role_type, basic_stream& s, boost::system::error_code& ec) { if( s.in_->fc && s.in_->fc->fail(ec)) return; s.close(); if( s.in_->fc && s.in_->fc->fail(ec)) ec = net::error::eof; else ec = {}; } //------------------------------------------------------------------------------ template basic_stream connect(basic_stream& to) { basic_stream from(to.get_executor()); from.connect(to); return from; } template void connect(basic_stream& s1, basic_stream& s2) { s1.connect(s2); } } // test } // beast } // boost #endif