Back to home page

EIC code displayed by LXR

 
 

    


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

0001 //
0002 // ssl/detail/io.hpp
0003 // ~~~~~~~~~~~~~~~~~
0004 //
0005 // Copyright (c) 2003-2023 Christopher M. Kohlhoff (chris at kohlhoff dot com)
0006 //
0007 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0008 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0009 //
0010 
0011 #ifndef BOOST_ASIO_SSL_DETAIL_IO_HPP
0012 #define BOOST_ASIO_SSL_DETAIL_IO_HPP
0013 
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
0017 
0018 #include <boost/asio/detail/config.hpp>
0019 
0020 #include <boost/asio/detail/base_from_cancellation_state.hpp>
0021 #include <boost/asio/detail/handler_tracking.hpp>
0022 #include <boost/asio/ssl/detail/engine.hpp>
0023 #include <boost/asio/ssl/detail/stream_core.hpp>
0024 #include <boost/asio/write.hpp>
0025 
0026 #include <boost/asio/detail/push_options.hpp>
0027 
0028 namespace boost {
0029 namespace asio {
0030 namespace ssl {
0031 namespace detail {
0032 
0033 template <typename Stream, typename Operation>
0034 std::size_t io(Stream& next_layer, stream_core& core,
0035     const Operation& op, boost::system::error_code& ec)
0036 {
0037   boost::system::error_code io_ec;
0038   std::size_t bytes_transferred = 0;
0039   do switch (op(core.engine_, ec, bytes_transferred))
0040   {
0041   case engine::want_input_and_retry:
0042 
0043     // If the input buffer is empty then we need to read some more data from
0044     // the underlying transport.
0045     if (core.input_.size() == 0)
0046     {
0047       core.input_ = boost::asio::buffer(core.input_buffer_,
0048           next_layer.read_some(core.input_buffer_, io_ec));
0049       if (!ec)
0050         ec = io_ec;
0051     }
0052 
0053     // Pass the new input data to the engine.
0054     core.input_ = core.engine_.put_input(core.input_);
0055 
0056     // Try the operation again.
0057     continue;
0058 
0059   case engine::want_output_and_retry:
0060 
0061     // Get output data from the engine and write it to the underlying
0062     // transport.
0063     boost::asio::write(next_layer,
0064         core.engine_.get_output(core.output_buffer_), io_ec);
0065     if (!ec)
0066       ec = io_ec;
0067 
0068     // Try the operation again.
0069     continue;
0070 
0071   case engine::want_output:
0072 
0073     // Get output data from the engine and write it to the underlying
0074     // transport.
0075     boost::asio::write(next_layer,
0076         core.engine_.get_output(core.output_buffer_), io_ec);
0077     if (!ec)
0078       ec = io_ec;
0079 
0080     // Operation is complete. Return result to caller.
0081     core.engine_.map_error_code(ec);
0082     return bytes_transferred;
0083 
0084   default:
0085 
0086     // Operation is complete. Return result to caller.
0087     core.engine_.map_error_code(ec);
0088     return bytes_transferred;
0089 
0090   } while (!ec);
0091 
0092   // Operation failed. Return result to caller.
0093   core.engine_.map_error_code(ec);
0094   return 0;
0095 }
0096 
0097 template <typename Stream, typename Operation, typename Handler>
0098 class io_op
0099   : public boost::asio::detail::base_from_cancellation_state<Handler>
0100 {
0101 public:
0102   io_op(Stream& next_layer, stream_core& core,
0103       const Operation& op, Handler& handler)
0104     : boost::asio::detail::base_from_cancellation_state<Handler>(handler),
0105       next_layer_(next_layer),
0106       core_(core),
0107       op_(op),
0108       start_(0),
0109       want_(engine::want_nothing),
0110       bytes_transferred_(0),
0111       handler_(static_cast<Handler&&>(handler))
0112   {
0113   }
0114 
0115   io_op(const io_op& other)
0116     : boost::asio::detail::base_from_cancellation_state<Handler>(other),
0117       next_layer_(other.next_layer_),
0118       core_(other.core_),
0119       op_(other.op_),
0120       start_(other.start_),
0121       want_(other.want_),
0122       ec_(other.ec_),
0123       bytes_transferred_(other.bytes_transferred_),
0124       handler_(other.handler_)
0125   {
0126   }
0127 
0128   io_op(io_op&& other)
0129     : boost::asio::detail::base_from_cancellation_state<Handler>(
0130         static_cast<
0131           boost::asio::detail::base_from_cancellation_state<Handler>&&>(other)),
0132       next_layer_(other.next_layer_),
0133       core_(other.core_),
0134       op_(static_cast<Operation&&>(other.op_)),
0135       start_(other.start_),
0136       want_(other.want_),
0137       ec_(other.ec_),
0138       bytes_transferred_(other.bytes_transferred_),
0139       handler_(static_cast<Handler&&>(other.handler_))
0140   {
0141   }
0142 
0143   void operator()(boost::system::error_code ec,
0144       std::size_t bytes_transferred = ~std::size_t(0), int start = 0)
0145   {
0146     switch (start_ = start)
0147     {
0148     case 1: // Called after at least one async operation.
0149       do
0150       {
0151         switch (want_ = op_(core_.engine_, ec_, bytes_transferred_))
0152         {
0153         case engine::want_input_and_retry:
0154 
0155           // If the input buffer already has data in it we can pass it to the
0156           // engine and then retry the operation immediately.
0157           if (core_.input_.size() != 0)
0158           {
0159             core_.input_ = core_.engine_.put_input(core_.input_);
0160             continue;
0161           }
0162 
0163           // The engine wants more data to be read from input. However, we
0164           // cannot allow more than one read operation at a time on the
0165           // underlying transport. The pending_read_ timer's expiry is set to
0166           // pos_infin if a read is in progress, and neg_infin otherwise.
0167           if (core_.expiry(core_.pending_read_) == core_.neg_infin())
0168           {
0169             // Prevent other read operations from being started.
0170             core_.pending_read_.expires_at(core_.pos_infin());
0171 
0172             BOOST_ASIO_HANDLER_LOCATION((
0173                   __FILE__, __LINE__, Operation::tracking_name()));
0174 
0175             // Start reading some data from the underlying transport.
0176             next_layer_.async_read_some(
0177                 boost::asio::buffer(core_.input_buffer_),
0178                 static_cast<io_op&&>(*this));
0179           }
0180           else
0181           {
0182             BOOST_ASIO_HANDLER_LOCATION((
0183                   __FILE__, __LINE__, Operation::tracking_name()));
0184 
0185             // Wait until the current read operation completes.
0186             core_.pending_read_.async_wait(static_cast<io_op&&>(*this));
0187           }
0188 
0189           // Yield control until asynchronous operation completes. Control
0190           // resumes at the "default:" label below.
0191           return;
0192 
0193         case engine::want_output_and_retry:
0194         case engine::want_output:
0195 
0196           // The engine wants some data to be written to the output. However, we
0197           // cannot allow more than one write operation at a time on the
0198           // underlying transport. The pending_write_ timer's expiry is set to
0199           // pos_infin if a write is in progress, and neg_infin otherwise.
0200           if (core_.expiry(core_.pending_write_) == core_.neg_infin())
0201           {
0202             // Prevent other write operations from being started.
0203             core_.pending_write_.expires_at(core_.pos_infin());
0204 
0205             BOOST_ASIO_HANDLER_LOCATION((
0206                   __FILE__, __LINE__, Operation::tracking_name()));
0207 
0208             // Start writing all the data to the underlying transport.
0209             boost::asio::async_write(next_layer_,
0210                 core_.engine_.get_output(core_.output_buffer_),
0211                 static_cast<io_op&&>(*this));
0212           }
0213           else
0214           {
0215             BOOST_ASIO_HANDLER_LOCATION((
0216                   __FILE__, __LINE__, Operation::tracking_name()));
0217 
0218             // Wait until the current write operation completes.
0219             core_.pending_write_.async_wait(static_cast<io_op&&>(*this));
0220           }
0221 
0222           // Yield control until asynchronous operation completes. Control
0223           // resumes at the "default:" label below.
0224           return;
0225 
0226         default:
0227 
0228           // The SSL operation is done and we can invoke the handler, but we
0229           // have to keep in mind that this function might be being called from
0230           // the async operation's initiating function. In this case we're not
0231           // allowed to call the handler directly. Instead, issue a zero-sized
0232           // read so the handler runs "as-if" posted using io_context::post().
0233           if (start)
0234           {
0235             BOOST_ASIO_HANDLER_LOCATION((
0236                   __FILE__, __LINE__, Operation::tracking_name()));
0237 
0238             next_layer_.async_read_some(
0239                 boost::asio::buffer(core_.input_buffer_, 0),
0240                 static_cast<io_op&&>(*this));
0241 
0242             // Yield control until asynchronous operation completes. Control
0243             // resumes at the "default:" label below.
0244             return;
0245           }
0246           else
0247           {
0248             // Continue on to run handler directly.
0249             break;
0250           }
0251         }
0252 
0253         default:
0254         if (bytes_transferred == ~std::size_t(0))
0255           bytes_transferred = 0; // Timer cancellation, no data transferred.
0256         else if (!ec_)
0257           ec_ = ec;
0258 
0259         switch (want_)
0260         {
0261         case engine::want_input_and_retry:
0262 
0263           // Add received data to the engine's input.
0264           core_.input_ = boost::asio::buffer(
0265               core_.input_buffer_, bytes_transferred);
0266           core_.input_ = core_.engine_.put_input(core_.input_);
0267 
0268           // Release any waiting read operations.
0269           core_.pending_read_.expires_at(core_.neg_infin());
0270 
0271           // Check for cancellation before continuing.
0272           if (this->cancelled() != cancellation_type::none)
0273           {
0274             ec_ = boost::asio::error::operation_aborted;
0275             break;
0276           }
0277 
0278           // Try the operation again.
0279           continue;
0280 
0281         case engine::want_output_and_retry:
0282 
0283           // Release any waiting write operations.
0284           core_.pending_write_.expires_at(core_.neg_infin());
0285 
0286           // Check for cancellation before continuing.
0287           if (this->cancelled() != cancellation_type::none)
0288           {
0289             ec_ = boost::asio::error::operation_aborted;
0290             break;
0291           }
0292 
0293           // Try the operation again.
0294           continue;
0295 
0296         case engine::want_output:
0297 
0298           // Release any waiting write operations.
0299           core_.pending_write_.expires_at(core_.neg_infin());
0300 
0301           // Fall through to call handler.
0302 
0303         default:
0304 
0305           // Pass the result to the handler.
0306           op_.call_handler(handler_,
0307               core_.engine_.map_error_code(ec_),
0308               ec_ ? 0 : bytes_transferred_);
0309 
0310           // Our work here is done.
0311           return;
0312         }
0313       } while (!ec_);
0314 
0315       // Operation failed. Pass the result to the handler.
0316       op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0);
0317     }
0318   }
0319 
0320 //private:
0321   Stream& next_layer_;
0322   stream_core& core_;
0323   Operation op_;
0324   int start_;
0325   engine::want want_;
0326   boost::system::error_code ec_;
0327   std::size_t bytes_transferred_;
0328   Handler handler_;
0329 };
0330 
0331 template <typename Stream, typename Operation, typename Handler>
0332 inline bool asio_handler_is_continuation(
0333     io_op<Stream, Operation, Handler>* this_handler)
0334 {
0335   return this_handler->start_ == 0 ? true
0336     : boost_asio_handler_cont_helpers::is_continuation(this_handler->handler_);
0337 }
0338 
0339 template <typename Stream, typename Operation, typename Handler>
0340 inline void async_io(Stream& next_layer, stream_core& core,
0341     const Operation& op, Handler& handler)
0342 {
0343   io_op<Stream, Operation, Handler>(
0344     next_layer, core, op, handler)(
0345       boost::system::error_code(), 0, 1);
0346 }
0347 
0348 } // namespace detail
0349 } // namespace ssl
0350 
0351 template <template <typename, typename> class Associator,
0352     typename Stream, typename Operation,
0353     typename Handler, typename DefaultCandidate>
0354 struct associator<Associator,
0355     ssl::detail::io_op<Stream, Operation, Handler>,
0356     DefaultCandidate>
0357   : Associator<Handler, DefaultCandidate>
0358 {
0359   static typename Associator<Handler, DefaultCandidate>::type get(
0360       const ssl::detail::io_op<Stream, Operation, Handler>& h) noexcept
0361   {
0362     return Associator<Handler, DefaultCandidate>::get(h.handler_);
0363   }
0364 
0365   static auto get(const ssl::detail::io_op<Stream, Operation, Handler>& h,
0366       const DefaultCandidate& c) noexcept
0367     -> decltype(Associator<Handler, DefaultCandidate>::get(h.handler_, c))
0368   {
0369     return Associator<Handler, DefaultCandidate>::get(h.handler_, c);
0370   }
0371 };
0372 
0373 } // namespace asio
0374 } // namespace boost
0375 
0376 #include <boost/asio/detail/pop_options.hpp>
0377 
0378 #endif // BOOST_ASIO_SSL_DETAIL_IO_HPP