Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:35

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