RESTinio

ws_connection.hpp
Go to the documentation of this file.
1/*
2 restinio
3*/
4
9#pragma once
10
11#include <queue>
12
13#include <restinio/asio_include.hpp>
14
15#include <http_parser.h>
16
17#include <restinio/impl/include_fmtlib.hpp>
18
19#include <restinio/all.hpp>
20#include <restinio/impl/executor_wrapper.hpp>
21#include <restinio/impl/write_group_output_ctx.hpp>
22#include <restinio/websocket/message.hpp>
23#include <restinio/websocket/impl/ws_parser.hpp>
24#include <restinio/websocket/impl/ws_protocol_validator.hpp>
25
26#include <restinio/utils/impl/safe_uint_truncate.hpp>
27
28#include <restinio/compiler_features.hpp>
29
30 namespace restinio
31{
32
33 namespace websocket
34{
35
36 namespace basic
37{
38
39 namespace impl
40{
41
42 using write_groups_queue_t = std::queue< write_group_t >;
43
45 constexpr size_t
46 websocket_header_max_size()
47{
48 return 14;
49}
50
51//
52// ws_outgoing_data_t
53//
54
56 class ws_outgoing_data_t
57{
58 public:
60 void
61 append( write_group_t wg )
62 {
63 m_awaiting_write_groups.emplace( std::move( wg ) );
64 }
65
66 optional_t< write_group_t >
67 pop_ready_buffers()
68 {
69 optional_t< write_group_t > result;
70
71 if( !m_awaiting_write_groups.empty() )
72 {
73 result = std::move( m_awaiting_write_groups.front() );
74 m_awaiting_write_groups.pop();
75 }
76
77 return result;
78 }
79
80 private:
82 write_groups_queue_t m_awaiting_write_groups;
83};
84
85//
86// connection_input_t
87//
88
90 struct connection_input_t
91{
92 connection_input_t( std::size_t buffer_size )
93 : m_buf{ buffer_size }
94 {}
95
97 ws_parser_t m_parser;
98
100 restinio::impl::fixed_buffer_t m_buf;
101
103 std::string m_payload;
104
106 void
107 reset_parser_and_payload()
108 {
109 m_parser.reset();
110 m_payload.clear();
111 }
112};
113
114//
115// ws_connection_t
116//
117
119 template <
120 typename Traits,
121 typename WS_Message_Handler >
122 class ws_connection_t final
123 : public ws_connection_base_t
124 , public restinio::impl::executor_wrapper_t< typename Traits::strand_t >
125{
126 using executor_wrapper_base_t = restinio::impl::executor_wrapper_t< typename Traits::strand_t >;
127
128 public:
129 using message_handler_t = WS_Message_Handler;
130
131 using timer_manager_t = typename Traits::timer_manager_t;
132 using timer_manager_handle_t = std::shared_ptr< timer_manager_t >;
133 using timer_guard_t = typename timer_manager_t::timer_guard_t;
134 using logger_t = typename Traits::logger_t;
135 using strand_t = typename Traits::strand_t;
136 using stream_socket_t = typename Traits::stream_socket_t;
137 using lifetime_monitor_t =
138 typename connection_count_limit_types<Traits>::lifetime_monitor_t;
139
140 using ws_weak_handle_t = std::weak_ptr< ws_t >;
141
142 ws_connection_t(
144 connection_id_t conn_id,
147 restinio::impl::connection_settings_handle_t< Traits > settings,
148 stream_socket_t socket,
149 lifetime_monitor_t lifetime_monitor,
151 message_handler_t msg_handler )
152 : ws_connection_base_t{ conn_id }
153 , executor_wrapper_base_t{ socket.get_executor() }
154 , m_settings{ std::move( settings ) }
155 , m_socket{ std::move( socket ) }
156 , m_lifetime_monitor{ std::move( lifetime_monitor ) }
157 , m_timer_guard{ m_settings->create_timer_guard() }
158 , m_input{ websocket_header_max_size() }
159 , m_msg_handler{ std::move( msg_handler ) }
160 , m_logger{ *( m_settings->m_logger ) }
161 {
162 // Notify of a new connection instance.
163 m_logger.trace( [&]{
164 return fmt::format(
165 "[connection:{}] move socket to [ws_connection:{}]",
166 connection_id(),
167 connection_id() );
168 } );
169
170 m_logger.trace( [&]{
171 return fmt::format(
172 "[ws_connection:{}] start connection with {}",
173 connection_id(),
174 m_socket.remote_endpoint() );
175 } );
176
177 // Inform state listener if it used.
178 m_settings->call_state_listener( [this]() noexcept {
179 return connection_state::notice_t {
180 connection_id(),
181 m_socket.remote_endpoint(),
182 connection_state::upgraded_to_websocket_t{}
183 };
184 } );
185 }
186
187 ws_connection_t( const ws_connection_t & ) = delete;
188 ws_connection_t( ws_connection_t && ) = delete;
189 ws_connection_t & operator = ( const ws_connection_t & ) = delete;
190 ws_connection_t & operator = ( ws_connection_t && ) = delete;
191
192 ~ws_connection_t() override
193 {
194 try
195 {
196 // Notify of a new connection instance.
197 m_logger.trace( [&]{
198 return fmt::format(
199 "[ws_connection:{}] destructor called",
200 connection_id() );
201 } );
202 }
203 catch( ... )
204 {}
205 }
206
208 virtual void
209 shutdown() override
210 {
211 asio_ns::dispatch(
212 this->get_executor(),
213 [ this, ctx = shared_from_this() ]
214 // NOTE: this lambda is noexcept since v.0.6.0.
215 () noexcept {
216 try
217 {
218 // An exception from logger shouldn't prevent
219 // main shutdown actions.
220 restinio::utils::log_trace_noexcept( m_logger,
221 [&]{
222 return fmt::format(
223 "[ws_connection:{}] shutdown",
224 connection_id() );
225 } );
226
227 m_close_frame_to_user.disable();
228 graceful_close();
229 }
230 catch( const std::exception & ex )
231 {
232 restinio::utils::log_error_noexcept( m_logger,
233 [&]{
234 return fmt::format(
235 "[ws_connection:{}] shutdown operation error: {}",
236 connection_id(),
237 ex.what() );
238 } );
239 }
240 } );
241 }
242
244 virtual void
245 kill() override
246 {
247 asio_ns::dispatch(
248 this->get_executor(),
249 [ this, ctx = shared_from_this() ]
250 // NOTE: this lambda is noexcept since v.0.6.0.
251 () noexcept
252 {
253 try
254 {
255 // An exception from logger shouldn't prevent
256 // main kill actions.
257 restinio::utils::log_trace_noexcept( m_logger,
258 [&]{
259 return fmt::format(
260 "[ws_connection:{}] kill",
261 connection_id() );
262 } );
263
264 m_close_frame_to_user.disable();
265 m_close_frame_to_peer.disable();
266
267 close_impl();
268 }
269 catch( const std::exception & ex )
270 {
271 restinio::utils::log_error_noexcept( m_logger,
272 [&]{
273 return fmt::format(
274 "[ws_connection:{}] kill operation error: {}",
275 connection_id(),
276 ex.what() );
277 } );
278 }
279 } );
280 }
281
283 void
284 init_read( ws_handle_t wsh ) override
285 {
286 ws_weak_handle_t wswh{ wsh };
287
288 // Run write message on io_context loop (direct invocation if possible).
289 asio_ns::dispatch(
290 this->get_executor(),
291 [ this, ctx = shared_from_this(), wswh = std::move( wswh ) ]
292 // NOTE: this lambda is noexcept since v.0.6.0.
293 () noexcept
294 {
295 try
296 {
297 // Start timeout checking.
298 m_prepared_weak_ctx = shared_from_this();
299 init_next_timeout_checking();
300
301 m_websocket_weak_handle = std::move( wswh );
302 m_read_state = read_state_t::read_any_frame;
303 start_read_header();
304 }
305 catch( const std::exception & ex )
306 {
307 trigger_error_and_close(
308 status_code_t::unexpected_condition,
309 [&]{
310 return fmt::format(
311 "[ws_connection:{}] unable to init read: {}",
312 connection_id(),
313 ex.what() );
314 } );
315 }
316 } );
317 }
318
320 virtual void
321 write_data(
322 write_group_t wg,
323 bool is_close_frame ) override
324 {
326 asio_ns::dispatch(
327 this->get_executor(),
328 [ this,
329 actual_wg = std::move( wg ),
330 ctx = shared_from_this(),
331 is_close_frame ]
332 // NOTE: this lambda is noexcept since v.0.6.0.
333 () mutable noexcept
334 {
335 try
336 {
337 if( write_state_t::write_enabled == m_write_state )
338 write_data_impl(
339 std::move( actual_wg ),
340 is_close_frame );
341 else
342 {
343 m_logger.warn( [&]{
344 return fmt::format(
345 "[ws_connection:{}] cannot write to websocket: "
346 "write operations disabled",
347 connection_id() );
348 } );
349 }
350 }
351 catch( const std::exception & ex )
352 {
353 trigger_error_and_close(
354 status_code_t::unexpected_condition,
355 [&]{
356 return fmt::format(
357 "[ws_connection:{}] unable to write data: {}",
358 connection_id(),
359 ex.what() );
360 } );
361 }
362 } );
363 }
364 private:
366
370 void
371 close_impl() noexcept
372 {
373 m_close_impl.run_if_first(
374 [&]() noexcept {
375 restinio::utils::log_trace_noexcept( m_logger,
376 [&]{
377 return fmt::format(
378 "[ws_connection:{}] close socket",
379 connection_id() );
380 } );
381
382 // This actions can throw and because of that we have
383 // to wrap them...
384 restinio::utils::suppress_exceptions(
385 m_logger,
386 "ws_connection.close_impl.socket.shutdown",
387 [&] {
388 asio_ns::error_code ignored_ec;
389 m_socket.shutdown(
390 asio_ns::ip::tcp::socket::shutdown_both,
391 ignored_ec );
392 } );
393
394 restinio::utils::suppress_exceptions(
395 m_logger,
396 "ws_connection.close_impl.socket.close",
397 [&] {
398 m_socket.close();
399 } );
400 } );
401 }
402
404 void
405 start_waiting_close_frame_only()
406 {
407 m_read_state = read_state_t::read_only_close_frame;
408 guard_close_frame_from_peer_operation();
409 }
410
412 void
413 graceful_close()
414 {
415 m_close_frame_to_peer.run_if_first(
416 [&]{
417 send_close_frame_to_peer( status_code_t::normal_closure );
418 start_waiting_close_frame_only();
419 } );
420 }
421
423 void
424 send_close_frame_to_peer( std::string payload )
425 {
426 writable_items_container_t bufs;
427 bufs.reserve( 2 );
428
429 bufs.emplace_back(
430 impl::write_message_details(
431 final_frame,
432 opcode_t::connection_close_frame,
433 payload.size() ) );
434
435 bufs.emplace_back( std::move( payload ) );
436 m_outgoing_data.append( write_group_t{ std::move( bufs ) } );
437
438 init_write_if_necessary();
439
440 // No more data must be written.
441 m_write_state = write_state_t::write_disabled;
442 }
443
445 void
446 send_close_frame_to_peer(
447 status_code_t code,
448 std::string desc = std::string{} )
449 {
450 send_close_frame_to_peer( std::string{ status_code_to_bin( code ) + desc } );
451 }
452
454
462 template< typename MSG_BUILDER >
463 void
464 trigger_error_and_close(
465 status_code_t status,
466 MSG_BUILDER msg_builder ) noexcept
467 {
468 // An exception in logger shouldn't prevent the main actions.
469 restinio::utils::log_error_noexcept(
470 m_logger, std::move( msg_builder ) );
471
472 // This can throw but we have to suppress any exceptions.
473 restinio::utils::suppress_exceptions(
474 m_logger, "ws_connection.call_close_handler_if_necessary",
475 [this, status] {
476 call_close_handler_if_necessary( status );
477 } );
478
479 RESTINIO_ENSURE_NOEXCEPT_CALL( close_impl() );
480 }
481
482
484 void
485 start_read_header()
486 {
487 m_logger.trace( [&]{
488 return fmt::format(
489 "[ws_connection:{}] start reading header",
490 connection_id() );
491 } );
492
493 // Prepare parser for consuming new message.
494 m_input.reset_parser_and_payload();
495
496 if( 0 == m_input.m_buf.length() )
497 {
498 consume_header_from_socket();
499 }
500 else
501 {
502 // Has something to read from m_input.m_buf.
503 consume_header_from_buffer(
504 m_input.m_buf.bytes(), m_input.m_buf.length() );
505 }
506 }
507
509 void
510 consume_header_from_socket()
511 {
512 m_logger.trace( [&]{
513 return fmt::format(
514 "[ws_connection:{}] continue reading message",
515 connection_id() );
516 } );
517
518 m_socket.async_read_some(
519 m_input.m_buf.make_asio_buffer(),
520 asio_ns::bind_executor(
521 this->get_executor(),
522 [ this, ctx = shared_from_this() ]
523 // NOTE: this lambda is noexcept since v.0.6.0.
524 ( const asio_ns::error_code & ec, std::size_t length ) noexcept
525 {
526 try
527 {
528 after_read_header( ec, length );
529 }
530 catch( const std::exception & ex )
531 {
532 trigger_error_and_close(
533 status_code_t::unexpected_condition,
534 [&]{
535 return fmt::format(
536 "[ws_connection:{}] after read header callback error: {}",
537 connection_id(),
538 ex.what() );
539 } );
540 }
541 } ) );
542 }
543
545 void
546 handle_read_error( const char * desc, const asio_ns::error_code & ec )
547 {
548 // Assume that connection is lost.
549 trigger_error_and_close(
550 status_code_t::connection_lost,
551 [&]{
552 return fmt::format(
553 "[ws_connection:{}] {}: {}",
554 connection_id(),
555 desc,
556 ec.message() );
557 } );
558 }
559
561 void
562 after_read_header(
563 const asio_ns::error_code & ec,
564 std::size_t length )
565 {
566 if( !ec )
567 {
568 m_logger.trace( [&]{
569 return fmt::format(
570 "[ws_connection:{}] received {} bytes",
571 this->connection_id(),
572 length );
573 } );
574
575 m_input.m_buf.obtained_bytes( length );
576 consume_header_from_buffer( m_input.m_buf.bytes(), length );
577 }
578 else
579 {
580 handle_read_error( "reading message header error", ec );
581 }
582 }
583
585 void
586 consume_header_from_buffer( const char * data, std::size_t length )
587 {
588 const auto nparsed = m_input.m_parser.parser_execute( data, length );
589
590 m_input.m_buf.consumed_bytes( nparsed );
591
592 if( m_input.m_parser.header_parsed() )
593 {
594 handle_parsed_header( m_input.m_parser.current_message() );
595 }
596 else
597 {
598 assert( nparsed == length );
599 consume_header_from_socket();
600 }
601 }
602
604 void
605 handle_parsed_header( const message_details_t & md )
606 {
607 m_logger.trace( [&]{
608 return fmt::format(
609 "[ws_connection:{}] start handling {} ({:#x})",
610 connection_id(),
611 opcode_to_string( md.m_opcode ),
612 static_cast<std::uint16_t>(md.m_opcode) );
613 } );
614
615 const auto validation_result =
616 m_protocol_validator.process_new_frame( md );
617
618 if( validation_state_t::frame_header_is_valid != validation_result )
619 {
620 m_logger.error( [&]{
621 return fmt::format(
622 "[ws_connection:{}] invalid header",
623 connection_id() );
624 } );
625
626 if( read_state_t::read_any_frame == m_read_state )
627 {
628 m_close_frame_to_peer.run_if_first(
629 [&]{
630 send_close_frame_to_peer( status_code_t::protocol_error );
631 // Do not wait anything in return, because
632 // protocol is violated.
633 } );
634
635 call_close_handler_if_necessary( status_code_t::protocol_error );
636 }
637 else if( read_state_t::read_only_close_frame == m_read_state )
638 {
639 // Wait for close frame cannot be done.
640 close_impl();
641 }
642
643 return;
644 }
645
646 handle_parsed_and_valid_header( md );
647 }
648
650 void
651 handle_parsed_and_valid_header( const message_details_t & md )
652 {
653 const auto payload_length =
654 restinio::utils::impl::uint64_to_size_t(md.payload_len());
655
656 m_input.m_payload.resize( payload_length );
657
658 if( payload_length == 0 )
659 {
660 // Callback for message with 0-size payload.
661 call_handler_on_current_message();
662 }
663 else
664 {
665 const auto payload_part_size =
666 std::min( m_input.m_buf.length(), payload_length );
667
668 std::memcpy(
669 &m_input.m_payload.front(),
670 m_input.m_buf.bytes(),
671 payload_part_size );
672
673 m_input.m_buf.consumed_bytes( payload_part_size );
674
675 const std::size_t length_remaining =
676 payload_length - payload_part_size;
677
678 if( validate_payload_part(
679 &m_input.m_payload.front(),
680 payload_part_size,
681 length_remaining ) )
682 {
683 if( 0 == length_remaining )
684 {
685 // All message is obtained.
686 call_handler_on_current_message();
687 }
688 else
689 {
690 // Read the rest of payload:
691 start_read_payload(
692 &m_input.m_payload.front() + payload_part_size,
693 length_remaining );
694 }
695 }
696 // Else payload is invalid and validate_payload_part()
697 // has handled the case so do nothing.
698 }
699 }
700
702 void
703 start_read_payload(
705 char * payload_data,
707 std::size_t length_remaining,
709 bool do_validate_payload_and_call_msg_handler = true )
710 {
711 m_socket.async_read_some(
712 asio_ns::buffer( payload_data, length_remaining ),
713 asio_ns::bind_executor(
714 this->get_executor(),
715 [ this,
716 ctx = shared_from_this(),
717 payload_data,
718 length_remaining,
719 do_validate_payload_and_call_msg_handler ]
720 // NOTE: this lambda is noexcept since v.0.6.0.
721 ( const asio_ns::error_code & ec, std::size_t length ) noexcept
722 {
723 try
724 {
725 after_read_payload(
726 payload_data,
727 length_remaining,
728 ec,
729 length,
730 do_validate_payload_and_call_msg_handler );
731 }
732 catch( const std::exception & ex )
733 {
734 trigger_error_and_close(
735 status_code_t::unexpected_condition,
736 [&]{
737 return fmt::format(
738 "[ws_connection:{}] after read payload callback error: {}",
739 connection_id(),
740 ex.what() );
741 } );
742 }
743 } ) );
744 }
745
747 void
748 after_read_payload(
749 char * payload_data,
750 std::size_t length_remaining,
751 const asio_ns::error_code & ec,
752 std::size_t length,
753 bool do_validate_payload_and_call_msg_handler = true )
754 {
755 if( !ec )
756 {
757 m_logger.trace( [&]{
758 return fmt::format(
759 "[ws_connection:{}] received {} bytes",
760 this->connection_id(),
761 length );
762 } );
763
764 assert( length <= length_remaining );
765
766 const std::size_t next_length_remaining =
767 length_remaining - length;
768
769 if( do_validate_payload_and_call_msg_handler )
770 {
771 if( validate_payload_part( payload_data, length, next_length_remaining ) )
772 {
773 if( 0 == next_length_remaining )
774 {
775 // Here: all the payload is ready.
776
777 // All message is obtained.
778 call_handler_on_current_message();
779 }
780 else
781 {
782 //Here: not all payload is obtained,
783 // so inintiate read once again:
784 start_read_payload(
785 payload_data + length,
786 next_length_remaining,
787 do_validate_payload_and_call_msg_handler );
788 }
789 }
790 // Else payload is invalid and validate_payload_part()
791 // has handled the case so do nothing.
792 }
793 else
794 {
795 if( 0 == next_length_remaining )
796 {
797 start_read_header();
798 }
799 else
800 {
801 start_read_payload(
802 payload_data + length,
803 length_remaining - length,
804 do_validate_payload_and_call_msg_handler );
805 }
806 }
807 }
808 else
809 {
810 handle_read_error( "reading message payload error", ec );
811 }
812 }
813
815 void
816 call_message_handler( message_handle_t close_frame )
817 {
818 if( auto wsh = m_websocket_weak_handle.lock() )
819 {
820 try
821 {
822 m_msg_handler(
823 std::move( wsh ),
824 std::move( close_frame ) );
825 }
826 catch( const std::exception & ex )
827 {
828 m_logger.error( [&]{
829 return fmt::format(
830 "[ws_connection:{}] execute handler error: {}",
831 connection_id(),
832 ex.what() );
833 } );
834 }
835 }
836 }
837
839 bool
840 validate_payload_part(
841 char * payload_data,
842 std::size_t length,
843 std::size_t next_length_remaining )
844 {
845 const auto validation_result =
846 m_protocol_validator.process_and_unmask_next_payload_part( payload_data, length );
847
848 if( validation_state_t::payload_part_is_valid != validation_result )
849 {
850 handle_invalid_payload( validation_result );
851
852 if( validation_state_t::incorrect_utf8_data == validation_result )
853 {
854 // Can skip this payload because it was not a bad close frame.
855
856 // It is the case we are expecting close frame
857 // so validator must be ready to receive more headers
858 // and payloads after this frame.
859 m_protocol_validator.reset();
860
861 if( 0 == next_length_remaining )
862 {
863 start_read_header();
864 }
865 else
866 {
867 // Skip checking payload for this frame:
868 const bool do_validate_payload_and_call_msg_handler = false;
869 start_read_payload(
870 payload_data + length,
871 next_length_remaining,
872 do_validate_payload_and_call_msg_handler );
873 }
874 }
875 return false;
876 }
877
878 return true;
879 }
880
882 void
883 handle_invalid_payload( validation_state_t validation_result )
884 {
885 m_logger.error( [&]{
886 return fmt::format(
887 "[ws_connection:{}] invalid paload",
888 connection_id() );
889 } );
890
891 if( validation_state_t::invalid_close_code == validation_result )
892 {
893 // A corner case: invalid payload in close frame.
894
895 if( read_state_t::read_any_frame == m_read_state )
896 {
897 // Case: close frame was not expected.
898
899 // This actually must be executed:
900 m_close_frame_to_peer.run_if_first(
901 [&]{
902 send_close_frame_to_peer( status_code_t::protocol_error );
903 // Do not wait anything in return, because
904 // protocol is violated.
905 } );
906
907 // Notify user of a close but use a correct close code.
908 call_close_handler_if_necessary( status_code_t::protocol_error );
909 }
910 else if( read_state_t::read_only_close_frame == m_read_state )
911 {
912 // Case: close frame was expected.
913
914 // We got a close frame but it is incorrect,
915 // so just close (there is not too much we can do).
916 close_impl();
917 }
918 }
919 else
920 {
921 if( read_state_t::read_any_frame == m_read_state )
922 {
923 m_close_frame_to_peer.run_if_first(
924 [&]{
925 send_close_frame_to_peer( status_code_t::invalid_message_data );
926 start_waiting_close_frame_only();
927 } );
928
929 call_close_handler_if_necessary( status_code_t::invalid_message_data );
930 }
931 }
932 }
933
934 void
935 call_handler_on_current_message()
936 {
937 auto & md = m_input.m_parser.current_message();
938
939 const auto validation_result = m_protocol_validator.finish_frame();
940 if( validation_state_t::frame_is_valid == validation_result )
941 {
942 if( read_state_t::read_any_frame == m_read_state )
943 {
944 if( opcode_t::connection_close_frame == md.m_opcode )
945 {
946 m_logger.trace( [&]{
947 return fmt::format(
948 "[ws_connection:{}] got close frame from peer, status: {}",
949 connection_id(),
950 static_cast<std::uint16_t>(
951 status_code_from_bin( m_input.m_payload )) );
952 } );
953
954 m_close_frame_to_user.disable();
955 m_close_frame_to_peer.run_if_first(
956 [&]{
957 send_close_frame_to_peer( m_input.m_payload );
958 } );
959
960 m_read_state = read_state_t::read_nothing;
961 }
962
963 call_message_handler(
964 std::make_shared< message_t >(
965 md.m_final_flag ? final_frame : not_final_frame,
966 md.m_opcode,
967 std::move( m_input.m_payload ) ) );
968
969 if( read_state_t::read_nothing != m_read_state )
970 start_read_header();
971 }
972 else
973 {
974 assert( read_state_t::read_only_close_frame == m_read_state );
975
976 if( opcode_t::connection_close_frame == md.m_opcode )
977 {
978 // Got it!
979 m_timer_guard.cancel();
980
981 close_impl();
982
983 m_logger.trace( [&]{
984 return fmt::format(
985 "[ws_connection:{}] expected close frame came",
986 connection_id() );
987 } );
988 }
989 else
990 {
991 // Wait for next frame.
992 start_read_header();
993 }
994 }
995 }
996 else
997 {
998 handle_invalid_payload( validation_result );
999 }
1000 }
1001
1002 void
1003 call_close_handler_if_necessary( status_code_t status )
1004 {
1005 m_close_frame_to_user.run_if_first(
1006 [&]{
1007 call_message_handler(
1008 std::make_shared< message_t >(
1009 final_frame,
1010 opcode_t::connection_close_frame,
1011 status_code_to_bin( status ) ) );
1012 } );
1013 }
1014
1016 void
1017 write_data_impl( write_group_t wg, bool is_close_frame )
1018 {
1019 if( m_socket.is_open() )
1020 {
1021 if( is_close_frame )
1022 {
1023 m_logger.trace( [&]{
1024 return fmt::format(
1025 "[ws_connection:{}] user sends close frame",
1026 connection_id() );
1027 } );
1028
1029 m_close_frame_to_peer.disable(); // It is formed and sent by user
1030 m_close_frame_to_user.disable(); // And user knows that websocket is closed.
1031 // No more writes.
1032 m_write_state = write_state_t::write_disabled;
1033
1034 // Start waiting only close-frame.
1035 start_waiting_close_frame_only();
1036 }
1037
1038 // Push write_group to queue.
1039 m_outgoing_data.append( std::move( wg ) );
1040
1041 init_write_if_necessary();
1042 }
1043 else
1044 {
1045 m_logger.warn( [&]{
1046 return fmt::format(
1047 "[ws_connection:{}] try to write while socket is closed",
1048 connection_id() );
1049 } );
1050
1051 try
1052 {
1053 wg.invoke_after_write_notificator_if_exists(
1054 make_asio_compaible_error(
1055 asio_convertible_error_t::write_was_not_executed ) );
1056 }
1057 catch( ... )
1058 {}
1059 }
1060 }
1061
1064 void
1065 init_write_if_necessary()
1066 {
1067 if( !m_write_output_ctx.transmitting() )
1068 {
1069 init_write();
1070 }
1071 }
1072
1074 void
1075 init_write()
1076 {
1077 // Here: not writing anything to socket, so
1078 // write operation can be initiated.
1079 auto next_write_group = m_outgoing_data.pop_ready_buffers();
1080
1081 if( next_write_group )
1082 {
1083 m_logger.trace( [&]{
1084 return fmt::format(
1085 "[ws_connection:{}] start next write group, "
1086 "size: {}",
1087 this->connection_id(),
1088 next_write_group->items_count() );
1089 } );
1090
1091 // Initialize write context with a new write group.
1092 m_write_output_ctx.start_next_write_group(
1093 std::move( next_write_group ) );
1094
1095 // Start the loop of sending data from current write group.
1096 handle_current_write_ctx();
1097 }
1098 }
1099
1100 // Use aliases for shorter names.
1101 using none_write_operation_t = ::restinio::impl::write_group_output_ctx_t::none_write_operation_t;
1102 using trivial_write_operation_t = ::restinio::impl::write_group_output_ctx_t::trivial_write_operation_t;
1103 using file_write_operation_t = ::restinio::impl::write_group_output_ctx_t::file_write_operation_t;
1104
1105 void
1106 handle_current_write_ctx()
1107 {
1108 try
1109 {
1110 auto wo = m_write_output_ctx.extract_next_write_operation();
1111
1112 if( holds_alternative< trivial_write_operation_t >( wo ) )
1113 {
1114 handle_trivial_write_operation( get< trivial_write_operation_t >( wo ) );
1115 }
1116 else if( holds_alternative< none_write_operation_t >( wo ) )
1117 {
1118 finish_handling_current_write_ctx();
1119 }
1120 else
1121 {
1122 assert( holds_alternative< file_write_operation_t >( wo ) );
1123 throw exception_t{ "sendfile write operation not implemented" };
1124 }
1125 }
1126 catch( const std::exception & ex )
1127 {
1128 trigger_error_and_close(
1129 status_code_t::unexpected_condition,
1130 [&]{
1131 return fmt::format(
1132 "[ws_connection:{}] handle_current_write_ctx failed: {}",
1133 connection_id(),
1134 ex.what() );
1135 } );
1136 }
1137 }
1138
1139 void
1140 handle_trivial_write_operation( const trivial_write_operation_t & op )
1141 {
1142 // Asio buffers (param for async write):
1143 auto & bufs = op.get_trivial_bufs();
1144
1145 m_logger.trace( [&]{
1146 return fmt::format(
1147 "[ws_connection:{}] sending data with "
1148 "buf count: {}, "
1149 "total size: {}",
1150 connection_id(),
1151 bufs.size(),
1152 op.size() ); } );
1153
1154 guard_write_operation();
1155
1156 // There is somethig to write.
1157 asio_ns::async_write(
1158 m_socket,
1159 bufs,
1160 asio_ns::bind_executor(
1161 this->get_executor(),
1162 [ this,
1163 ctx = shared_from_this() ]
1164 // NOTE: this lambda is noexcept since v.0.6.0.
1165 ( const asio_ns::error_code & ec, std::size_t written ) noexcept
1166 {
1167 try
1168 {
1169 if( !ec )
1170 {
1171 m_logger.trace( [&]{
1172 return fmt::format(
1173 "[ws_connection:{}] outgoing data was sent: {} bytes",
1174 connection_id(),
1175 written );
1176 } );
1177 }
1178
1179 after_write( ec );
1180 }
1181 catch( const std::exception & ex )
1182 {
1183 trigger_error_and_close(
1184 status_code_t::unexpected_condition,
1185 [&]{
1186 return fmt::format(
1187 "[ws_connection:{}] after write callback error: {}",
1188 connection_id(),
1189 ex.what() );
1190 } );
1191 }
1192 } ) );
1193 }
1194
1196 void
1197 finish_handling_current_write_ctx()
1198 {
1199 // Finishing writing this group.
1200 m_logger.trace( [&]{
1201 return fmt::format(
1202 "[ws_connection:{}] finishing current write group",
1203 this->connection_id() );
1204 } );
1205
1206 // Group notificators are called from here (if exist):
1207 m_write_output_ctx.finish_write_group();
1208
1209 // Start another write opertion
1210 // if there is something to send.
1211 init_write_if_necessary();
1212 }
1213
1215 void
1216 after_write( const asio_ns::error_code & ec )
1217 {
1218 if( !ec )
1219 {
1220 handle_current_write_ctx();
1221 }
1222 else
1223 {
1224 trigger_error_and_close(
1225 status_code_t::connection_lost,
1226 [&]{
1227 return fmt::format(
1228 "[ws_connection:{}] unable to write: {}",
1229 connection_id(),
1230 ec.message() );
1231 } );
1232
1233 try
1234 {
1235 m_write_output_ctx.fail_write_group( ec );
1236 }
1237 catch( const std::exception & ex )
1238 {
1239 m_logger.error( [&]{
1240 return fmt::format(
1241 "[ws_connection:{}] notificator error: {}",
1242 connection_id(),
1243 ex.what() );
1244 } );
1245 }
1246 }
1247 }
1248
1250 restinio::impl::connection_settings_handle_t< Traits > m_settings;
1251
1253 stream_socket_t m_socket;
1254
1260 lifetime_monitor_t m_lifetime_monitor;
1261
1264 static ws_connection_t &
1265 cast_to_self( tcp_connection_ctx_base_t & base )
1266 {
1267 return static_cast< ws_connection_t & >( base );
1268 }
1269
1270 virtual void
1271 check_timeout( tcp_connection_ctx_handle_t & self ) override
1272 {
1273 asio_ns::dispatch(
1274 this->get_executor(),
1275 [ ctx = std::move( self ) ]
1276 // NOTE: this lambda is noexcept since v.0.6.0.
1277 () noexcept
1278 {
1279 auto & conn_object = cast_to_self( *ctx );
1280 // If an exception will be thrown we can only
1281 // close the connection.
1282 try
1283 {
1284 conn_object.check_timeout_impl();
1285 }
1286 catch( const std::exception & x )
1287 {
1288 conn_object.trigger_error_and_close(
1289 status_code_t::unexpected_condition,
1290 [&] {
1291 return fmt::format( "[connection: {}] unexpected "
1292 "error during timeout handling: {}",
1293 conn_object.connection_id(),
1294 x.what() );
1295 } );
1296 }
1297 } );
1298 }
1299
1300 std::chrono::steady_clock::time_point m_write_operation_timeout_after;
1301 std::chrono::steady_clock::time_point m_close_frame_from_peer_timeout_after =
1302 std::chrono::steady_clock::time_point::max();
1303 tcp_connection_ctx_weak_handle_t m_prepared_weak_ctx;
1304 timer_guard_t m_timer_guard;
1305
1306 void
1307 check_timeout_impl()
1308 {
1309 const auto now = std::chrono::steady_clock::now();
1310 if( m_write_output_ctx.transmitting() && now > m_write_operation_timeout_after )
1311 {
1312 m_logger.trace( [&]{
1313 return fmt::format(
1314 "[wd_connection:{}] write operation timed out",
1315 connection_id() );
1316 } );
1317 m_close_frame_to_peer.disable();
1318 call_close_handler_if_necessary( status_code_t::unexpected_condition );
1319 close_impl();
1320 }
1321 else if( now > m_close_frame_from_peer_timeout_after )
1322 {
1323 m_logger.trace( [&]{
1324 return fmt::format(
1325 "[wd_connection:{}] waiting for close-frame from peer timed out",
1326 connection_id() );
1327 } );
1328 close_impl();
1329 }
1330 else
1331 {
1332 init_next_timeout_checking();
1333 }
1334 }
1335
1337 void
1338 init_next_timeout_checking()
1339 {
1340 m_timer_guard.schedule( m_prepared_weak_ctx );
1341 }
1342
1344 void
1345 guard_write_operation()
1346 {
1347 m_write_operation_timeout_after =
1348 std::chrono::steady_clock::now() + m_settings->m_write_http_response_timelimit;
1349 }
1350
1351 void
1352 guard_close_frame_from_peer_operation()
1353 {
1354 m_close_frame_from_peer_timeout_after =
1355 std::chrono::steady_clock::now() + m_settings->m_read_next_http_message_timelimit;
1356 }
1358
1360 connection_input_t m_input;
1361
1363 ws_protocol_validator_t m_protocol_validator{ true };
1364
1366 message_handler_t m_msg_handler;
1367
1369 logger_t & m_logger;
1370
1372 restinio::impl::write_group_output_ctx_t m_write_output_ctx;
1373
1375 ws_outgoing_data_t m_outgoing_data;
1376
1378 ws_weak_handle_t m_websocket_weak_handle;
1379
1381 enum class write_state_t
1382 {
1384 write_enabled,
1386 write_disabled
1387 };
1388
1390 write_state_t m_write_state = write_state_t::write_enabled;
1391
1393 enum class read_state_t
1394 {
1396 read_any_frame,
1398 read_only_close_frame,
1400 read_nothing
1401 };
1402
1404 read_state_t m_read_state = read_state_t::read_nothing;
1405
1408 class one_shot_action_t
1409 {
1410 public:
1411 template < typename Action >
1412 void
1413 run_if_first( Action && action ) noexcept(noexcept(action()))
1414 {
1415 if( m_not_executed_yet )
1416 {
1417 m_not_executed_yet = false;
1418 action();
1419 }
1420 }
1421
1423 void
1424 disable()
1425 {
1426 m_not_executed_yet = false;
1427 }
1428
1429 private:
1430 bool m_not_executed_yet{ true };
1431 };
1432
1433 one_shot_action_t m_close_frame_to_user;
1434 one_shot_action_t m_close_frame_to_peer;
1435 one_shot_action_t m_close_impl;
1436};
1437
1438} /* namespace impl */
1439
1440} /* namespace basic */
1441
1442} /* namespace websocket */
1443
1444} /* namespace restinio */
all.hpp
asio_include.hpp
nonstd::optional_lite::optional
class optional
Definition: optional.hpp:919
restinio::connection_count_limits::connection_lifetime_monitor_t
Helper type for controlling the lifetime of the connection.
Definition: connection_count_limiter.hpp:375
restinio::connection_state::notice_t
An object with info about connection to be passed to state listener.
Definition: connection_state_listener.hpp:225
restinio::connection_state::upgraded_to_websocket_t
Type of object that tells that the connection has been upgraded to WebSocket.
Definition: connection_state_listener.hpp:196
restinio::exception_t
Exception class for all exceptions thrown by RESTinio.
Definition: exception.hpp:26
restinio::impl::executor_wrapper_t
Wrapper for an executor (strand) used by connections.
Definition: executor_wrapper.hpp:25
restinio::impl::executor_wrapper_t< Traits::strand_t >::get_executor
Traits::strand_t & get_executor() noexcept
An executor for callbacks on async operations.
Definition: executor_wrapper.hpp:35
restinio::impl::fixed_buffer_t
Helper class for reading bytes and feeding them to parser.
Definition: fixed_buffer.hpp:27
restinio::impl::fixed_buffer_t::length
std::size_t length() const noexcept
How many unconsumed bytes are there in buffer.
Definition: fixed_buffer.hpp:63
restinio::impl::fixed_buffer_t::consumed_bytes
void consumed_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
Definition: fixed_buffer.hpp:56
restinio::impl::fixed_buffer_t::obtained_bytes
void obtained_bytes(std::size_t length) noexcept
Mark how many bytes were obtained.
Definition: fixed_buffer.hpp:48
restinio::impl::fixed_buffer_t::make_asio_buffer
auto make_asio_buffer() noexcept
Make asio buffer for reading bytes from socket.
Definition: fixed_buffer.hpp:41
restinio::impl::fixed_buffer_t::bytes
const char * bytes() const noexcept
Get pointer to unconsumed bytes.
Definition: fixed_buffer.hpp:69
restinio::impl::write_group_output_ctx_t::file_write_operation_t
Write operaton using sendfile.
Definition: write_group_output_ctx.hpp:142
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t
Trivial write operaton.
Definition: write_group_output_ctx.hpp:106
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::size
auto size() const noexcept
The size of data within this operation.
Definition: write_group_output_ctx.hpp:133
restinio::impl::write_group_output_ctx_t::trivial_write_operation_t::get_trivial_bufs
const std::vector< asio_ns::const_buffer > & get_trivial_bufs() const noexcept
Get buffer "iovec" for performing gather write.
Definition: write_group_output_ctx.hpp:127
restinio::impl::write_group_output_ctx_t
Helper class for writting response data.
Definition: write_group_output_ctx.hpp:80
restinio::impl::write_group_output_ctx_t::fail_write_group
void fail_write_group(const asio_ns::error_code &ec)
Handle current group write process failed.
Definition: write_group_output_ctx.hpp:283
restinio::impl::write_group_output_ctx_t::extract_next_write_operation
solid_write_operation_variant_t extract_next_write_operation()
et an object with next write operation to perform.
Definition: write_group_output_ctx.hpp:253
restinio::impl::write_group_output_ctx_t::finish_write_group
void finish_write_group()
Finish writing group normally.
Definition: write_group_output_ctx.hpp:294
restinio::impl::write_group_output_ctx_t::start_next_write_group
void start_next_write_group(optional_t< write_group_t > next_wg) noexcept
Start handlong next write group.
Definition: write_group_output_ctx.hpp:239
restinio::impl::write_group_output_ctx_t::transmitting
bool transmitting() const noexcept
Check if data is trunsmitting now.
Definition: write_group_output_ctx.hpp:235
restinio::tcp_connection_ctx_base_t
TCP connection base.
Definition: tcp_connection_ctx_base.hpp:29
restinio::tcp_connection_ctx_base_t::connection_id
connection_id_t connection_id() const noexcept
Get connection id.
Definition: tcp_connection_ctx_base.hpp:38
restinio::websocket::basic::impl::message_details_t
Websocket message class with more detailed protocol information.
Definition: ws_parser.hpp:63
restinio::websocket::basic::impl::message_details_t::payload_len
std::uint64_t payload_len() const
Get payload len.
Definition: ws_parser.hpp:92
restinio::websocket::basic::impl::message_details_t::m_opcode
opcode_t m_opcode
Opcode.
Definition: ws_parser.hpp:117
restinio::websocket::basic::impl::ws_connection_base_t
WebSocket connection base.
Definition: ws_connection_base.hpp:39
restinio::websocket::basic::impl::ws_connection_t::one_shot_action_t
A helper class for running exclusive action. Only a first action will run.
Definition: ws_connection.hpp:1409
restinio::websocket::basic::impl::ws_connection_t::one_shot_action_t::run_if_first
void run_if_first(Action &&action) noexcept(noexcept(action()))
Definition: ws_connection.hpp:1413
restinio::websocket::basic::impl::ws_connection_t::one_shot_action_t::disable
void disable()
Disable ation: action will not be executed even on a first shot.
Definition: ws_connection.hpp:1424
restinio::websocket::basic::impl::ws_connection_t::one_shot_action_t::m_not_executed_yet
bool m_not_executed_yet
Definition: ws_connection.hpp:1430
restinio::websocket::basic::impl::ws_connection_t
Context for handling websocket connections.
Definition: ws_connection.hpp:125
restinio::websocket::basic::impl::ws_connection_t::m_timer_guard
timer_guard_t m_timer_guard
Definition: ws_connection.hpp:1304
restinio::websocket::basic::impl::ws_connection_t::finish_handling_current_write_ctx
void finish_handling_current_write_ctx()
Do post write actions for current write group.
Definition: ws_connection.hpp:1197
restinio::websocket::basic::impl::ws_connection_t::after_read_header
void after_read_header(const asio_ns::error_code &ec, std::size_t length)
Handle read operation result, when reading header.
Definition: ws_connection.hpp:562
restinio::websocket::basic::impl::ws_connection_t::m_settings
restinio::impl::connection_settings_handle_t< Traits > m_settings
Common paramaters of a connection.
Definition: ws_connection.hpp:1250
restinio::websocket::basic::impl::ws_connection_t::consume_header_from_socket
void consume_header_from_socket()
Initiate read operation on socket to receive bytes for header.
Definition: ws_connection.hpp:510
restinio::websocket::basic::impl::ws_connection_t::m_msg_handler
message_handler_t m_msg_handler
Websocket message handler provided by user.
Definition: ws_connection.hpp:1366
restinio::websocket::basic::impl::ws_connection_t::handle_parsed_header
void handle_parsed_header(const message_details_t &md)
Handle parsed header.
Definition: ws_connection.hpp:605
restinio::websocket::basic::impl::ws_connection_t::message_handler_t
WS_Message_Handler message_handler_t
Definition: ws_connection.hpp:129
restinio::websocket::basic::impl::ws_connection_t::validate_payload_part
bool validate_payload_part(char *payload_data, std::size_t length, std::size_t next_length_remaining)
Validates a part of received payload.
Definition: ws_connection.hpp:840
restinio::websocket::basic::impl::ws_connection_t::m_websocket_weak_handle
ws_weak_handle_t m_websocket_weak_handle
A waek handler for owning ws_t to use it when call message handler.
Definition: ws_connection.hpp:1378
restinio::websocket::basic::impl::ws_connection_t::shutdown
virtual void shutdown() override
Shutdown websocket.
Definition: ws_connection.hpp:209
restinio::websocket::basic::impl::ws_connection_t::lifetime_monitor_t
typename connection_count_limit_types< Traits >::lifetime_monitor_t lifetime_monitor_t
Definition: ws_connection.hpp:138
restinio::websocket::basic::impl::ws_connection_t::send_close_frame_to_peer
void send_close_frame_to_peer(std::string payload)
Send close frame to peer.
Definition: ws_connection.hpp:424
restinio::websocket::basic::impl::ws_connection_t::write_data_impl
void write_data_impl(write_group_t wg, bool is_close_frame)
Implementation of writing data performed on the asio_ns::io_context.
Definition: ws_connection.hpp:1017
restinio::websocket::basic::impl::ws_connection_t::read_state_t
read_state_t
Websocket input states.
Definition: ws_connection.hpp:1394
restinio::websocket::basic::impl::ws_connection_t::read_state_t::read_only_close_frame
@ read_only_close_frame
Reads only close frame: skip all frames until close-frame.
restinio::websocket::basic::impl::ws_connection_t::read_state_t::read_nothing
@ read_nothing
Do not read anything (before activation).
restinio::websocket::basic::impl::ws_connection_t::read_state_t::read_any_frame
@ read_any_frame
Reads any type of frame and serve it to user.
restinio::websocket::basic::impl::ws_connection_t::ws_weak_handle_t
std::weak_ptr< ws_t > ws_weak_handle_t
Definition: ws_connection.hpp:140
restinio::websocket::basic::impl::ws_connection_t::check_timeout_impl
void check_timeout_impl()
Definition: ws_connection.hpp:1307
restinio::websocket::basic::impl::ws_connection_t::logger_t
typename Traits::logger_t logger_t
Definition: ws_connection.hpp:134
restinio::websocket::basic::impl::ws_connection_t::write_state_t
write_state_t
Websocket output states.
Definition: ws_connection.hpp:1382
restinio::websocket::basic::impl::ws_connection_t::write_state_t::write_enabled
@ write_enabled
Able to append outgoing data.
restinio::websocket::basic::impl::ws_connection_t::write_state_t::write_disabled
@ write_disabled
No more outgoing data can be added (e.g. close-frame was sent).
restinio::websocket::basic::impl::ws_connection_t::guard_close_frame_from_peer_operation
void guard_close_frame_from_peer_operation()
Definition: ws_connection.hpp:1352
restinio::websocket::basic::impl::ws_connection_t::m_close_frame_from_peer_timeout_after
std::chrono::steady_clock::time_point m_close_frame_from_peer_timeout_after
Definition: ws_connection.hpp:1301
restinio::websocket::basic::impl::ws_connection_t::timer_guard_t
typename timer_manager_t::timer_guard_t timer_guard_t
Definition: ws_connection.hpp:133
restinio::websocket::basic::impl::ws_connection_t::m_close_impl
one_shot_action_t m_close_impl
Definition: ws_connection.hpp:1435
restinio::websocket::basic::impl::ws_connection_t::init_write_if_necessary
void init_write_if_necessary()
Checks if there is something to write, and if so starts write operation.
Definition: ws_connection.hpp:1065
restinio::websocket::basic::impl::ws_connection_t::trigger_error_and_close
void trigger_error_and_close(status_code_t status, MSG_BUILDER msg_builder) noexcept
Trigger an error.
Definition: ws_connection.hpp:464
restinio::websocket::basic::impl::ws_connection_t::start_read_header
void start_read_header()
Start the process of reading ws messages from socket.
Definition: ws_connection.hpp:485
restinio::websocket::basic::impl::ws_connection_t::start_read_payload
void start_read_payload(char *payload_data, std::size_t length_remaining, bool do_validate_payload_and_call_msg_handler=true)
Start reading message payload.
Definition: ws_connection.hpp:703
restinio::websocket::basic::impl::ws_connection_t::m_logger
logger_t & m_logger
Logger for operation.
Definition: ws_connection.hpp:1369
restinio::websocket::basic::impl::ws_connection_t::m_close_frame_to_peer
one_shot_action_t m_close_frame_to_peer
Definition: ws_connection.hpp:1434
restinio::websocket::basic::impl::ws_connection_t::m_close_frame_to_user
one_shot_action_t m_close_frame_to_user
Definition: ws_connection.hpp:1433
restinio::websocket::basic::impl::ws_connection_t::m_prepared_weak_ctx
tcp_connection_ctx_weak_handle_t m_prepared_weak_ctx
Definition: ws_connection.hpp:1303
restinio::websocket::basic::impl::ws_connection_t::handle_trivial_write_operation
void handle_trivial_write_operation(const trivial_write_operation_t &op)
Definition: ws_connection.hpp:1140
restinio::websocket::basic::impl::ws_connection_t::init_next_timeout_checking
void init_next_timeout_checking()
schedule next timeout checking.
Definition: ws_connection.hpp:1338
restinio::websocket::basic::impl::ws_connection_t::handle_invalid_payload
void handle_invalid_payload(validation_state_t validation_result)
Handle payload errors.
Definition: ws_connection.hpp:883
restinio::websocket::basic::impl::ws_connection_t::handle_current_write_ctx
void handle_current_write_ctx()
Definition: ws_connection.hpp:1106
restinio::websocket::basic::impl::ws_connection_t::after_read_payload
void after_read_payload(char *payload_data, std::size_t length_remaining, const asio_ns::error_code &ec, std::size_t length, bool do_validate_payload_and_call_msg_handler=true)
Handle read operation result, when reading payload.
Definition: ws_connection.hpp:748
restinio::websocket::basic::impl::ws_connection_t::call_close_handler_if_necessary
void call_close_handler_if_necessary(status_code_t status)
Definition: ws_connection.hpp:1003
restinio::websocket::basic::impl::ws_connection_t::consume_header_from_buffer
void consume_header_from_buffer(const char *data, std::size_t length)
Parse header from internal buffer.
Definition: ws_connection.hpp:586
restinio::websocket::basic::impl::ws_connection_t::send_close_frame_to_peer
void send_close_frame_to_peer(status_code_t code, std::string desc=std::string{})
Send close frame to peer.
Definition: ws_connection.hpp:446
restinio::websocket::basic::impl::ws_connection_t::ws_connection_t
ws_connection_t(const ws_connection_t &)=delete
restinio::websocket::basic::impl::ws_connection_t::check_timeout
virtual void check_timeout(tcp_connection_ctx_handle_t &self) override
Definition: ws_connection.hpp:1271
restinio::websocket::basic::impl::ws_connection_t::m_input
connection_input_t m_input
Input routine.
Definition: ws_connection.hpp:1360
restinio::websocket::basic::impl::ws_connection_t::handle_read_error
void handle_read_error(const char *desc, const asio_ns::error_code &ec)
Handle read error (reading header or payload)
Definition: ws_connection.hpp:546
restinio::websocket::basic::impl::ws_connection_t::call_handler_on_current_message
void call_handler_on_current_message()
Definition: ws_connection.hpp:935
restinio::websocket::basic::impl::ws_connection_t::m_write_state
write_state_t m_write_state
A state of a websocket output.
Definition: ws_connection.hpp:1390
restinio::websocket::basic::impl::ws_connection_t::m_protocol_validator
ws_protocol_validator_t m_protocol_validator
Helper for validating protocol.
Definition: ws_connection.hpp:1363
restinio::websocket::basic::impl::ws_connection_t::handle_parsed_and_valid_header
void handle_parsed_and_valid_header(const message_details_t &md)
Handle parsed and valid header.
Definition: ws_connection.hpp:651
restinio::websocket::basic::impl::ws_connection_t::operator=
ws_connection_t & operator=(const ws_connection_t &)=delete
restinio::websocket::basic::impl::ws_connection_t::ws_connection_t
ws_connection_t(ws_connection_t &&)=delete
restinio::websocket::basic::impl::ws_connection_t::start_waiting_close_frame_only
void start_waiting_close_frame_only()
Start waiting for close-frame.
Definition: ws_connection.hpp:405
restinio::websocket::basic::impl::ws_connection_t::m_write_operation_timeout_after
std::chrono::steady_clock::time_point m_write_operation_timeout_after
Definition: ws_connection.hpp:1300
restinio::websocket::basic::impl::ws_connection_t::strand_t
typename Traits::strand_t strand_t
Definition: ws_connection.hpp:135
restinio::websocket::basic::impl::ws_connection_t::kill
virtual void kill() override
Kill websocket.
Definition: ws_connection.hpp:245
restinio::websocket::basic::impl::ws_connection_t::guard_write_operation
void guard_write_operation()
Start guard write operation if necessary.
Definition: ws_connection.hpp:1345
restinio::websocket::basic::impl::ws_connection_t::~ws_connection_t
~ws_connection_t() override
Definition: ws_connection.hpp:192
restinio::websocket::basic::impl::ws_connection_t::m_outgoing_data
ws_outgoing_data_t m_outgoing_data
Output buffers queue.
Definition: ws_connection.hpp:1375
restinio::websocket::basic::impl::ws_connection_t::init_read
void init_read(ws_handle_t wsh) override
Start reading ws-messages.
Definition: ws_connection.hpp:284
restinio::websocket::basic::impl::ws_connection_t::timer_manager_handle_t
std::shared_ptr< timer_manager_t > timer_manager_handle_t
Definition: ws_connection.hpp:132
restinio::websocket::basic::impl::ws_connection_t::call_message_handler
void call_message_handler(message_handle_t close_frame)
Call user message handler with current message.
Definition: ws_connection.hpp:816
restinio::websocket::basic::impl::ws_connection_t::cast_to_self
static ws_connection_t & cast_to_self(tcp_connection_ctx_base_t &base)
Timers.
Definition: ws_connection.hpp:1265
restinio::websocket::basic::impl::ws_connection_t::init_write
void init_write()
Initiate write operation.
Definition: ws_connection.hpp:1075
restinio::websocket::basic::impl::ws_connection_t::m_lifetime_monitor
lifetime_monitor_t m_lifetime_monitor
Monitor of the connection lifetime.
Definition: ws_connection.hpp:1260
restinio::websocket::basic::impl::ws_connection_t::after_write
void after_write(const asio_ns::error_code &ec)
Handle write response finished.
Definition: ws_connection.hpp:1216
restinio::websocket::basic::impl::ws_connection_t::m_write_output_ctx
restinio::impl::write_group_output_ctx_t m_write_output_ctx
Write to socket operation context.
Definition: ws_connection.hpp:1372
restinio::websocket::basic::impl::ws_connection_t::close_impl
void close_impl() noexcept
Standard close routine.
Definition: ws_connection.hpp:371
restinio::websocket::basic::impl::ws_connection_t::stream_socket_t
typename Traits::stream_socket_t stream_socket_t
Definition: ws_connection.hpp:136
restinio::websocket::basic::impl::ws_connection_t::write_data
virtual void write_data(write_group_t wg, bool is_close_frame) override
Write pieces of outgoing data.
Definition: ws_connection.hpp:321
restinio::websocket::basic::impl::ws_connection_t::m_socket
stream_socket_t m_socket
Connection.
Definition: ws_connection.hpp:1253
restinio::websocket::basic::impl::ws_connection_t::graceful_close
void graceful_close()
Close WebSocket connection in a graceful manner.
Definition: ws_connection.hpp:413
restinio::websocket::basic::impl::ws_connection_t::m_read_state
read_state_t m_read_state
A state of a websocket input.
Definition: ws_connection.hpp:1404
restinio::websocket::basic::impl::ws_connection_t::timer_manager_t
typename Traits::timer_manager_t timer_manager_t
Definition: ws_connection.hpp:131
restinio::websocket::basic::impl::ws_outgoing_data_t
A queue for outgoing buffers.
Definition: ws_connection.hpp:57
restinio::websocket::basic::impl::ws_outgoing_data_t::pop_ready_buffers
optional_t< write_group_t > pop_ready_buffers()
Definition: ws_connection.hpp:67
restinio::websocket::basic::impl::ws_outgoing_data_t::m_awaiting_write_groups
write_groups_queue_t m_awaiting_write_groups
A queue of buffers.
Definition: ws_connection.hpp:82
restinio::websocket::basic::impl::ws_outgoing_data_t::append
void append(write_group_t wg)
Add buffers to queue.
Definition: ws_connection.hpp:61
restinio::websocket::basic::impl::ws_parser_t
Websocket parser.
Definition: ws_parser.hpp:260
restinio::websocket::basic::impl::ws_parser_t::reset
void reset()
Reset internal state.
Definition: ws_parser.hpp:294
restinio::websocket::basic::impl::ws_parser_t::current_message
const message_details_t & current_message() const
Get current mesasge details.
Definition: ws_parser.hpp:303
restinio::websocket::basic::impl::ws_parser_t::parser_execute
size_t parser_execute(const char *data, size_t size)
Parse piece of data from buffer.
Definition: ws_parser.hpp:265
restinio::websocket::basic::impl::ws_parser_t::header_parsed
bool header_parsed() const
Check header of current websocket message is parsed.
Definition: ws_parser.hpp:284
restinio::websocket::basic::impl::ws_protocol_validator_t
Class for websocket protocol validations.
Definition: ws_protocol_validator.hpp:195
restinio::websocket::basic::impl::ws_protocol_validator_t::process_and_unmask_next_payload_part
validation_state_t process_and_unmask_next_payload_part(char *data, size_t size)
Validate next part of current frame and reset source part to unmasked data.
Definition: ws_protocol_validator.hpp:278
restinio::websocket::basic::impl::ws_protocol_validator_t::process_new_frame
validation_state_t process_new_frame(const message_details_t &frame)
Start work with new frame.
Definition: ws_protocol_validator.hpp:211
restinio::websocket::basic::impl::ws_protocol_validator_t::finish_frame
validation_state_t finish_frame()
Make final checks of payload if it is necessary and reset state.
Definition: ws_protocol_validator.hpp:303
restinio::websocket::basic::impl::ws_protocol_validator_t::reset
void reset()
Reset to initial state.
Definition: ws_protocol_validator.hpp:341
restinio::write_group_t
Group of writable items transported to the context of underlying connection as one solid piece.
Definition: buffers.hpp:692
restinio::write_group_t::invoke_after_write_notificator_if_exists
void invoke_after_write_notificator_if_exists(const asio_ns::error_code &ec)
Get after write notificator.
Definition: buffers.hpp:815
compiler_features.hpp
Detection of compiler version and absence of various features.
RESTINIO_ENSURE_NOEXCEPT_CALL
#define RESTINIO_ENSURE_NOEXCEPT_CALL(expr)
A wrapper around static_assert for checking that an expression is noexcept and execution of that expr...
Definition: compiler_features.hpp:60
executor_wrapper.hpp
include_fmtlib.hpp
A special wrapper around fmtlib include files.
message.hpp
nonstd::optional_lite::std11::move
T & move(T &t)
Definition: optional.hpp:465
restinio::impl::connection_settings_handle_t
std::shared_ptr< connection_settings_t< Traits > > connection_settings_handle_t
Definition: connection_settings.hpp:235
restinio::utils::impl::uint64_to_size_t
std::size_t uint64_to_size_t(std::uint64_t v)
Helper function for truncating uint64 to std::size_t with exception if that truncation will lead to d...
Definition: safe_uint_truncate.hpp:59
restinio::utils::suppress_exceptions
void suppress_exceptions(Logger &&logger, const char *block_description, Lambda &&lambda) noexcept
Helper function for execution a block of code with suppression of any exceptions raised inside that b...
Definition: suppress_exceptions.hpp:94
restinio::utils::log_error_noexcept
void log_error_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
Definition: suppress_exceptions.hpp:71
restinio::utils::log_trace_noexcept
void log_trace_noexcept(Logger &&logger, Message_Builder &&builder) noexcept
Definition: suppress_exceptions.hpp:32
restinio::websocket::basic::impl::write_message_details
raw_data_t write_message_details(const message_details_t &message)
Serialize websocket message details into bytes buffer.
Definition: ws_parser.hpp:515
restinio::websocket::basic::impl::websocket_header_max_size
constexpr size_t websocket_header_max_size()
Max possible size of websocket frame header (a part before payload).
Definition: ws_connection.hpp:46
restinio::websocket::basic::impl::write_groups_queue_t
std::queue< write_group_t > write_groups_queue_t
Definition: ws_connection.hpp:42
restinio::websocket::basic::impl::validation_state_t
validation_state_t
States of validated frame.
Definition: ws_protocol_validator.hpp:29
restinio::websocket::basic::impl::validation_state_t::payload_part_is_valid
@ payload_part_is_valid
restinio::websocket::basic::impl::validation_state_t::frame_header_is_valid
@ frame_header_is_valid
restinio::websocket::basic::impl::validation_state_t::incorrect_utf8_data
@ incorrect_utf8_data
restinio::websocket::basic::impl::validation_state_t::invalid_close_code
@ invalid_close_code
restinio::websocket::basic::impl::validation_state_t::frame_is_valid
@ frame_is_valid
restinio::websocket::basic::status_code_t
status_code_t
Definition: message.hpp:86
restinio::websocket::basic::status_code_t::unexpected_condition
@ unexpected_condition
restinio::websocket::basic::status_code_t::connection_lost
@ connection_lost
restinio::websocket::basic::status_code_t::invalid_message_data
@ invalid_message_data
restinio::websocket::basic::status_code_t::protocol_error
@ protocol_error
restinio::websocket::basic::status_code_t::normal_closure
@ normal_closure
restinio::websocket::basic::message_handle_t
std::shared_ptr< message_t > message_handle_t
Request handler, that is the type for calling request handlers.
Definition: message.hpp:227
restinio::websocket::basic::final_frame
constexpr final_frame_flag_t final_frame
Definition: message.hpp:135
restinio::websocket::basic::not_final_frame
constexpr final_frame_flag_t not_final_frame
Definition: message.hpp:136
restinio::websocket::basic::opcode_to_string
const char * opcode_to_string(opcode_t opcode)
Helper sunction to get method string name.
Definition: message.hpp:46
restinio::websocket::basic::status_code_from_bin
status_code_t status_code_from_bin(string_view_t data)
Definition: message.hpp:112
restinio::websocket::basic::status_code_to_bin
std::string status_code_to_bin(status_code_t code)
Definition: message.hpp:101
restinio::websocket::basic::ws_handle_t
std::shared_ptr< ws_t > ws_handle_t
Alias for ws_t handle.
Definition: ws_connection_base.hpp:27
restinio
Definition: asio_include.hpp:21
restinio::tcp_connection_ctx_handle_t
std::shared_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_handle_t
Alias for http connection handle.
Definition: tcp_connection_ctx_base.hpp:62
restinio::writable_items_container_t
std::vector< writable_item_t > writable_items_container_t
Definition: buffers.hpp:668
restinio::tcp_connection_ctx_weak_handle_t
std::weak_ptr< tcp_connection_ctx_base_t > tcp_connection_ctx_weak_handle_t
Alias for http connection weak handle.
Definition: tcp_connection_ctx_base.hpp:65
restinio::asio_convertible_error_t::write_was_not_executed
@ write_was_not_executed
After write notificator error: data was not sent, connection closed (or aborted) before a given piece...
restinio::make_asio_compaible_error
asio_ns::error_code make_asio_compaible_error(asio_convertible_error_t err) noexcept
Make restinio error_code compatible with asio_ns::error_code.
Definition: asio_include.hpp:210
restinio::connection_id_t
std::uint64_t connection_id_t
Type for ID of connection.
Definition: common_types.hpp:174
std
STL namespace.
safe_uint_truncate.hpp
Helpers for safe truncation of unsigned integers.
code
Definition: inftrees.h:24
restinio::impl::write_group_output_ctx_t::none_write_operation_t
None write operation.
Definition: write_group_output_ctx.hpp:232
restinio::websocket::basic::impl::connection_input_t
Websocket input stuff.
Definition: ws_connection.hpp:91
restinio::websocket::basic::impl::connection_input_t::m_parser
ws_parser_t m_parser
websocket parser.
Definition: ws_connection.hpp:97
restinio::websocket::basic::impl::connection_input_t::m_buf
restinio::impl::fixed_buffer_t m_buf
Input buffer.
Definition: ws_connection.hpp:100
restinio::websocket::basic::impl::connection_input_t::reset_parser_and_payload
void reset_parser_and_payload()
Prepare parser for reading new http-message.
Definition: ws_connection.hpp:107
restinio::websocket::basic::impl::connection_input_t::connection_input_t
connection_input_t(std::size_t buffer_size)
Definition: ws_connection.hpp:92
restinio::websocket::basic::impl::connection_input_t::m_payload
std::string m_payload
Current payload.
Definition: ws_connection.hpp:103
write_group_output_ctx.hpp
ws_parser.hpp
ws_protocol_validator.hpp