29#include "ipc/transport/struc/schema/detail/structured_msg.capnp.h" 
   33#include <boost/endian.hpp> 
   34#include <boost/move/make_unique.hpp> 
  152template<
typename Message_body, 
typename Struct_builder_t>
 
  544template<
typename Message_body, 
typename Struct_reader_config>
 
  546  private boost::noncopyable
 
  642  using Mdt = schema::detail::StructuredMessage;
 
  852#define TEMPLATE_STRUCT_MSG_OUT \ 
  853  template<typename Message_body, typename Struct_builder_t> 
  855#define CLASS_STRUCT_MSG_OUT \ 
  856  Msg_out<Message_body, Struct_builder_t> 
  858#define TEMPLATE_STRUCT_MSG_IN \ 
  859  template<typename Message_body, typename Struct_reader_config> 
  861#define CLASS_STRUCT_MSG_IN \ 
  862  Msg_in<Message_body, Struct_reader_config> 
  867CLASS_STRUCT_MSG_OUT::Msg_out() :
 
  874CLASS_STRUCT_MSG_OUT::Msg_out
 
  886CLASS_STRUCT_MSG_OUT::Msg_out(
Builder&& struct_builder) :
 
  895  m_builder(std::move(struct_builder)), 
 
  896  m_body_root(m_builder.payload_msg_builder()->template getRoot<
Body>()) 
 
  979CLASS_STRUCT_MSG_OUT::~Msg_out()
 
  990  m_builder = std::move(src.m_builder);
 
 1003  m_body_root = std::move(src.m_body_root);
 
 1006  if (m_hndl_or_null != src.m_hndl_or_null)
 
 1012  m_hndl_or_null = std::move(src.m_hndl_or_null);
 
 1018typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root()
 
 1020  return &m_body_root;
 
 1024const typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root()
 const 
 1026  return const_cast<Msg_out*
>(
this)->body_root();
 
 1030typename CLASS_STRUCT_MSG_OUT::Orphanage CLASS_STRUCT_MSG_OUT::orphanage()
 
 1032  return m_builder.payload_msg_builder()->getOrphanage();
 
 1038void CLASS_STRUCT_MSG_OUT::store_native_handle_or_null (
Native_handle&& native_handle_or_null)
 
 1040  if (native_handle_or_null == m_hndl_or_null)
 
 1045  if (!m_hndl_or_null.null())
 
 1049  m_hndl_or_null = std::move(native_handle_or_null);
 
 1055  return m_hndl_or_null;
 
 1059void CLASS_STRUCT_MSG_OUT::emit_serialization(
Segment_ptrs* target_blobs, 
const typename Builder::Session& session,
 
 1062  m_builder.emit_serialization(target_blobs, session, err_code); 
 
 1066size_t CLASS_STRUCT_MSG_OUT::n_serialization_segments()
 const 
 1068  return m_builder.n_serialization_segments();
 
 1072void CLASS_STRUCT_MSG_OUT::to_ostream(std::ostream* os_ptr)
 const 
 1076  constexpr size_t MAX_SZ = 256;
 
 1082  os << 
"[n_serialization_segs[" << n_serialization_segments() << 
"] ";
 
 1084  const auto hndl_or_null = native_handle_or_null();
 
 1085  if (!hndl_or_null.null())
 
 1088    os << hndl_or_null << 
' ';
 
 1094  const kj::String capnp_str = kj::str(*(body_root()));
 
 1095  if (capnp_str.size() > MAX_SZ)
 
 1097    os << 
String_view(capnp_str.begin(), MAX_SZ - TRUNC_SUFFIX.size()) << TRUNC_SUFFIX;
 
 1101    os << capnp_str.cStr();
 
 1110  val.to_ostream(&os);
 
 1118  m_reader_config(struct_reader_config),
 
 1119  m_mdt_deserialized_ok(false),
 
 1120  m_body_deserialized_ok(false)
 
 1127void CLASS_STRUCT_MSG_IN::store_native_handle_or_null(
Native_handle&& native_handle_or_null)
 
 1129  assert(m_hndl_or_null.null() && 
"Call this at most once (probably upon finalizing 1st segment as well).");
 
 1131  m_hndl_or_null = std::move(native_handle_or_null);
 
 1135CLASS_STRUCT_MSG_IN::~Msg_in() = 
default;
 
 1138flow::util::Blob* CLASS_STRUCT_MSG_IN::add_serialization_segment(
size_t max_sz)
 
 1140  using boost::movelib::make_unique;
 
 1142  assert((!m_body_deserialized_ok)
 
 1143         && 
"Do not call add_serialization_segment() after both deserialize_*().");
 
 1149    m_mdt_reader.emplace(m_reader_config);
 
 1150    return m_mdt_reader->add_serialization_segment(max_sz);
 
 1155    m_body_reader.emplace(m_reader_config);
 
 1157  return m_body_reader->add_serialization_segment(max_sz);
 
 1161size_t CLASS_STRUCT_MSG_IN::deserialize_mdt(flow::log::Logger* logger_ptr, 
Error_code* err_code)
 
 1164  using boost::endian::little_to_native;
 
 1167  assert((!m_mdt_deserialized_ok) && 
"Do not call deserialize_mdt() after it returns.");
 
 1168  assert(m_mdt_reader && 
"Must call add_serialization_segment() exactly 1x before deserialize_mdt().");
 
 1170  m_mdt_root = m_mdt_reader->template deserialization<Mdt>(err_code);
 
 1176  m_mdt_deserialized_ok = 
true;
 
 1178  FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT); 
 
 1192  const auto error_out = [&](
String_view msg) -> 
size_t 
 1195    FLOW_LOG_WARNING(msg);
 
 1196    m_mdt_deserialized_ok = 
