25#include <flow/error/error.hpp>
26#include <flow/util/util_fwd.hpp>
35template<
typename Msg_resource>
37 bool assume_would_block,
39 flow::async::Task_asio_err&& on_done_func)
41 return async_receive_batch_impl<Native_handle_batch_in<Msg_resource>,
false>
42 (batch, assume_would_block, sync_err_code, std::move(on_done_func));
45template<
typename Msg_resource>
47 bool assume_would_block,
49 flow::async::Task_asio_err&& on_done_func)
51 return async_receive_batch_impl<Blob_batch_in<Msg_resource>,
true>
52 (batch, assume_would_block, sync_err_code, std::move(on_done_func));
55template<
typename Batch,
bool NO_HNDLS>
57 bool assume_would_block,
59 flow::async::Task_asio_err&& on_done_func)
61 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool,
62 (async_receive_batch_impl<Batch, NO_HNDLS>),
63 batch, assume_would_block, _1, std::move(on_done_func));
65 auto& sync_err_code = *err_code;
67 assert(!on_done_func.empty());
70 if ((!op_started<Op::S_RCV>(
"async_receive_batch_impl()"))
71 || (!
state_peer(
"async_receive_batch_impl()")))
78 FLOW_LOG_WARNING(
"Socket stream [" << *
this <<
"]: Async-receive-batch for in-batch [" << *batch <<
"] "
79 "requested, but a preceding request is still in progress; the message has not arrived yet. "
80 "Likely a user error, but who are we to judge? Ignoring.");
86 FLOW_LOG_WARNING(
"Socket stream [" << *
this <<
"]: "
87 "User async-receive-batch for in-batch [" << *batch <<
"] requested: "
88 "Error already encountered earlier. Emitting via sync-args. Note this is not necessarily "
89 "the user acting oddly; in batch-receive case it is normal to detect an error like "
90 "graceful-close just after 1+ user in-messages -- in which case we cache the error but "
91 "emit the message(s) plus success; so we might be emitting the cached error now.");
98 if (!batch->initialized())
100 FLOW_LOG_WARNING(
"Socket stream [" << *
this <<
"]: Async-receive-batch for in-batch [" << *batch <<
"] "
101 "requested, but batch object is not initialized() (not all slots have been "
102 "prepare_target_payload()ed); emitting INVALID_ARGUMENT.");
109 FLOW_LOG_WARNING(
"Socket stream [" << *
this <<
"]: Async-receive-batch for in-batch [" << *batch <<
"] "
110 "requested, but batch object is already full; emitting INVALID_ARGUMENT.");
119 FLOW_LOG_TRACE(
"Socket stream [" << *
this <<
"]: User async-receive-batch (natively) request "
120 "for in-batch [" << *batch <<
"]; native-handles allowed? = [" << (!NO_HNDLS) <<
"]; "
121 "assume initial would-block? = [" << assume_would_block <<
"].");
127 rcv_read_batch_from_pkt_stream<Batch>(batch, assume_would_block, &sync_err_code);
131 FLOW_LOG_TRACE(
"Async-request for in-batch [" << *batch <<
"] completed synchronously (result "
132 "[" << sync_err_code <<
"] [" << sync_err_code.message() <<
"]); emitting synchronously and "
133 "disregarding handler.");
140 async_receive_batch_emulation<NO_HNDLS>(get_logger(), batch, assume_would_block,
141 &sync_err_code, std::move(on_done_func),
142 [
this](
auto&&... args)
144 if constexpr(NO_HNDLS)
160 rcv_log_stats(
"async_receive_batch_impl(): while sync-processing rcv-pipe hosed");
166template<
typename Batch>
168 bool assume_would_block,
173 using flow::util::Lock_guard;
177 &&
"@todo Really this function should be made to not compile in this case, and this then should be "
178 "static_assert() rather than run-time.");
199 if (assume_would_block)
210 FLOW_LOG_TRACE(
"Got nothing but would-block (pre-assumed) for in-batch [" << *batch <<
"]. "
211 "Awaiting readability.");
215 rcv_on_ev_peer_socket_pkt_stream_batch_readable_or_error<Batch>(batch);
221 bool not_idle_on_would_block;
222 auto n_rcvd_or_zero = batch->n_used();
231 assert(ok &&
"By contract, do not pass us an already-full batch object; we should have already emitted "
232 "INVALID_ARGUMENT without calling this.");
233 n_rcvd_or_zero = batch->n_used() - n_rcvd_or_zero;
236 &&
"By contract, do not pass us an un-initialized() batch object; we should have already emitted "
237 "INVALID_ARGUMENT without calling this.");
254 assert(n_rcvd_or_zero == 0);
256 FLOW_LOG_TRACE(
"Got nothing but would-block for in-batch [" << *batch <<
"]. Awaiting readability.");
266 boost::make_shared<Task>([
this, batch]()
268 rcv_on_ev_peer_socket_pkt_stream_batch_readable_or_error<Batch>(batch);
278 if (not_idle_on_would_block)
332 &&
"m_peer_socket_hosed must start as null and only become non-null once. Bug?");
334 assert((!
m_peer_socket) &&
"Shocking unique_ptr misbehavior!");
367 if (n_rcvd_or_zero == 0)
373 FLOW_LOG_TRACE(
"Socket stream [" << *
this <<
"]: User async-receive-batch request "
374 "for in-batch [" << *batch <<
"]; native-handles allowed? = "
376 "Batch-read encountered error "
378 "[" << n_rcvd_or_zero <<
"] user in-dgrams; as advertised will emit success + "
379 "the messages but cache the error to immediately emit to the next async-receive.");
380 sync_err_code->clear();
390 assert(n_rcvd_or_zero != 0);
393 sync_err_code->clear();
401 FLOW_LOG_WARNING(
"Socket stream [" << *
this <<
"]: "
402 "User async-receive-batch request for in-batch [" << *batch <<
"]: "
403 "was about to batch-read but discovered opposite-direction socket-hosing error; "
410template<
typename Batch>
415 &&
"@todo Really this function should be made to not compile in this case, and this then should be "
416 "static_assert() rather than run-time.");
420 FLOW_LOG_WARNING(
"Socket stream [" << *
this <<
"]: User's wait-for-readable finished (readable or error, "
421 "we do not know which yet); would resume processing depending on what we were doing before; "
422 "however an error was detected in the meantime (as of this writing: idle timeout). "
423 "Stopping read chain (batch); in-batch [" << *batch <<
"].");
425 &&
"If rcv-error emitted during low-level async-wait, we should have fed it to any pending async-receive.");
435 FLOW_LOG_TRACE(
"Socket stream [" << *
this <<
"]: User-performed wait-for-readable finished (readable or error, "
436 "we do not know which yet). Retrying to resume read chain (batch); in-batch [" << *batch <<
"].");
438 rcv_read_batch_from_pkt_stream<Batch>(batch,
false, &sync_err_code);
451 rcv_log_stats(
"rcv_on_ev_peer_socket_pkt_stream_batch_readable_or_error(): "
452 "while processing ev-ready rcv-pipe hosed");
455 FLOW_LOG_TRACE(
"Socket stream [" << *
this <<
"]: Async-op (batch) result for in-batch [" << *batch <<
"] "
456 "ready after successful async-wait. Executing handler now.");
462 on_done_func(sync_err_code);
463 FLOW_LOG_TRACE(
"Socket stream [" << *
this <<
"]: Handler completed for in-batch [" << *batch <<
"].");
static constexpr bool S_USE_OS_DGRAM_BATCH_SUPPORT
Whether the OS provides, and we shall use for sync_io::Native_socket_stream and derivative(s),...
static constexpr bool S_USE_OS_DGRAM_SUPPORT
Whether the OS provides, and we shall use for sync_io::Native_socket_stream and derivative(s),...
util::sync_io::Event_wait_func m_rcv_ev_wait_func
Function (set forever in start_receive_*_ops()) through which we invoke the outside event loop's asyn...
decltype(m_peer_socket) m_peer_socket_hosed
Null to start, this takes on the value from m_peer_socket when and only when m_peer_socket is nullifi...
std::optional< Rcv_user_request > m_rcv_user_request
Null if no single-message async-receive request is currently pending; else describes the arguments to...
void rcv_on_ev_peer_socket_pkt_stream_batch_readable_or_error(Batch *batch)
Completion handler, from outside event loop via sync_io pattern, for the async-wait initiated by the ...
bool async_receive_blob_batch(Blob_batch_in< Msg_resource > *batch, bool assume_would_block, Error_code *sync_err_code, flow::async::Task_asio_err &&on_done_func)
See Native_socket_stream counterpart.
void rcv_read_batch_from_pkt_stream(Batch *batch, bool assume_would_block, Error_code *sync_err_code)
Conceptually similar to rcv_read_msg_from_pkt_stream() but tries to read not at-most-1 in-message but...
util::sync_io::Asio_waitable_native_handle m_ev_wait_hndl_peer_socket
Descriptor waitable by outside event loop async-waits – storing the same Native_handle as (and thus b...
std::conditional_t< Native_socket_stream_cfg::S_USE_OS_DGRAM_SUPPORT &&Native_socket_stream_cfg::S_USE_OS_DGRAM_BATCH_SUPPORT, Native_socket_stream_msg_batch_in< Msg_resource >, Generic_msg_batch_in< Msg_resource, true > > Blob_batch_in
See Native_socket_stream counterpart / sync_io::Blob_receiver::Blob_batch_in.
boost::movelib::unique_ptr< asio_local_stream_socket::Peer_socket< Native_socket_stream_cfg::Protocol > > m_peer_socket
The peer Unix domain socket; or null pointer if we've detected the connection has become hosed and he...
bool state_peer(util::String_view context) const
Checks whether m_state has reached State::S_PEER; if so returns true; if not logs WARNING and returns...
flow::util::Mutex_non_recursive m_peer_socket_mutex
Protects m_peer_socket and its bros m_ev_wait_hndl_peer_socket and m_peer_socket_hosed.
std::optional< Rcv_user_batch_request > m_rcv_user_batch_request
Null if no native async-batch-receive request is currently pending; else describes the arguments to t...
Protocol_negotiator m_protocol_negotiator
Handles the protocol negotiation at the start of the pipe.
void async_receive_core(Native_handle *target_hndl_or_null, bool assume_would_block, const util::Blob_mutable &target_meta_blob, Error_code *sync_err_code, size_t *sync_sz, flow::async::Task_asio_err_sz &&on_done_func_or_none)
Core of either async_receive_impl() (if user invoked single-message receiving directly) or the functi...
Error_code m_rcv_pending_err_code
The first and only connection-hosing error condition detected when attempting to low-level-read on m_...
void rcv_not_idle()
No-ops if idle_timer_run() is not engaged; otherwise reacts to non-idleness of the in-pipe by resched...
bool async_receive_batch_impl(Batch *batch, bool assume_would_block, Error_code *sync_err_code, flow::async::Task_asio_err &&on_done_func)
Body of both async_receive_native_handle_batch() and async_receive_blob_batch().
void rcv_log_stats(util::String_view context) const
INFO-logs current rcv-half stats: as log_stats() but callable from receive-op context (see "Which hal...
bool async_receive_native_handle_batch(Native_handle_batch_in< Msg_resource > *batch, bool assume_would_block, Error_code *sync_err_code, flow::async::Task_asio_err &&on_done_func)
See Native_socket_stream counterpart.
std::conditional_t< Native_socket_stream_cfg::S_USE_OS_DGRAM_SUPPORT &&Native_socket_stream_cfg::S_USE_OS_DGRAM_BATCH_SUPPORT, Native_socket_stream_msg_batch_in< Msg_resource >, Generic_msg_batch_in< Msg_resource, false > > Native_handle_batch_in
See Native_socket_stream counterpart.
stat::Blob_rcv_stats m_rcv_stats
Incoming-direction (receive-pipe) stats.
@ S_LOW_LVL_TRANSPORT_HOSED_CANNOT_RECEIVE
Unable to receive incoming traffic: an earlier-reported, or at least logged, system error had hosed t...
@ S_SYNC_IO_WOULD_BLOCK
A sync_io operation could not immediately complete; it will complete contingent on active async-wait ...
@ S_RECEIVES_FINISHED_CANNOT_RECEIVE
Will not receive message: opposing user sent graceful-close via API.
@ S_INVALID_ARGUMENT
User called an API with 1 or more arguments against the API spec.
@ S_MESSAGE_SIZE_EXCEEDS_USER_STORAGE
User protocol-code mismatch: local user-provided storage cannot fit entire message received from oppo...
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
flow::async::Task Task
Short-hand for polymorphic function (a-la std::function<>) that takes no arguments and returns nothin...
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
This is the friend facade of Native_socket_stream_msg_batch_in that exposes private APIs hidden from ...
bool nb_read(Args &&... args)
Forwards to same-named (private) privileged-API of Base.