29#include "ipc/transport/struc/schema/detail/structured_msg.capnp.h"
39#include <flow/error/error.hpp>
40#include <boost/endian.hpp>
41#include <boost/move/make_unique.hpp>
111 kj::ArrayPtr<::capnp::word>
allocateSegment(
unsigned int min_sz_words)
override;
146 private kj::ArrayPtr<const ::capnp::word>,
147 public ::capnp::SegmentArrayMessageReader
338template<
typename Body_t,
typename Builder_t>
664 template<
typename... Load_mdt_args>
666 const typename Builder::Session& session,
667 Error_code* err_code, Load_mdt_args&&... load_mdt_args);
796template<
typename Body_t,
typename Reader_config_t>
798 private boost::noncopyable
930 using Mdt = schema::detail::StructuredMessage;
1208#define TEMPLATE_STRUCT_MSG_OUT \
1209 template<typename Body_t, typename Builder_t>
1211#define CLASS_STRUCT_MSG_OUT \
1212 Msg_out<Body_t, Builder_t>
1214#define TEMPLATE_STRUCT_MSG_IN \
1215 template<typename Body_t, typename Reader_config_t>
1217#define CLASS_STRUCT_MSG_IN \
1218 Msg_in<Body_t, Reader_config_t>
1223CLASS_STRUCT_MSG_OUT::Msg_out() :
1224 m_body_root(nullptr)
1230CLASS_STRUCT_MSG_OUT::Msg_out
1242CLASS_STRUCT_MSG_OUT::Msg_out(
Builder&& struct_builder) :
1251 m_builder(std::move(struct_builder)),
1252 m_body_root(m_builder.payload_msg_builder()->template getRoot<
Body>())
1258CLASS_STRUCT_MSG_OUT::Msg_out(
Msg_out&&) =
default;
1261CLASS_STRUCT_MSG_OUT::~Msg_out() =
default;
1283typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root()
1285 return &m_body_root;
1289const typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root()
const
1291 return const_cast<Msg_out*
>(
this)->body_root();
1295typename CLASS_STRUCT_MSG_OUT::Orphanage CLASS_STRUCT_MSG_OUT::orphanage()
1297 return m_builder.payload_msg_builder()->getOrphanage();
1303void CLASS_STRUCT_MSG_OUT::store_native_handle_or_null(
Native_handle&& native_handle_or_null)
1305 if (native_handle_or_null == m_hndl_or_null.get())
1308 native_handle_or_null = {};
1313 m_hndl_or_null.reset(std::move(native_handle_or_null));
1319 return m_hndl_or_null.get();
1323template<
typename... Load_mdt_args>
1326 const typename Builder::Session& session,
1327 Error_code* err_code, Load_mdt_args&&... load_mdt_args)
1331 using boost::movelib::make_unique;
1335 auto& segs_out = *segs_out_ptr;
1347 m_builder.emit_serialization(segs_out_ptr, &hdr_blob, &split_segs, session, err_code);
1354 const auto n_segs = segs_out.size();
1355 assert(n_segs != 0);
1357 if (hdr_blob.size() < HDR_SZ)
1367 m_mdt_builder = make_unique<Capped_sz_capnp_message_builder>
1372 if (!
struc::load_mdt(m_mdt_builder.get(),
nullptr, err_code, std::forward<Load_mdt_args>(load_mdt_args)...,
1374 split_segs.empty() ?
nullptr : &split_segs))
1379 m_mdt_builder = make_unique<Capped_sz_capnp_message_builder>
1385 struc::load_mdt(m_mdt_builder.get(),
nullptr, err_code, std::forward<Load_mdt_args>(load_mdt_args)...,
1387 split_segs.empty() ?
nullptr : &split_segs);
1388 assert(ok &&
"We've made a fresh *m_mdt_builder, so there should be no reason it would fail.");
1396 if (split_segs_out_or_null)
1401 *split_segs_out_or_null = std::move(split_segs);
1428 if (split_segs_out_or_null)
1430 *split_segs_out_or_null = std::move(split_segs);
1437 auto& seg1 = segs_out.front();
1438 seg1 =
Blob_const{hdr_blob.data(), hdr_blob.size() + seg1.size()};
1442void CLASS_STRUCT_MSG_OUT::to_ostream(std::ostream* os_ptr)
const
1447 os <<
"[n_serialization_segs[" << m_builder.n_serialization_segments() <<
"] ";
1449 const auto hndl_or_null = native_handle_or_null();
1450 if (!hndl_or_null.null())
1453 os << hndl_or_null <<
' ';
1460template<
typename Body_t,
typename Struct_builder_t>
1473 m_body_reader(struct_reader_config),
1474 m_mdt_deserialized_ok(false),
1475 m_body_deserialized_ok(false)
1482void CLASS_STRUCT_MSG_IN::store_native_handle_or_null(
Native_handle&& native_handle_or_null)
1484 assert(m_hndl_or_null.get().null() &&
"Call this at most once (probably upon finalizing 1st segment as well).");
1486 m_hndl_or_null.reset(std::move(native_handle_or_null));
1490CLASS_STRUCT_MSG_IN::~Msg_in() =
default;
1495 assert((!m_body_deserialized_ok)
1496 &&
"Do not call add_serialization_segment() after both deserialize_*().");
1498 m_total_sz += blob.size();
1500 if (!m_mdt_header_area.data())
1504 m_mdt_header_area = blob.const_buffer();
1511 assert((blob.start() == 0)
1512 &&
"We haven't chged start() yet; why is it framing something already? Bug?");
1526 blob.start_past_prefix(std::min(
size_t(HDR_SZ), blob.size()));
1530 m_body_reader.add_serialization_segment(std::move(blob));
1534size_t CLASS_STRUCT_MSG_IN::serialization_size()
const
1540size_t CLASS_STRUCT_MSG_IN::deserialize_mdt(flow::log::Logger* logger_ptr,
Error_code* err_code,
1544 using flow::util::ostream_op_string;
1545 using boost::endian::little_to_native;
1546 using std::exception;
1552 assert(stats_rcv_msg_internal_only &&
"For code simplicity we assume this is always of interest for now.");
1553 assert((!m_mdt_reader) &&
"Do not call deserialize_mdt() after it returns.");
1554 assert(m_mdt_header_area.data()
1555 &&
"Do not call deserialize_mdt() unless you've called add_serialization_segment() once.");
1564 auto& msg_if_internal = *stats_rcv_msg_internal_only;
1601 const auto error_out = [&](
String_view msg) ->
size_t
1604 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
1605 FLOW_LOG_WARNING(msg);
1609 m_mdt_deserialized_ok =
false;
1613 m_mdt_deserialized_ok =
true;
1617 m_mdt_reader.emplace(m_mdt_header_area);
1622 m_mdt_root = m_mdt_reader->getRoot<
Mdt>();
1624 catch (
const exception& exc)
1626 return error_out(ostream_op_string(
"In-mdt-header could not be capnp-deserialized; capnp threw exception [",
1627 exc.what(),
"]. Other side misbehaved?"));
1641 if (!m_mdt_root.hasAuthHeader())
1643 return error_out(
"In-mdt-header has null .authHeader. Other side misbehaved?");
1646 const auto auth_header = m_mdt_root.getAuthHeader();
1648 if (!auth_header.hasSessionToken())
1650 return error_out(
"In-mdt-header has null .authHeader.sessionToken. Other side misbehaved?");
1654 const auto capnp_uuid = auth_header.getSessionToken();
1655 static_assert(
decltype(m_session_token)::static_size() == 2 *
sizeof(uint64_t),
1656 "World is broken: UUIDs expected to be 16 bytes!");
1657 const uint64_t first8 = little_to_native(capnp_uuid.getFirst8());
1658 const uint64_t last8 = little_to_native(capnp_uuid.getLast8());
1659 memcpy(m_session_token.data(), &first8,
sizeof(first8));
1660 memcpy(m_session_token.data() +
sizeof(first8), &last8,
sizeof(last8));
1662 const auto id_or_0 = id_or_none();
1663 if (m_mdt_root.isInternalMessageBody())
1667 return error_out(
"In-mdt-header top union specifies .internalMessageBody; but .id=/=0, the sentinel value. "
1668 "Other side misbehaved?");
1679 ++msg_if_internal.m_internal_msgs;
1680 ++msg_if_internal.m_single_segment_msgs;
1681 ++msg_if_internal.m_total_segments;
1682 ++msg_if_internal.m_total_low_lvl_blobs;
1683 msg_if_internal.m_histo_msg_sz.record_value(m_total_sz);
1693 return error_out(
"In-mdt-header top union specifies no .internalMessageBody; but .id=0, the sentinel value. "
1694 "Other side misbehaved?");
1698 const size_t n_body_segs = m_mdt_root.getBodySerializationInfo().getNumBodySerializationSegments();
1699 if (n_body_segs == 0)
1701 return error_out(
"In-mdt-header top union specifies no .internalMessageBody; and .id=/=0 (so: user message); "
1702 "but body-segment-count is 0 which is illegal. Other side misbehaved?");
1710 if (m_mdt_header_area.size() < HDR_SZ)
1712 return error_out(ostream_op_string(
"Lead in-message contains (apparently valid) mdt-header, "
1713 "but there are not enough bytes to hold the entire reserved header area: "
1714 "The entire blob is not even max-mdt-header-size [", HDR_SZ,
"] long but "
1715 "rather sized only [", m_mdt_header_area.size(),
"]. Other side misbehaved?"));
1726 assert(m_mdt_deserialized_ok &&
"Do not call deserialize_body() until deserialize_mdt() succeeds.");
1727 assert((id_or_none() != 0) &&
"Do not call deserialize_body() on internal messages.");
1728 assert((!m_body_deserialized_ok) &&
"Do not call deserialize_body() after it returns.");
1729 assert(stats_rcv_msg &&
"For code simplicity we assume this is always of interest for now.");
1731 auto& msg = *stats_rcv_msg;
1732 const auto body_serialization_info = m_mdt_root.getBodySerializationInfo();
1734 size_t n_body_segs = body_serialization_info.getNumBodySerializationSegments();
1745 if (body_serialization_info.hasSplitSegmentsOrNull())
1747 const auto split_segs_list = body_serialization_info.getSplitSegmentsOrNull();
1748 const auto n_split_segs = split_segs_list.size();
1751 split_segs.reserve(n_split_segs);
1752 for (
size_t idx = 0; idx != n_split_segs; ++idx)
1758 const auto split_segs_list_element_in_capnp = split_segs_list[idx];
1759 constexpr size_t N_BITS_SPLIT_SEG_SZ =
sizeof(split_segs_list_element_in_capnp) * 4;
1760 constexpr size_t START_IDX_MASK = (
size_t(1) << N_BITS_SPLIT_SEG_SZ) - 1;
1762 const auto split_segs_list_element =
size_t(split_segs_list_element_in_capnp);
1765 const auto n_cont = split_segs_list_element >> N_BITS_SPLIT_SEG_SZ;
1767 split_segs.emplace_back(
Split_segment{ split_segs_list_element & START_IDX_MASK,
1771 msg.m_histo_split_blobs_per_seg.record_value(n_cont + 1);
1774 n_body_segs -= n_cont;
1777 m_body_root = m_body_reader.template deserialization<Body>(&split_segs,
1781 assert((n_split_segs != 0) &&
"If other side messed up and set that to zero, err_code would reflect that now.");
1782 ++msg.m_msgs_with_split_segments;
1788 m_body_root = m_body_reader.template deserialization<Body>(
nullptr, err_code);
1796 m_body_deserialized_ok =
true;
1808 ++msg.m_notifications;
1809 (originating_msg_id_or_none() == 0) || (++msg.m_notification_responses);
1810 m_hndl_or_null.get().null() || (++msg.m_handle_bearing_msgs);
1811 msg.m_total_segments += n_body_segs;
1812 ++((n_body_segs == 1) ? msg.m_single_segment_msgs : msg.m_multi_segment_msgs);
1813 msg.m_histo_msg_sz.record_value(m_total_sz);
1820 assert(m_mdt_deserialized_ok &&
"Call deserialize_mdt() successfully before calling accessors.");
1821 return m_mdt_root.getId();
1825msg_id_t CLASS_STRUCT_MSG_IN::originating_msg_id_or_none()
const
1827 assert(m_mdt_deserialized_ok &&
"Call deserialize_mdt() successfully before calling accessors.");
1828 return m_mdt_root.getOriginatingMessageIdOrNone();
1834 assert(m_mdt_deserialized_ok &&
"Call deserialize_mdt() successfully before calling accessors.");
1835 return m_session_token;
1839typename CLASS_STRUCT_MSG_IN::Internal_msg_body_reader CLASS_STRUCT_MSG_IN::internal_msg_body_root()
const
1841 assert(m_mdt_deserialized_ok &&
"Call deserialize_mdt() successfully before calling accessors.");
1842 assert((id_or_none() == 0) &&
"Access internal_msg_body_root() only if `id_or_none() == 0`.");
1843 return m_mdt_root.getInternalMessageBody();
1847const typename CLASS_STRUCT_MSG_IN::Body_reader& CLASS_STRUCT_MSG_IN::body_root()
const
1849 assert(m_body_deserialized_ok &&
"Call deserialize_body() successfully before calling body_root() accessor.");
1854const typename CLASS_STRUCT_MSG_IN::Mdt_reader& CLASS_STRUCT_MSG_IN::mdt_root()
const
1856 assert(m_mdt_deserialized_ok &&
"Call deserialize_mdt() successfully before calling mdt_root() accessor.");
1867void CLASS_STRUCT_MSG_IN::to_ostream(std::ostream* os_ptr)
const
1873 if (!m_hndl_or_null.get().null())
1876 os << m_hndl_or_null.get() <<
' ';
1880 if (m_mdt_deserialized_ok)
1882 const auto id_or_0 = id_or_none();
1890 os << ::kj::str(internal_msg_body_root()).cStr();
1898 os <<
"id[" << id_or_0 <<
"] ";
1899 const auto originating_msg_id_or_0 = originating_msg_id_or_none();
1900 if (originating_msg_id_or_0 != 0)
1902 os <<
"rsp_to_id[" << originating_msg_id_or_0 <<
"] ";
1905 if (m_body_deserialized_ok)
1912 os <<
" ( incomplete )";
1918 os <<
"( incomplete )";
1921 os <<
" sz[" << serialization_size() <<
"]]@" <<
this;
1927 val.to_ostream(&os);
1931#undef TEMPLATE_STRUCT_MSG_OUT
1932#undef CLASS_STRUCT_MSG_OUT
1933#undef TEMPLATE_STRUCT_MSG_IN
1934#undef CLASS_STRUCT_MSG_IN
Simple utility: a capnp MessageBuilder operating over a single, contiguous, user-supplied area in vir...
kj::ArrayPtr<::capnp::word > allocateSegment(unsigned int min_sz_words) override
Implements MessageBuilder API.
util::Blob_mutable m_seg
Copy of seg (the buffer description... not the actual buffer!) given to ctor.
Capped_sz_capnp_message_builder(const util::Blob_mutable &seg, bool zero_it_please)
Constructor that remembers the given memory area.
bool m_returned_seg
true if and only if allocateSegment() has been called.
Simple utility: a capnp MessageReader operating over a single, contiguous, user-supplied area in virt...
kj::ArrayPtr< const ::capnp::word > Word_array_ptr_base
Convenience alias for capnp equivalent of util::Blob_const but in words as opposed to bytes.
Capped_sz_capnp_message_reader(const util::Blob_const &seg)
Constructs MessageReader based on an existing contiguous memory area; is equivalent to the simple Seg...
::capnp::SegmentArrayMessageReader Seg_array_msg_reader_base
Convenient alias for capnp SegmentArrayMessageReader.
A structured in-message instance suitable as received and emittable (to user) by struc::Channel.
Body_t Body
See struc::Channel::Msg_body.
bool m_body_deserialized_ok
Starts false; becomes true immutably once deserialize_body() succeeds (never if it's an internal mess...
Internal_msg_body_reader internal_msg_body_root() const
(Access via Msg_in_impl) To be called only after deserialize_mdt(), similar to body_root() but for th...
Body_reader m_body_root
See body_root(); meaningless until m_body_deserialized_ok.
Session_token m_session_token
Starts uninitialized, this is assigned exactly once by deserialize_mdt(), storing the session-token t...
schema::detail::StructuredMessage Mdt
capnp struct StructuredMessage which is the structured view of the metadata (mdt) header.
typename Reader_config::Reader Reader
Short-hand for user-indirectly-specified Struct_reader concept impl.
bool m_mdt_deserialized_ok
Starts false; becomes true immutably once deserialize_mdt() succeeds.
util::Own_native_handle m_hndl_or_null
See store_native_handle_or_null().
Mdt_reader m_mdt_root
See internal_msg_body_root(); meaningless until m_mdt_deserialized_ok.
typename Body::Reader Body_reader
Short-hand for capnp-generated read-only-accessing Reader nested class of Body. See body_root().
Msg_in(const Reader_config &struct_reader_config)
(Access via Msg_in_impl) Constructs a not-ready-for-public-consumption in-message which awaits serial...
typename schema::detail::StructuredMessage::InternalMessageBody::Reader Internal_msg_body_reader
Short-hand for capnp-generated reader API for the internal-message sub-area of an Mdt.
void deserialize_body(Error_code *err_code, Channel_stats::Msg *stats_rcv_msg)
(Access via Msg_in_impl) To be invoked after deserialize_mdt() == N, and add_serialization_segment() ...
const Session_token & session_token() const
(Access via Msg_in_impl) To be called only after deserialize_mdt(), returns session token tagging thi...
Reader m_body_reader
The Struct_reader concept impl that does much of the heavy lifting (e.g., it might be SHM-enabled; or...
Native_handle emit_native_handle_or_null()
Returns the Native_handle – potentially null meaning none – embedded in this message; and forgets tha...
void store_native_handle_or_null(Native_handle &&native_handle_or_null)
(Access via Msg_in_impl) Store the Native_handle (potentially .null(), meaning none) in this in-messa...
msg_id_t originating_msg_id_or_none() const
(Access via Msg_in_impl) To be called only after deserialize_mdt(), returns the message ID of the out...
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
size_t m_total_sz
Sum of blob sizes in add_serialization_segment() calls so far.
msg_id_t id_or_none() const
(Access via Msg_in_impl) To be called only after deserialize_mdt(), returns the message ID of this in...
~Msg_in()
Returns resources, potentially including potentially significant RAM resources, taken before emitting...
size_t deserialize_mdt(flow::log::Logger *logger_ptr, Error_code *err_code, Channel_stats::Msg *stats_rcv_msg_internal_only)
(Access via Msg_in_impl) To be invoked after exactly one add_serialization_segment() call: finalizes ...
void add_serialization_segment(Segment_blob_in &&blob)
(Access via Msg_in_impl) Records the first or next, in order, unstructured-data chunk that is part of...
const Mdt_reader & mdt_root() const
(Access via Msg_in_impl) The Mdt root capnp-generated accessor object.
Reader_config_t Reader_config
See struc::Channel::Reader_config.
util::Blob_const m_mdt_header_area
Meaningful from add_serialization_segment() on, this simply describes the memory area that begins wit...
typename Mdt::Reader Mdt_reader
capnp-generated reader API for Mdt structures.
size_t serialization_size() const
Size of the serialization in memory in bytes; only the serialization as transmitted via IPC counts.
std::optional< Capped_sz_capnp_message_reader > m_mdt_reader
A very simple capnp::MessageReader that provides structured access to the mdt header.
const Body_reader & body_root() const
The Body root capnp-generated accessor object.
A structured out-message suitable to be sent via struc::Channel::send() (et al).
typename Body::Builder Body_builder
Short-hand for capnp-generated mutating Builder nested class of Body. See body_root().
boost::movelib::unique_ptr< Capped_sz_capnp_message_builder > m_mdt_builder
Mdt header builder lazily de-nullified by the first successful emit_serialization() and then (by any ...
Body_builder m_body_root
See body_root().
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Native_handle native_handle_or_null() const
Returns whatever was the last word according to store_native_handle_or_null().
void store_native_handle_or_null(Native_handle &&native_handle_or_null)
Store the Native_handle (potentially .null(), meaning none) in this out-message; and,...
typename Builder::Config Builder_config
Short-hand for user-specified Struct_builder::Config.
Builder m_builder
The guy serializing a Body, as well as storing – but not itself loading – a frame-prefix big-enough f...
Msg_out & operator=(Msg_out &&src)
Move assignment: Destroy *this contents; make *this equal to src, while src becomes as-if default-cte...
~Msg_out()
Returns resources, including potentially significant RAM resources and native_handle_or_null(),...
Builder_t Builder
Short-hand for user-specified Struct_builder type.
Body_builder * body_root()
The Body root capnp-generated mutator object.
Msg_out & operator=(const Msg_out &)=delete
Disallow copying.
void emit_serialization(Segment_bufs *segs_out_ptr, Split_segments *split_segs_out_or_null, const typename Builder::Session &session, Error_code *err_code, Load_mdt_args &&... load_mdt_args)
(Access via Msg_out_impl) Finalizes (for at least IPC-transmission) the serialization of metadata and...
Msg_out(Msg_out &&src)
Move ctor: Make *this equal to src, while src becomes as-if default-cted (in that any operation excep...
::capnp::Orphanage Orphanage
Short-hand for capnp orphan factory. See orphanage().
Orphanage orphanage()
Convenience method that returns a capnp::Orphan factory in the same capnp::MessageBuilder as body_roo...
Msg_out(const Msg_out &)=delete
Disallow copying.
Msg_out()
Creates non-message; any operation except move-to or destruction results in undefined behavior subseq...
util::Own_native_handle m_hndl_or_null
The Native_handle, if any, embedded inside this message; auto-closed on destruction/replacement.
Body_t Body
See struc::Channel::Msg_body.
#define TEMPLATE_STRUCT_MSG_OUT
Internally used macro; public API users should disregard (same deal as in struc/channel....
#define CLASS_STRUCT_MSG_IN
Internally used macro; public API users should disregard (same deal as in struc/channel....
#define TEMPLATE_STRUCT_MSG_IN
Internally used macro; public API users should disregard (same deal as in struc/channel....
#define CLASS_STRUCT_MSG_OUT
Internally used macro; public API users should disregard (same deal as in struc/channel....
@ S_STRUCT_CHANNEL_INTERNAL_PROTOCOL_MISUSED_SCHEMA
Structured channel: received structured message with invalid internally-set/used fields.
@ S_INVALID_ARGUMENT
User called an API with 1 or more arguments against the API spec.
Builder< ipc::shm::classic::Pool_arena > Builder
Convenience alias: transport::struc::shm::Builder that works with boost.ipc.shm pools from ipc::shm::...
Reader< ipc::shm::classic::Pool_arena > Reader
Convenience alias: transport::struc::shm::Reader that works with boost.ipc.shm pools from ipc::shm::c...
Sub-module of Flow-IPC module ipc::transport providing transmission of structured messages specifical...
Ostreamable_capnp_brief< Capnp_reader > ostreamable_capnp_brief(const Capnp_reader &capnp_reader)
Convenience function that returns an object passable to ostream<< to print a one-line/potentially-tru...
static constexpr size_t BUILDER_CONFIG_FRAME_PREFIX_SZ_VIA_STRUC_CHANNEL
struc::Channel (and struc::sync_io::Channel) requires, for internal purposes, that any Msg_out transm...
std::vector< Split_segment > Split_segments
A simple data structure describing the segments (if any) in a Segment_bufs (or similar) structure whi...
boost::uuids::uuid Session_token
A type used by struc::Channel for internal safety/security/auth needs.
bool load_mdt(Capped_sz_capnp_message_builder *builder, schema::detail::StructuredMessage::InternalMessageBody::Builder *internal_msg_builder_or_null, Error_code *err_code, const Session_token &session_token, msg_id_t originating_msg_id_or_none, msg_id_t id_or_none, size_t n_serialization_segments_or_none, const Split_segments *split_segs)
Given user- or internal-message-describing metadata values as arguments, loads (via the provided capn...
std::ostream & operator<<(std::ostream &os, const Heap_fixed_builder &val)
Prints string representation of the given Heap_fixed_builder to the given ostream.
flow::util::Blob_sans_log_context Segment_blob_in
Short-hand for a high-performance blob structure that represents an IPC-incoming (sub-)segment 1+ of ...
std::vector< util::Blob_const > Segment_bufs
Simpler cousin of Segment_ptrs, this represents the IPC-transmissible representation of a capnp seria...
uint64_t msg_id_t
Message ID uniquely identifying outgoing message (Msg_out, among all other Msg_outs),...
Native_handle disowned_native_handle(Own_native_handle &&src) noexcept
Returns Native_handle constructed by relieving an existing auto-closing Own_native_handle of its owne...
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
flow::util::String_view String_view
Short-hand for Flow's String_view.
boost::scope::unique_resource< Native_handle, Native_handle::Closer, Native_handle > Own_native_handle
A unique_resource wrapper for Native_handle useful to avoid descriptor leaks and double-closing; can ...
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
This is the friend facade of Msg_in that exposes private APIs hidden from public user by providing pu...
This is the friend facade of Msg_out that exposes private APIs hidden from public user by providing p...
Simple structure describing how a pre-split single segment was turned into 2+ post-split component su...
Per-message stats shared between send and receive directions.
uint64_t m_total_low_lvl_blobs
Total low-level blobs (each segment of m_total_segments maps to 1 blob unless split; in which case to...
Cumulative stats from a struc::sync_io::Channel, covering both send and receive directions as well as...
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.