false; 
 
 1200  if (!m_mdt_root.hasAuthHeader())
 
 1202    return error_out(
"In-mdt-message has null .authHeader.  Other side misbehaved?");
 
 1205  const auto auth_header = m_mdt_root.getAuthHeader();
 
 1207  if (!auth_header.hasSessionToken())
 
 1209    return error_out(
"In-mdt-message has null .authHeader.  Other side misbehaved?");
 
 1213  const auto capnp_uuid = auth_header.getSessionToken();
 
 1214  static_assert(
decltype(m_session_token)::static_size() == 2 * 
sizeof(uint64_t),
 
 1215                "World is broken: UUIDs expected to be 16 bytes!");
 
 1216  auto& first8 = *(
reinterpret_cast<uint64_t*
>(m_session_token.data())); 
 
 1217  auto& last8 = *(
reinterpret_cast<uint64_t*
>(m_session_token.data() + 
sizeof(uint64_t))); 
 
 1218  first8 = little_to_native(capnp_uuid.getFirst8()); 
 
 1219  last8 = little_to_native(capnp_uuid.getLast8()); 
 
 1222  if (m_mdt_root.hasOriginatingMessageOrNull() && (originating_msg_id_or_none() == 0))
 
 1224    return error_out(
"In-mdt-message top union specifies .originatingMessageOrNull.id but it is 0.  Responses to " 
 1225                     "internal messages (with .id=sentinel) are not allowed.  Other side misbehaved?");
 
 1229  const auto id_or_0 = id_or_none();
 
 1230  if (m_mdt_root.isInternalMessageBody())
 
 1234      return error_out(
"In-mdt-message top union specifies .internalMessageBody; but .id=/=0, the sentinel value.  " 
 1235                       "Other side misbehaved?");
 
 1248    return error_out(
"In-mdt-message top union specifies no .internalMessageBody; but .id=0, the sentinel value.  " 
 1249                     "Other side misbehaved?");
 
 1253  const size_t n_body_segs = m_mdt_root.getNumBodySerializationSegments();
 
 1254  if (n_body_segs == 0)
 
 1256    return error_out(
"In-mdt-message top union specifies no .internalMessageBody; and .id=0, the sentinel value; " 
 1257                     "but body-segment-count is 0 which is illegal.  Other side misbehaved?");
 
 1269  assert(m_mdt_deserialized_ok && 
"Do not call deserialize_body() until deserialize_mdt() succeeds.");
 
 1270  assert((id_or_none() != 0) && 
"Do not call deserialize_body() on internal messages.");
 
 1271  assert((!m_body_deserialized_ok) && 
"Do not call deserialize_body() after it returns.");
 
 1272  assert(m_body_reader && 
"Must call add_serialization_segment() at least once after deserialize_mdt() but before " 
 1273                          "deserialize_body().");
 
 1275  m_body_root = m_body_reader->template deserialization<Body>(err_code);
 
 1281  m_body_deserialized_ok = 
