28#include <flow/error/error.hpp>
29#include <flow/util/stat/histo.hpp>
31#include <boost/array.hpp>
32#include <boost/move/unique_ptr.hpp>
33#include <boost/noncopyable.hpp>
91template<
typename Msg_resource_t>
93 private boost::noncopyable
113#ifdef IPC_DOXYGEN_ONLY
383 bool nb_read(flow::log::Logger* logger_ptr,
386 bool no_hndls,
bool* not_idle_on_would_block,
Error_code* err_code =
nullptr,
int message_flags = 0,
438template<
typename Msg_resource_t>
440 m_batch(max_msg_count),
441 m_target_payload_sz(0),
447 m_histo_raw_read_n_msgs_filtered_out(1 + (max_msg_count /
Native_socket_stream_cfg::S_STATS_HISTO_MSG_CT_BUCKET_SZ),
451 m_histo_usr_read_n_raw_reads(10, 1, 1, 1)
456template<
typename Msg_resource_t>
462 if (target_payload_size() == 0)
464 m_target_payload_sz = target_blob.size();
468 assert((target_payload_size() == target_blob.size())
469 &&
"Msg_batch_in concept requires the max message size be the same across all slots.");
483 boost::movelib::unique_ptr<msg_type_t>(
new msg_type_t{0}) };
487 m_batch.prepare_target_payload(buf_seq, std::move(msg_resource_impl), idx);
490template<
typename Msg_resource_t>
493 return m_target_payload_sz;
496template<
typename Msg_resource_t>
501 assert((idx < n_used()) &&
"Attempt by outside user to access a result in a slot that was not received-to "
502 "and/or holds no user in-message; could also be an internal bug in *this class.");
505 if (msg_resource_ptr)
508 n_rcvd = m_batch.result_payload_blob(idx, &msg_resource_impl);
513 n_rcvd = m_batch.result_payload_blob(idx);
517 &&
"Bug in *this class? Apparently gave user access to not-a-user-in-message.");
521template<
typename Msg_resource_t>
524 assert((idx < n_used()) &&
"Attempt by outside user to access a result in a slot that was not received-to; "
525 "could also be an internal bug in *this class.");
527 return m_batch.result_payload_hndl(idx);
530template<
typename Msg_resource_t>
533 return m_batch.initialized();
536template<
typename Msg_resource_t>
539 return m_batch.n_used();
542template<
typename Msg_resource_t>
545 return m_batch.full();
548template<
typename Msg_resource_t>
551 m_batch.clear_used();
554template<
typename Msg_resource_t>
556 (flow::log::Logger* logger_ptr,
559 bool no_hndls,
bool* not_idle_on_would_block,
Error_code* err_code,
int message_flags,
562 using flow::log::Sev;
566 constexpr auto MSG_TYPE_SZ =
sizeof(
msg_type_t);
568 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool, nb_read,
569 logger_ptr, peer_socket_ptr, protocol_negotiator, no_hndls,
570 not_idle_on_would_block, _1, message_flags, rcv_stats);
573 assert(not_idle_on_would_block);
581 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
583 bool not_idle_val =
false;
608 = asio_local_stream_socket::nb_read_some_with_native_handle<asio_local_stream_socket::Protocol_pkt_stream>
609 (logger_ptr, peer_socket_ptr, &hndl_or_null,
Blob_mutable{&proto_ver_as_msg_type, MSG_TYPE_SZ},
610 err_code, message_flags);
615 (*err_code == boost::asio::error::would_block) && (*not_idle_on_would_block =
false);
621 if (n_rcvd < MSG_TYPE_SZ)
624 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
625 "Native_socket_stream batch nb-read of protocol-negotiation dgram: "
626 "illegal too-short in-dgram.");
627 hndl_or_null.
close();
632 if (!hndl_or_null.
null())
634 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
635 "Native_socket_stream batch nb-read of protocol-negotiation dgram: "
636 "Expecting protocol-negotiation (first) in-dgram "
637 "to contain *only* a meta-blob: but received Native_handle is non-null which is "
639 hndl_or_null.
close();
645 assert(ok &&
"Protocol_negotiator breaking contract? Bug?");
647 &&
"Protocol_negotiator should have emitted error given intentionally bad version.");
659 assert(ok &&
"Protocol_negotiator breaking contract? Bug?");
679 const bool do_log_trace = logger_ptr && logger_ptr->should_log(Sev::S_TRACE, get_log_component());
729 bool got_a_user_msg =
false;
732 bool implied_would_block;
734 unsigned int n_iters = 0;
735 const auto orig_n_used = m_batch.n_used();
751 const auto n_used_pre_read = m_batch.n_used();
752 bool low_graceful_close;
753 size_t iter_low_lvl_bytes;
757 m_batch.nb_read(logger_ptr, peer_socket_ptr, &low_graceful_close, err_code, message_flags,
758 &iter_low_lvl_bytes);
759 assert(ok &&
"For 1st iteration we should've returned pre-loop; "
760 "for others we should've stopped the loop (b/c full()) before trying another nb-read.");
817 const auto n_used_post_read = m_batch.n_used();
825 const auto cleanup_on_error = [](
auto this_obj,
size_t orig_n_used,
size_t n_used_post_read)
827 auto& batch = this_obj->m_batch;
843 for (
auto idx = orig_n_used; idx != n_used_post_read; ++idx)
850 batch.result_payload_hndl(idx).close();
852 batch.clear_used(orig_n_used);
855 m_histo_raw_read_n_msgs.record_value(n_used_post_read - n_used_pre_read);
859 assert((n_used_post_read == n_used_pre_read) &&
"Expected low-level .nb_read() to emit error <=> no in-msgs.");
861 if ((*err_code == boost::asio::error::would_block) && got_a_user_msg)
864 FLOW_LOG_INFO(
"Native_socket_stream_batch [" << *
this <<
"]: "
865 "Native_socket_stream batch nb-read: raw nb-read got would-block in iteration 2+; but earlier "
866 "iteration got a user in-message + filled all slots + enough auto-pings to free some slot(s) "
867 "for further iteration(s). Will not emit official would-block but will stop reading due to "
868 "overall implied would-block.");
871 implied_would_block =
true;
875 implied_would_block =
false;
884 cleanup_on_error(
this, orig_n_used, n_used_post_read);
887 m_histo_raw_read_n_msgs_filtered_out.record_value(0);
890 else if (n_used_pre_read == n_used_post_read)
892 assert(low_graceful_close &&
"Basic nb_read() yielding no error but no messages must mean low_graceful_close.");
899 *err_code = boost::asio::error::eof;
900 implied_would_block =
false;
902 m_histo_raw_read_n_msgs_filtered_out.record_value(0);
908 implied_would_block = !full();
954 size_t idx_past_user_msg;
955 if (low_graceful_close)
957 idx_past_user_msg = n_used_pre_read;
967 for (idx_past_user_msg = n_used_pre_read; idx_past_user_msg != n_used_post_read; ++idx_past_user_msg)
974 const auto n_rcvd = m_batch.result_payload_blob(idx_past_user_msg, &msg_resource_impl);
975 if ((n_rcvd <= MSG_TYPE_SZ) || (*msg_resource_impl->
m_msg_type != TYPE0)
976 || (!m_batch.result_payload_hndl(idx_past_user_msg).null()))
987 for (idx_past_user_msg = n_used_pre_read; idx_past_user_msg != n_used_post_read; ++idx_past_user_msg)
999 const auto n_rcvd = m_batch.result_payload_blob(idx_past_user_msg, &msg_resource_impl);
1005 const bool got_hndl = !m_batch.result_payload_hndl(idx_past_user_msg).null();
1007 if ((n_rcvd < MSG_TYPE_SZ) || (*msg_resource_impl->
m_msg_type != TYPE0)
1008 || ((n_rcvd == MSG_TYPE_SZ) && (!got_hndl)))
1020 if (idx_past_user_msg == n_used_post_read)
1022 m_histo_raw_read_n_msgs_filtered_out.record_value(0);
1027 const auto n_user_msgs = n_used_post_read - n_used_pre_read;
1030 rcv_stats->
m_total_bytes += (iter_low_lvl_bytes - (MSG_TYPE_SZ * n_user_msgs));
1035 got_a_user_msg =
true;
1064 FLOW_LOG_TRACE_WITHOUT_CHECKING
1065 (
"Native_socket_stream_batch [" << *
this <<
"]: "
1066 "Native_socket_stream batch iteration [" << n_iters <<
"] (1-based): raw nb-read yielded 1+ in-dgrams; "
1067 "heuristic-optimization pre-check detected low-graceful-close "
1068 "and/or at least 1 non-vanilla in-dgram; therefore we must execute "
1069 "the full post-processing algorithm (that looks for auto-pings, graceful-close x 2, and illegal msgs); "
1070 "proceeding. This should NOT occur under load, with the exception of a potential 1-time graceful-close.");
1075 m_batch.reuse_result_payloads(n_used_pre_read,
1076 [
this, logger_ptr, no_hndls](
size_t idx) ->
bool
1077 {
return is_not_user_message(logger_ptr, idx, no_hndls); });
1079 const auto n_used_post_prune = m_batch.n_used();
1082 assert((n_used_post_prune <= n_used_post_read)
1083 &&
"Expected .reuse_result_payloads() to lower or not-touch .n_used().");
1084 assert((n_used_pre_read <= n_used_post_prune)
1085 &&
"Expected .reuse_result_payloads() to operate only on range [n_used_pre_read, ...).");
1087 m_histo_raw_read_n_msgs_filtered_out.record_value(n_used_post_read - n_used_post_prune);
1089 if (n_used_pre_read != n_used_post_prune)
1091 got_a_user_msg =
true;
1095 size_t rother_auto_pings = 0;
1096 for (
size_t idx = n_used_post_prune; (!*err_code) && (idx != n_used_post_read); ++idx)
1099 const auto n_rcvd = m_batch.result_payload_blob(idx, &msg_resource_impl);
1100 if (n_rcvd < MSG_TYPE_SZ)
1104 cleanup_on_error(
this, orig_n_used, n_used_post_read);
1105 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
1106 "Native_socket_stream batch nb-read post-post-processing scan of slot [" << idx <<
"]: "
1107 "illegal too-short in-dgram.");
1112 const auto& msg_type = *msg_resource_impl->
m_msg_type;
1113 if (msg_type == PING)
1115 if ((n_rcvd != MSG_TYPE_SZ) || (!m_batch.result_payload_hndl(idx).null()))
1119 cleanup_on_error(
this, orig_n_used, n_used_post_read);
1120 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
1121 "Native_socket_stream batch nb-read post-post-processing scan of slot [" << idx <<
"]: "
1122 "illegal auto-ping-like in-dgram: "
1123 "contains blob payload sized [" << (n_rcvd - MSG_TYPE_SZ) <<
"] and/or "
1124 "native-handle [" << m_batch.result_payload_hndl(idx) <<
"].");
1128 ++rother_auto_pings;
1134 if (msg_type != TYPE0)
1138 cleanup_on_error(
this, orig_n_used, n_used_post_read);
1139 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
1140 "Native_socket_stream batch nb-read post-post-processing scan of slot [" << idx <<
"]: "
1141 "illegal in-dgram with unexpected msg-type value [" << msg_type <<
"].");
1152 if ((!no_hndls) || m_batch.result_payload_hndl(idx).null())
1172 FLOW_LOG_INFO(
"Native_socket_stream_batch [" << *
this <<
"]: "
1173 "Native_socket_stream batch nb-read post-post-processing scan of slot [" << idx <<
"]: "
1174 "got NSS-protocol graceful-close.");
1179 cleanup_on_error(
this, orig_n_used, n_used_post_read);
1180 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
1181 "Native_socket_stream batch nb-read post-post-processing scan of slot [" << idx <<
"]: "
1182 "illegal in-dgram contains only a native handle "
1183 "[" << m_batch.result_payload_hndl(idx) <<
"], but handles unexpected in this channel.");
1189 if ((!*err_code) && low_graceful_close)
1192 *err_code = boost::asio::error::eof;
1204 else if ((!*err_code) && implied_would_block && (!got_a_user_msg))
1208 FLOW_LOG_TRACE_WITHOUT_CHECKING
1209 (
"Native_socket_stream_batch [" << *
this <<
"]: "
1210 "Native_socket_stream batch nb-read: raw nb-read got 0 user in-messages but 1+ auto-pings, "
1211 "with empty slots available (implied would-block); and 0 user in-messages in any preceding "
1212 "iterations also. Since pings are ignorable, this amounts to overall actual would-block; "
1215 *err_code = boost::asio::error::would_block;
1216 implied_would_block =
false;
1241 if (rcv_stats && ((!*err_code)
1243 || (*err_code == boost::asio::error::would_block)
1244 || (*err_code == boost::asio::error::eof)))
1246 const auto n_rother = n_used_post_read - n_used_post_prune;
1247 const auto rother_low_lvl_bytes = n_rother * MSG_TYPE_SZ;
1248 const auto n_ruser = n_used_post_prune - n_used_pre_read;
1255 rcv_stats->
m_total_bytes += ((iter_low_lvl_bytes - rother_low_lvl_bytes) - (MSG_TYPE_SZ * n_ruser));
1271 for ( ; idx_past_user_msg != n_used_post_prune; ++idx_past_user_msg)
1273 rcv_stats->
m_histo_payload_sz.record_value(m_batch.result_payload_blob(idx_past_user_msg) - MSG_TYPE_SZ);
1275 (!no_hndls) && (!m_batch.result_payload_hndl(idx_past_user_msg).null())
1289 while ((!implied_would_block) && (!*err_code) && (!full()));
1291 m_histo_usr_read_n_raw_reads.record_value(n_iters);
1295 FLOW_LOG_TRACE_WITHOUT_CHECKING
1296 (
"Native_socket_stream_batch [" << *
this <<
"]: "
1297 "Native_socket_stream batch nb-read, after iteration, stopped for one of these reasons: "
1298 "implied would-block? = [" << implied_would_block <<
"]; "
1299 "error/would-block [" << *err_code <<
"] [" << err_code->message() <<
"]; "
1300 "all slots filled? = [" << full() <<
"].");
1304 (*err_code == boost::asio::error::would_block) && (*not_idle_on_would_block = not_idle_val);
1309 if (logger_ptr && logger_ptr->should_log(STATS_SEV, get_log_component()))
1311 using boost::chrono::milliseconds;
1312 using boost::chrono::round;
1313 using flow::Fine_clock;
1316 const Native_handle peer_hndl{peer_socket_ptr->native_handle()};
1317 const auto now = Fine_clock::now();
1319 if (m_stats_next_output_when.time_since_epoch() == Fine_duration::zero())
1322 FLOW_LOG_WITHOUT_CHECKING
1324 "STATS: Native_socket_stream_batch [" << *
this <<
'/' << peer_hndl <<
"]: "
1325 "First log checkpt; next real one shall be in "
1326 "[" << round<milliseconds>(m_stats_next_output_when - now) <<
"].");
1328 else if (now >= m_stats_next_output_when)
1330 const auto since_last_checkpt = round<milliseconds>((now - m_stats_next_output_when)
1333 FLOW_LOG_WITHOUT_CHECKING
1335 "STATS: Native_socket_stream_batch [" << *
this <<
'/' << peer_hndl <<
"]: "
1336 "Since last log [" << since_last_checkpt <<
"]: "
1337 "Histogram: # raw in-dgrams from each raw batch-recv: "
1338 "[" << m_histo_raw_read_n_msgs <<
"].");
1339 FLOW_LOG_WITHOUT_CHECKING
1341 "STATS: Native_socket_stream_batch [" << *
this <<
'/' << peer_hndl <<
"]: "
1342 "Since last log [" << since_last_checkpt <<
"]: "
1343 "Histogram: # ping/close/bad in-dgrams from each raw batch-recv: "
1344 "[" << m_histo_raw_read_n_msgs_filtered_out <<
"].");
1345 FLOW_LOG_WITHOUT_CHECKING
1347 "STATS: Native_socket_stream_batch [" << *
this <<
'/' << peer_hndl <<
"]: "
1348 "Since last log [" << since_last_checkpt <<
"]: "
1349 "Histogram: # raw batch-recvs from each higher-lvl batch-recv: "
1350 "[" << m_histo_usr_read_n_raw_reads <<
"].");
1354 else if (do_log_trace)
1356 FLOW_LOG_TRACE_WITHOUT_CHECKING
1357 (
"STATS: Native_socket_stream_batch [" << *
this <<
'/' << peer_hndl <<
"]: "
1358 "Between checkpts; next one shall be in "
1359 "[" << round<milliseconds>(m_stats_next_output_when - now) <<
"].");
1367template<
typename Msg_resource_t>
1369 size_t idx,
bool no_hndls)
const
1372 constexpr auto MSG_TYPE_SZ =
sizeof(
msg_type_t);
1383 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
1391 if (n_rcvd < MSG_TYPE_SZ)
1393 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
1394 "Native_socket_stream batch nb-read post-processing slot [" << idx <<
"]: "
1395 "illegal in-dgram of only [" << n_rcvd <<
"] bytes.");
1408 if (n_rcvd != MSG_TYPE_SZ)
1412 if (m_batch.result_payload_hndl(idx).null()
1418 FLOW_LOG_WARNING(
"Native_socket_stream_batch [" << *
this <<
"]: "
1419 "Native_socket_stream batch nb-read post-processing slot [" << idx <<
"]: "
1420 "illegal in-dgram contains a native handle, but we were instructed that is illegal in this "
1428 if ((!no_hndls) && (!m_batch.result_payload_hndl(idx).null()))
1435 (
"Native_socket_stream_batch [" << *
this <<
"]: "
1436 "Native_socket_stream batch nb-read post-processing slot [" << idx <<
"]: "
1437 "in-dgram (msg-type 0x0) contains graceful-close, or else it contains only a native handle, but "
1438 "we were instructed handles are illegal in this channel (will emit the proper error code "
1445 (
"Native_socket_stream_batch [" << *
this <<
"]: "
1446 "Native_socket_stream batch nb-read post-processing slot [" << idx <<
"]: "
1447 "(msg-type [" << *msg_resource_impl->
m_msg_type <<
"]): "
1448 "either auto-ping or unknown-type or illegal auto-ping-like in-dgram (if 1 of the latter 2: "
1449 "will emit error).");
1453template<
typename Msg_resource_t>
1456 *os <<
"Nss[blob_sz[" << target_payload_size() <<
"] " << m_batch <<
']';
1460template<
typename Msg_resource_t>
1461const flow::util::stat::Histogram_counter&
1464 return m_histo_raw_read_n_msgs;
1467template<
typename Msg_resource_t>
1468const flow::util::stat::Histogram_counter&
1471 return m_histo_raw_read_n_msgs_filtered_out;
1474template<
typename Msg_resource_t>
1475const flow::util::stat::Histogram_counter&
1478 return m_histo_usr_read_n_raw_reads;
1481template<
typename Msg_resource_t>
Grouping of compile-type config/knobs (such as type aliases, constants) governing some of the behavio...
static constexpr bool S_STATS_LOG_ENABLED
Whether to periodically log various statistics about Native_socket_stream.
static constexpr flow::log::Sev S_STATS_LOG_SEV
If S_STATS_LOG_ENABLED: the log severity for stats output.
static constexpr util::Fine_duration S_STATS_LOG_PERIOD
If S_STATS_LOG_ENABLED: how often to output stats via logs.
uint16_t low_lvl_payload_blob_length_t
The type used to encode the internal meta-blob length/type-indicator for sync_io::Native_socket_strea...
static constexpr low_lvl_payload_blob_length_t S_PING_SENTINEL
For sync_io::Native_socket_stream and derivative(s): Value for the length/type-indicator field in eac...
Msg_batch_in concept implementation for at least sync_io::Native_socket_stream (as taken by APIs Nati...
const flow::util::stat::Histogram_counter & histo_raw_read_n_msgs() const
Stats: Histogram tracking how many raw in-dgrams were received by each raw OS batch-read (recvmmsg() ...
bool initialized() const
Identical to Generic_msg_batch_in.
bool full() const
Identical to Generic_msg_batch_in.
void prepare_target_payload(const Mutable_buffer_sequence &target_blob, Msg_resource &&msg_resource, size_t idx=-1)
Identical to Generic_msg_batch_in.
Msg_resource_t Msg_resource
Alias for template param Msg_resource_t.
void clear_used()
Identical to Generic_msg_batch_in.
bool is_not_user_message(flow::log::Logger *logger_ptr, size_t idx, bool no_hndls) const
nb_read() helper: Checks in-dgram at given index, returning true if and only if the dgram represents ...
bool nb_read(flow::log::Logger *logger_ptr, asio_local_stream_socket::Peer_socket< asio_local_stream_socket::Protocol_pkt_stream > *peer_socket_ptr, Protocol_negotiator *protocol_negotiator, bool no_hndls, bool *not_idle_on_would_block, Error_code *err_code=nullptr, int message_flags=0, stat::Blob_rcv_stats *rcv_stats=nullptr)
The API for the receiver-engine (sync_io::Native_socket_stream) to perform the core batch-receive.
boost::array< util::Blob_mutable, 2 > Mutable_buffer_sequence_impl
Scatter/gather structure subsuming the user's "big" Blob_mutable preceded by our internal-needs tiny ...
const flow::util::stat::Histogram_counter & histo_raw_read_n_msgs_filtered_out() const
Stats: Histogram tracking how many of the in-dgrams counted by histo_raw_read_n_msgs() were then filt...
Native_socket_stream_cfg::low_lvl_payload_blob_length_t msg_type_t
Alias (for more accurate naming in context; brevity) for type of the message-type internal field,...
size_t n_used() const
Identical to Generic_msg_batch_in.
size_t target_payload_size() const
Identical to Generic_msg_batch_in.
Native_handle result_payload_hndl(size_t idx) const
Identical to Generic_msg_batch_in, except idx >= n_used() is undefined behavior (assertion may trip).
void to_ostream(std::ostream *os) const
Identical to Generic_msg_batch_in.
util::Fine_time_pt m_stats_next_output_when
The results in m_histo_raw_read_n_msgs et al shall be logged opportunistically inside nb_read() once ...
const flow::util::stat::Histogram_counter & histo_usr_read_n_raw_reads() const
Stats: Histogram tracking how many OS batch-reads (recvmmsg() in Linux) resulted from each Native_soc...
~Native_socket_stream_msg_batch_in()
Clears all resources – including any Msg_resource currently attached to any receive-slot.
flow::util::stat::Histogram_counter m_histo_raw_read_n_msgs_filtered_out
See histo_raw_read_n_msgs_filtered_out().
Native_socket_stream_msg_batch_in(size_t max_msg_count)
Identical to ctor of Generic_msg_batch_in.
asio_local_stream_socket::Msg_batch_in< Mutable_buffer_sequence_impl, Msg_resource_impl > m_batch
The natively-batched batch containing target buffer(s) from the user plus a bit of added buffer-age o...
util::Blob_mutable Mutable_buffer_sequence
Buffer(s) description type (conforming to boost.asio MutableBufferSequence concept) supported by *thi...
size_t m_target_payload_sz
Determined permanently by the first prepare_target_payload(), this is the max size in bytes of each i...
size_t result_payload_blob(size_t idx, Msg_resource **msg_resource_ptr=nullptr)
Identical to Generic_msg_batch_in, except idx >= n_used() is undefined behavior (assertion may trip).
flow::util::stat::Histogram_counter m_histo_usr_read_n_raw_reads
See histo_usr_read_n_raw_reads().
flow::util::stat::Histogram_counter m_histo_raw_read_n_msgs
See histo_raw_read_n_msgs().
A simple state machine that, assuming the opposing side of a comm pathway uses an equivalent state ma...
int16_t proto_ver_t
Type sufficient to store a protocol version; positive values identify newer versions of a protocol; w...
bool compute_negotiated_proto_ver(proto_ver_t opposing_max_proto_ver, Error_code *err_code=nullptr)
Based on the presumably-just-received-from-opposing-side value of their local_max_proto_ver,...
proto_ver_t negotiated_proto_ver() const
Returns S_VER_UNKNOWN before compute_negotiated_proto_ver(); then either the positive version of the ...
static constexpr proto_ver_t S_VER_UNKNOWN
A proto_ver_t value, namely a negative one, which is a reserved value indicating "unknown version"; i...
Similarly to the transport::Msg_batch_in concept (as taken by API {Blob|Native_handle}_receiver::asyn...
typename Protocol::socket Peer_socket
Short-hand for boost.asio Unix domain peer stream-socket (usually-connected-or-empty guy).
@ S_LOW_LVL_INTERNAL_PROTOCOL_INVALID_HEADER
Unable to receive incoming traffic: Opposing side sent invalid internal per-message header.
@ S_RECEIVES_FINISHED_CANNOT_RECEIVE
Will not receive message: opposing user sent graceful-close via API.
@ S_BLOB_RECEIVER_GOT_NON_BLOB
User protocol-code mismatch: local user expected blob only and no native handle; received at least th...
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
std::ostream & operator<<(std::ostream &os, const Generic_msg_batch_in< Msg_resource_t, NO_HNDLS > &val)
Prints string representation of the given Generic_msg_batch_in to the given ostream.
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::Fine_time_pt Fine_time_pt
Short-hand for Flow's Fine_time_pt.
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
The Msg_resource type attached to each slot of our internal m_batch.
Msg_resource m_msg_resource
Per-slot resource moved from user's object via prepare_target_payload().
boost::movelib::unique_ptr< msg_type_t > m_msg_type
This slot's potential/actual in-dgram's message-type field, where the actual OS receive-batch call sh...
This is the friend facade of Native_socket_stream_msg_batch_in that exposes private APIs hidden from ...
Cumulative stats from the incoming-direction (receive) pipe of a Blob_receiver or Native_handle_recei...
uint64_t m_total_bytes
Total user blob bytes received (sum of in-message blob sizes).
uint64_t m_total_msgs
Total user messages fully received and delivered.
uint64_t m_total_low_lvl_bytes
Total low-level bytes received (user blob bytes plus protocol headers and framing).
uint64_t m_msgs_with_hndls
Number of messages received that carried at least one native handle. Currently at most 1 handle per m...
uint64_t m_auto_pings
Number of auto-pings received from the opposing sender.
flow::util::stat::Histogram_counter m_histo_payload_sz
Payload-size histogram for received user messages.
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.
constexpr bool null() const noexcept
Returns true if and only if m_native_handle equals S_NULL_HANDLE.
void close() noexcept
Little utility that returns m_native_handle to the OS.