in demo_example/asio/asio/ssl/detail/io.hpp [145:320]
void operator()(asio::error_code ec,
std::size_t bytes_transferred = ~std::size_t(0), int start = 0)
{
switch (start_ = start)
{
case 1: // Called after at least one async operation.
do
{
switch (want_ = op_(core_.engine_, ec_, bytes_transferred_))
{
case engine::want_input_and_retry:
// If the input buffer already has data in it we can pass it to the
// engine and then retry the operation immediately.
if (core_.input_.size() != 0)
{
core_.input_ = core_.engine_.put_input(core_.input_);
continue;
}
// The engine wants more data to be read from input. However, we
// cannot allow more than one read operation at a time on the
// underlying transport. The pending_read_ timer's expiry is set to
// pos_infin if a read is in progress, and neg_infin otherwise.
if (core_.expiry(core_.pending_read_) == core_.neg_infin())
{
// Prevent other read operations from being started.
core_.pending_read_.expires_at(core_.pos_infin());
ASIO_HANDLER_LOCATION((
__FILE__, __LINE__, Operation::tracking_name()));
// Start reading some data from the underlying transport.
next_layer_.async_read_some(
asio::buffer(core_.input_buffer_),
ASIO_MOVE_CAST(io_op)(*this));
}
else
{
ASIO_HANDLER_LOCATION((
__FILE__, __LINE__, Operation::tracking_name()));
// Wait until the current read operation completes.
core_.pending_read_.async_wait(ASIO_MOVE_CAST(io_op)(*this));
}
// Yield control until asynchronous operation completes. Control
// resumes at the "default:" label below.
return;
case engine::want_output_and_retry:
case engine::want_output:
// The engine wants some data to be written to the output. However, we
// cannot allow more than one write operation at a time on the
// underlying transport. The pending_write_ timer's expiry is set to
// pos_infin if a write is in progress, and neg_infin otherwise.
if (core_.expiry(core_.pending_write_) == core_.neg_infin())
{
// Prevent other write operations from being started.
core_.pending_write_.expires_at(core_.pos_infin());
ASIO_HANDLER_LOCATION((
__FILE__, __LINE__, Operation::tracking_name()));
// Start writing all the data to the underlying transport.
asio::async_write(next_layer_,
core_.engine_.get_output(core_.output_buffer_),
ASIO_MOVE_CAST(io_op)(*this));
}
else
{
ASIO_HANDLER_LOCATION((
__FILE__, __LINE__, Operation::tracking_name()));
// Wait until the current write operation completes.
core_.pending_write_.async_wait(ASIO_MOVE_CAST(io_op)(*this));
}
// Yield control until asynchronous operation completes. Control
// resumes at the "default:" label below.
return;
default:
// The SSL operation is done and we can invoke the handler, but we
// have to keep in mind that this function might be being called from
// the async operation's initiating function. In this case we're not
// allowed to call the handler directly. Instead, issue a zero-sized
// read so the handler runs "as-if" posted using io_context::post().
if (start)
{
ASIO_HANDLER_LOCATION((
__FILE__, __LINE__, Operation::tracking_name()));
next_layer_.async_read_some(
asio::buffer(core_.input_buffer_, 0),
ASIO_MOVE_CAST(io_op)(*this));
// Yield control until asynchronous operation completes. Control
// resumes at the "default:" label below.
return;
}
else
{
// Continue on to run handler directly.
break;
}
}
default:
if (bytes_transferred == ~std::size_t(0))
bytes_transferred = 0; // Timer cancellation, no data transferred.
else if (!ec_)
ec_ = ec;
switch (want_)
{
case engine::want_input_and_retry:
// Add received data to the engine's input.
core_.input_ = asio::buffer(
core_.input_buffer_, bytes_transferred);
core_.input_ = core_.engine_.put_input(core_.input_);
// Release any waiting read operations.
core_.pending_read_.expires_at(core_.neg_infin());
// Check for cancellation before continuing.
if (this->cancelled() != cancellation_type::none)
{
ec_ = asio::error::operation_aborted;
break;
}
// Try the operation again.
continue;
case engine::want_output_and_retry:
// Release any waiting write operations.
core_.pending_write_.expires_at(core_.neg_infin());
// Check for cancellation before continuing.
if (this->cancelled() != cancellation_type::none)
{
ec_ = asio::error::operation_aborted;
break;
}
// Try the operation again.
continue;
case engine::want_output:
// Release any waiting write operations.
core_.pending_write_.expires_at(core_.neg_infin());
// Fall through to call handler.
default:
// Pass the result to the handler.
op_.call_handler(handler_,
core_.engine_.map_error_code(ec_),
ec_ ? 0 : bytes_transferred_);
// Our work here is done.
return;
}
} while (!ec_);
// Operation failed. Pass the result to the handler.
op_.call_handler(handler_, core_.engine_.map_error_code(ec_), 0);
}
}