message_parser.ipp 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. //
  2. // Copyright (c) 2019-2023 Ruben Perez Hidalgo (rubenperez038 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. #ifndef BHO_MYSQL_IMPL_INTERNAL_CHANNEL_MESSAGE_PARSER_IPP
  8. #define BHO_MYSQL_IMPL_INTERNAL_CHANNEL_MESSAGE_PARSER_IPP
  9. #pragma once
  10. #include <asio2/bho/mysql/impl/internal/channel/message_parser.hpp>
  11. #include <asio2/bho/mysql/impl/internal/protocol/protocol.hpp>
  12. void bho::mysql::detail::message_parser::parse_message(read_buffer& buff, result& res) noexcept
  13. {
  14. while (true)
  15. {
  16. if (state_.reading_header)
  17. {
  18. // If there are not enough bytes to process a header, request more
  19. if (buff.pending_size() < HEADER_SIZE)
  20. {
  21. res.set_required_size(HEADER_SIZE - buff.pending_size());
  22. return;
  23. }
  24. // Mark the header as belonging to the current message
  25. buff.move_to_current_message(HEADER_SIZE);
  26. // Deserialize the header
  27. auto header = deserialize_frame_header(
  28. span<const std::uint8_t, frame_header_size>(buff.pending_first() - HEADER_SIZE, HEADER_SIZE)
  29. );
  30. // Process the sequence number
  31. if (state_.is_first_frame)
  32. {
  33. state_.seqnum_first = header.sequence_number;
  34. state_.seqnum_last = header.sequence_number;
  35. }
  36. else
  37. {
  38. std::uint8_t expected_seqnum = state_.seqnum_last + 1;
  39. if (header.sequence_number != expected_seqnum)
  40. {
  41. state_.has_seqnum_mismatch = true;
  42. }
  43. state_.seqnum_last = expected_seqnum;
  44. }
  45. // Process the packet size
  46. state_.remaining_bytes = header.size;
  47. state_.more_frames_follow = (state_.remaining_bytes == max_frame_size_);
  48. // We are done with the header
  49. if (state_.is_first_frame)
  50. {
  51. // If it's the 1st frame, we can just move the header bytes to the reserved
  52. // area, avoiding a big memmove
  53. buff.move_to_reserved(HEADER_SIZE);
  54. }
  55. else
  56. {
  57. buff.remove_current_message_last(HEADER_SIZE);
  58. }
  59. state_.is_first_frame = false;
  60. state_.reading_header = false;
  61. }
  62. if (!state_.reading_header)
  63. {
  64. // Get the number of bytes belonging to this message
  65. std::size_t new_bytes = (std::min)(buff.pending_size(), state_.remaining_bytes);
  66. // Mark them as belonging to the current message in the buffer
  67. buff.move_to_current_message(new_bytes);
  68. // Update remaining bytes
  69. state_.remaining_bytes -= new_bytes;
  70. if (state_.remaining_bytes == 0)
  71. {
  72. state_.reading_header = true;
  73. }
  74. else
  75. {
  76. res.set_required_size(state_.remaining_bytes);
  77. return;
  78. }
  79. // If we've fully read a message, we're done
  80. if (!state_.remaining_bytes && !state_.more_frames_follow)
  81. {
  82. std::size_t message_size = buff.current_message_size();
  83. buff.move_to_reserved(message_size);
  84. res.set_message({
  85. state_.seqnum_first,
  86. state_.seqnum_last,
  87. message_size,
  88. state_.has_seqnum_mismatch,
  89. });
  90. state_ = state_t();
  91. return;
  92. }
  93. }
  94. }
  95. }
  96. #endif