]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/beast/websocket/impl/write.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / beast / websocket / impl / write.hpp
CommitLineData
92f5a8d4
TL
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#ifndef BOOST_BEAST_WEBSOCKET_IMPL_WRITE_HPP
11#define BOOST_BEAST_WEBSOCKET_IMPL_WRITE_HPP
12
13#include <boost/beast/websocket/detail/mask.hpp>
14#include <boost/beast/core/async_base.hpp>
15#include <boost/beast/core/bind_handler.hpp>
16#include <boost/beast/core/buffer_traits.hpp>
17#include <boost/beast/core/buffers_cat.hpp>
18#include <boost/beast/core/buffers_prefix.hpp>
19#include <boost/beast/core/buffers_range.hpp>
20#include <boost/beast/core/buffers_suffix.hpp>
21#include <boost/beast/core/flat_static_buffer.hpp>
22#include <boost/beast/core/stream_traits.hpp>
23#include <boost/beast/core/detail/bind_continuation.hpp>
24#include <boost/beast/core/detail/clamp.hpp>
25#include <boost/beast/core/detail/config.hpp>
26#include <boost/beast/websocket/detail/frame.hpp>
27#include <boost/beast/websocket/impl/stream_impl.hpp>
28#include <boost/asio/coroutine.hpp>
29#include <boost/assert.hpp>
30#include <boost/config.hpp>
31#include <boost/throw_exception.hpp>
32#include <algorithm>
33#include <memory>
34
35namespace boost {
36namespace beast {
37namespace websocket {
38
39template<class NextLayer, bool deflateSupported>
40template<class Handler, class Buffers>
41class stream<NextLayer, deflateSupported>::write_some_op
42 : public beast::async_base<
43 Handler, beast::executor_type<stream>>
44 , public asio::coroutine
45{
46 enum
47 {
48 do_nomask_nofrag,
49 do_nomask_frag,
50 do_mask_nofrag,
51 do_mask_frag,
52 do_deflate
53 };
54
55 boost::weak_ptr<impl_type> wp_;
56 buffers_suffix<Buffers> cb_;
57 detail::frame_header fh_;
58 detail::prepared_key key_;
59 std::size_t bytes_transferred_ = 0;
60 std::size_t remain_;
61 std::size_t in_;
62 int how_;
63 bool fin_;
64 bool more_ = false; // for ubsan
65 bool cont_ = false;
66
67public:
68 static constexpr int id = 2; // for soft_mutex
69
70 template<class Handler_>
71 write_some_op(
72 Handler_&& h,
73 boost::shared_ptr<impl_type> const& sp,
74 bool fin,
75 Buffers const& bs)
76 : beast::async_base<Handler,
77 beast::executor_type<stream>>(
78 std::forward<Handler_>(h),
79 sp->stream().get_executor())
80 , wp_(sp)
81 , cb_(bs)
82 , fin_(fin)
83 {
84 auto& impl = *sp;
85
86 // Set up the outgoing frame header
87 if(! impl.wr_cont)
88 {
89 impl.begin_msg();
90 fh_.rsv1 = impl.wr_compress;
91 }
92 else
93 {
94 fh_.rsv1 = false;
95 }
96 fh_.rsv2 = false;
97 fh_.rsv3 = false;
98 fh_.op = impl.wr_cont ?
99 detail::opcode::cont : impl.wr_opcode;
100 fh_.mask =
101 impl.role == role_type::client;
102
103 // Choose a write algorithm
104 if(impl.wr_compress)
105 {
106 how_ = do_deflate;
107 }
108 else if(! fh_.mask)
109 {
110 if(! impl.wr_frag)
111 {
112 how_ = do_nomask_nofrag;
113 }
114 else
115 {
116 BOOST_ASSERT(impl.wr_buf_size != 0);
117 remain_ = buffer_bytes(cb_);
118 if(remain_ > impl.wr_buf_size)
119 how_ = do_nomask_frag;
120 else
121 how_ = do_nomask_nofrag;
122 }
123 }
124 else
125 {
126 if(! impl.wr_frag)
127 {
128 how_ = do_mask_nofrag;
129 }
130 else
131 {
132 BOOST_ASSERT(impl.wr_buf_size != 0);
133 remain_ = buffer_bytes(cb_);
134 if(remain_ > impl.wr_buf_size)
135 how_ = do_mask_frag;
136 else
137 how_ = do_mask_nofrag;
138 }
139 }
140 (*this)({}, 0, false);
141 }
142
143 void operator()(
144 error_code ec = {},
145 std::size_t bytes_transferred = 0,
146 bool cont = true);
147};
148
149template<class NextLayer, bool deflateSupported>
1e59de90 150template<class Handler, class Buffers>
92f5a8d4
TL
151void
152stream<NextLayer, deflateSupported>::
1e59de90 153write_some_op<Handler, Buffers>::
92f5a8d4
TL
154operator()(
155 error_code ec,
156 std::size_t bytes_transferred,
157 bool cont)
158{
159 using beast::detail::clamp;
160 std::size_t n;
161 net::mutable_buffer b;
162 auto sp = wp_.lock();
163 if(! sp)
164 {
165 ec = net::error::operation_aborted;
166 bytes_transferred_ = 0;
167 return this->complete(cont, ec, bytes_transferred_);
168 }
169 auto& impl = *sp;
170 BOOST_ASIO_CORO_REENTER(*this)
171 {
172 // Acquire the write lock
173 if(! impl.wr_block.try_lock(this))
174 {
175 do_suspend:
176 BOOST_ASIO_CORO_YIELD
20effc67
TL
177 {
178 BOOST_ASIO_HANDLER_LOCATION((
179 __FILE__, __LINE__,
180 fin_ ?
181 "websocket::async_write" :
182 "websocket::async_write_some"
183 ));
184
185 impl.op_wr.emplace(std::move(*this));
186 }
92f5a8d4
TL
187 impl.wr_block.lock(this);
188 BOOST_ASIO_CORO_YIELD
20effc67
TL
189 {
190 BOOST_ASIO_HANDLER_LOCATION((
191 __FILE__, __LINE__,
192 fin_ ?
193 "websocket::async_write" :
194 "websocket::async_write_some"
195 ));
196
197 net::post(std::move(*this));
198 }
92f5a8d4
TL
199 BOOST_ASSERT(impl.wr_block.is_locked(this));
200 }
201 if(impl.check_stop_now(ec))
202 goto upcall;
203
204 //------------------------------------------------------------------
205
206 if(how_ == do_nomask_nofrag)
207 {
208 // send a single frame
209 fh_.fin = fin_;
210 fh_.len = buffer_bytes(cb_);
211 impl.wr_fb.clear();
212 detail::write<flat_static_buffer_base>(
213 impl.wr_fb, fh_);
214 impl.wr_cont = ! fin_;
215 BOOST_ASIO_CORO_YIELD
20effc67
TL
216 {
217 BOOST_ASIO_HANDLER_LOCATION((
218 __FILE__, __LINE__,
219 fin_ ?
220 "websocket::async_write" :
221 "websocket::async_write_some"
222 ));
223
224 net::async_write(impl.stream(),
1e59de90
TL
225 buffers_cat(
226 net::const_buffer(impl.wr_fb.data()),
227 net::const_buffer(0, 0),
228 cb_,
229 buffers_prefix(0, cb_)
230 ),
20effc67
TL
231 beast::detail::bind_continuation(std::move(*this)));
232 }
92f5a8d4
TL
233 bytes_transferred_ += clamp(fh_.len);
234 if(impl.check_stop_now(ec))
235 goto upcall;
236 goto upcall;
237 }
238
239 //------------------------------------------------------------------
240
241 if(how_ == do_nomask_frag)
242 {
243 // send multiple frames
244 for(;;)
245 {
246 n = clamp(remain_, impl.wr_buf_size);
247 fh_.len = n;
248 remain_ -= n;
249 fh_.fin = fin_ ? remain_ == 0 : false;
250 impl.wr_fb.clear();
251 detail::write<flat_static_buffer_base>(
252 impl.wr_fb, fh_);
253 impl.wr_cont = ! fin_;
254 // Send frame
255 BOOST_ASIO_CORO_YIELD
20effc67
TL
256 {
257 BOOST_ASIO_HANDLER_LOCATION((
258 __FILE__, __LINE__,
259 fin_ ?
260 "websocket::async_write" :
261 "websocket::async_write_some"
262 ));
263
1e59de90
TL
264 buffers_suffix<Buffers> empty_cb(cb_);
265 empty_cb.consume(~std::size_t(0));
266
267 net::async_write(impl.stream(),
268 buffers_cat(
269 net::const_buffer(impl.wr_fb.data()),
270 net::const_buffer(0, 0),
271 empty_cb,
272 buffers_prefix(clamp(fh_.len), cb_)
273 ),
20effc67
TL
274 beast::detail::bind_continuation(std::move(*this)));
275 }
92f5a8d4
TL
276 n = clamp(fh_.len); // restore `n` on yield
277 bytes_transferred_ += n;
278 if(impl.check_stop_now(ec))
279 goto upcall;
280 if(remain_ == 0)
281 break;
282 cb_.consume(n);
283 fh_.op = detail::opcode::cont;
284
285 // Give up the write lock in between each frame
286 // so that outgoing control frames might be sent.
287 impl.wr_block.unlock(this);
288 if( impl.op_close.maybe_invoke()
289 || impl.op_idle_ping.maybe_invoke()
290 || impl.op_rd.maybe_invoke()
291 || impl.op_ping.maybe_invoke())
292 {
293 BOOST_ASSERT(impl.wr_block.is_locked());
294 goto do_suspend;
295 }
296 impl.wr_block.lock(this);
297 }
298 goto upcall;
299 }
300
301 //------------------------------------------------------------------
302
303 if(how_ == do_mask_nofrag)
304 {
305 // send a single frame using multiple writes
306 remain_ = beast::buffer_bytes(cb_);
307 fh_.fin = fin_;
308 fh_.len = remain_;
309 fh_.key = impl.create_mask();
310 detail::prepare_key(key_, fh_.key);
311 impl.wr_fb.clear();
312 detail::write<flat_static_buffer_base>(
313 impl.wr_fb, fh_);
314 n = clamp(remain_, impl.wr_buf_size);
315 net::buffer_copy(net::buffer(
316 impl.wr_buf.get(), n), cb_);
317 detail::mask_inplace(net::buffer(
318 impl.wr_buf.get(), n), key_);
319 remain_ -= n;
320 impl.wr_cont = ! fin_;
321 // write frame header and some payload
322 BOOST_ASIO_CORO_YIELD
20effc67
TL
323 {
324 BOOST_ASIO_HANDLER_LOCATION((
325 __FILE__, __LINE__,
326 fin_ ?
327 "websocket::async_write" :
328 "websocket::async_write_some"
329 ));
330
1e59de90
TL
331 buffers_suffix<Buffers> empty_cb(cb_);
332 empty_cb.consume(~std::size_t(0));
333
334 net::async_write(impl.stream(),
335 buffers_cat(
336 net::const_buffer(impl.wr_fb.data()),
337 net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
338 empty_cb,
339 buffers_prefix(0, empty_cb)
340 ),
20effc67
TL
341 beast::detail::bind_continuation(std::move(*this)));
342 }
92f5a8d4
TL
343 // VFALCO What about consuming the buffer on error?
344 bytes_transferred_ +=
345 bytes_transferred - impl.wr_fb.size();
346 if(impl.check_stop_now(ec))
347 goto upcall;
348 while(remain_ > 0)
349 {
350 cb_.consume(impl.wr_buf_size);
351 n = clamp(remain_, impl.wr_buf_size);
352 net::buffer_copy(net::buffer(
353 impl.wr_buf.get(), n), cb_);
354 detail::mask_inplace(net::buffer(
355 impl.wr_buf.get(), n), key_);
356 remain_ -= n;
357 // write more payload
358 BOOST_ASIO_CORO_YIELD
20effc67
TL
359 {
360 BOOST_ASIO_HANDLER_LOCATION((
361 __FILE__, __LINE__,
362 fin_ ?
363 "websocket::async_write" :
364 "websocket::async_write_some"
365 ));
366
1e59de90
TL
367 buffers_suffix<Buffers> empty_cb(cb_);
368 empty_cb.consume(~std::size_t(0));
369
20effc67 370 net::async_write(impl.stream(),
1e59de90
TL
371 buffers_cat(
372 net::const_buffer(0, 0),
373 net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
374 empty_cb,
375 buffers_prefix(0, empty_cb)
376 ),
20effc67
TL
377 beast::detail::bind_continuation(std::move(*this)));
378 }
92f5a8d4
TL
379 bytes_transferred_ += bytes_transferred;
380 if(impl.check_stop_now(ec))
381 goto upcall;
382 }
383 goto upcall;
384 }
385
386 //------------------------------------------------------------------
387
388 if(how_ == do_mask_frag)
389 {
390 // send multiple frames
391 for(;;)
392 {
393 n = clamp(remain_, impl.wr_buf_size);
394 remain_ -= n;
395 fh_.len = n;
396 fh_.key = impl.create_mask();
397 fh_.fin = fin_ ? remain_ == 0 : false;
398 detail::prepare_key(key_, fh_.key);
399 net::buffer_copy(net::buffer(
400 impl.wr_buf.get(), n), cb_);
401 detail::mask_inplace(net::buffer(
402 impl.wr_buf.get(), n), key_);
403 impl.wr_fb.clear();
404 detail::write<flat_static_buffer_base>(
405 impl.wr_fb, fh_);
406 impl.wr_cont = ! fin_;
407 // Send frame
408 BOOST_ASIO_CORO_YIELD
20effc67
TL
409 {
410 BOOST_ASIO_HANDLER_LOCATION((
411 __FILE__, __LINE__,
412 fin_ ?
413 "websocket::async_write" :
414 "websocket::async_write_some"
415 ));
416
1e59de90
TL
417 buffers_suffix<Buffers> empty_cb(cb_);
418 empty_cb.consume(~std::size_t(0));
419
420 net::async_write(impl.stream(),
421 buffers_cat(
422 net::const_buffer(impl.wr_fb.data()),
423 net::const_buffer(net::buffer(impl.wr_buf.get(), n)),
424 empty_cb,
425 buffers_prefix(0, empty_cb)
426 ),
20effc67
TL
427 beast::detail::bind_continuation(std::move(*this)));
428 }
92f5a8d4
TL
429 n = bytes_transferred - impl.wr_fb.size();
430 bytes_transferred_ += n;
431 if(impl.check_stop_now(ec))
432 goto upcall;
433 if(remain_ == 0)
434 break;
435 cb_.consume(n);
436 fh_.op = detail::opcode::cont;
437 // Give up the write lock in between each frame
438 // so that outgoing control frames might be sent.
439 impl.wr_block.unlock(this);
440 if( impl.op_close.maybe_invoke()
441 || impl.op_idle_ping.maybe_invoke()
442 || impl.op_rd.maybe_invoke()
443 || impl.op_ping.maybe_invoke())
444 {
445 BOOST_ASSERT(impl.wr_block.is_locked());
446 goto do_suspend;
447 }
448 impl.wr_block.lock(this);
449 }
450 goto upcall;
451 }
452
453 //------------------------------------------------------------------
454
455 if(how_ == do_deflate)
456 {
457 // send compressed frames
458 for(;;)
459 {
460 b = net::buffer(impl.wr_buf.get(),
461 impl.wr_buf_size);
462 more_ = impl.deflate(b, cb_, fin_, in_, ec);
463 if(impl.check_stop_now(ec))
464 goto upcall;
465 n = buffer_bytes(b);
466 if(n == 0)
467 {
468 // The input was consumed, but there is
469 // no output due to compression latency.
470 BOOST_ASSERT(! fin_);
471 BOOST_ASSERT(buffer_bytes(cb_) == 0);
472 goto upcall;
473 }
474 if(fh_.mask)
475 {
476 fh_.key = impl.create_mask();
477 detail::prepared_key key;
478 detail::prepare_key(key, fh_.key);
479 detail::mask_inplace(b, key);
480 }
481 fh_.fin = ! more_;
482 fh_.len = n;
483 impl.wr_fb.clear();
484 detail::write<
485 flat_static_buffer_base>(impl.wr_fb, fh_);
486 impl.wr_cont = ! fin_;
487 // Send frame
488 BOOST_ASIO_CORO_YIELD
20effc67
TL
489 {
490 BOOST_ASIO_HANDLER_LOCATION((
491 __FILE__, __LINE__,
492 fin_ ?
493 "websocket::async_write" :
494 "websocket::async_write_some"
495 ));
496
1e59de90
TL
497 buffers_suffix<Buffers> empty_cb(cb_);
498 empty_cb.consume(~std::size_t(0));
499
500 net::async_write(impl.stream(),
501 buffers_cat(
502 net::const_buffer(impl.wr_fb.data()),
503 net::const_buffer(b),
504 empty_cb,
505 buffers_prefix(0, empty_cb)
506 ),
20effc67
TL
507 beast::detail::bind_continuation(std::move(*this)));
508 }
92f5a8d4
TL
509 bytes_transferred_ += in_;
510 if(impl.check_stop_now(ec))
511 goto upcall;
512 if(more_)
513 {
514 fh_.op = detail::opcode::cont;
515 fh_.rsv1 = false;
516 // Give up the write lock in between each frame
517 // so that outgoing control frames might be sent.
518 impl.wr_block.unlock(this);
519 if( impl.op_close.maybe_invoke()
520 || impl.op_idle_ping.maybe_invoke()
521 || impl.op_rd.maybe_invoke()
522 || impl.op_ping.maybe_invoke())
523 {
524 BOOST_ASSERT(impl.wr_block.is_locked());
525 goto do_suspend;
526 }
527 impl.wr_block.lock(this);
528 }
529 else
530 {
531 if(fh_.fin)
532 impl.do_context_takeover_write(impl.role);
533 goto upcall;
534 }
535 }
536 }
537
538 //--------------------------------------------------------------------------
539
540 upcall:
541 impl.wr_block.unlock(this);
542 impl.op_close.maybe_invoke()
543 || impl.op_idle_ping.maybe_invoke()
544 || impl.op_rd.maybe_invoke()
545 || impl.op_ping.maybe_invoke();
546 this->complete(cont, ec, bytes_transferred_);
547 }
548}
549
550template<class NextLayer, bool deflateSupported>
551struct stream<NextLayer, deflateSupported>::
552 run_write_some_op
553{
554 template<
555 class WriteHandler,
556 class ConstBufferSequence>
557 void
558 operator()(
559 WriteHandler&& h,
560 boost::shared_ptr<impl_type> const& sp,
561 bool fin,
562 ConstBufferSequence const& b)
563 {
564 // If you get an error on the following line it means
565 // that your handler does not meet the documented type
566 // requirements for the handler.
567
568 static_assert(
569 beast::detail::is_invocable<WriteHandler,
570 void(error_code, std::size_t)>::value,
571 "WriteHandler type requirements not met");
572
573 write_some_op<
574 typename std::decay<WriteHandler>::type,
575 ConstBufferSequence>(
576 std::forward<WriteHandler>(h),
577 sp,
578 fin,
579 b);
580 }
581};
582
583//------------------------------------------------------------------------------
584
585template<class NextLayer, bool deflateSupported>
586template<class ConstBufferSequence>
587std::size_t
588stream<NextLayer, deflateSupported>::
589write_some(bool fin, ConstBufferSequence const& buffers)
590{
591 static_assert(is_sync_stream<next_layer_type>::value,
592 "SyncStream type requirements not met");
593 static_assert(net::is_const_buffer_sequence<
594 ConstBufferSequence>::value,
595 "ConstBufferSequence type requirements not met");
596 error_code ec;
597 auto const bytes_transferred =
598 write_some(fin, buffers, ec);
599 if(ec)
600 BOOST_THROW_EXCEPTION(system_error{ec});
601 return bytes_transferred;
602}
603
604template<class NextLayer, bool deflateSupported>
605template<class ConstBufferSequence>
606std::size_t
607stream<NextLayer, deflateSupported>::
608write_some(bool fin,
609 ConstBufferSequence const& buffers, error_code& ec)
610{
611 static_assert(is_sync_stream<next_layer_type>::value,
612 "SyncStream type requirements not met");
613 static_assert(net::is_const_buffer_sequence<
614 ConstBufferSequence>::value,
615 "ConstBufferSequence type requirements not met");
616 using beast::detail::clamp;
617 auto& impl = *impl_;
618 std::size_t bytes_transferred = 0;
619 ec = {};
620 if(impl.check_stop_now(ec))
621 return bytes_transferred;
622 detail::frame_header fh;
623 if(! impl.wr_cont)
624 {
625 impl.begin_msg();
626 fh.rsv1 = impl.wr_compress;
627 }
628 else
629 {
630 fh.rsv1 = false;
631 }
632 fh.rsv2 = false;
633 fh.rsv3 = false;
634 fh.op = impl.wr_cont ?
635 detail::opcode::cont : impl.wr_opcode;
636 fh.mask = impl.role == role_type::client;
637 auto remain = buffer_bytes(buffers);
638 if(impl.wr_compress)
639 {
640
641 buffers_suffix<
642 ConstBufferSequence> cb(buffers);
643 for(;;)
644 {
645 auto b = net::buffer(
646 impl.wr_buf.get(), impl.wr_buf_size);
647 auto const more = impl.deflate(
648 b, cb, fin, bytes_transferred, ec);
649 if(impl.check_stop_now(ec))
650 return bytes_transferred;
651 auto const n = buffer_bytes(b);
652 if(n == 0)
653 {
654 // The input was consumed, but there
655 // is no output due to compression
656 // latency.
657 BOOST_ASSERT(! fin);
658 BOOST_ASSERT(buffer_bytes(cb) == 0);
659 fh.fin = false;
660 break;
661 }
662 if(fh.mask)
663 {
664 fh.key = this->impl_->create_mask();
665 detail::prepared_key key;
666 detail::prepare_key(key, fh.key);
667 detail::mask_inplace(b, key);
668 }
669 fh.fin = ! more;
670 fh.len = n;
671 detail::fh_buffer fh_buf;
672 detail::write<
673 flat_static_buffer_base>(fh_buf, fh);
674 impl.wr_cont = ! fin;
675 net::write(impl.stream(),
676 buffers_cat(fh_buf.data(), b), ec);
677 if(impl.check_stop_now(ec))
678 return bytes_transferred;
679 if(! more)
680 break;
681 fh.op = detail::opcode::cont;
682 fh.rsv1 = false;
683 }
684 if(fh.fin)
685 impl.do_context_takeover_write(impl.role);
686 }
687 else if(! fh.mask)
688 {
689 if(! impl.wr_frag)
690 {
691 // no mask, no autofrag
692 fh.fin = fin;
693 fh.len = remain;
694 detail::fh_buffer fh_buf;
695 detail::write<
696 flat_static_buffer_base>(fh_buf, fh);
697 impl.wr_cont = ! fin;
698 net::write(impl.stream(),
699 buffers_cat(fh_buf.data(), buffers), ec);
700 if(impl.check_stop_now(ec))
701 return bytes_transferred;
702 bytes_transferred += remain;
703 }
704 else
705 {
706 // no mask, autofrag
707 BOOST_ASSERT(impl.wr_buf_size != 0);
708 buffers_suffix<
709 ConstBufferSequence> cb{buffers};
710 for(;;)
711 {
712 auto const n = clamp(remain, impl.wr_buf_size);
713 remain -= n;
714 fh.len = n;
715 fh.fin = fin ? remain == 0 : false;
716 detail::fh_buffer fh_buf;
717 detail::write<
718 flat_static_buffer_base>(fh_buf, fh);
719 impl.wr_cont = ! fin;
720 net::write(impl.stream(),
721 beast::buffers_cat(fh_buf.data(),
722 beast::buffers_prefix(n, cb)), ec);
723 bytes_transferred += n;
724 if(impl.check_stop_now(ec))
725 return bytes_transferred;
726 if(remain == 0)
727 break;
728 fh.op = detail::opcode::cont;
729 cb.consume(n);
730 }
731 }
732 }
733 else if(! impl.wr_frag)
734 {
735 // mask, no autofrag
736 fh.fin = fin;
737 fh.len = remain;
738 fh.key = this->impl_->create_mask();
739 detail::prepared_key key;
740 detail::prepare_key(key, fh.key);
741 detail::fh_buffer fh_buf;
742 detail::write<
743 flat_static_buffer_base>(fh_buf, fh);
744 buffers_suffix<
745 ConstBufferSequence> cb{buffers};
746 {
747 auto const n =
748 clamp(remain, impl.wr_buf_size);
749 auto const b =
750 net::buffer(impl.wr_buf.get(), n);
751 net::buffer_copy(b, cb);
752 cb.consume(n);
753 remain -= n;
754 detail::mask_inplace(b, key);
755 impl.wr_cont = ! fin;
756 net::write(impl.stream(),
757 buffers_cat(fh_buf.data(), b), ec);
758 bytes_transferred += n;
759 if(impl.check_stop_now(ec))
760 return bytes_transferred;
761 }
762 while(remain > 0)
763 {
764 auto const n =
765 clamp(remain, impl.wr_buf_size);
766 auto const b =
767 net::buffer(impl.wr_buf.get(), n);
768 net::buffer_copy(b, cb);
769 cb.consume(n);
770 remain -= n;
771 detail::mask_inplace(b, key);
772 net::write(impl.stream(), b, ec);
773 bytes_transferred += n;
774 if(impl.check_stop_now(ec))
775 return bytes_transferred;
776 }
777 }
778 else
779 {
780 // mask, autofrag
781 BOOST_ASSERT(impl.wr_buf_size != 0);
782 buffers_suffix<
783 ConstBufferSequence> cb(buffers);
784 for(;;)
785 {
786 fh.key = this->impl_->create_mask();
787 detail::prepared_key key;
788 detail::prepare_key(key, fh.key);
789 auto const n =
790 clamp(remain, impl.wr_buf_size);
791 auto const b =
792 net::buffer(impl.wr_buf.get(), n);
793 net::buffer_copy(b, cb);
794 detail::mask_inplace(b, key);
795 fh.len = n;
796 remain -= n;
797 fh.fin = fin ? remain == 0 : false;
798 impl.wr_cont = ! fh.fin;
799 detail::fh_buffer fh_buf;
800 detail::write<
801 flat_static_buffer_base>(fh_buf, fh);
802 net::write(impl.stream(),
803 buffers_cat(fh_buf.data(), b), ec);
804 bytes_transferred += n;
805 if(impl.check_stop_now(ec))
806 return bytes_transferred;
807 if(remain == 0)
808 break;
809 fh.op = detail::opcode::cont;
810 cb.consume(n);
811 }
812 }
813 return bytes_transferred;
814}
815
816template<class NextLayer, bool deflateSupported>
20effc67 817template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
92f5a8d4
TL
818BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
819stream<NextLayer, deflateSupported>::
820async_write_some(bool fin,
821 ConstBufferSequence const& bs, WriteHandler&& handler)
822{
823 static_assert(is_async_stream<next_layer_type>::value,
824 "AsyncStream type requirements not met");
825 static_assert(net::is_const_buffer_sequence<
826 ConstBufferSequence>::value,
827 "ConstBufferSequence type requirements not met");
828 return net::async_initiate<
829 WriteHandler,
830 void(error_code, std::size_t)>(
831 run_write_some_op{},
832 handler,
833 impl_,
834 fin,
835 bs);
836}
837
838//------------------------------------------------------------------------------
839
840template<class NextLayer, bool deflateSupported>
841template<class ConstBufferSequence>
842std::size_t
843stream<NextLayer, deflateSupported>::
844write(ConstBufferSequence const& buffers)
845{
846 static_assert(is_sync_stream<next_layer_type>::value,
847 "SyncStream type requirements not met");
848 static_assert(net::is_const_buffer_sequence<
849 ConstBufferSequence>::value,
850 "ConstBufferSequence type requirements not met");
851 error_code ec;
852 auto const bytes_transferred = write(buffers, ec);
853 if(ec)
854 BOOST_THROW_EXCEPTION(system_error{ec});
855 return bytes_transferred;
856}
857
858template<class NextLayer, bool deflateSupported>
859template<class ConstBufferSequence>
860std::size_t
861stream<NextLayer, deflateSupported>::
862write(ConstBufferSequence const& buffers, error_code& ec)
863{
864 static_assert(is_sync_stream<next_layer_type>::value,
865 "SyncStream type requirements not met");
866 static_assert(net::is_const_buffer_sequence<
867 ConstBufferSequence>::value,
868 "ConstBufferSequence type requirements not met");
869 return write_some(true, buffers, ec);
870}
871
872template<class NextLayer, bool deflateSupported>
20effc67 873template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler>
92f5a8d4
TL
874BOOST_BEAST_ASYNC_RESULT2(WriteHandler)
875stream<NextLayer, deflateSupported>::
876async_write(
877 ConstBufferSequence const& bs, WriteHandler&& handler)
878{
879 static_assert(is_async_stream<next_layer_type>::value,
880 "AsyncStream type requirements not met");
881 static_assert(net::is_const_buffer_sequence<
882 ConstBufferSequence>::value,
883 "ConstBufferSequence type requirements not met");
884 return net::async_initiate<
885 WriteHandler,
886 void(error_code, std::size_t)>(
887 run_write_some_op{},
888 handler,
889 impl_,
890 true,
891 bs);
892}
893
894} // websocket
895} // beast
896} // boost
897
898#endif