true;
 
 1287  assert(m_mdt_deserialized_ok && 
"Call deserialize_mdt() successfully before calling accessors.");
 
 1288  return m_mdt_root.getId();
 
 1292msg_id_t CLASS_STRUCT_MSG_IN::originating_msg_id_or_none()
 const 
 1294  assert(m_mdt_deserialized_ok && 
"Call deserialize_mdt() successfully before calling accessors.");
 
 1295  return m_mdt_root.hasOriginatingMessageOrNull()
 
 1296           ? m_mdt_root.getOriginatingMessageOrNull().getId()
 
 1303  assert(m_mdt_deserialized_ok && 
"Call deserialize_mdt() successfully before calling accessors.");
 
 1304  return m_session_token;
 
 1308typename CLASS_STRUCT_MSG_IN::Internal_msg_body_reader CLASS_STRUCT_MSG_IN::internal_msg_body_root()
 const 
 1310  assert(m_mdt_deserialized_ok && 
"Call deserialize_mdt() successfully before calling accessors.");
 
 1311  assert((!m_body_reader) && 
"Access internal_msg_body_root() only if `id_or_none() == 0`.");
 
 1312  return m_mdt_root.getInternalMessageBody();
 
 1316const typename CLASS_STRUCT_MSG_IN::Body_reader& CLASS_STRUCT_MSG_IN::body_root()
 const 
 1318  assert(m_body_deserialized_ok && 
"Call deserialize_body() successfully before calling body_root() accessor.");
 
 1323const typename CLASS_STRUCT_MSG_IN::Mdt_reader& CLASS_STRUCT_MSG_IN::mdt_root()
 const 
 1325  assert(m_mdt_deserialized_ok && 
"Call deserialize_mdt() successfully before calling mdt_root() accessor.");
 
 1332  return m_hndl_or_null;
 
 1336void CLASS_STRUCT_MSG_IN::to_ostream(std::ostream* os_ptr)
 const 
 1340  constexpr size_t MAX_SZ = 256;
 
 1347  const auto hndl_or_null = native_handle_or_null();
 
 1348  if (!hndl_or_null.null())
 
 1351    os << hndl_or_null << 
' ';
 
 1355  if (m_mdt_deserialized_ok)
 
 1357    const auto id_or_0 = id_or_none();
 
 1364      os << ::kj::str(internal_msg_body_root()).cStr();
 
 1372      os << 
"id[" << id_or_0 << 
"] ";
 
 1373      const auto originating_msg_id_or_0 = originating_msg_id_or_none();
 
 1374      if (originating_msg_id_or_0 != 0)
 
 1376        os << 
"rsp_to_id[" << originating_msg_id_or_0 << 
"] ";
 
 1379      if (m_body_deserialized_ok)
 
 1382        const kj::String capnp_str = kj::str(body_root());
 
 1383        if (capnp_str.size() > MAX_SZ)
 
 1385          os << 
String_view(capnp_str.begin(), MAX_SZ - TRUNC_SUFFIX.size()) << TRUNC_SUFFIX;
 
 1389          os << capnp_str.cStr();
 
 1394        os << 
" ( incomplete )"; 
 
 1400    os << 
"( incomplete )"; 
 
 1409  val.to_ostream(&os);
 
 1413#undef TEMPLATE_STRUCT_MSG_OUT 
 1414#undef CLASS_STRUCT_MSG_OUT 
 1415#undef TEMPLATE_STRUCT_MSG_IN 
 1416#undef CLASS_STRUCT_MSG_IN 
