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),
1120m_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
Methods.
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().
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.