// // 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_WEBSOCKET_IMPL_STREAM_HPP #define BOOST_BEAST_WEBSOCKET_IMPL_STREAM_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace beast { namespace websocket { template stream:: ~stream() { if(impl_) impl_->remove(); } template template stream:: stream(Args&&... args) : impl_(boost::make_shared( std::forward(args)...)) { BOOST_ASSERT(impl_->rd_buf.max_size() >= max_control_frame_size); } template auto stream:: get_executor() noexcept -> executor_type { return impl_->stream().get_executor(); } template auto stream:: next_layer() noexcept -> next_layer_type& { return impl_->stream(); } template auto stream:: next_layer() const noexcept -> next_layer_type const& { return impl_->stream(); } template bool stream:: is_open() const noexcept { return impl_->status_ == status::open; } template bool stream:: got_binary() const noexcept { return impl_->rd_op == detail::opcode::binary; } template bool stream:: is_message_done() const noexcept { return impl_->rd_done; } template close_reason const& stream:: reason() const noexcept { return impl_->cr; } template std::size_t stream:: read_size_hint( std::size_t initial_size) const { return impl_->read_size_hint_pmd( initial_size, impl_->rd_done, impl_->rd_remain, impl_->rd_fh); } template template std::size_t stream:: read_size_hint(DynamicBuffer& buffer) const { static_assert( net::is_dynamic_buffer::value, "DynamicBuffer type requirements not met"); return impl_->read_size_hint_db(buffer); } //------------------------------------------------------------------------------ // // Settings // //------------------------------------------------------------------------------ // decorator template void stream:: set_option(decorator opt) { impl_->decorator_opt = std::move(opt.d_); } // timeout template void stream:: get_option(timeout& opt) { opt = impl_->timeout_opt; } template void stream:: set_option(timeout const& opt) { impl_->set_option(opt); } // template void stream:: set_option(permessage_deflate const& o) { impl_->set_option_pmd(o); } template void stream:: get_option(permessage_deflate& o) { impl_->get_option_pmd(o); } template void stream:: auto_fragment(bool value) { impl_->wr_frag_opt = value; } template bool stream:: auto_fragment() const { return impl_->wr_frag_opt; } template void stream:: binary(bool value) { impl_->wr_opcode = value ? detail::opcode::binary : detail::opcode::text; } template bool stream:: binary() const { return impl_->wr_opcode == detail::opcode::binary; } template void stream:: control_callback(std::function< void(frame_type, string_view)> cb) { impl_->ctrl_cb = std::move(cb); } template void stream:: control_callback() { impl_->ctrl_cb = {}; } template void stream:: read_message_max(std::size_t amount) { impl_->rd_msg_max = amount; } template std::size_t stream:: read_message_max() const { return impl_->rd_msg_max; } template void stream:: secure_prng(bool value) { this->impl_->secure_prng_ = value; } template void stream:: write_buffer_bytes(std::size_t amount) { if(amount < 8) BOOST_THROW_EXCEPTION(std::invalid_argument{ "write buffer size underflow"}); impl_->wr_buf_opt = amount; } template std::size_t stream:: write_buffer_bytes() const { return impl_->wr_buf_opt; } template void stream:: text(bool value) { impl_->wr_opcode = value ? detail::opcode::text : detail::opcode::binary; } template bool stream:: text() const { return impl_->wr_opcode == detail::opcode::text; } //------------------------------------------------------------------------------ // _Fail the WebSocket Connection_ template void stream:: do_fail( std::uint16_t code, // if set, send a close frame first error_code ev, // error code to use upon success error_code& ec) // set to the error, else set to ev { BOOST_ASSERT(ev); impl_->change_status(status::closing); if(code != close_code::none && ! impl_->wr_close) { impl_->wr_close = true; detail::frame_buffer fb; impl_->template write_close< flat_static_buffer_base>(fb, code); net::write(impl_->stream(), fb.data(), ec); if(impl_->check_stop_now(ec)) return; } using beast::websocket::teardown; teardown(impl_->role, impl_->stream(), ec); if(ec == net::error::eof) { // Rationale: // http://stackoverflow.com/questions/25587403/boost-asio-ssl-async-shutdown-always-finishes-with-an-error ec = {}; } if(! ec) ec = ev; if(ec && ec != error::closed) impl_->change_status(status::failed); else impl_->change_status(status::closed); impl_->close(); } } // websocket } // beast } // boost #endif