A structured in-message instance suitable as received and emittable (to user) by struc::Channel.
Mdt_reader m_mdt_root
See internal_msg_body_root(); meaningless until m_mdt_deserialized_ok.
~Msg_in()
Returns resources, potentially including potentially significant RAM resources, taken before emitting...
flow::util::Blob * add_serialization_segment(size_t max_sz)
Prior to deserialization_*() obtains a memory area max_sz bytes long into which the user may write-to...
bool m_mdt_deserialized_ok
Starts false; becomes true immutably once deserialize_mdt() succeeds.
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
const Mdt_reader & mdt_root() const
The Mdt root capnp-generated accessor object.
const Body_reader & body_root() const
The Body root capnp-generated accessor object.
Native_handle m_hndl_or_null
See store_native_handle_or_null().
typename Body::Reader Body_reader
Short-hand for capnp-generated read-only-accessing Reader nested class of Body. See body_root().
std::optional< Reader > m_mdt_reader
Deserializes the metadata sub-message, invisible to user: the thing describing the user message (if a...
Reader_config m_reader_config
See ctor.
Internal_msg_body_reader internal_msg_body_root() const
To be called only after deserialize_mdt(), similar to body_root() but for the internal-message root.
Body_reader m_body_root
See body_root(); meaningless until m_body_deserialized_ok.
typename Mdt::Reader Mdt_reader
Same as Msg_mdt_out::Body_builder but the Reader instead.
const Session_token & session_token() const
To be called only after deserialize_mdt(), returns session token tagging this in-message.
Message_body Body
See struc::Channel::Msg_body.
Session_token m_session_token
Starts uninitialized, this is assigned exactly once by deserialize_mdt(), storing the session-token t...
schema::detail::StructuredMessage Mdt
Same as Msg_mdt_out::Body.
Native_handle native_handle_or_null() const
The Native_handle – potentially null meaning none – embedded in this message.
msg_id_t originating_msg_id_or_none() const
To be called only after deserialize_mdt(), returns the message ID of the out-message to which this in...
void store_native_handle_or_null(Native_handle &&native_handle_or_null)
Store the Native_handle (potentially .null(), meaning none) in this in-message.
void deserialize_body(Error_code *err_code)
To be invoked after deserialize_mdt() == N, and add_serialization_segment() was called N times (with ...
size_t deserialize_mdt(flow::log::Logger *logger_ptr, Error_code *err_code)
To be invoked after exactly one successful add_serialization_segment() call (and that Blob being fill...
typename Reader_config::Reader Reader
Same as Msg_out::Builder but the reader that can decode what that serializing Builder did.
msg_id_t id_or_none() const
To be called only after deserialize_mdt(), returns the message ID of this in-message; 0 means it's an...
Msg_in(const Reader_config &struct_reader_config)
Constructs a not-ready-for-public-consumption in-message which awaits serialization-storing segments ...
std::optional< Reader > m_body_reader
Like m_mdt_reader but for the user message if any.
bool m_body_deserialized_ok
Starts false; becomes true immutably once deserialize_body() succeeds (never if it's an internal mess...
Struct_reader_config Reader_config
See struc::Channel::Reader_config.
typename schema::detail::StructuredMessage::InternalMessageBody::Reader Internal_msg_body_reader
Reader counterpart to Msg_mdt_out::Internal_msg_body_builder.
A structured out-message suitable to be sent via struc::Channel::send() (et al).
typename Builder::Config Builder_config
Short-hand for user-specified Struct_builder::Config.
Native_handle m_hndl_or_null
The Native_handle, if any, embedded inside this message.
Msg_out(Msg_out &&src)
Move ctor: Make *this equal to src, while src becomes as-if default-cted (in that any operation excep...
Msg_out & operator=(const Msg_out &)=delete
Disallow copying.
const Body_builder * body_root() const
Equivalent to the other body_root() overload but immutable version.
typename Body::Builder Body_builder
Short-hand for capnp-generated mutating Builder nested class of Body. See body_root().
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(),...
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Body_builder m_body_root
See body_root().
void emit_serialization(Segment_ptrs *target_blobs, const typename Builder::Session &session, Error_code *err_code) const
Returns the serialization in the form of a sequence of 1+ Blobs.
Msg_out()
Creates non-message; any operation except move-to or destruction results in undefined behavior subseq...
Orphanage orphanage()
Convenience method that returns a capnp::Orphan factory in the same capnp::MessageBuilder as body_roo...
Msg_out(Builder &&struct_builder)
Advanced technique: Creates message by subsuming the provided already-prepared Capnp_msg_builder_inte...
Body_builder * body_root()
The Body root capnp-generated mutator object.
Msg_out(const Builder_config &struct_builder_config)
Creates blank Body-bearing out-message message, with no native handle, all of which can be modified v...
Msg_out(const Msg_out &)=delete
Disallow copying.
Builder m_builder
The guy serializing a Body. Underlying serialization potentially futher mutated by user via body_root...
Message_body Body
See struc::Channel::Msg_body.
Struct_builder_t Builder
Short-hand for user-specified Struct_builder type.
::capnp::Orphanage Orphanage
Short-hand for capnp orphan factory. See orphanage().
void store_native_handle_or_null(Native_handle &&native_handle_or_null)
Store the Native_handle (potentially .null(), meaning none) in this out-message; no-ops if the same ....
size_t n_serialization_segments() const
Returns what target_blobs.size() would return after calling emit_serialization(&target_blobs) (with a...
Native_handle native_handle_or_null() const
Returns whatever was the last word according to store_native_handle_or_null().
#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....
void release_native_peer_socket(Native_handle &&peer_socket_native_or_null)
Little utility that returns the raw Native_handle suitable for Peer_socket to the OS.
@ S_STRUCT_CHANNEL_INTERNAL_PROTOCOL_MISUSED_SCHEMA
Structured channel: received structured message with invalid internally-set/used fields.
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...
boost::uuids::uuid Session_token
A type used by struc::Channel for internal safety/security/auth needs.
std::vector< flow::util::Blob * > Segment_ptrs
Sequence of 1+ Blob pointers to blobs which must stay alive while these pointers may be dereferenced,...
std::ostream & operator<<(std::ostream &os, const Heap_fixed_builder &val)
Prints string representation of the given Heap_fixed_builder to the given ostream.
uint64_t msg_id_t
Message ID uniquely identifying outgoing message (Msg_out, among all other Msg_outs),...
util::Native_handle Native_handle
Convenience alias for the commonly used type util::Native_handle.
flow::util::String_view String_view
Short-hand for Flow's String_view.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.