Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-05 08:28:04

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_WEBSOCKET_IMPL_WRITE_HPP
0011 #define BOOST_BEAST_WEBSOCKET_IMPL_WRITE_HPP
0012 
0013 #include <boost/beast/websocket/detail/mask.hpp>
0014 #include <boost/beast/core/async_base.hpp>
0015 #include <boost/beast/core/buffer_traits.hpp>
0016 #include <boost/beast/core/buffers_cat.hpp>
0017 #include <boost/beast/core/buffers_prefix.hpp>
0018 #include <boost/beast/core/buffers_range.hpp>
0019 #include <boost/beast/core/buffers_suffix.hpp>
0020 #include <boost/beast/core/flat_static_buffer.hpp>
0021 #include <boost/beast/core/stream_traits.hpp>
0022 #include <boost/beast/core/detail/bind_continuation.hpp>
0023 #include <boost/beast/core/detail/clamp.hpp>
0024 #include <boost/beast/core/detail/config.hpp>
0025 #include <boost/beast/websocket/detail/frame.hpp>
0026 #include <boost/beast/websocket/impl/stream_impl.hpp>
0027 #include <boost/asio/coroutine.hpp>
0028 #include <boost/assert.hpp>
0029 #include <boost/config.hpp>
0030 #include <boost/throw_exception.hpp>
0031 #include <algorithm>
0032 #include <memory>
0033 
0034 namespace boost {
0035 namespace beast {
0036 namespace websocket {
0037 
0038 template<class NextLayer, bool deflateSupported>
0039 template<class Handler, class Buffers>
0040 class stream<NextLayer, deflateSupported>::write_some_op
0041     : public beast::async_base<
0042         Handler, beast::executor_type<stream>>
0043     , public asio::coroutine
0044 {
0045     enum
0046     {
0047         do_nomask_nofrag,
0048         do_nomask_frag,
0049         do_mask_nofrag,
0050         do_mask_frag,
0051         do_deflate
0052     };
0053 
0054     boost::weak_ptr<impl_type> wp_;
0055     buffers_suffix<Buffers> cb_;
0056     detail::frame_header fh_;
0057     detail::prepared_key key_;
0058     std::size_t bytes_transferred_ = 0;
0059     std::size_t remain_;
0060     std::size_t in_;
0061     int how_;
0062     bool fin_;
0063     bool more_ = false; // for ubsan
0064     bool cont_ = false;
0065 
0066 public:
0067     static constexpr int id = 2; // for soft_mutex
0068 
0069     template<class Handler_>
0070     write_some_op(
0071         Handler_&& h,
0072         boost::shared_ptr<impl_type> const& sp,
0073         bool fin,
0074         Buffers const& bs)
0075         : beast::async_base<Handler,
0076             beast::executor_type<stream>>(
0077                 std::forward<Handler_>(h),
0078                     sp->stream().get_executor())
0079         , wp_(sp)
0080         , cb_(bs)
0081         , fin_(fin)
0082     {
0083         auto& impl = *sp;
0084 
0085         // Set up the outgoing frame header
0086         if(! impl.wr_cont)
0087         {
0088             impl.begin_msg(beast::buffer_bytes(bs));
0089             fh_.rsv1 = impl.wr_compress;
0090         }
0091         else
0092         {
0093             fh_.rsv1 = false;
0094         }
0095         fh_.rsv2 = false;
0096         fh_.rsv3 = false;
0097         fh_.op = impl.wr_cont ?
0098             detail::opcode::cont : impl.wr_opcode;
0099         fh_.mask =
0100             impl.role == role_type::client;
0101 
0102         // Choose a write algorithm
0103         if(impl.wr_compress)
0104         {
0105             how_ = do_deflate;
0106         }
0107         else if(! fh_.mask)
0108         {
0109             if(! impl.wr_frag)
0110             {
0111                 how_ = do_nomask_nofrag;
0112             }
0113             else
0114             {
0115                 BOOST_ASSERT(impl.wr_buf_size != 0);
0116                 remain_ = beast::buffer_bytes(cb_);
0117                 if(remain_ > impl.wr_buf_size)
0118                     how_ = do_nomask_frag;
0119                 else
0120                     how_ = do_nomask_nofrag;
0121             }
0122         }
0123         else
0124         {
0125             if(! impl.wr_frag)
0126             {
0127                 how_ = do_mask_nofrag;
0128             }
0129             else
0130             {
0131                 BOOST_ASSERT(impl.wr_buf_size != 0);
0132                 remain_ = beast::buffer_bytes(cb_);
0133                 if(remain_ > impl.wr_buf_size)
0134                     how_ = do_mask_frag;
0135                 else
0136                     how_ = do_mask_nofrag;
0137             }
0138         }
0139         (*this)({}, 0, false);
0140     }
0141 
0142     void operator()(
0143         error_code ec = {},
0144         std::size_t bytes_transferred = 0,
0145         bool cont = true);
0146 };
0147 
0148 template<class NextLayer, bool deflateSupported>
0149 template<class Handler, class Buffers>
0150 void
0151 stream<NextLayer, deflateSupported>::
0152 write_some_op<Handler, Buffers>::
0153 operator()(
0154     error_code ec,
0155     std::size_t bytes_transferred,
0156     bool cont)
0157 {
0158     using beast::detail::clamp;
0159     std::size_t n;
0160     net::mutable_buffer b;
0161     auto sp = wp_.lock();
0162     if(! sp)
0163     {
0164         BOOST_BEAST_ASSIGN_EC(ec, net::error::operation_aborted);
0165         bytes_transferred_ = 0;
0166         return this->complete(cont, ec, bytes_transferred_);
0167     }
0168     auto& impl = *sp;
0169     BOOST_ASIO_CORO_REENTER(*this)
0170     {
0171         // Acquire the write lock
0172         if(! impl.wr_block.try_lock(this))
0173         {
0174         do_suspend:
0175             BOOST_ASIO_CORO_YIELD
0176             {
0177                 BOOST_ASIO_HANDLER_LOCATION((
0178                     __FILE__, __LINE__,
0179                     fin_ ?
0180                         "websocket::async_write" :
0181                         "websocket::async_write_some"
0182                     ));
0183                 this->set_allowed_cancellation(net::cancellation_type::all);
0184                 impl.op_wr.emplace(std::move(*this),
0185                                    net::cancellation_type::all);
0186             }
0187             if (ec)
0188                 return this->complete(cont, ec, bytes_transferred_);
0189 
0190             this->set_allowed_cancellation(net::cancellation_type::terminal);
0191             impl.wr_block.lock(this);
0192             BOOST_ASIO_CORO_YIELD
0193             {
0194                 BOOST_ASIO_HANDLER_LOCATION((
0195                     __FILE__, __LINE__,
0196                     fin_ ?
0197                         "websocket::async_write" :
0198                         "websocket::async_write_some"
0199                     ));
0200 
0201                 const auto ex = this->get_immediate_executor();
0202                 net::dispatch(ex, std::move(*this));
0203             }
0204             BOOST_ASSERT(impl.wr_block.is_locked(this));
0205         }
0206         if(impl.check_stop_now(ec))
0207             goto upcall;
0208 
0209         //------------------------------------------------------------------
0210 
0211         if(how_ == do_nomask_nofrag)
0212         {
0213             // send a single frame
0214             fh_.fin = fin_;
0215             fh_.len = beast::buffer_bytes(cb_);
0216             impl.wr_fb.clear();
0217             detail::write<flat_static_buffer_base>(
0218                 impl.wr_fb, fh_);
0219             impl.wr_cont = ! fin_;
0220             BOOST_ASIO_CORO_YIELD
0221             {
0222                 BOOST_ASIO_HANDLER_LOCATION((
0223                     __FILE__, __LINE__,
0224                     fin_ ?
0225                         "websocket::async_write" :
0226                         "websocket::async_write_some"
0227                     ));
0228 
0229                 net::async_write(impl.stream(),
0230                     buffers_cat(
0231                         net::const_buffer(impl.wr_fb.data()),
0232                         net::const_buffer(0, 0),
0233                         cb_,
0234                         buffers_prefix(0, cb_)
0235                         ),
0236                         beast::detail::bind_continuation(std::move(*this)));
0237             }
0238             bytes_transferred_ += clamp(fh_.len);
0239             if(impl.check_stop_now(ec))
0240                 goto upcall;
0241             goto upcall;
0242         }
0243 
0244         //------------------------------------------------------------------
0245 
0246         if(how_ == do_nomask_frag)
0247         {
0248             // send multiple frames
0249             for(;;)
0250             {
0251                 n = clamp(remain_, impl.wr_buf_size);
0252                 fh_.len = n;
0253                 remain_ -= n;
0254                 fh_.fin = fin_ ? remain_ == 0 : false;
0255                 impl.wr_fb.clear();
0256                 detail::write<flat_static_buffer_base>(
0257                     impl.wr_fb, fh_);
0258                 impl.wr_cont = ! fin_;
0259                 // Send frame
0260                 BOOST_ASIO_CORO_YIELD
0261                 {
0262                     BOOST_ASIO_HANDLER_LOCATION((
0263                         __FILE__, __LINE__,
0264                         fin_ ?
0265                             "websocket::async_write" :
0266                             "websocket::async_write_some"
0267                         ));
0268 
0269                     buffers_suffix<Buffers> empty_cb(cb_);
0270                     empty_cb.consume(~std::size_t(0));
0271 
0272                     net::async_write(impl.stream(),
0273                         buffers_cat(
0274                             net::const_buffer(impl.wr_fb.data()),
0275                             net::const_buffer(0, 0),
0276                             empty_cb,
0277                             buffers_prefix(clamp(fh_.len), cb_)
0278                             ),
0279                             beast::detail::bind_continuation(std::move(*this)));
0280                 }
0281                 n = clamp(fh_.len); // restore `n` on yield
0282                 bytes_transferred_ += n;
0283                 if(impl.check_stop_now(ec))
0284                     goto upcall;
0285                 if(remain_ == 0)
0286                     break;
0287                 cb_.consume(n);
0288                 fh_.op = detail::opcode::cont;
0289 
0290                 // Give up the write lock in between each frame
0291                 // so that outgoing control frames might be sent.
0292                 impl.wr_block.unlock(this);
0293                 if( impl.op_close.maybe_invoke()
0294                     || impl.op_idle_ping.maybe_invoke()
0295                     || impl.op_rd.maybe_invoke()
0296                     || impl.op_ping.maybe_invoke())
0297                 {
0298                     BOOST_ASSERT(impl.wr_block.is_locked());
0299                     goto do_suspend;
0300                 }
0301                 impl.wr_block.lock(this);
0302             }
0303             goto upcall;
0304         }
0305 
0306         //------------------------------------------------------------------
0307 
0308         if(how_ == do_mask_nofrag)
0309         {
0310             // send a single frame using multiple writes
0311             remain_ = beast::buffer_bytes(cb_);
0312             fh_.fin = fin_;
0313             fh_.len = remain_;
0314             fh_.key = impl.create_mask();
0315             detail::prepare_key(key_, fh_.key);
0316             impl.wr_fb.clear();
0317             detail::write<flat_static_buffer_base>(
0318                 impl.wr_fb, fh_);
0319             n = clamp(remain_, impl.wr_buf_size);
0320             net::buffer_copy(net::buffer(
0321                 impl.wr_buf.get(), n), cb_);
0322             detail::mask_inplace(net::buffer(
0323                 impl.wr_buf.get(), n), key_);
0324             remain_ -= n;
0325             impl.wr_cont = ! fin_;
0326             // write frame header and some payload
0327             BOOST_ASIO_CORO_YIELD
0328             {
0329                 BOOST_ASIO_HANDLER_LOCATION((
0330                     __FILE__, __LINE__,
0331                     fin_ ?
0332                         "websocket::async_write" :
0333                         "websocket::async_write_some"
0334                     ));
0335 
0336                 buffers_suffix<Buffers> empty_cb(cb_);
0337                 empty_cb.consume(~std::size_t(0));
0338 
0339                 net::async_write(impl.stream(),
0340                     buffers_cat(
0341                         net::const_buffer(impl.wr_fb.data()),
0342                         net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
0343                         empty_cb,
0344                         buffers_prefix(0, empty_cb)
0345                         ),
0346                         beast::detail::bind_continuation(std::move(*this)));
0347             }
0348             // VFALCO What about consuming the buffer on error?
0349             if(bytes_transferred > impl.wr_fb.size())
0350                 bytes_transferred_ += bytes_transferred - impl.wr_fb.size();
0351             if(impl.check_stop_now(ec))
0352                 goto upcall;
0353             while(remain_ > 0)
0354             {
0355                 cb_.consume(impl.wr_buf_size);
0356                 n = clamp(remain_, impl.wr_buf_size);
0357                 net::buffer_copy(net::buffer(
0358                     impl.wr_buf.get(), n), cb_);
0359                 detail::mask_inplace(net::buffer(
0360                     impl.wr_buf.get(), n), key_);
0361                 remain_ -= n;
0362                 // write more payload
0363                 BOOST_ASIO_CORO_YIELD
0364                 {
0365                     BOOST_ASIO_HANDLER_LOCATION((
0366                         __FILE__, __LINE__,
0367                         fin_ ?
0368                             "websocket::async_write" :
0369                             "websocket::async_write_some"
0370                         ));
0371 
0372                     buffers_suffix<Buffers> empty_cb(cb_);
0373                     empty_cb.consume(~std::size_t(0));
0374 
0375                     net::async_write(impl.stream(),
0376                         buffers_cat(
0377                             net::const_buffer(0, 0),
0378                             net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
0379                             empty_cb,
0380                             buffers_prefix(0, empty_cb)
0381                             ),
0382                             beast::detail::bind_continuation(std::move(*this)));
0383                 }
0384                 bytes_transferred_ += bytes_transferred;
0385                 if(impl.check_stop_now(ec))
0386                     goto upcall;
0387             }
0388             goto upcall;
0389         }
0390 
0391         //------------------------------------------------------------------
0392 
0393         if(how_ == do_mask_frag)
0394         {
0395             // send multiple frames
0396             for(;;)
0397             {
0398                 n = clamp(remain_, impl.wr_buf_size);
0399                 remain_ -= n;
0400                 fh_.len = n;
0401                 fh_.key = impl.create_mask();
0402                 fh_.fin = fin_ ? remain_ == 0 : false;
0403                 detail::prepare_key(key_, fh_.key);
0404                 net::buffer_copy(net::buffer(
0405                     impl.wr_buf.get(), n), cb_);
0406                 detail::mask_inplace(net::buffer(
0407                     impl.wr_buf.get(), n), key_);
0408                 impl.wr_fb.clear();
0409                 detail::write<flat_static_buffer_base>(
0410                     impl.wr_fb, fh_);
0411                 impl.wr_cont = ! fin_;
0412                 // Send frame
0413                 BOOST_ASIO_CORO_YIELD
0414                 {
0415                     BOOST_ASIO_HANDLER_LOCATION((
0416                         __FILE__, __LINE__,
0417                         fin_ ?
0418                             "websocket::async_write" :
0419                             "websocket::async_write_some"
0420                         ));
0421 
0422                     buffers_suffix<Buffers> empty_cb(cb_);
0423                     empty_cb.consume(~std::size_t(0));
0424 
0425                     net::async_write(impl.stream(),
0426                         buffers_cat(
0427                             net::const_buffer(impl.wr_fb.data()),
0428                             net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
0429                             empty_cb,
0430                             buffers_prefix(0, empty_cb)
0431                             ),
0432                             beast::detail::bind_continuation(std::move(*this)));
0433                 }
0434                 if(bytes_transferred > impl.wr_fb.size())
0435                     n = bytes_transferred - impl.wr_fb.size();
0436                 else
0437                     n = 0;
0438                 bytes_transferred_ += n;
0439                 if(impl.check_stop_now(ec))
0440                     goto upcall;
0441                 if(remain_ == 0)
0442                     break;
0443                 cb_.consume(n);
0444                 fh_.op = detail::opcode::cont;
0445                 // Give up the write lock in between each frame
0446                 // so that outgoing control frames might be sent.
0447                 impl.wr_block.unlock(this);
0448                 if( impl.op_close.maybe_invoke()
0449                     || impl.op_idle_ping.maybe_invoke()
0450                     || impl.op_rd.maybe_invoke()
0451                     || impl.op_ping.maybe_invoke())
0452                 {
0453                     BOOST_ASSERT(impl.wr_block.is_locked());
0454                     goto do_suspend;
0455                 }
0456                 impl.wr_block.lock(this);
0457             }
0458             goto upcall;
0459         }
0460 
0461         //------------------------------------------------------------------
0462 
0463         if(how_ == do_deflate)
0464         {
0465             // send compressed frames
0466             for(;;)
0467             {
0468                 b = net::buffer(impl.wr_buf.get(),
0469                     impl.wr_buf_size);
0470                 more_ = impl.deflate(b, cb_, fin_, in_, ec);
0471                 if(impl.check_stop_now(ec))
0472                     goto upcall;
0473                 n = beast::buffer_bytes(b);
0474                 if(n == 0)
0475                 {
0476                     // The input was consumed, but there is
0477                     // no output due to compression latency.
0478                     BOOST_ASSERT(! fin_);
0479                     BOOST_ASSERT(beast::buffer_bytes(cb_) == 0);
0480                     goto upcall;
0481                 }
0482                 if(fh_.mask)
0483                 {
0484                     fh_.key = impl.create_mask();
0485                     detail::prepared_key key;
0486                     detail::prepare_key(key, fh_.key);
0487                     detail::mask_inplace(b, key);
0488                 }
0489                 fh_.fin = ! more_;
0490                 fh_.len = n;
0491                 impl.wr_fb.clear();
0492                 detail::write<
0493                     flat_static_buffer_base>(impl.wr_fb, fh_);
0494                 impl.wr_cont = ! fin_;
0495                 // Send frame
0496                 BOOST_ASIO_CORO_YIELD
0497                 {
0498                     BOOST_ASIO_HANDLER_LOCATION((
0499                         __FILE__, __LINE__,
0500                         fin_ ?
0501                             "websocket::async_write" :
0502                             "websocket::async_write_some"
0503                         ));
0504 
0505                     buffers_suffix<Buffers> empty_cb(cb_);
0506                     empty_cb.consume(~std::size_t(0));
0507 
0508                     net::async_write(impl.stream(),
0509                         buffers_cat(
0510                             net::const_buffer(impl.wr_fb.data()),
0511                             net::const_buffer(b),
0512                             empty_cb,
0513                             buffers_prefix(0, empty_cb)
0514                             ),
0515                             beast::detail::bind_continuation(std::move(*this)));
0516                 }
0517                 bytes_transferred_ += in_;
0518                 if(impl.check_stop_now(ec))
0519                     goto upcall;
0520                 if(more_)
0521                 {
0522                     fh_.op = detail::opcode::cont;
0523                     fh_.rsv1 = false;
0524                     // Give up the write lock in between each frame
0525                     // so that outgoing control frames might be sent.
0526                     impl.wr_block.unlock(this);
0527                     if( impl.op_close.maybe_invoke()
0528                         || impl.op_idle_ping.maybe_invoke()
0529                         || impl.op_rd.maybe_invoke()
0530                         || impl.op_ping.maybe_invoke())
0531                     {
0532                         BOOST_ASSERT(impl.wr_block.is_locked());
0533                         goto do_suspend;
0534                     }
0535                     impl.wr_block.lock(this);
0536                 }
0537                 else
0538                 {
0539                     if(fh_.fin)
0540                         impl.do_context_takeover_write(impl.role);
0541                     goto upcall;
0542                 }
0543             }
0544         }
0545 
0546     //--------------------------------------------------------------------------
0547 
0548     upcall:
0549         impl.wr_block.unlock(this);
0550         impl.op_close.maybe_invoke()
0551             || impl.op_idle_ping.maybe_invoke()
0552             || impl.op_rd.maybe_invoke()
0553             || impl.op_ping.maybe_invoke();
0554         this->complete(cont, ec, bytes_transferred_);
0555     }
0556 }
0557 
0558 template<class NextLayer, bool deflateSupported>
0559 struct stream<NextLayer, deflateSupported>::
0560     run_write_some_op
0561 {
0562     boost::shared_ptr<impl_type> const& self;
0563 
0564     using executor_type = typename stream::executor_type;
0565 
0566     executor_type
0567     get_executor() const noexcept
0568     {
0569         return self->stream().get_executor();
0570     }
0571 
0572     template<
0573         class WriteHandler,
0574         class ConstBufferSequence>
0575     void
0576     operator()(
0577         WriteHandler&& h,
0578         bool fin,
0579         ConstBufferSequence const& b)
0580     {
0581         // If you get an error on the following line it means
0582         // that your handler does not meet the documented type
0583         // requirements for the handler.
0584 
0585         static_assert(
0586             beast::detail::is_invocable<WriteHandler,
0587                 void(error_code, std::size_t)>::value,
0588             "WriteHandler type requirements not met");
0589 
0590         write_some_op<
0591             typename std::decay<WriteHandler>::type,
0592             ConstBufferSequence>(
0593                 std::forward<WriteHandler>(h),
0594                 self,
0595                 fin,
0596                 b);
0597     }
0598 };
0599 
0600 //------------------------------------------------------------------------------
0601 
0602 template<class NextLayer, bool deflateSupported>
0603 template<class ConstBufferSequence>
0604 std::size_t
0605 stream<NextLayer, deflateSupported>::
0606 write_some(bool fin, ConstBufferSequence const& buffers)
0607 {
0608     static_assert(is_sync_stream<next_layer_type>::value,
0609         "SyncStream type requirements not met");
0610     static_assert(net::is_const_buffer_sequence<
0611         ConstBufferSequence>::value,
0612             "ConstBufferSequence type requirements not met");
0613     error_code ec;
0614     auto const bytes_transferred =
0615         write_some(fin, buffers, ec);
0616     if(ec)
0617         BOOST_THROW_EXCEPTION(system_error{ec});
0618     return bytes_transferred;
0619 }
0620 
0621 template<class NextLayer, bool deflateSupported>
0622 template<class ConstBufferSequence>
0623 std::size_t
0624 stream<NextLayer, deflateSupported>::
0625 write_some(bool fin,
0626     ConstBufferSequence const& buffers, error_code& ec)
0627 {
0628     static_assert(is_sync_stream<next_layer_type>::value,
0629         "SyncStream type requirements not met");
0630     static_assert(net::is_const_buffer_sequence<
0631         ConstBufferSequence>::value,
0632             "ConstBufferSequence type requirements not met");
0633     using beast::detail::clamp;
0634     auto& impl = *impl_;
0635     std::size_t bytes_transferred = 0;
0636     ec = {};
0637     if(impl.check_stop_now(ec))
0638         return bytes_transferred;
0639     detail::frame_header fh;
0640     if(! impl.wr_cont)
0641     {
0642         impl.begin_msg(beast::buffer_bytes(buffers));
0643         fh.rsv1 = impl.wr_compress;
0644     }
0645     else
0646     {
0647         fh.rsv1 = false;
0648     }
0649     fh.rsv2 = false;
0650     fh.rsv3 = false;
0651     fh.op = impl.wr_cont ?
0652         detail::opcode::cont : impl.wr_opcode;
0653     fh.mask = impl.role == role_type::client;
0654     auto remain = beast::buffer_bytes(buffers);
0655     if(impl.wr_compress)
0656     {
0657 
0658         buffers_suffix<
0659             ConstBufferSequence> cb(buffers);
0660         for(;;)
0661         {
0662             auto b = net::buffer(
0663                 impl.wr_buf.get(), impl.wr_buf_size);
0664             auto const more = impl.deflate(
0665                 b, cb, fin, bytes_transferred, ec);
0666             if(impl.check_stop_now(ec))
0667                 return bytes_transferred;
0668             auto const n = beast::buffer_bytes(b);
0669             if(n == 0)
0670             {
0671                 // The input was consumed, but there
0672                 // is no output due to compression
0673                 // latency.
0674                 BOOST_ASSERT(! fin);
0675                 BOOST_ASSERT(beast::buffer_bytes(cb) == 0);
0676                 fh.fin = false;
0677                 break;
0678             }
0679             if(fh.mask)
0680             {
0681                 fh.key = this->impl_->create_mask();
0682                 detail::prepared_key key;
0683                 detail::prepare_key(key, fh.key);
0684                 detail::mask_inplace(b, key);
0685             }
0686             fh.fin = ! more;
0687             fh.len = n;
0688             detail::fh_buffer fh_buf;
0689             detail::write<
0690                 flat_static_buffer_base>(fh_buf, fh);
0691             impl.wr_cont = ! fin;
0692             net::write(impl.stream(),
0693                 buffers_cat(fh_buf.data(), b), ec);
0694             if(impl.check_stop_now(ec))
0695                 return bytes_transferred;
0696             if(! more)
0697                 break;
0698             fh.op = detail::opcode::cont;
0699             fh.rsv1 = false;
0700         }
0701         if(fh.fin)
0702             impl.do_context_takeover_write(impl.role);
0703     }
0704     else if(! fh.mask)
0705     {
0706         if(! impl.wr_frag)
0707         {
0708             // no mask, no autofrag
0709             fh.fin = fin;
0710             fh.len = remain;
0711             detail::fh_buffer fh_buf;
0712             detail::write<
0713                 flat_static_buffer_base>(fh_buf, fh);
0714             impl.wr_cont = ! fin;
0715             net::write(impl.stream(),
0716                 buffers_cat(fh_buf.data(), buffers), ec);
0717             if(impl.check_stop_now(ec))
0718                 return bytes_transferred;
0719             bytes_transferred += remain;
0720         }
0721         else
0722         {
0723             // no mask, autofrag
0724             BOOST_ASSERT(impl.wr_buf_size != 0);
0725             buffers_suffix<
0726                 ConstBufferSequence> cb{buffers};
0727             for(;;)
0728             {
0729                 auto const n = clamp(remain, impl.wr_buf_size);
0730                 remain -= n;
0731                 fh.len = n;
0732                 fh.fin = fin ? remain == 0 : false;
0733                 detail::fh_buffer fh_buf;
0734                 detail::write<
0735                     flat_static_buffer_base>(fh_buf, fh);
0736                 impl.wr_cont = ! fin;
0737                 net::write(impl.stream(),
0738                     beast::buffers_cat(fh_buf.data(),
0739                         beast::buffers_prefix(n, cb)), ec);
0740                 bytes_transferred += n;
0741                 if(impl.check_stop_now(ec))
0742                     return bytes_transferred;
0743                 if(remain == 0)
0744                     break;
0745                 fh.op = detail::opcode::cont;
0746                 cb.consume(n);
0747             }
0748         }
0749     }
0750     else if(! impl.wr_frag)
0751     {
0752         // mask, no autofrag
0753         fh.fin = fin;
0754         fh.len = remain;
0755         fh.key = this->impl_->create_mask();
0756         detail::prepared_key key;
0757         detail::prepare_key(key, fh.key);
0758         detail::fh_buffer fh_buf;
0759         detail::write<
0760             flat_static_buffer_base>(fh_buf, fh);
0761         buffers_suffix<
0762             ConstBufferSequence> cb{buffers};
0763         {
0764             auto const n =
0765                 clamp(remain, impl.wr_buf_size);
0766             auto const b =
0767                 net::buffer(impl.wr_buf.get(), n);
0768             net::buffer_copy(b, cb);
0769             cb.consume(n);
0770             remain -= n;
0771             detail::mask_inplace(b, key);
0772             impl.wr_cont = ! fin;
0773             net::write(impl.stream(),
0774                 buffers_cat(fh_buf.data(), b), ec);
0775             bytes_transferred += n;
0776             if(impl.check_stop_now(ec))
0777                 return bytes_transferred;
0778         }
0779         while(remain > 0)
0780         {
0781             auto const n =
0782                 clamp(remain, impl.wr_buf_size);
0783             auto const b =
0784                 net::buffer(impl.wr_buf.get(), n);
0785             net::buffer_copy(b, cb);
0786             cb.consume(n);
0787             remain -= n;
0788             detail::mask_inplace(b, key);
0789             net::write(impl.stream(), b, ec);
0790             bytes_transferred += n;
0791             if(impl.check_stop_now(ec))
0792                 return bytes_transferred;
0793         }
0794     }
0795     else
0796     {
0797         // mask, autofrag
0798         BOOST_ASSERT(impl.wr_buf_size != 0);
0799         buffers_suffix<
0800             ConstBufferSequence> cb(buffers);
0801         for(;;)
0802         {
0803             fh.key = this->impl_->create_mask();
0804             detail::prepared_key key;
0805             detail::prepare_key(key, fh.key);
0806             auto const n =
0807                 clamp(remain, impl.wr_buf_size);
0808             auto const b =
0809                 net::buffer(impl.wr_buf.get(), n);
0810             net::buffer_copy(b, cb);
0811             detail::mask_inplace(b, key);
0812             fh.len = n;
0813             remain -= n;
0814             fh.fin = fin ? remain == 0 : false;
0815             impl.wr_cont = ! fh.fin;
0816             detail::fh_buffer fh_buf;
0817             detail::write<
0818                 flat_static_buffer_base>(fh_buf, fh);
0819             net::write(impl.stream(),
0820                 buffers_cat(fh_buf.data(), b), ec);
0821             bytes_transferred += n;
0822             if(impl.check_stop_now(ec))
0823                 return bytes_transferred;
0824             if(remain == 0)
0825                 break;
0826             fh.op = detail::opcode::cont;
0827             cb.consume(n);
0828         }
0829     }
0830     return bytes_transferred;
0831 }
0832 
0833 template<class NextLayer, bool deflateSupported>
0834 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0835 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0836 stream<NextLayer, deflateSupported>::
0837 async_write_some(bool fin,
0838     ConstBufferSequence const& bs, WriteHandler&& handler)
0839 {
0840     static_assert(is_async_stream<next_layer_type>::value,
0841         "AsyncStream type requirements not met");
0842     static_assert(net::is_const_buffer_sequence<
0843         ConstBufferSequence>::value,
0844             "ConstBufferSequence type requirements not met");
0845     return net::async_initiate<
0846         WriteHandler,
0847         void(error_code, std::size_t)>(
0848             run_write_some_op{impl_},
0849             handler,
0850             fin,
0851             bs);
0852 }
0853 
0854 //------------------------------------------------------------------------------
0855 
0856 template<class NextLayer, bool deflateSupported>
0857 template<class ConstBufferSequence>
0858 std::size_t
0859 stream<NextLayer, deflateSupported>::
0860 write(ConstBufferSequence const& buffers)
0861 {
0862     static_assert(is_sync_stream<next_layer_type>::value,
0863         "SyncStream type requirements not met");
0864     static_assert(net::is_const_buffer_sequence<
0865         ConstBufferSequence>::value,
0866             "ConstBufferSequence type requirements not met");
0867     error_code ec;
0868     auto const bytes_transferred = write(buffers, ec);
0869     if(ec)
0870         BOOST_THROW_EXCEPTION(system_error{ec});
0871     return bytes_transferred;
0872 }
0873 
0874 template<class NextLayer, bool deflateSupported>
0875 template<class ConstBufferSequence>
0876 std::size_t
0877 stream<NextLayer, deflateSupported>::
0878 write(ConstBufferSequence const& buffers, error_code& ec)
0879 {
0880     static_assert(is_sync_stream<next_layer_type>::value,
0881         "SyncStream type requirements not met");
0882     static_assert(net::is_const_buffer_sequence<
0883         ConstBufferSequence>::value,
0884             "ConstBufferSequence type requirements not met");
0885     return write_some(true, buffers, ec);
0886 }
0887 
0888 template<class NextLayer, bool deflateSupported>
0889 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
0890 BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
0891 stream<NextLayer, deflateSupported>::
0892 async_write(
0893     ConstBufferSequence const& bs, WriteHandler&& handler)
0894 {
0895     static_assert(is_async_stream<next_layer_type>::value,
0896         "AsyncStream type requirements not met");
0897     static_assert(net::is_const_buffer_sequence<
0898         ConstBufferSequence>::value,
0899             "ConstBufferSequence type requirements not met");
0900     return net::async_initiate<
0901         WriteHandler,
0902         void(error_code, std::size_t)>(
0903             run_write_some_op{impl_},
0904             handler,
0905             true,
0906             bs);
0907 }
0908 
0909 } // websocket
0910 } // beast
0911 } // boost
0912 
0913 #endif