Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:33:52

0001 //
0002 // Copyright (c) 2019-2024 Ruben Perez Hidalgo (rubenperez038 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 
0008 #ifndef BOOST_MYSQL_IMPL_INTERNAL_SANSIO_TOP_LEVEL_ALGO_HPP
0009 #define BOOST_MYSQL_IMPL_INTERNAL_SANSIO_TOP_LEVEL_ALGO_HPP
0010 
0011 #include <boost/mysql/client_errc.hpp>
0012 #include <boost/mysql/error_code.hpp>
0013 
0014 #include <boost/mysql/detail/next_action.hpp>
0015 
0016 #include <boost/mysql/impl/internal/coroutine.hpp>
0017 #include <boost/mysql/impl/internal/sansio/connection_state_data.hpp>
0018 
0019 #include <boost/core/span.hpp>
0020 
0021 #include <cstddef>
0022 #include <cstdint>
0023 
0024 #ifdef BOOST_USE_VALGRIND
0025 #include <valgrind/memcheck.h>
0026 #endif
0027 
0028 namespace boost {
0029 namespace mysql {
0030 namespace detail {
0031 
0032 // Valgrind
0033 #ifdef BOOST_USE_VALGRIND
0034 inline void valgrind_make_mem_defined(const void* data, std::size_t size)
0035 {
0036     VALGRIND_MAKE_MEM_DEFINED(data, size);
0037 }
0038 #else
0039 inline void valgrind_make_mem_defined(const void*, std::size_t) noexcept {}
0040 #endif
0041 
0042 // InnerAlgo should have
0043 //   Constructible from the args forwarded by the ctor.
0044 //   next_action resume(connection_state_data&, error_code);
0045 //   AlgoParams::result_type result(const connection_state_data&) const; // if AlgoParams::result_type != void
0046 template <class InnerAlgo>
0047 class top_level_algo
0048 {
0049     int resume_point_{0};
0050     connection_state_data* st_;
0051     InnerAlgo algo_;
0052     span<const std::uint8_t> bytes_to_write_;
0053 
0054 public:
0055     template <class... Args>
0056     top_level_algo(connection_state_data& st, Args&&... args) : st_(&st), algo_(std::forward<Args>(args)...)
0057     {
0058     }
0059 
0060     const InnerAlgo& inner_algo() const { return algo_; }
0061 
0062     next_action resume(error_code ec, std::size_t bytes_transferred)
0063     {
0064         next_action act;
0065 
0066         switch (resume_point_)
0067         {
0068         case 0:
0069 
0070             // Run until completion
0071             while (true)
0072             {
0073                 // Run the op
0074                 act = algo_.resume(*st_, ec);
0075 
0076                 // Check next action
0077                 if (act.is_done())
0078                 {
0079                     return act;
0080                 }
0081                 else if (act.type() == next_action_type::read)
0082                 {
0083                     // Read until a complete message is received
0084                     // (may be zero times if cached)
0085                     while (!st_->reader.done() && !ec)
0086                     {
0087                         ec = st_->reader.prepare_buffer();
0088                         if (ec)
0089                             break;
0090                         BOOST_MYSQL_YIELD(
0091                             resume_point_,
0092                             1,
0093                             next_action::read({st_->reader.buffer(), st_->ssl_active()})
0094                         )
0095                         valgrind_make_mem_defined(st_->reader.buffer().data(), bytes_transferred);
0096                         st_->reader.resume(bytes_transferred);
0097                     }
0098 
0099                     // Check for errors
0100                     if (!ec)
0101                         ec = st_->reader.error();
0102 
0103                     // We've got a message, continue
0104                 }
0105                 else if (act.type() == next_action_type::write)
0106                 {
0107                     // Write until a complete message was written
0108                     bytes_to_write_ = act.write_args().buffer;
0109 
0110                     // Check buffer size. We should check this before
0111                     // resizing the buffer, but requires non-trivial changes.
0112                     // For now, this yields the right user-facing behavior.
0113                     // https://github.com/boostorg/mysql/issues/297
0114                     // https://github.com/boostorg/mysql/issues/279
0115                     if (bytes_to_write_.size() > st_->max_buffer_size())
0116                     {
0117                         ec = client_errc::max_buffer_size_exceeded;
0118                         continue;
0119                     }
0120 
0121                     while (!bytes_to_write_.empty() && !ec)
0122                     {
0123                         BOOST_MYSQL_YIELD(
0124                             resume_point_,
0125                             2,
0126                             next_action::write({bytes_to_write_, st_->ssl_active()})
0127                         )
0128                         bytes_to_write_ = bytes_to_write_.subspan(bytes_transferred);
0129                     }
0130 
0131                     // We fully wrote a message, continue
0132                 }
0133                 else
0134                 {
0135                     // Other ops always require I/O
0136                     BOOST_MYSQL_YIELD(resume_point_, 3, act)
0137                 }
0138             }
0139         }
0140 
0141         return next_action();
0142     }
0143 };
0144 
0145 }  // namespace detail
0146 }  // namespace mysql
0147 }  // namespace boost
0148 
0149 #endif