Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
msg.hpp
Go to the documentation of this file.
1/* Flow-IPC: Structured Transport
2 * Copyright (c) 2023 Akamai Technologies, Inc.; and other contributors.
3 * Each commit is copyright by its respective author or author's employer.
4 *
5 * Licensed under the MIT License:
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE. */
24
25/// @file
26#pragma once
27
29#include "ipc/transport/struc/schema/detail/structured_msg.capnp.h"
38#include "ipc/util/util_fwd.hpp"
39#include <flow/error/error.hpp>
40#include <boost/endian.hpp>
41#include <boost/move/make_unique.hpp>
42#include <cstring>
43#include <vector>
44
46{
47
48// Types.
49
50/**
51 * Simple utility: a capnp `MessageBuilder` operating over a single, contiguous, user-supplied area in virtual memory.
52 *
53 * If subsequent mutators calls are such that this area is insufficient in size, a `flow::error::Runtime_error`,
54 * with error::Code::S_INVALID_ARGUMENT, is thrown. To avoid this use a `*this` only when it is absolutely guaranteed
55 * that the provided area is big enough. (This can be quite easy with simple schemas and/or trusted data sources.)
56 *
57 * This is ~equal to capnp's own `MallocMessageBuilder`, when one chooses to supply a pre-existing
58 * buffer for the first segment and then never needs to add more segments beyond that one. A `*this` is just
59 * leaner and easier to use for this specific purpose.
60 *
61 * ### Rationale ###
62 * We use it internally in Flow-IPC (at least in Msg_out impl); but it is simple and useful and thus is supplied as
63 * a public API to the user also. (There is no expectation, or lack thereof, that the typical Flow-IPC user will
64 * need it.)
65 */
68{
69public:
70 // Constructors/destructor.
71
72 /**
73 * Constructor that remembers the given memory area. It can optionally zero that area.
74 *
75 * The area must remain valid until the last time `*this` is accessed (this excludes `*this` destruction which
76 * does not access the area; but it includes touching the serialization through any capnp mutators).
77 *
78 * The area must be aligned to `alignof(::capnp::word)`: capnp requires word-aligned segments. Beware, e.g.,
79 * a byte-array on the stack: it guarantees no such thing without an `alignas`. (A `word`-array would be fine.)
80 *
81 * @note If you are able to guarantee that the `seg`-described area is already filled with zeroes, it may bring
82 * significant perf gains to specify `zero_it_please = false`.
83 * @note If you are *not* able to guarantee it, you *must* specify the converse. Otherwise intermittent undefined
84 * behaviors *will* happen... and they'll be hard to trace back to this bug.
85 *
86 * @param seg
87 * The area where to build message subsequently.
88 * @param zero_it_please
89 * If and only if `true` we shall presently fill `seg`-described area with zeroes.
90 */
91 explicit Capped_sz_capnp_message_builder(const util::Blob_mutable& seg, bool zero_it_please);
92
93 // Methods.
94
95 /**
96 * Implements `MessageBuilder` API. Invoked by capnp, as the user mutates via `Builder`s. Do not invoke directly.
97 *
98 * If called a 2nd (or 3rd, 4th, ...) time, throws `flow::error::Runtime_error` with error::Code::S_INVALID_ARGUMENT.
99 * This occurs if and only if the `seg` given to ctor describes an area insufficiently large to support the
100 * mutator calls invoked on `*this`. A mutator internally determines another segment is necessary, calls
101 * `allocateSegment()`, and we throw.
102 *
103 * @note The strange capitalization (that goes against standard Flow-IPC style) is because we are implementing
104 * a capnp API.
105 *
106 * @param min_sz_words
107 * See `MessageBuilder` API.
108 * @return See `MessageBuilder` API.
109 * The ptr and size of the area for capnp to serialize-to... namely same area as `seg` given to ctor.
110 */
111 kj::ArrayPtr<::capnp::word> allocateSegment(unsigned int min_sz_words) override;
112
113private:
114 // Data.
115
116 /// Copy of `seg` (the buffer description... not the actual buffer!) given to ctor.
118
119 /// `true` if and only if allocateSegment() has been called.
121}; // class Capped_sz_capnp_message_builder
122
123/**
124 * Simple utility: a capnp `MessageReader` operating over a single, contiguous, user-supplied area in virtual memory.
125 * It is a (public sub-class of) `capnp::SegmentArrayMessageReader`.
126 *
127 * This is ~equal to capnp's own `SegmentArrayMessageReader`, when one chooses to supply a single segment to it.
128 * A `*this` is just easier to use for this specific purpose, providing a simpler (and arguably more Flow-y)
129 * ctor.
130 *
131 * ### Rationale ###
132 * Same as for Capped_sz_capnp_message_builder.
133 *
134 * @internal
135 *
136 * ### Impl ###
137 * It's obviously quite short. Still there is a technicality that might be non-obvious and is really a result
138 * of C++ quirks: Our super-class/work-horse `SegmentArrayMessageReader` takes a pointer and size of an array
139 * of pointer/size pairs, and that array must outlive said `MessageReader`. (In our case this array is not an array
140 * but simply 1 pointer/size pair... or an array of 1 such element, if you will.) But super-objects are initialized
141 * before any would-be data members of ours, creating an ordering problem. To get around it we use a `private` base
142 * instead of a data-member and list it before the `public SegmentArrayMessageReader` base. Hence the somewhat
143 * odd-looking (but perfectly reasonable) `private` base thing.
144 */
146 private kj::ArrayPtr<const ::capnp::word>,
147 public ::capnp::SegmentArrayMessageReader // Hence we also implement `::capnp::MessageReader` interface.
148{
149public:
150 // Constructors/destructor.
151
152 /**
153 * Constructs `MessageReader` based on an existing contiguous memory area; is equivalent to the simple
154 * `SegmentArrayMessageReader` ctor taking a 1-array.
155 *
156 * The area must be aligned to `alignof(::capnp::word)`: capnp requires word-aligned segments. Beware, e.g.,
157 * a byte-array on the stack: it guarantees no such thing without an `alignas`. (A `word`-array would be fine.)
158 *
159 * @param seg
160 * The memory area with the serialization.
161 */
163
164private:
165 // Types.
166
167 /// Convenience alias for capnp equivalent of util::Blob_const but in `word`s as opposed to bytes.
168 using Word_array_ptr_base = kj::ArrayPtr<const ::capnp::word>;
169
170 /// Convenient alias for capnp `SegmentArrayMessageReader`.
171 using Seg_array_msg_reader_base = ::capnp::SegmentArrayMessageReader;
172}; // class Capped_sz_capnp_message_reader
173
174/**
175 * A structured out-message suitable to be sent via struc::Channel::send() (et al). Publicly this can be constructed
176 * directly; or via struc::Channel::create_msg(). The latter has the advantage of reusing the serialization
177 * engine knobs registered with the channel and hence is simply easier to write. If one uses the direct-construction
178 * route, the builder (serialization) engine type -- Struct_builder #Builder -- must match that of the
179 * struc::Channel used to `send()` a `*this`; otherwise it simply will not compile.
180 *
181 * @see "Lifecycle of an out-message" section of struc::Channel class doc header for useful context.
182 *
183 * As explained in that doc section, a Msg_out (struc::Channel::Msg_out) is akin to a container,
184 * like `vector<uint8_t>`; and the #Builder template param + ctor arg are akin to the allocator
185 * used by such a container. A given `*this` represents the message payload; *and* separately/independently
186 * it also represents a particular `send()`t (past/present/future) *instance* of that payload.
187 * - The message payload (as accessed via body_root() and subsequent capnp mutators/builders) is relevant
188 * throughout a `*this`'s life. This is not unlike the data in a `vector`.
189 * - Modifying it is akin to modifying the `vector<uint8_t>`, albeit in structured-schema fashion -- available API
190 * controlled by `Body_t` template param -- and with an optionally attached #Native_handle.
191 * - The (internally-only accessed/accessible) metadata payload, required for performant operation of
192 * struc::Channel and struc::sync_io::Channel, is relevant only *during* the execution of
193 * sync_io::Channel::send() and sync_io::Channel::async_request() (and therefore wrappers
194 * struc::Channel::send(), struc::Channel::async_request(), and struc::Channel::sync_request()).
195 * - This internal metadata-payload is small (as of this writing it is 128 bytes).
196 * - This bifurcation is necessary for performance, internally, and typically it should not matter to the user of
197 * a `*this`. The way in which it *does* matter is with regards to `const`ness of its APIs and therefore
198 * thread safety. To wit observe that the aforementioned `Channel` send-y methods take a pointer to *mutable*
199 * Msg_out: not a ref-to-`const`; that is because such send-y methods must modify the metadata-payload of `*this`.
200 * Consequently do not invoke such send-y methods on a given `*this` concurrently, even via different `Channel`s.
201 *
202 * As explained in that doc section, like any container, once another process has access to it -- which is
203 * only possible in read-only fashion as of this writing -- modifying it must be done with concurrency/synchronization
204 * considered. If the compile-time-chosen #Builder is SHM-based, then this is a concern.
205 * If it is heap-based (notably Heap_fixed_builder), then it is not: the serialization is *copied* into
206 * and out of the transport.
207 *
208 * @note The (internally-only-used) metadata-payload section of a `*this` is as of this writing always copied
209 * when transmitted (and is small), so no concurrency/synchronization worries apply.
210 *
211 * After construction, one mutates the message via body_root() and/or store_native_handle_or_null().
212 * You may also use orphanage() to build the message in bottom-up fashion, eventually grafting pieces in via
213 * `body_root()->....adopt...()`. See orphanage() doc header for more information on this technique.
214 * Lastly consider the following section for another, more holistic bottom-up approach (or perhaps
215 * taking the orphanage technique further).
216 *
217 * ### Advanced technique: Construction from earlier-prepared raw #Capnp_msg_builder_interface ###
218 * To enable the straightforward operation implied above, one uses the 1st/simple ctor form which
219 * by definition necessitates specifying the root schema, #Body (as to construct one must know the type).
220 * This is typically perfectly natural: a module knows it's building a message of schema #Body, so they
221 * construct a `Msg_out<Body>` (which already auto-creates a blank #Body via
222 * `initRoot<Body>()`), then fills it out via body_root() (which points to what `initRoot()` returned).
223 * The orphanage technique above is a slight complication, in that things can be built bottom-up, but in any case
224 * by then the root schema already had to be specified, even if it's actually mutated only somewhat later, once
225 * the component orphan(s) can be plugged in.
226 *
227 * When working with capnp outside of ::ipc, users typically do basically the same thing:
228 * start with `M.initRoot<Body>()`, then set stuff in its tree; or in more complex cases maybe use
229 * `M.getOrphanage()` from the same `MessageBuilder M` to help build bottom-up.
230 *
231 * However consider a complex schema `Huge_body` built by collaboration between modules A and B.
232 * Now module A may be aware the ultimate product is rooted at
233 * `Huge_body`, while module B has no idea, and yet they work together to build parts of the final
234 * thing. In that case B does not necessarily think of any particular overall `Huge_body` tree but only the
235 * sub-schema types it cares about; so to it the `MessageBuilder M` is just a memory pool or heap of sorts;
236 * it makes whatever structures it wants (via `M.getOrphanage()`) from it but does
237 * not call or know about `initRoot<Huge_body>()`. Conceivably, even, module B is first to run its
238 * procedures (before module A) and to create `M` in the first place; and only later module A perhaps
239 * finally sets the root (`initRoot<HugeBody>()`) and attaches whatever orphan values module B produces,
240 * hooking them into the `HugeBody`.
241 *
242 * The straightforward use of Msg_out, as described before, does in fact force one (from the start) to
243 * specify `HugeBody` by definition (it's -- again -- a template argument to the class template), and that may not
244 * be desirable in this module A-B scenario. So to support it: use the 2nd/advanced ctor form which
245 * takes over (via `std::move()`) an already-created #Builder -- not templated on any schema `Body`.
246 * The #Builder exposes the direct `MessageBuilder`, so the tree can be built using whatever features in whatever
247 * order one desires... and only *then* create the Msg_out. The only constraint is that
248 * by ctor time, the `MessageBuilder` (a/k/a #Capnp_msg_builder_interface) *is* initialized to be rooted at `Body`;
249 * but this could be done anytime up to that point; so module B need not do it, while module A might ultimately
250 * do it and then construct the `Msg_out<Body>`. Alternatively, the user can omit performing
251 * `initRoot<Body>()`, and it will be done as needed by the ctor, resulting in a blank message at that point
252 * which then can be filled-out via body_root() mutations. (Note: This is just an example. The point is
253 * with this technique one can use a `MessageBuilder` in any fashion desired, and the only constraint is
254 * it is in fact rooted at some structure `S`, at which point `Msg_out<S>` can be cted. In that
255 * sense it removes any -- albeit typically simplifying -- ipc::transport constraints on how one builds a message,
256 * allowing one to use the full builder API provided by capnp without any stylistic concessions.)
257 *
258 * ### Resource use: RAM ###
259 * Creating a `*this`, and mutating it via body_root(), uses proportionally large RAM resources; e.g.,
260 * if you successfully store a multi-megabyte blob, `*this` will allocate RAM accordingly. Conversely,
261 * destroying `*this` returns such resources. However, if #Builder is SHM-based, then a process-counting
262 * ref-count (conceptually) exists. It is 1 after construction. It is incremented each time
263 * it is `struc::Channel::send()`t. For each such increment, there is a decrement when the receiving
264 * process's counterpart Msg_in, which is always passed-around by `shared_ptr`, is no longer
265 * owned by that process (when that `shared_ptr` group's ref-count drops to zero). Once `*this` is destroyed,
266 * *and* each `send()` target process has both yielded the struc::Channel::Msg_in_ptr and let that
267 * `shared_ptr` drop to ref-count-zero, the backing RAM is released.
268 *
269 * ### Resource use: the #Native_handle (if any) ###
270 * It is returned to the OS by our destructor. This does not, necessarily, destroy whatever resource it references:
271 * presumably the idea is to send it, via IPC, to the opposing process. The handle (FD) that process receives
272 * is really a new one in that process's table; there are at that point two *descriptors* referencing one
273 * resource *description*, and the latter disappears in the kernel only once both descriptors go away.
274 * If you do not wish to let the local handle (FD) be destroyed by `*this` destructor, consider (in Unix-type OS)
275 * passing-in `your_hndl.dup()` (or equivalent) instead of `your_hndl` itself.
276 *
277 * Corollary: `*this` *owns* the stored handle. Do not store the same handle value in 2+ `Msg_out`s (or otherwise
278 * retain ownership of it elsewhere): each owner would close it which is formally undefined behavior (in Unix-type
279 * OS it could close some unrelated resource). Again: Native_handle::dup() it (or equivalent) instead.
280 *
281 * The #Native_handle, if any, stored via store_native_handle_or_null() is not a part of the
282 * serialization/deserialization/sharing schema described above. It just sits in `*this` until `*this` dtor runs
283 * (or it is replaced/unloaded via store_native_handle_or_null()). If at send() time there's one in `*this`,
284 * then a copy is transmitted to the recipient process. store_native_handle_or_null() on `*this` will never
285 * have any direct effect on any received copy.
286 *
287 * @internal
288 *
289 * Impl notes
290 * ----------
291 * ### Metadata sharing message payload's segment 1 ###
292 * First the user constructs a `*this` and modifies the message payload; this is all essentially vanilla.
293 * Then the user transmits a `*this` via e.g. sync_io::Channel::send() which takes a pointer to mutable
294 * `*this`. (Why mutable, if it's only sending? The answer is above when explaining internally-used metadata.)
295 * The user can then continue serially doing either thing an indefinite number of times. However:
296 *
297 * Consider the aforementioned `Channel send()` (et al). Conceptually what it does is still straightforward:
298 * fills out certain metadata, for example a message ID, inside `*this`; then IPC-transmits the metadata
299 * (which is small) and then some representation of the message payload. Why not just deal with the metadata
300 * separately? It could after all "just" keep the metadata in a totally separate structure and even take
301 * a `const Msg_out` after all. (Indeed an earlier version of Flow-IPC did just that.) Answer: it is because of
302 * performance. This is easiest explained with the simplest possible situation: a small message, backed by
303 * a Heap_fixed_builder, requiring only 1 segment -- let's say sized 4Ki bytes. Plus we internally must send
304 * metadata (as of this writing fitting into 128 bytes) also. The easy/elegant thing to do is make an OS-send
305 * syscall for the mdt and then another for the payload. However this is deceptively expensive at high loads:
306 * each syscall entry/exit is relatively expensive; plus (details omitted) the same is ~mirrored on the receive
307 * end; plus (and this can dwarf the syscall aspect) it is 2x the amount of allocating.
308 * We've empirically shown that it is much better to "embed" the mdt as (e.g.) a header into the single memory
309 * area containing the message-payload segment 1 (which is often the only segment, period). So that is what we do.
310 *
311 * Any #Builder, to be compatible with this system, for this reason *must* supply a sufficiently large
312 * frame-prefix area in its segment 1; this will hold the mdt header Flow-IPC internals load there.
313 *
314 * In short: a `Channel` send-y function (or any equivalent) must
315 * call emit_serialization() to fill-out the mdt (based partially on items like the msg ID passed to that method)
316 * and obtain the final list (often 1-long) of segments (buffers in memory)
317 * to IPC-transmit. Segment 1 of these will transparently contain the mdt header in a way that
318 * Msg_in internals will properly decode.
319 *
320 * ### Facade design ###
321 * You may have noted that emit_serialization() is a back-end operation: sync_io::Channel (or equivalent) needs
322 * access to it, but the user need not even know of its existence.
323 *
324 * Indeed this API is `private`. The detail/ `friend`-facade type Msg_out_impl exposes it publicly (but by
325 * convention user has no access to detail/ types).
326 *
327 * Incidentally emit_serialization() is what sets the metadata aspects of the serialization; so it is not `const`.
328 * It is what sync_io::Channel::send() calls that requires that guy (and similar) to take `Msg_out*` and not
329 * `const Msg_out&`.
330 *
331 * @endinternal
332 *
333 * @tparam Body_t
334 * See struc::Channel.
335 * @tparam Builder_t
336 * See struc::Channel.
337 */
338template<typename Body_t, typename Builder_t>
339class Msg_out // Reminder: It is movable but not copyable.
340{
341public:
342 // Types.
343
344 /// See struc::Channel::Msg_body.
345 using Body = Body_t;
346
347 /// Short-hand for capnp-generated mutating `Builder` nested class of #Body. See body_root().
348 using Body_builder = typename Body::Builder;
349
350 /**
351 * Short-hand for user-specified Struct_builder type. An internally stored instance of this contains the user
352 * payload.
353 */
354 using Builder = Builder_t;
355
356 /**
357 * Short-hand for user-specified Struct_builder::Config. One can construct a #Builder via
358 * `Builder(const Builder_config&)`.
359 */
360 using Builder_config = typename Builder::Config;
361
362 /// Short-hand for capnp orphan factory. See orphanage().
363 using Orphanage = ::capnp::Orphanage;
364
365 // Constructors/destructor.
366
367 /**
368 * Creates blank #Body-bearing out-message, with no native handle,
369 * all of which can be modified via body_root() and the ancillary mutator store_native_handle_or_null().
370 *
371 * See also the alternate (advanced-technique) ctor form which may be more suitable in more complex scenarios.
372 * This is discussed in our class doc header.
373 *
374 * ### Obtaining the #Builder_config object ###
375 * In the first place it is often easier/better to not invoke this ctor directly but rather
376 * invoke struc::Channel::create_msg() which will do so for you and supply the proper #Builder_config.
377 * However it is definitely possible for a Msg_out to be constructed orthogonally to a
378 * particular struc::Channel -- or even to a particular ipc::Session (if even applicable). How to get
379 * the `struct_builder_config` arg for this ctor then? Informally: if you're constructing the #Builder_config
380 * directly, you're probably not doing the right thing. The following places are available to obtain one
381 * for safety and efficiency (and code maintainability):
382 * - From another, compatible, struc::Channel via struc::Channel::struct_builder_config().
383 * - Heap-backed: Via `static` struc::Channel::heap_fixed_builder_config().
384 * - SHM-backed (e.g., SHM-classic):
385 * - session::shm::classic::Session_mv::session_shm_builder_config(),
386 * session::shm::classic::Session_mv::app_shm_builder_config(). Requires a `Session` object.
387 * - session::shm::classic::Session_server::app_shm_builder_config() (requires session::Client_app).
388 * Server-only; if a `Session` is not available or applicable.
389 *
390 * @param struct_builder_config
391 * See above.
392 */
393 explicit Msg_out(const Builder_config& struct_builder_config);
394
395 /**
396 * Advanced technique: Creates message by subsuming the provided already-prepared
397 * `Capnp_msg_builder_interface`-bearing, root-initialized-to-#Body #Builder object (which is moved-to `*this`),
398 * with no native handle, all of which can be (further) modified via body_root() and the ancillary
399 * mutator store_native_handle_or_null().
400 *
401 * The advanced technique revolving around the use of this ctor form is discussed in our class doc header.
402 * That said:
403 * - `*struct_builder.payload_msg_builder()` -- a #Capnp_msg_builder_interface -- *must* already have
404 * been root-initialized, and the root type *must* be #Body; or *must* not have been root-initialized
405 * at all (in which case the ctor will perform `initRoot<Body>()`).
406 * - If it was already root-initialized, but not with `<Body>`, then behavior is undefined, and the trouble
407 * may only be detected on the opposing side upon receipt of `*this` message, in trying to
408 * deserialize it in Msg_in.
409 * - If you chose to not root-initialize before this ctor, and therefore it performs `initRoot<Body>()`,
410 * then naturally the message root tree shall be blank, similarly to the other/vanilla ctor.
411 * - This is typically accomplished via `struct_builder.payload_msg_builder()->initRoot<Body>()`, although
412 * there are other techniques available. See capnp docs for `capnp::MessageBuilder`
413 * (#Capnp_msg_builder_interface).
414 * - That having been guaranteed, the message may be further mutated via body_root().
415 * - Naturally it may also have already been mutated (beyond `initRoot()`/etc.), possibly to its final intended
416 * form.
417 * - Conversely, in practice, if you chose to not root-initialize `struct_builder`, you'll want to in fact
418 * use body_root() mutations to actually load the message with something useful.
419 *
420 * For exposition purposes: note that the other ctor form, which takes a `Builder::Config`, behaves as-if
421 * delegating to the present ctor: `Msg_out{Builder{struct_builder_config}}`.
422 * When creating a straightforward message in ~one place in the user code, using that other ctor form is
423 * usually therefore more convenient, avoiding some boiler-plate.
424 *
425 * @param struct_builder
426 * See above. Note the requirements listed.
427 */
428 explicit Msg_out(Builder&& struct_builder);
429
430 /// Creates non-message; any operation except move-to or destruction results in undefined behavior subsequently.
431 Msg_out();
432
433 /**
434 * Move ctor: Make `*this` equal to `src`, while `src` becomes as-if default-cted (in that any operation
435 * except move-to or destruction results in undefined behavior subsequently).
436 *
437 * @param src
438 * Source object.
439 */
441
442 /// Disallow copying.
443 Msg_out(const Msg_out&) = delete;
444
445 /**
446 * Returns resources, including potentially significant RAM resources and native_handle_or_null(), taken throughout;
447 * in the case of SHM-based RAM resources their return may be delayed until counterpart `Msg_in`s
448 * are also destroyed. See class doc header for discussion.
449 */
451
452 // Methods.
453
454 /**
455 * Move assignment: Destroy `*this` contents; make `*this` equal to `src`, while `src` becomes as-if
456 * default-cted (in that any operation except move-to or destruction results in undefined behavior subsequently).
457 *
458 * @param src
459 * Source object.
460 * @return `*this`.
461 */
463
464 /// Disallow copying.
465 Msg_out& operator=(const Msg_out&) = delete;
466
467 /**
468 * The #Body root capnp-generated mutator object. E.g.: `this->body_root()->initSomeStruct().setSomeField(123)`
469 * will create the capnp-`struct`-typed root field `someStruct` and set the value `someField` -- presumably an
470 * integer -- within it. The pointer returned shall always be the same value until `*this` is destroyed.
471 *
472 * #Body_builder is light-weight, so you may make a copy and then mutate via that, if desired. However
473 * whether `*(body_root())` or such a copy, such a `Builder` object may not be accessed after `*this` is destroyed.
474 *
475 * Informally we recommend against copying `*(body_root())`: Light-weight or not, it's a copy, and copying a pointer
476 * is cheaper; and it may not live past `*this` anyway; and body_root() always returns the same pointer. So just
477 * store the pointer (or reference from it).
478 *
479 * ### Quick capnp tips ###
480 * You should really read all of capnp docs at its web site. They are very useful and well written and not
481 * overly formal despite being quite comprehensive. That said a couple of gotchas/tips:
482 * - On a `Builder`, `.getX()` and `.setX()` are fast, like accessing `struct` members directly --
483 * but only when `X` is of a scalar type. Compound types, where `.getX()` returns not a native type
484 * but another `Builder`, need to perform some pointer checking and are slower. Therefore,
485 * if you plan to `.getX()` and then `.setA()` and `.setB()` (and similar) on that `X`, you should
486 * save the result (`auto x = ....getX();`); then mutate via the saved result (`x.setA(...); x.setB(...)`).
487 * - Let `X` be a compound field, particularly `List`, `Text` (string/list-of-characters),
488 * `Data` (list-of-bytes). It is usually, to begin, null; you must perform `.initX(size_t n)` or equivalent
489 * to initialize it (fill it with `n` zeroes). However, suppose you are mutating a message, such as
490 * a previously-sent message, and wish to *modify* the `X`. If the new value might have the same length (which is
491 * common), the correct thing to do is: check `.hasX()`; if `true`, modify `.getX()`;
492 * but if `false` then `.initX(n)` (as `X` was null after all). Performing `.initX()` on an already-`.initX()`ed
493 * value works but has a nasty invisible effect: the existing datum continues taking space in the
494 * serialization; the new datum takes a new chunk of the serialization segments (and might even cause
495 * the allocation of a new segment if needed). As of this writing capnp does not reuse such orphaned
496 * space. If the new `n` equals the old `n`, this is a straight waste of RAM; and can lead to pathologically
497 * growing memory leaks if done many times.
498 * - However, if the new `n` is different from the preceding, then there is no choice but to
499 * re-`.initX()`. A list/blob/string's size cannot be modified in capnp.
500 * - It is best to avoid any situation where the `n` would change; try to design your protocol differently.
501 *
502 * @return See above.
503 */
505
506 /**
507 * Equivalent to the other body_root() overload but immutable version. May be useful for, say, pretty-printing it
508 * to log (e.g.: `os << ostreamable_capnp_full(M.body_root()->asReader());`).
509 *
510 * @return See above.
511 */
512 const Body_builder* body_root() const;
513
514 /**
515 * Convenience method that returns a `capnp::Orphan` factory in the same `capnp::MessageBuilder` as body_root().
516 * Therefore `Orphan`s generated via the returned #Orphanage can be `adopt...()`ed by the `Builder` `*(body_root())`
517 * and its various sub-fields' `Builder`s (at any depth).
518 *
519 * ### Suggested technique ###
520 * In general, the orphan concept is discussed briefly but usefully in the "C++ serialization" section of
521 * capnp docs (the web site). We do not attempt to get into all these topics. However consider the following
522 * pattern.
523 *
524 * In general the Flow-IPC system places almost no constraints on #Body (the schema), but there is one:
525 * Generally there must be an anonymous capnp-`union` at the top of #Body, and in practice any message will
526 * eventually load the root (body_root()) with one of the `union` choices. (This is to operate within the
527 * struc::Channel::expect_msg() and struc::Channel::expect_msgs() APIs.) The vanilla approach to building
528 * the message is top-down: body_root() is pre-initialized to be a #Body; then, say, if your plan is to
529 * load it with the `union` choice `someChoice`, then you'd do `body_root()->initSomeChoice()`; then
530 * mutate stuff inside the `Builder` returned by that. There could be an arbitrarily complex sub-tree within that,
531 * built top-down in the same fashion.
532 *
533 * Instead you may choose to build it bottom-up. For this discussion let's assume `struct SomeChoice`
534 * has a number of scalars. You would first obtain and save an `Orphanage`:
535 * `auto orphan_factory = M.orphanage()`. Next you would create an orphan, not yet connected to the root
536 * body_root(), like so:
537 * `auto some_choice_orphan = orphan_factory.newOrphan<SomeChoice>(); some_choice_builder = some_choice_orphan.get()`.
538 * Next you'd set the scalars within it: `some_choice_builder.set...(...)`. Lastly, when it's ready, graft it into
539 * the actual root: `body_root()->adoptSomeChoice(some_choice_orphan)`.
540 *
541 * Due to the simplicity of this example one might wonder why not simply build it top-down in the first place.
542 * Indeed. However, if `struct SomeChoice` is a complex tree of `struct`s within `List`s within (...),
543 * it would be reasonable to build the lowest levels of that tree by generating intermediate orphans
544 * (via `orphan_factory.newOrphan<LowerLevelStructOrListOrWhatever>()`), adopting them into higher-level
545 * orphans, and so on, finishing it via the top-level `body_root()->adoptSomeChoice()` call.
546 *
547 * ### Similar technique ###
548 * See also the 2nd (advanced) ctor form. It allows one to do the above but takes it further by not even
549 * needing a Msg_out until the time comes to actually struc::Channel::send() the message.
550 * I.e., one would work with essentially a #Capnp_msg_builder_interface directly, including
551 * invoking `Capnp_msg_builder_interface.getOrphanage()`.
552 *
553 * @return See above.
554 */
556
557 /**
558 * Store the `Native_handle` (potentially `.null()`, meaning none) in this out-message; and, unless the same
559 * handle value is already stored, returns the previously stored native handle to the OS (similarly to dtor).
560 *
561 * Any non-null stored handle shall be returned to the OS by `*this` destructor; if you wish to avoid this then
562 * consider (in Unix-type OS) passing-in `your_hndl.dup()` instead of `your_hndl` itself. In particular do not
563 * store the same handle value in 2+ `Msg_out`s (or otherwise co-own it): see class doc header ("Resource use").
564 *
565 * @param native_handle_or_null
566 * The `Native_handle` (`.null() == true` if none) to move into `*this`. Made `.null() == true` upon return.
567 * The latter occurs even if `this->native_handle_or_null() == native_handle_or_null` was pre-condition
568 * (meaning `this->native_handle_or_null()` was not returned to OS).
569 */
571
572 /**
573 * Returns whatever was the last word according to store_native_handle_or_null(). Note it is a copy;
574 * `*this` retains ownership of the OS resource.
575 *
576 * @return See ctor (which stores no handle), store_native_handle_or_null().
577 */
579
580 /**
581 * Prints string representation to the given `ostream`. This representation lacks newlines/indentation;
582 * includes a (potentially truncated) pretty-printed representation of `body_root()` contents; and includes
583 * native_handle_or_null().
584 *
585 * Caution: This could be an operation expensive in processor cycles and, temporarily, RAM; and thus should
586 * be used judiciously. To help drive your decision-making: This method, internally,
587 * -# uses ostreamable_capnp_brief() -- which internally generates, via capnp `kj::str()`, a *full*
588 * single-line pretty-print of body_root() contents, truncating the result as needed for a reasonably
589 * short output -- and prints the result;
590 * -# adds native_handle_or_null() and possibly a few other small information items.
591 *
592 * Because there is no reasonably-available way to stop generating the pretty-print in step 1 upon reaching
593 * a certain number of characters, the operation may take a while, if many non-default bytes have been
594 * mutated-in; and before truncation the resulting string may take significant RAM accordingly.
595 *
596 * @param os
597 * Stream to which to write.
598 */
599 void to_ostream(std::ostream* os) const;
600
601private:
602 // Friends.
603
604 /// Facade type that exposes specific `private` APIs of `*this` to other internal Flow-IPC code.
605 template<typename T>
606 friend struct Msg_out_impl;
607
608 // Methods.
609
610 /**
611 * (Access via Msg_out_impl) Finalizes (for at least IPC-transmission) the serialization of metadata and
612 * user-payload in memory and emits the locations/sizes of the (1+) segments in that serialization.
613 * It is meant to be invoked at struc::sync_io::Channel::send() time.
614 *
615 * It can be invoked repeatedly: `session` can specify a different destination each time; or the same
616 * destination each time; or an arbitrary mix thereof. In particular struc::sync_io::Channel::send() (and its
617 * derivatives including `async_request()`) shall each time specify the
618 * channel's opposing process as the destination -- regardless of which struc::Channel's
619 * struc::Channel::create_msg() originally generated `*this` (assuming that method was even used for
620 * construction of `*this` -- in no way required, just often convenient).
621 *
622 * @see our class doc header and/or "Lifecycle of an out-message" section of struc::Channel class doc
623 * header. Recall that where it mentions `Channel send()`, you can understand
624 * there to be a 1-1 relationship with a synchronous call to `this->emit_serialization()`.
625 *
626 * @note Reminder: Msg_out is for user out-messages; an internal out-message has only metadata and thus can/should
627 * be created and serialized using a single blob + simple Capped_sz_capnp_message_builder and direct
628 * load_mdt() call.
629 *
630 * ### Errors ###
631 * See Struct_builder::emit_serialization(). This essentially forwards to that and emits its errors if any.
632 *
633 * Additionally the error error::Code::S_INVALID_ARGUMENT may be emitted, if segment 1 (computed by the
634 * serialization-engine given at construction) lacks a sufficiently-large frame-prefix to hold the mdt header.
635 *
636 * Additionally the errors from load_mdt() may be emitted (see its doc header; as of this writing
637 * in particular watch out for error::Code::S_SERIALIZE_FAILED_SPLIT_ENCODING_TOO_BIG and
638 * error::Code::S_SERIALIZE_FAILED_SPLIT_SEGS_TOO_MANY).
639 *
640 * @note On error the out-args' contents are unspecified, except for the following:
641 * If emitting error::Code::S_SERIALIZE_FAILED_SPLIT_ENCODING_TOO_BIG or
642 * error::Code::S_SERIALIZE_FAILED_SPLIT_SEGS_TOO_MANY: `*split_segs_out_or_null`
643 * shall be correctly set. (Rationale: For logging/reporting/stats.)
644 *
645 * @param segs_out_ptr
646 * On success (no error emitted) this is cleared and replaced with the sequence of segments as
647 * pointer/size pairs.
648 * @param split_segs_out_or_null
649 * If not null, `*split_segs_out_or_null` is set (on success) to the split-segment metadata
650 * describing which of the output segments were split across multiple blobs. Empty if no
651 * splitting occurred. Useful for stats instrumentation without re-parsing the mdt header.
652 * Perf cost is low, as we only `move()` a thing required internally anyway.
653 * @param session
654 * Specifies the opposing recipient for which the serialization is intended.
655 * If `Builder::Session` is Null_session, then `{}` is the only value to supply here. Otherwise more
656 * information is necessary.
657 * @param err_code
658 * Caution: Unlike user-facing methods, this does not throw (except capnp-generated exceptions);
659 * and `err_code` may not be null. See above regarding emitted codes.
660 * @param load_mdt_args
661 * Arguments to forward to struc::load_mdt() during the metadata-filling steps;
662 * specifically the args `session_token`, `originating_msg_id_or_none`, `id_or_none`.
663 */
664 template<typename... Load_mdt_args>
665 void emit_serialization(Segment_bufs* segs_out_ptr, Split_segments* split_segs_out_or_null,
666 const typename Builder::Session& session,
667 Error_code* err_code, Load_mdt_args&&... load_mdt_args);
668
669 // Data.
670
671 /**
672 * The guy serializing a #Body, as well as storing -- but not itself loading -- a frame-prefix big-enough for
673 * our mdt header in its mandatory segment 1. Underlying serialization potentially further mutated by user via
674 * body_root(); while emit_serialization() finalizes the mdt header's contents.
675 */
677
678 /**
679 * See body_root().
680 *
681 * ### Rationale ###
682 * We don't strictly need to save this; we could have body_root() return the #Body_builder, not a pointer to
683 * it. This would not be out of line; it is a general capnp-documented tip to act on a given `Builder` repeatedly
684 * as opposed to accessing it via an accessor each time; so we could encourage the user to do that -- not
685 * our problem. (Though I (ygoldfel) am not positive that perf tip applies to the root capnp-`struct`; maybe
686 * look into it sometime for education.) It would also reduce `*this` footprint a bit and simplify/speed-up
687 * the move-ctor and move-assignment somewhat (a capnp `Builder` is light-weight but not totally tiny, consisting
688 * of a few pointers and integers). So why do this?
689 *
690 * Honestly keeping it this way is firstly a historic artifact from an earlier situation where keeping a
691 * pointer made sense in a no-longer-relevant sense (explaining how here would be uninteresting).
692 * That said it's a fairly cheap little optimization that allows the repeated use of body_root() with no perf
693 * penalty, and it is nice and expressive to have a non-`const` accessor returning a pointer to *the*
694 * thing that would mutate `*this`. Similarly it's nice to have a `const` accessor returning pointer-to-`const`
695 * suitable for pretty-printing. Throw in now having to change existing call sites, and voila, this decision.
696 */
698
699 /**
700 * Mdt header builder lazily de-nullified by the first successful emit_serialization() and then (by any
701 * successful emit_serialization()) filled-out with appropriate mdt (e.g. the message ID).
702 *
703 * ### Design/rationale ###
704 * Note that:
705 * - this does not own the backing (small) memory but merely provides us capnp-mutator access to it; while
706 * - #m_builder in fact owns that memory in its segment 1; so
707 * - why do we even store it as a data member rather than entirely creating/destroying this guy inside
708 * emit_serialization(), the only place where it is needed?
709 *
710 * Answer: This is done purely for perf in the event that emit_serialization() is successfully used 2+ times.
711 * The first time we create it but choose not to destroy it. The second time, then, struc::load_mdt() (as
712 * invoked by emit_serialization()) can mutate capnp-accessed fields instead of the relatively expensive op where it
713 * would:
714 * -# fill backing header area with zeroes;
715 * -# inside it have capnp create various parts (however small) from scratch and then mutate them.
716 *
717 * At the cost of storing, basically, a little capnp `Builder` we can avoid a bunch compute that would result
718 * in the same thing anyway.
719 */
720 boost::movelib::unique_ptr<Capped_sz_capnp_message_builder> m_mdt_builder;
721
722 /// The `Native_handle`, if any, embedded inside this message; auto-closed on destruction/replacement.
724}; // class Msg_out
725
726/**
727 * A structured in-message *instance* suitable as received and emittable (to user) by struc::Channel. Publicly
728 * these are never constructed but emitted into `Channel`-passed handlers, wrapped in `shared_ptr`
729 * Channel::Msg_in_ptr. The APIS involved include Channel::expect_msg(),
730 * Channel::expect_msgs(), Channel::async_request(), and Channel::sync_request(); plus
731 * similar sync_io::Channel APIs.
732 *
733 * Once available to the user, one accesses the in-place (zero-copy) capnp serialization via body_root(),
734 * via which one can access the message's read-only contents.
735 *
736 * @see Msg_out
737 * @see "Lifecycle of an out-message" section of struc::Channel class doc header for useful context.
738 * Note that for each Msg_out, there will exist 0+ `Msg_in`s, one per
739 * successful `send()` (et al) paired with emission to user via aforementioned handlers. The latter represent
740 * each instance of the original message being received; the former represents the original message.
741 * Hence Msg_in access is read-only (`Reader` access only); Msg_out access
742 * is read/write (`Builder` access).
743 *
744 * ### Resource use: RAM ###
745 * If #Reader_config is non-SHM-based, then a `*this` is analogous to a Msg_out; the
746 * RAM used is released once `*this` is destroyed. If it *is* SHM-based, then the cross-process ref-count
747 * scheme explained in Msg_out doc header is in force.
748 *
749 * ### Resource use: the #Native_handle (if any) ###
750 * Firstly see similarly named section in Msg_out doc header. In particular note that
751 * the `*this`-stored descriptor is not the same descriptor as the one in the out-message object;
752 * rather it's a descriptor in a different process referring to the same description, with an OS/kernel-held
753 * ref-count.
754 *
755 * We wish to help you avoid leaking any stored non-null #Native_handle until process exit, so *if*
756 * `*this` contains one, then it owns it, and like Msg_out will return it to the OS (Native_handle::close())
757 * in dtor. However if you wish to yourself use the #Native_handle -- which is typical in most non-error
758 * scenarios -- then call emit_native_handle_or_null(). Note that it is *not* `const`; it *will* cause
759 * `*this` to forget the `Native_handle`; and decision as to when/how to return it to the OS becomes yours.
760 *
761 * @internal
762 * ### Impl notes ###
763 * This follows the same facade-API pattern as Msg_out; see similar place in its doc header.
764 * Same applies here. It also similarly represents *both*
765 * - metadata-message about the associated user-message, if any, or the internal message; message ID,
766 * originating message ID, etc.; and
767 * - the user message (if any).
768 *
769 * Subtlety: That said, the decision to include the mdt in Msg_in is different from the one leading to doing the same
770 * for Msg_out. For Msg_in it is natural regardless: We can only receive an in-message together with its metadata;
771 * it was never (as an in-message) conceptually separated into those 2 parts; it did not exist, until we received it.
772 * Msg_out, however, does it just for performance, because mechanically the mdt header belongs with the first segment
773 * of the (outer) serialization of the user out-message. In fact no metadata even exists until
774 * send-time (Msg_out::emit_serialization()); and *after* send-time the metadata becomes irrelevant (and is
775 * overwritten at next send, if any, time).
776 *
777 * Corollary: In the case of an internal message, a `*this` is never emitted to the user. In that case
778 * internal_msg_body_root() provides internal access to the message. This is, as of this writing, asymmetrical
779 * to Msg_out which never represents an internal message -- there is no need to, in that case, as one can just
780 * use a `Blob` + Capped_sz_capnp_message_builder + load_mdt(); Msg_out is irrelevant and too-complex by comparison.
781 * Msg_in, though, means an in-message... so it applies to *any* received message.
782 *
783 * The expected sequence of calls (via Msg_in_impl facade) required to load a `*this` with the required
784 * serialization payload, so that either internal_msg_body_root() or body_root() can finally be used to access
785 * the deserialized structured data, is explained in some detail in the add_serialization_segment() doc header.
786 * To be clear the end user only gets access to a `*this` once body_root() is available (all that stuff has been done
787 * already).
788 *
789 * @endinternal
790 *
791 * @tparam Body_t
792 * See Msg_out: this is the counterpart.
793 * @tparam Reader_config_t
794 * See Msg_out: this is the counterpart.
795 */
796template<typename Body_t, typename Reader_config_t>
797class Msg_in :
798 private boost::noncopyable
799{
800public:
801 // Types.
802
803 /// See struc::Channel::Msg_body.
804 using Body = Body_t;
805
806 /// Short-hand for capnp-generated read-only-accessing `Reader` nested class of #Body. See body_root().
807 using Body_reader = typename Body::Reader;
808
809 /// See struc::Channel::Reader_config.
810 using Reader_config = Reader_config_t;
811
812 // Constructors/destructor.
813
814 /**
815 * Returns resources, potentially including potentially significant RAM resources, taken before emitting to the user.
816 * The value that *would* currently be returned by emit_native_handle_or_null(), if not `.null()`, is returned to
817 * the OS. (Use emit_native_handle_or_null() if you wish to make use of it first instead.)
818 *
819 * See class doc header for discussion.
820 */
822
823 // Methods.
824
825 /**
826 * The #Body root capnp-generated accessor object. E.g.: `this->body_root().getSomeStruct().setSomeField()`
827 * will access the capnp-`struct`-typed root field `someStruct` and pluck out the value `someField` -- presumably an
828 * integer -- within it. The ref returned shall always be to the same address until `*this` is destroyed.
829 *
830 * #Body_reader is light-weight, so you may make a copy and then access via that, if desired. However
831 * whether `body_root()` itself or such a copy, such a `Reader` object may not be accessed after `*this` is destroyed.
832 *
833 * Informally we recommend against value-copying body_root(): Light-weight or not, it's a copy, and copying a
834 * pointer/cref is cheaper; and it may not live past `*this` anyway; and body_root() always returns the same address.
835 * So just store the cref (or pointer-to-`const` with the same addr).
836 *
837 * ### Quick capnp tips ###
838 * You should really read all of capnp docs at its web site. They are very useful and well written and not
839 * overly formal despite being quite comprehensive. That said a couple of gotchas/tips:
840 * - On a `Reader`, `.getX()` is fast, like accessing `struct` members directly --
841 * but only when `X` is of a scalar type. Compound types, where `.getX()` returns not a native type
842 * but another `Reader`, need to perform some pointer checking and are slower. Therefore,
843 * if you plan to `.getX()` and then `.getA()` and `.getB()` (and similar) on that `X`, you should
844 * save the result (`auto x = ....getX();`); then access via the saved result
845 * (`a = x.getA(...); b = x.getB(...)`).
846 *
847 * To pretty-print (with indent/newlines) you can use: `os << ostreamable_capnp_full(M.body_root());`.
848 *
849 * @internal
850 * @see add_serialization_segment() doc header for the overall expected call sequence including the present
851 * method.
852 * @endinternal
853 *
854 * @return See above.
855 */
856 const Body_reader& body_root() const;
857
858 /**
859 * Returns the #Native_handle -- potentially null meaning none -- embedded in this message; and forgets
860 * that #Native_handle. The next call to `this->emit_native_handle_or_null()` shall return a
861 * `.null() == true` object.
862 *
863 * @warning Returning the handle (if not null) to the OS (via Native_handle::close() or another technique),
864 * if it is undesirable to leak it until process exit, is the caller's responsibility.
865 * However if you do not call emit_native_handle_or_null(), then our dtor will handle it,
866 * thus not leaking it past `*this` existence.
867 *
868 * @return See above.
869 */
871
872 /**
873 * Size of the serialization in memory in bytes; only the serialization as transmitted via IPC counts.
874 * That is, if #Reader_config means we are SHM-backed (or anything else involving an outer and inner
875 * serialization), then the in-SHM (or equivalent inner) serialization does not count.
876 *
877 * This is meant purely informationally as for logging/reporting/alerting: not for algorithmic purposes.
878 *
879 * @internal
880 * The precipitating use case was for stats tracking. However it is healthy to expose this publicly too.
881 * @endinternal
882 *
883 * @return See above.
884 */
885 size_t serialization_size() const;
886
887 /**
888 * Prints string representation to the given `ostream`. This representation lacks newlines/indentation;
889 * includes a (potentially truncated) pretty-printed representation of `body_root()` contents; and includes
890 * value that would be returned by emit_native_handle_or_null().
891 *
892 * Caution: This could be an operation expensive in processor cycles and, temporarily, RAM; and thus should
893 * be used judiciously. To help drive your decision-making: This method, internally,
894 * -# uses ostreamable_capnp_brief() -- which internally generates, via capnp `kj::str()`, a *full*
895 * single-line pretty-print of body_root() contents, truncating the result as needed for a reasonably
896 * short output -- and prints the result;
897 * -# adds handle that would be returned by emit_native_handle_or_null() and possibly a few other small
898 * information items.
899 *
900 * Because there is no reasonably-available way to stop generating the pretty-print in step 1 upon reaching
901 * a certain number of characters, the operation may take a while, if many non-default bytes have been
902 * mutated-in; and before truncation the resulting string may take significant RAM accordingly.
903 *
904 * @internal
905 * If used by internal code before successful deserialize_mdt() and/or before successful deserialize_body()
906 * (if one would even be possible in the first place -- not so with internal messages), this method will print
907 * some useful things. However the above public-facing description is no longer complete in that case.
908 * In any case the method remains suitable for TRACE-logging but not INFO-logging by internal code, at least
909 * in the per-message common code path.
910 * @endinternal
911 *
912 * @param os
913 * Stream to which to write.
914 */
915 void to_ostream(std::ostream* os) const;
916
917private:
918 // Friends.
919
920 /// Facade type that exposes specific `private` APIs of `*this` to other internal Flow-IPC code.
921 template<typename T>
922 friend struct Msg_in_impl;
923
924 // Types.
925
926 /**
927 * capnp `struct StructuredMessage` which is the structured view of the metadata (mdt) header.
928 * See `detail/structured_msg.capnp`.
929 */
930 using Mdt = schema::detail::StructuredMessage;
931
932 /**
933 * Short-hand for capnp-generated reader API for the internal-message sub-area of an #Mdt.
934 * See `detail/structured_msg.capnp`.
935 */
937
938 /// capnp-generated reader API for #Mdt structures.
939 using Mdt_reader = typename Mdt::Reader;
940
941 /**
942 * Short-hand for user-indirectly-specified Struct_reader concept impl. This can be used to interpret
943 * the user payload body_root() if any.
944 */
946
947 /// Short-hand for sync_io::stat::Channel_stats.
949
950 // Constructors/destructor.
951
952 /**
953 * (Access via Msg_in_impl) Constructs a not-ready-for-public-consumption in-message which awaits
954 * serialization-storing segments to be added via add_serialization_segment() and then finalized with
955 * deserialize_mdt() and possibly deserialize_body(). After the latter 1-2: body_root() or internal_msg_body_root()
956 * can be used to access the deserialized data; as can id_or_none() and similar accessors.
957 *
958 * @see add_serialization_segment() doc header for a more detailed description of what's next.
959 *
960 * @param struct_reader_config
961 * See struc::Channel ctors. This is copied, memorized.
962 */
963 explicit Msg_in(const Reader_config& struct_reader_config);
964
965 // Methods.
966
967 /**
968 * (Access via Msg_in_impl) Store the #Native_handle (potentially `.null()`, meaning none) in this in-message.
969 * Call this at most once; or behavior undefined (assertion may trip).
970 *
971 * @param native_handle_or_null
972 * The #Native_handle (`.null() == true` if none) to move into `*this`. Made `.null() == true` upon return.
973 */
974 void store_native_handle_or_null(Native_handle&& native_handle_or_null);
975
976 /**
977 * (Access via Msg_in_impl) Records the first or next, in order, unstructured-data chunk that is part of the eventual
978 * serialization of both the mdt header and the user in-message payload (if any). Once the proper number
979 * (typically/ideally) of these calls were made, at various points deserialize_mdt() and (if relevant)
980 * deserialize_body() are possible.
981 *
982 * Matching how Msg_out::emit_serialization() outputs the original serialization, this overall works as follows:
983 * -# add_serialization_segment() 1 (mandatory): After this it is possible to deserialize_mdt() which, importantly,
984 * returns the total # of calls that are needed (at least 1, including this one; but possibly 2+ if more are
985 * needed). This first blob shall contain the mdt header and, if it's a user message (not internal message),
986 * the first chunk of the user message's serialization.
987 * - This solidifies N (total # of blobs expected) and is-user-msg (whether it's a user message or not).
988 * - If is-user-msg is false, then done (`*this` is immutable from now on).
989 * internal_msg_body_root() is available.
990 * - Other mdt accessors -- id_or_none(), etc. -- are available.
991 * -# add_serialization_segment() 2, 3, ..., N (possible): N is from the previous bullet. This loads the remaining
992 * needed blobs comprised by the serialization of the user message. To be clear, though, it is possible and
993 * probable that N=1, even though is-user-msg is true. So, often there are no further
994 * add_serialization_segment() calls past the 1st one above.
995 * -# deserialize_body() (mandatory if is-user-msg): All data are available, so it sets up capnp-stuff. Hence:
996 * - body_root() is available.
997 *
998 * @note add_serialization_segment() doesn't care about the following, but since we're explicating the whole
999 * process here, here it is FYI: Usually each add_serialization_segment() indeed delivers exactly
1000 * one capnp-segment in the user message's serialization (plus the mdt header with the first one). However
1001 * at times a given capnp-segment is too large to fit in an IPC message and has to be split pre-send
1002 * by Msg_out::emit_serialization(). Therefore deserialize_body() has to do the reverse (join some of
1003 * the blobs into original segment(s)). (This involves copying and is relatively slow, so various parts
1004 * of the system take some pains to avoid it. When the `Struct_builder` is SHM-enabled, in particular,
1005 * splitting never occurs; but even otherwise we try to avoid it. Outside our scope here to discuss though.)
1006 * Hence the blobs delivered via add_serialization_segment() are not, technically, necessarily segments per se
1007 * but segment chunks. There is some mis-naming there, partially for historical reasons, but it's not too bad.
1008 * In any case the caller of these APIs can assume it'll just work, as Msg_out::emit_serialization()
1009 * and Msg_in::deserialize_body() take care of it. Last thing: This joining can only work, if we know which
1010 * segments were split into how many chunks; this information is in the mdt header delivered in
1011 * add_serialization_segment() 1.
1012 *
1013 * @param blob
1014 * The first or next chunk. The payload must be exactly in [`blob.begin()`, `blob.end()`).
1015 * In the case of the first chunk, said payload includes both the mdt header and (sub-)segment 1 following it.
1016 * We take over this blob; on return it shall be ~as-if default-cted due to a move-from.
1017 */
1019
1020 /**
1021 * (Access via Msg_in_impl) To be invoked after exactly one add_serialization_segment() call:
1022 * finalizes the deserialization of everything except the potential user-message body.
1023 * This must be called strictly before any calls to internal_msg_body_root(), id_or_none(),
1024 * originating_msg_id_or_none(), or session_token(); and any subsequent add_serialization_segment()
1025 * calls (if any).
1026 *
1027 * @see add_serialization_segment() doc header for the overall expected call sequence including the present
1028 * method.
1029 *
1030 * The value this returns (sans error) dictates the exact # of further add_serialization_segment() calls to make.
1031 * - If 1: You may use the accessor API immediately. internal_msg_body_root() is OK; `id_or_none() == 0`;
1032 * body_root() may not be used.
1033 * - Else: You may use the accessor API immediately. `id_or_none() != 0`; internal_msg_body_root() may not be
1034 * used (ever); body_root() may not be used *yet* until successful deserialize_body().
1035 *
1036 * If called before add_serialization_segment() 1, behavior is undefined (assertion may trip).
1037 * If called after add_serialization_segment() 2, behavior is undefined.
1038 * If called more than once, behavior is undefined (assertion may trip).
1039 *
1040 * If it fails (emits truthy #Error_code), it is pointless to use `*this`. Recommend destruction.
1041 *
1042 * @param logger_ptr
1043 * Logger to use for logging within this method.
1044 * @param err_code
1045 * Caution: Unlike user-facing methods, this does not throw (except capnp-generated exceptions);
1046 * and `err_code` may not be null. Other than that:
1047 * #Error_code generated: falsy on success, else:
1048 * error::Code::S_STRUCT_CHANNEL_INTERNAL_PROTOCOL_MISUSED_SCHEMA (opposing Msg_out code
1049 * filled out the fields in an unexpected way),
1050 * anything emitted by Struct_reader::deserialization().
1051 * @param stats_rcv_msg_internal_only
1052 * Method updates the following receive-side stats as appropriate *if and only if*
1053 * `*this` represents an internal message (otherwise deserialize_body() is to be used for this):
1054 * Channel_stats::Msg::m_internal_msgs, Channel_stats::Msg::m_total_low_lvl_blobs,
1055 * Channel_stats::Msg::m_total_segments, Channel_stats::Msg::m_single_segment_msgs,
1056 * Channel_stats::Msg::m_histo_msg_sz. On error some or all stats may still be updated; informally
1057 * we consider this harmless, as an error here is catastrophic (as opposed to a normal channel-hosing).
1058 * @return Total # of add_serialization_segment() calls required -- *including* the 1 that has already occurred.
1059 * See above.
1060 */
1061 size_t deserialize_mdt(flow::log::Logger* logger_ptr, Error_code* err_code,
1062 Channel_stats::Msg* stats_rcv_msg_internal_only);
1063
1064 /**
1065 * (Access via Msg_in_impl) To be invoked after `deserialize_mdt() == N`, and add_serialization_segment() has been
1066 * called N times: finalizes the deserialization of the user-message body. This must be called before any calls
1067 * to body_root().
1068 *
1069 * @see add_serialization_segment() doc header for the overall expected call sequence including the present
1070 * method.
1071 *
1072 * If called before a post-`deserialize_mdt()` add_serialization_segment(), behavior is undefined (assertion may
1073 * trip). If called more than once, behavior is undefined (assertion may trip).
1074 *
1075 * If it fails (emits truthy #Error_code), it is pointless to use `*this`. Recommend destruction.
1076 *
1077 * @param err_code
1078 * See deserialize_mdt().
1079 * @param stats_rcv_msg
1080 * Method updates the following receive-side stats as appropriate:
1081 * Channel_stats::Msg::m_user_msgs, Channel_stats::Msg::m_notifications,
1082 * Channel_stats::Msg::m_notification_responses, Channel_stats::Msg::m_handle_bearing_msgs,
1083 * Channel_stats::Msg::m_total_low_lvl_blobs, Channel_stats::Msg::m_msgs_with_split_segments,
1084 * Channel_stats::Msg::m_histo_split_blobs_per_seg, Channel_stats::Msg::m_total_segments,
1085 * Channel_stats::Msg::m_single_segment_msgs, Channel_stats::Msg::m_multi_segment_msgs,
1086 * Channel_stats::Msg::m_histo_msg_sz. On error some or all stats may still be updated; informally
1087 * we consider this harmless, as an error here is catastrophic (as opposed to a normal channel-hosing).
1088 */
1089 void deserialize_body(Error_code* err_code, Channel_stats::Msg* stats_rcv_msg);
1090
1091 /**
1092 * (Access via Msg_in_impl) To be called only after deserialize_mdt(), returns the message ID of this in-message;
1093 * 0 means it's an internal message (internal_msg_body_root() applies), else it's a user message (body_root()
1094 * applies).
1095 *
1096 * @return See above.
1097 */
1098 msg_id_t id_or_none() const;
1099
1100 /**
1101 * (Access via Msg_in_impl) To be called only after deserialize_mdt(), returns the message ID of the out-message
1102 * to which this in-message claims to be responding; or 0 if it is not a response.
1103 *
1104 * @return See above.
1105 */
1107
1108 /**
1109 * (Access via Msg_in_impl) To be called only after deserialize_mdt(), similar to body_root() but for the
1110 * internal-message root. See #Internal_msg_body_reader doc header.
1111 *
1112 * @return See above.
1113 */
1115
1116 /**
1117 * (Access via Msg_in_impl) To be called only after deserialize_mdt(), returns session token tagging this in-message.
1118 *
1119 * @return See above.
1120 */
1121 const Session_token& session_token() const;
1122
1123 /**
1124 * (Access via Msg_in_impl) The #Mdt root capnp-generated accessor object. May be useful for, say, pretty-printing it
1125 * to log (e.g.: `os << ostreamable_capnp_full(M.mdt_root());`). We do not recommend its use for
1126 * other purposes; stylistically it is better to access items via individual accessors like session_token()
1127 * or internal_msg_body_root(). See #Mdt doc header.
1128 *
1129 * @return See above.
1130 */
1131 const Mdt_reader& mdt_root() const;
1132
1133 // Data.
1134
1135 /// Sum of blob sizes in add_serialization_segment() calls so far.
1137
1138 /**
1139 * A very simple `capnp::MessageReader` that provides structured access to the mdt header.
1140 * Null until successful deserialize_mdt(), non-null thereafter. At that point #m_mdt_root is available
1141 * for capnp-accessor access to the stuff, but that guy is lightweight and needs the daddy `MessageReader`
1142 * (this thing here) to live. (Also the underlying memory, of course, has to remain valid/unchanged for either
1143 * of them to make any sense.)
1144 */
1145 std::optional<Capped_sz_capnp_message_reader> m_mdt_reader;
1146
1147 /**
1148 * The Struct_reader concept impl that does much of the heavy lifting (e.g., it might be SHM-enabled; or just
1149 * be a basic Heap_reader) when it comes to the user message's deserialization (if any).
1150 * Things like add_serialization_segment() and deserialize_body() mostly forward to it. However: all work
1151 * w/r/t the mdt header is up to `*this` proper; by the time deserialize_body() invokes
1152 * `m_body_reader.deserialization()` we would have already grokked the mdt stuff fully and fixed-up blob 1
1153 * inside #m_body_reader to begin *after* the mdt header. Hence Struct_reader::deserialization() can actually
1154 * interpret the user message without being aware of the mdt header that shares a buffer with the user-message
1155 * serialization. (Reminder: That setup is for perf.)
1156 *
1157 * @note `m_body_reader` owns the memory containing all of the serialization of everything.
1158 * add_serialization_segment() transfers the caller-supplied `Blob` to it via move-semantics.
1159 */
1161
1162 /**
1163 * Meaningful from add_serialization_segment() on, this simply describes the memory
1164 * area that begins with the mdt header and ends anywhere past its last byte. In actual fact, for simplicity,
1165 * it is simply `B.const_buffer()`, where `B` was passed to the first add_serialization_segment() call.
1166 * (Even though this includes possible seg 1 user-message payload that follows the mdt header, when deserializing
1167 * the header anything such trailing stuff is never looked-at. There's no point in finding the actual end of
1168 * the header's serialization.)
1169 *
1170 * Before that: it is default-cted. After deserialize_mdt() the values themselves are no longer needed, but
1171 * it is left alone, because `bool(m_mdt_header_area.data())` is useful for determining whether
1172 * add_serialization_segment() has been called already.
1173 *
1174 * By then we have the #m_mdt_root, which is all we wanted in the first place, and that continues to work fine,
1175 * as long as this memory area still holds the same *contents*. This *description* of those contents is not required
1176 * anymore (but, again, is as of this writing used as a flag).
1177 */
1179
1180 /// Starts `false`; becomes `true` immutably once deserialize_mdt() succeeds.
1182
1183 /// Starts `false`; becomes `true` immutably once deserialize_body() succeeds (never if it's an internal message).
1185
1186 /// See internal_msg_body_root(); meaningless until #m_mdt_deserialized_ok.
1188
1189 /// See body_root(); meaningless until #m_body_deserialized_ok.
1191
1192 /**
1193 * Starts uninitialized, this is assigned exactly once by deserialize_mdt(), storing the session-token that
1194 * was embedded in the in-message. This is cached from the encoding in the tree accessed via #m_mdt_root.
1195 * It is cached for session_token() perf only.
1196 */
1198
1199 /// See store_native_handle_or_null().
1201}; // class Msg_in
1202
1203// Free functions: in *_fwd.hpp.
1204
1205// Template implementations.
1206
1207/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
1208#define TEMPLATE_STRUCT_MSG_OUT \
1209 template<typename Body_t, typename Builder_t>
1210/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
1211#define CLASS_STRUCT_MSG_OUT \
1212 Msg_out<Body_t, Builder_t>
1213/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
1214#define TEMPLATE_STRUCT_MSG_IN \
1215 template<typename Body_t, typename Reader_config_t>
1216/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
1217#define CLASS_STRUCT_MSG_IN \
1218 Msg_in<Body_t, Reader_config_t>
1219
1220// Msg_out template implementations.
1221
1223CLASS_STRUCT_MSG_OUT::Msg_out() :
1224 m_body_root(nullptr) // capnp deletes default ctor to "discourage incorrect usage" but makes this available.
1225{
1226 // OK then. Useless *this until moved-to.
1227}
1228
1230CLASS_STRUCT_MSG_OUT::Msg_out
1231 (const Builder_config& struct_builder_config) :
1232
1233 /* As promised, in this simple (typical) form we create the new capnp::MessageBuilder and initRoot<Body>() it
1234 * for them. Simply delegating as follows causes getRoot<Body>() to act as-if initRoot<Body>() due to lacking
1235 * an initialized root at that point. */
1236 Msg_out(Builder{struct_builder_config})
1237{
1238 // OK then. Mutate away, user.
1239}
1240
1242CLASS_STRUCT_MSG_OUT::Msg_out(Builder&& struct_builder) :
1243
1244 /* In this more advanced (from user's PoV) ctor form they already are giving us m_builder and guaranteeing
1245 * its getRoot<Body>() is either already a thing... or it is not root-initialized at all.
1246 * getRoot<Body>() by us will thus not modify the tree, if it is initialized; or will create a blank tree
1247 * (same as the other ctor), if it is not. The only problematic situation -- as advertised -- is
1248 * if they root-initialized it to something other than Body (e.g., initRoot<SomeOtherThing>()); then getRoot<Body>()
1249 * will try to treat non-Body as Body, and something will probably blow up at some point
1250 * (possibly during deserialization). */
1251 m_builder(std::move(struct_builder)), // Eat theirs!
1252 m_body_root(m_builder.payload_msg_builder()->template getRoot<Body>()) // Pluck out theirs, or initialize if needed!
1253{
1254 // OK then. Mutate away, user (though they may well have finalized m_body_root tree already).
1255}
1256
1258CLASS_STRUCT_MSG_OUT::Msg_out(Msg_out&&) = default;
1259
1261CLASS_STRUCT_MSG_OUT::~Msg_out() = default; // As promised m_hndl_or_null returns the handle (if any) to OS.
1262
1263/* The following `=default` will (among other things) perform `m_body_root = std::move(src.m_body_root)`.
1264 * I was a bit worried about this perf-wise (and note this of course similarly auto-occurs in the =default-ed
1265 * move ctor), but I (ygoldfel) did some due diligence on it:
1266 * - It is after all move()able (or this wouldn't compile), with implicitly-default move ops.
1267 * This doesn't "nullify" src.m_body_root, but that is perfectly fine; m_builder sure is made as-if
1268 * default-cted, and anyway using (other than move-to) of a moved-from `*this` is advertised as undefined
1269 * behavior.
1270 * - `Builder`s are generally treated as light-weight in capnp docs.
1271 * - Looking inside the current (version 0.10) code shows that a capnp-`struct` Builder is, internally,
1272 * entirely consisting of something called StructBuilder, and the latter consists of 4 pointers and 2
1273 * integers.
1274 * So it is fine (and so is the move ctor).
1275 *
1276 * Subtlety 2 (almost trivia): Own_native_handle a/k/a Boost's unique_resource, looking at latest source (9/2026),
1277 * appears not to guard against `this == &src` in its move-assignment, nor do the docs talk about that corner case.
1278 * So we don't advertise that behavior either. */
1280CLASS_STRUCT_MSG_OUT& CLASS_STRUCT_MSG_OUT::operator=(Msg_out&& src) = default;
1281
1283typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root()
1284{
1285 return &m_body_root;
1286}
1287
1289const typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root() const
1290{
1291 return const_cast<Msg_out*>(this)->body_root();
1292}
1293
1295typename CLASS_STRUCT_MSG_OUT::Orphanage CLASS_STRUCT_MSG_OUT::orphanage()
1296{
1297 return m_builder.payload_msg_builder()->getOrphanage();
1298 /* Aside: Per capnp docs ("C++ serialization") one can also do:
1299 * return ::capnp::Orphanage::getForMessageContaining(*(body_root())); */
1300}
1301
1303void CLASS_STRUCT_MSG_OUT::store_native_handle_or_null(Native_handle&& native_handle_or_null)
1304{
1305 if (native_handle_or_null == m_hndl_or_null.get())
1306 {
1307 // As promised: the stored handle is unchanged (not returned to OS); src is made null.
1308 native_handle_or_null = {};
1309 return;
1310 }
1311 // else
1312
1313 m_hndl_or_null.reset(std::move(native_handle_or_null)); // <prev value> is returned to OS; src is made null.
1314}
1315
1317Native_handle CLASS_STRUCT_MSG_OUT::native_handle_or_null() const
1318{
1319 return m_hndl_or_null.get();
1320}
1321
1323template<typename... Load_mdt_args>
1324void CLASS_STRUCT_MSG_OUT::emit_serialization(Segment_bufs* segs_out_ptr,
1325 Split_segments* split_segs_out_or_null,
1326 const typename Builder::Session& session,
1327 Error_code* err_code, Load_mdt_args&&... load_mdt_args)
1328{
1329 using util::Blob_mutable;
1330 using util::Blob_const;
1331 using boost::movelib::make_unique;
1332 constexpr size_t HDR_SZ = BUILDER_CONFIG_FRAME_PREFIX_SZ_VIA_STRUC_CHANNEL;
1333
1334 assert(err_code);
1335 auto& segs_out = *segs_out_ptr;
1336
1337 /* In the (hopefully rare) case where a seg ended up too big to fit into the per-segment cap in m_builder
1338 * such a seg shall be split into (replaced by) small-enough sub-segment views into it. We will essentially just
1339 * emit those via segs_out to caller; and it will just send them all out probably, one per (now small-enough)
1340 * message; but the receiver will need to reassemble (un-split, join) such segs before accessing the serialization.
1341 * Without knowing which of the segs_out are post-split sub-segs, as opposed to just being the mainstream case of
1342 * the original segs, this reassembly could not happen. Hence split_segs shall hold that information in compact
1343 * form -- and we shall encode it the metadata header (along with a few other important things). */
1344 Split_segments split_segs; // Again: This is info about *which* segs were split; not the segs themselves.
1345 Blob_mutable hdr_blob; // Header location ahead of seg 1.
1346
1347 m_builder.emit_serialization(segs_out_ptr, &hdr_blob, &split_segs, session, err_code);
1348 if (*err_code)
1349 {
1350 return;
1351 }
1352 // else
1353
1354 const auto n_segs = segs_out.size();
1355 assert(n_segs != 0);
1356
1357 if (hdr_blob.size() < HDR_SZ)
1358 {
1359 *err_code = error::Code::S_INVALID_ARGUMENT; // As advertised.
1360 return;
1361 }
1362 // else: Carry on. Errors still possible after this (see err_code accesses).
1363
1364 if (!m_mdt_builder)
1365 {
1366 // First emit_serialization() call (first send over IPC probably).
1367 m_mdt_builder = make_unique<Capped_sz_capnp_message_builder>
1368 (hdr_blob,
1369 false); // It is pre-zeroed by `Builder m_builder` when seg 1 is allocated.
1370 }
1371 // else { 2nd/3rd/... emit_serialization(). struc::load_mdt() will modify existing capnp-tree (unless it can't). }
1372 if (!struc::load_mdt(m_mdt_builder.get(), nullptr, err_code, std::forward<Load_mdt_args>(load_mdt_args)...,
1373 n_segs,
1374 split_segs.empty() ? nullptr : &split_segs))
1375 {
1376 /* We were trying to reuse m_mdt_builder for perf, but its existing split-segs thing is incompatible; so we cannot
1377 * reuse it and must make it afresh. (Because this is rare, perf-wise it should be OK. Also load_mdt() takes care
1378 * to check the bad condition first-thing hopefully getting us here snappily.) */
1379 m_mdt_builder = make_unique<Capped_sz_capnp_message_builder>
1380 (hdr_blob,
1381 true); // In this case there is stuff there from pre-existing m_mdt_builder; must re-zero it.
1382#ifndef NDEBUG
1383 const bool ok =
1384#endif
1385 struc::load_mdt(m_mdt_builder.get(), nullptr, err_code, std::forward<Load_mdt_args>(load_mdt_args)...,
1386 n_segs,
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.");
1389 }
1390 // else { Fast-path; nothing exotic. m_mdt_builder was fresh or was reused successfully (modulo *err_code). }
1391
1392 // However, if a load_mdt() returned true, it might still have failed by emitting *err_code.
1393 if (*err_code)
1394 {
1395 m_mdt_builder = {}; // It was loading *m_mdt_builder and hit an error and bailed out midway. Reduce entropy.
1396 if (split_segs_out_or_null)
1397 {
1398 /* As promised: occurrence of one of the particular things load_mdt() can fail with <=> *split_segs_out_or_null
1399 * shall be set for logging/etc. (If it's another error, contract = out-args undetermined... but
1400 * that doesn't disallow still doing this.) */
1401 *split_segs_out_or_null = std::move(split_segs);
1402 }
1403 return;
1404 }
1405 // else: load_mdt() succeeded. Note: no errors possible past this point.
1406
1407 /* As of this writing we do not consult m_mdt_builder (in its form now, until the next round of emit_serialization()
1408 * if any) from this point on; while the data it wrote remains for further use, since m_builder is
1409 * still around.
1410 *
1411 * That said by not consulting it we *will* ignore the following bit of information: How much space (of HDR_SZ)
1412 * was *actually* necessary for what load_mdt() loaded; m_mdt_builder->getSegmentsForOutput()[0].asBytes().size()
1413 * would be that; but it is stored in m_mdt_builder which is gonna be ignored. In fact we could destroy it now
1414 * and are only keeping it around for a more efficient struc::load_mdt() if they decide to emit_serialization() again.
1415 *
1416 * That is fine however: The idea is *all* of seg1 (and any -- possibly zero -- more needed segments
1417 * output by emit_serialization() here) shall be transmitted. The receiver shall first process the entire
1418 * seg1 blob -- which contains HDR_SZ bytes of mdt; then seg1 of the user message after that; but capnp will
1419 * just ignore anything beyond the blob-leading mdt serialization at this stage. Then, the receiver will
1420 * process the rest of seg1 plus any further segments (whose # is contained in mdt by the way: arg to load_mdt()),
1421 * yielding the user message.
1422 *
1423 * Yes, it *is* OK to give a capnp MessageReader a seg size greater (or equal to, obv) than the actual size used;
1424 * capnp will not go into areas that are of no interest to it anyway, and it doesn't have an unnecessary barf-response
1425 * to their existence. */
1426
1427 // Output split-segment metadata if requested (for stats instrumentation by caller).
1428 if (split_segs_out_or_null)
1429 {
1430 *split_segs_out_or_null = std::move(split_segs);
1431 }
1432
1433 /* Lastly output the list of `Blob_const`s (to IPC-transmit presumably) describing the n_segs segments... great --
1434 * segs_out is already that. Caveat: at the moment the load_mdt()-loaded stuff lives in the frame-prefix
1435 * area ([0, .start()) range) of seg1's Blob container. So "correct" seg1 to include that area; thus the
1436 * contiguous buffer that is the header plus seg1 shall be the first IPC-message. */
1437 auto& seg1 = segs_out.front();
1438 seg1 = Blob_const{hdr_blob.data(), hdr_blob.size() + seg1.size()};
1439} // Msg_out::emit_serialization()
1440
1442void CLASS_STRUCT_MSG_OUT::to_ostream(std::ostream* os_ptr) const
1443{
1444 auto& os = *os_ptr;
1445
1446 // This is not a public API but OK to output publicly methinks.
1447 os << "[n_serialization_segs[" << m_builder.n_serialization_segments() << "] ";
1448
1449 const auto hndl_or_null = native_handle_or_null();
1450 if (!hndl_or_null.null())
1451 {
1452 // As of this writing it's, like, "native_hndl[<the FD>]" -- that looks pretty good and pithy.
1453 os << hndl_or_null << ' ';
1454 }
1455 // else { No need to output anything; pithier. }
1456
1457 os << ostreamable_capnp_brief(body_root()->asReader()) << "]@" << this;
1458} // Msg_out::to_ostream()
1459
1460template<typename Body_t, typename Struct_builder_t>
1461std::ostream& operator<<(std::ostream& os, const Msg_out<Body_t, Struct_builder_t>& val)
1462// Doxygen 1.9.4 gets confused here with *_STRUCT_MSG_OUT; avoid 'em to work-around it. @todo Revisit with later ver.
1463{
1464 val.to_ostream(&os);
1465 return os;
1466}
1467
1468// Msg_in template implementations.
1469
1471CLASS_STRUCT_MSG_IN::Msg_in(const Reader_config& struct_reader_config) :
1472 m_total_sz(0),
1473 m_body_reader(struct_reader_config),
1474 m_mdt_deserialized_ok(false),
1475 m_body_deserialized_ok(false)
1476 // m_session_token is uninitialized garbage.
1477{
1478 // That's it: need to feed segment(s) into m_body_reader before can deserialize anything.
1479}
1480
1482void CLASS_STRUCT_MSG_IN::store_native_handle_or_null(Native_handle&& native_handle_or_null)
1483{
1484 assert(m_hndl_or_null.get().null() && "Call this at most once (probably upon finalizing 1st segment as well).");
1485
1486 m_hndl_or_null.reset(std::move(native_handle_or_null));
1487}
1488
1490CLASS_STRUCT_MSG_IN::~Msg_in() = default;
1491
1493void CLASS_STRUCT_MSG_IN::add_serialization_segment(Segment_blob_in&& blob)
1494{
1495 assert((!m_body_deserialized_ok)
1496 && "Do not call add_serialization_segment() after both deserialize_*().");
1497
1498 m_total_sz += blob.size();
1499
1500 if (!m_mdt_header_area.data())
1501 {
1502 /* This is (sub-)segment 1. Grab the location and size (actually more than its real size; that's fine)
1503 * of the mdt header which precedes the actual (sub-)segment 1 if any. */
1504 m_mdt_header_area = blob.const_buffer();
1505
1506 /* We got that, and only we care about it; m_body_reader does not and merely promises not to blow away
1507 * the underlying memory until its own destruction. So now we massage `blob`, so that it starts past the
1508 * header. To the extent m_body_reader must perform further deserialization, it'll now ignore the header
1509 * (other than letting it exist). */
1511 assert((blob.start() == 0)
1512 && "We haven't chged start() yet; why is it framing something already? Bug?");
1513
1514 /* Subtlety 1: If blob is somehow too small for the header even, it's an error, but for now we'll just let it go
1515 * and leave it to deserialize_mdt() which will be actually analyzing contents of area m_mdt_header_area. We can't
1516 * emit any error in any case. So for now just protect against a weird .start_past_prefix() call via min().
1517 *
1518 * Subtlety 2: If *this msg describes a user message, then that header stuff applies. If *this msg, however,
1519 * describes an internal message, then (1) the whole blob *is* metadata, and (2) there will be no further
1520 * blobs. Therefore HDR_SZ, and `blob`, and the notion of a mere header ahead of more stuff in this blob:
1521 * none applies. So for internal messages (which we do not know is the case yet without looking inside
1522 * the payload/deserializing it: deserialize_mdt()) the following statement is harmless but could be omitted.
1523 * m_body_reader will simply not be touched.
1524 *
1525 * See little diagram inside deserialize_mdt() to visualize it if desired. */
1526 blob.start_past_prefix(std::min(size_t(HDR_SZ), blob.size()));
1527 }
1528 // else { It is (sub-)seg 2+; they don't have headers. }
1529
1530 m_body_reader.add_serialization_segment(std::move(blob));
1531} // Msg_in::add_serialization_segment()
1532
1534size_t CLASS_STRUCT_MSG_IN::serialization_size() const
1535{
1536 return m_total_sz;
1537}
1538
1540size_t CLASS_STRUCT_MSG_IN::deserialize_mdt(flow::log::Logger* logger_ptr, Error_code* err_code,
1541 Channel_stats::Msg* stats_rcv_msg_internal_only)
1542{
1543 using util::String_view;
1544 using flow::util::ostream_op_string;
1545 using boost::endian::little_to_native;
1546 using std::exception;
1547 using std::memcpy;
1548
1549 assert(err_code);
1550 err_code->clear(); // Formally we promised it must be falsy.
1551
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.");
1556 /* Also it must not be called after a_s_s() 2; always between 1 and 2 (by contract).
1557 *
1558 * @todo Check it somehow. Though officially it's undefined behavior, so we aren't obligated to check it.
1559 * ...Really it would be tighter if deserialize_{body|mdt}() weren't APIs but simply happened automatically
1560 * after each appropriate a_s_s() call. Only problem is Error_code emission; but a_s_s() could have that...
1561 * though only the 1st and last one would ever emit; which is a bit "loose" after all. Revisit. It's internal
1562 * code, though; we don't have to precious about such things (but it's nice to be tight). */
1563
1564 auto& msg_if_internal = *stats_rcv_msg_internal_only;
1565
1566 /* Let's recap the situation. add_serialization_segment() 1 was called before us. m_mdt_header_area describes
1567 * that whole blob. Before recapping what's in the blob, reminder of how capnp in-place deserialization works --
1568 * in this case the simplest situation where there's exactly 1 segment: Supposing capnp-payload X is in Blob_const
1569 * B, then its serialization starts at some byte at (<-- our case) or past B.data() and ending
1570 * just past B.size() *or earlier* (if not every byte was necessary, meaning 1+ bytes are irrelevant to the
1571 * serialization). So then one feeds capnp the segment: starting at that byte 0 and ending *anywhere past*
1572 * the true last-serialization-byte; capnp will know not to go into the irrelevant trailing area (if any). So
1573 * given that:
1574 * - (If internal message) m_mdt_header_area = entire blob 1 from add_serialization_segment() 1 that was
1575 * called before us. The true serialization area is from byte 0 of that to, probably, last byte of
1576 * m_mdt_header_area. That describes a StructuredMessage struct, which has some metadata, and
1577 * the internal message payload itself is inside there (union is set to internalMessageBody variant; it contains
1578 * said payload). There's nothing else. To get at the mdt, just pass m_mdt_header_area to deserializer;
1579 * and after that there's nothing more for *this in there:
1580 * - [StructuredMessage, contains mdt w/ internal msg]
1581 * - 0................................................
1582 * - m_mdt_header_area describes that whole thing.
1583 * - m_mdt_header_area fed into deserializer => deserializes StructuredMessage mdt w/ internal msg.
1584 * - (If user message) m_mdt_header_area = entire blob 1 from add_serialization_segment() 1 that was
1585 * called before us, again. However, that blob in fact contains 2 capnp encodings: the mdt *header*
1586 * (also StructuredMessage but with a different union setting and contents in there) and sub-seg 1 of N (possibly
1587 * of 1) of the user message:
1588 * - [StructuredMessage, contains mdt]---------------------------------[user message sub-seg 1]
1589 * - 0.................................................................K.......................
1590 * (where K = BUILDER_CONFIG_FRAME_PREFIX_SZ_VIA_STRUC_CHANNEL = max header size in bytes)
1591 * - m_mdt_header_area describes that whole thing
1592 * - m_mdt_header_area fed into deserializer => deserializes StructuredMessage mdt
1593 * (the part from first `-`, in above diagram, on will be ignored).
1594 * - m_builder's stored sub-seg 1 = the area [K, end of blob 1) (already done in add_serialization_segment()).
1595 *
1596 * So everything is cool already; except we must now interpret the mdt-header for various key info, including
1597 * whether there *is* a user-message body (otherwise it's an internal message). To do that: give
1598 * m_mdt_header_area to deserializer. */
1599
1600 // Error helper.
1601 const auto error_out = [&](String_view msg) -> size_t
1602 {
1603 {
1604 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT); // Log on errors (at least).
1605 FLOW_LOG_WARNING(msg);
1606 }
1607
1609 m_mdt_deserialized_ok = false; // Mark us as failed again.
1610 return 0;
1611 }; // const auto error_out =
1612
1613 m_mdt_deserialized_ok = true; // error_out() would undo it.
1614
1615 /* Set up the super-simple/fast capnp::MessageReader for the mdt-header. Don't bother decreasing its .size(),
1616 * even if we could: as noted earlier, deserializer will just ignore anything past last real serialization byte. */
1617 m_mdt_reader.emplace(m_mdt_header_area);
1618
1619 // Grab the StructuredMessage::Reader of the mdt-header.
1620 try
1621 {
1622 m_mdt_root = m_mdt_reader->getRoot<Mdt>();
1623 }
1624 catch (const exception& exc)
1625 {
1626 return error_out(ostream_op_string("In-mdt-header could not be capnp-deserialized; capnp threw exception [",
1627 exc.what(), "]. Other side misbehaved?"));
1628 }
1629 // Got here: Now the mdt-related accessors will work (including for us below).
1630
1631 /* Refer to structured_msg.capnp StructuredMessage. m_mdt_root is ready for us. Let's go over it:
1632 * - authHeader.sessionToken: We decode it here and save it (for accessor perf).
1633 * - id: It's accessible through accessor id_or_none() (perf is good enough to not need caching).
1634 * However we check it for correctness and emit error if bad.
1635 * - originatingMessageIdOrNone: Ditto; though there are no invalid values => no error applicable (0 means this
1636 * not a response).
1637 * - internalMessageBody: Present if and only if there will be no m_body_root (no user message, just mdt). */
1638
1639 // Deal with sessionToken. Decode as mandated in .capnp Uuid doc header. @todo Factor this out into a util method.
1640
1641 if (!m_mdt_root.hasAuthHeader())
1642 {
1643 return error_out("In-mdt-header has null .authHeader. Other side misbehaved?");
1644 }
1645 // else
1646 const auto auth_header = m_mdt_root.getAuthHeader();
1647
1648 if (!auth_header.hasSessionToken())
1649 {
1650 return error_out("In-mdt-header has null .authHeader.sessionToken. Other side misbehaved?");
1651 }
1652 // else
1653
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()); // Reminder: Likely no-op + copy of uint64_t.
1658 const uint64_t last8 = little_to_native(capnp_uuid.getLast8()); // Ditto.
1659 memcpy(m_session_token.data(), &first8, sizeof(first8));
1660 memcpy(m_session_token.data() + sizeof(first8), &last8, sizeof(last8));
1661
1662 const auto id_or_0 = id_or_none();
1663 if (m_mdt_root.isInternalMessageBody())
1664 {
1665 if (id_or_0 != 0)
1666 {
1667 return error_out("In-mdt-header top union specifies .internalMessageBody; but .id=/=0, the sentinel value. "
1668 "Other side misbehaved?");
1669 }
1670 // else
1671
1672 /* And that's that. Stuff like IDs may still be wrong compared to preceding messages, which we can't check yet.
1673 * struc::Channel will before any emission of anything to user. */
1674 assert(!*err_code);
1675
1676 /* Stats: internal msg is always single-seg, single-blob. We will not do deserialize_body() (there is no body),
1677 * so we update these now in this case as advertised. */
1678 {
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);
1684 }
1685 return 0; // Means we're an internal message.
1686 }
1687 // else if (!.isInternalMessageBody()):
1688
1689 // Very exciting... we have the metadata, and it indicates this is part of user message (not internal message).
1690
1691 if (id_or_0 == 0)
1692 {
1693 return error_out("In-mdt-header top union specifies no .internalMessageBody; but .id=0, the sentinel value. "
1694 "Other side misbehaved?");
1695 }
1696 // else
1697
1698 const size_t n_body_segs = m_mdt_root.getBodySerializationInfo().getNumBodySerializationSegments();
1699 if (n_body_segs == 0)
1700 {
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?");
1703 }
1704 // else
1705
1706 /* Last sanity check (user-message case): We apparently deserialized mdt fine, so ostensibly there was enough
1707 * space for the header; but the body serialization must begin exactly after the *reserved* header area.
1708 * So: */
1710 if (m_mdt_header_area.size() < HDR_SZ)
1711 {
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?"));
1716 }
1717 // else
1718
1719 return n_body_segs; // And that's that. (Same comment as above in internal-message case.)
1720} // Msg_in::deserialize_mdt()
1721
1723void CLASS_STRUCT_MSG_IN::deserialize_body(Error_code* err_code, Channel_stats::Msg* stats_rcv_msg)
1724{
1725 assert(err_code);
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.");
1730
1731 auto& msg = *stats_rcv_msg;
1732 const auto body_serialization_info = m_mdt_root.getBodySerializationInfo();
1733 // Careful; we will modify this; at first it's post-split blobs; then it becomes pre-split segments.
1734 size_t n_body_segs = body_serialization_info.getNumBodySerializationSegments();
1735
1736 // Stats. There's more below, but use n_body_segs before it is "corrected" into an actual segment count.
1737 msg.m_total_low_lvl_blobs += n_body_segs;
1738
1739 /* We have the segments, but to deserialize we may need to reassemble split-segments (context: rarely but
1740 * possibly sometimes, though for e.g. Reader being shm::Reader it would be never). So as
1741 * emit_serialization()/load_mdt() makes a capnp-List from a Split_segments, we do the opposite.
1742 * (We could have done so in deserialize_mdt() and saved it in an m_, but we're only going to be called once,
1743 * and nothing else needs that info, so why keep more state?) */
1744
1745 if (body_serialization_info.hasSplitSegmentsOrNull())
1746 {
1747 const auto split_segs_list = body_serialization_info.getSplitSegmentsOrNull();
1748 const auto n_split_segs = split_segs_list.size(); // (0 is illegal, but just let m_body_reader deal with it.)
1749
1750 Split_segments split_segs;
1751 split_segs.reserve(n_split_segs);
1752 for (size_t idx = 0; idx != n_split_segs; ++idx)
1753 {
1754 /* See doc header for `using SplitSegment` in .capnp for full strategy/tactics here.
1755 * Bottom line is we encode each Split_segment not as a capnp-struct but as a single double-width integer
1756 * containing the two equally-sized integers within it:
1757 * Encode = OR + SHL; so decode = AND + SHR (a/k/a modulo + floor-divide). */
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; // Suppose this = `n`.
1760 constexpr size_t START_IDX_MASK = (size_t(1) << N_BITS_SPLIT_SEG_SZ) - 1; // Then this = bits 1{n}.
1761
1762 const auto split_segs_list_element = size_t(split_segs_list_element_in_capnp);
1763
1764 // E.g., if encoded = uint16_t, shift-right by 8 bits to get n_cont.
1765 const auto n_cont = split_segs_list_element >> N_BITS_SPLIT_SEG_SZ; // SHR a/k/a: /.
1766
1767 split_segs.emplace_back(Split_segment{ split_segs_list_element & START_IDX_MASK, // AND a/k/a: %.
1768 n_cont });
1769
1770 // Stats.
1771 msg.m_histo_split_blobs_per_seg.record_value(n_cont + 1); // E.g.: 2 continuation blobs <=> 3 blobs.
1772 /* Progressive "correct" n_body_segs.
1773 * E.g.: 3 blobs post-split = one segment <=> n_cont = 2. So: 3-2=1 actual segment. Hence -= 2.*/
1774 n_body_segs -= n_cont;
1775 }
1776
1777 m_body_root = m_body_reader.template deserialization<Body>(&split_segs, // Won't change split_segs; don't worry.
1778 err_code);
1779 if (!*err_code) // We don't have to gate this, but we can; it's somewhat convenient for the assert().
1780 {
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; // For sure splitting occurred.
1783 }
1784 } // if (body_serialization_info.hasSplitSegmentsOrNull())
1785 else
1786 {
1787 // Fast-path (should generally be the norm): no split_segs -- no reassembly required.
1788 m_body_root = m_body_reader.template deserialization<Body>(nullptr, err_code);
1789 }
1790
1791 if (*err_code)
1792 {
1793 return;
1794 }
1795 // else: Now body_root() works.
1796 m_body_deserialized_ok = true;
1797
1798 /* Stats (all but split-related and m_total_low_lvl_blobs, which is also split-related really).
1799 *
1800 * Reminder: In our contract, and in stat-keeping generally, we have allowed ourselves in the event
1801 * of catastrophic error (*err_code becoming truthy above is indeed that) for some stats to be recorded
1802 * but not necessarily all. */
1803 {
1804 ++msg.m_user_msgs;
1805 /* On receive side m_requests/m_requests_one_off/m_request_responses are always 0 (can't distinguish
1806 * requests from notifications). All user messages count as notifications. m_notification_responses
1807 * counts those with originating_msg_id (receiver *can* see this). */
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);
1814 }
1815} // Msg_in::deserialize_body()
1816
1818msg_id_t CLASS_STRUCT_MSG_IN::id_or_none() const
1819{
1820 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1821 return m_mdt_root.getId();
1822}
1823
1825msg_id_t CLASS_STRUCT_MSG_IN::originating_msg_id_or_none() const
1826{
1827 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1828 return m_mdt_root.getOriginatingMessageIdOrNone(); // 0 means none.
1829}
1830
1832const Session_token& CLASS_STRUCT_MSG_IN::session_token() const
1833{
1834 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1835 return m_session_token;
1836}
1837
1839typename CLASS_STRUCT_MSG_IN::Internal_msg_body_reader CLASS_STRUCT_MSG_IN::internal_msg_body_root() const
1840{
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();
1844}
1845
1847const typename CLASS_STRUCT_MSG_IN::Body_reader& CLASS_STRUCT_MSG_IN::body_root() const
1848{
1849 assert(m_body_deserialized_ok && "Call deserialize_body() successfully before calling body_root() accessor.");
1850 return m_body_root;
1851}
1852
1854const typename CLASS_STRUCT_MSG_IN::Mdt_reader& CLASS_STRUCT_MSG_IN::mdt_root() const
1855{
1856 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling mdt_root() accessor.");
1857 return m_mdt_root;
1858}
1859
1861Native_handle CLASS_STRUCT_MSG_IN::emit_native_handle_or_null()
1862{
1863 return util::disowned_native_handle(std::move(m_hndl_or_null));
1864}
1865
1867void CLASS_STRUCT_MSG_IN::to_ostream(std::ostream* os_ptr) const
1868{
1869 auto& os = *os_ptr;
1870
1871 os << '[';
1872
1873 if (!m_hndl_or_null.get().null())
1874 {
1875 // As of this writing it's, like, "native_hndl[<the FD>]" -- that looks pretty good and pithy.
1876 os << m_hndl_or_null.get() << ' ';
1877 }
1878 // else { No need to output anything; pithier. }
1879
1880 if (m_mdt_deserialized_ok)
1881 {
1882 const auto id_or_0 = id_or_none();
1883 if (id_or_0 == 0)
1884 {
1885 /* Internal message. Might as well simply print the entire metadata-header; it's all interesting, and
1886 * an internal message never reaches the user; so internal code may well want to print all this.
1887 * Plus there's simply nothing else to print, at all, so it's complete.
1888 * As in Msg_out::to_ostream() use the non-indent/newline pretty-print but no truncation desired -- hence
1889 * do not use ostreamable_capnp_brief(). */
1890 os << ::kj::str(internal_msg_body_root()).cStr();
1891 }
1892 else // if (id_or_0 != 0)
1893 {
1894 /* User message. We should be somewhat judicious as to what to print; it does not strictly have to be
1895 * stuff available via public APIs -- but don't go overboard either. E.g., session token is of low interest
1896 * and takes space more than anything and is an internal detail; but message ID and originating message ID
1897 * (if any) both help correlate messages versus other messages. */
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)
1901 {
1902 os << "rsp_to_id[" << originating_msg_id_or_0 << "] ";
1903 }
1904
1905 if (m_body_deserialized_ok)
1906 {
1907 // Similarly to Msg_out::to_ostream() print the body but truncated if needed.
1908 os << ostreamable_capnp_brief(body_root());
1909 }
1910 else // if (!m_body_deserialized_ok)
1911 {
1912 os << " ( incomplete )"; // Perhaps we're being printed internally, before deserialize_body().
1913 }
1914 } // else if (id_or_0 != 0)
1915 }
1916 else // if (!m_mdt_deserialized_ok)
1917 {
1918 os << "( incomplete )"; // Perhaps we're being printed internally, before deserialize_mdt().
1919 }
1920
1921 os << " sz[" << serialization_size() << "]]@" << this;
1922} // Msg_in::to_ostream()
1923
1925std::ostream& operator<<(std::ostream& os, const CLASS_STRUCT_MSG_IN& val)
1926{
1927 val.to_ostream(&os);
1928 return os;
1929}
1930
1931#undef TEMPLATE_STRUCT_MSG_OUT
1932#undef CLASS_STRUCT_MSG_OUT
1933#undef TEMPLATE_STRUCT_MSG_IN
1934#undef CLASS_STRUCT_MSG_IN
1935
1936} // namespace ipc::transport::struc
Simple utility: a capnp MessageBuilder operating over a single, contiguous, user-supplied area in vir...
Definition: msg.hpp:68
kj::ArrayPtr<::capnp::word > allocateSegment(unsigned int min_sz_words) override
Implements MessageBuilder API.
Definition: msg.cpp:53
util::Blob_mutable m_seg
Copy of seg (the buffer description... not the actual buffer!) given to ctor.
Definition: msg.hpp:117
Capped_sz_capnp_message_builder(const util::Blob_mutable &seg, bool zero_it_please)
Constructor that remembers the given memory area.
Definition: msg.cpp:39
bool m_returned_seg
true if and only if allocateSegment() has been called.
Definition: msg.hpp:120
Simple utility: a capnp MessageReader operating over a single, contiguous, user-supplied area in virt...
Definition: msg.hpp:148
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.
Definition: msg.hpp:168
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...
Definition: msg.cpp:75
::capnp::SegmentArrayMessageReader Seg_array_msg_reader_base
Convenient alias for capnp SegmentArrayMessageReader.
Definition: msg.hpp:171
A structured in-message instance suitable as received and emittable (to user) by struc::Channel.
Definition: msg.hpp:799
Body_t Body
See struc::Channel::Msg_body.
Definition: msg.hpp:804
bool m_body_deserialized_ok
Starts false; becomes true immutably once deserialize_body() succeeds (never if it's an internal mess...
Definition: msg.hpp:1184
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...
Definition: msg.hpp:1839
Body_reader m_body_root
See body_root(); meaningless until m_body_deserialized_ok.
Definition: msg.hpp:1190
Session_token m_session_token
Starts uninitialized, this is assigned exactly once by deserialize_mdt(), storing the session-token t...
Definition: msg.hpp:1197
schema::detail::StructuredMessage Mdt
capnp struct StructuredMessage which is the structured view of the metadata (mdt) header.
Definition: msg.hpp:930
typename Reader_config::Reader Reader
Short-hand for user-indirectly-specified Struct_reader concept impl.
Definition: msg.hpp:945
bool m_mdt_deserialized_ok
Starts false; becomes true immutably once deserialize_mdt() succeeds.
Definition: msg.hpp:1181
util::Own_native_handle m_hndl_or_null
See store_native_handle_or_null().
Definition: msg.hpp:1200
Mdt_reader m_mdt_root
See internal_msg_body_root(); meaningless until m_mdt_deserialized_ok.
Definition: msg.hpp:1187
typename Body::Reader Body_reader
Short-hand for capnp-generated read-only-accessing Reader nested class of Body. See body_root().
Definition: msg.hpp:807
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...
Definition: msg.hpp:1471
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.
Definition: msg.hpp:936
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() ...
Definition: msg.hpp:1723
const Session_token & session_token() const
(Access via Msg_in_impl) To be called only after deserialize_mdt(), returns session token tagging thi...
Definition: msg.hpp:1832
Reader m_body_reader
The Struct_reader concept impl that does much of the heavy lifting (e.g., it might be SHM-enabled; or...
Definition: msg.hpp:1160
Native_handle emit_native_handle_or_null()
Returns the Native_handle – potentially null meaning none – embedded in this message; and forgets tha...
Definition: msg.hpp:1861
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...
Definition: msg.hpp:1482
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...
Definition: msg.hpp:1825
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Definition: msg.hpp:1867
size_t m_total_sz
Sum of blob sizes in add_serialization_segment() calls so far.
Definition: msg.hpp:1136
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...
Definition: msg.hpp:1818
~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 ...
Definition: msg.hpp:1540
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...
Definition: msg.hpp:1493
const Mdt_reader & mdt_root() const
(Access via Msg_in_impl) The Mdt root capnp-generated accessor object.
Definition: msg.hpp:1854
Reader_config_t Reader_config
See struc::Channel::Reader_config.
Definition: msg.hpp:810
util::Blob_const m_mdt_header_area
Meaningful from add_serialization_segment() on, this simply describes the memory area that begins wit...
Definition: msg.hpp:1178
typename Mdt::Reader Mdt_reader
capnp-generated reader API for Mdt structures.
Definition: msg.hpp:939
size_t serialization_size() const
Size of the serialization in memory in bytes; only the serialization as transmitted via IPC counts.
Definition: msg.hpp:1534
std::optional< Capped_sz_capnp_message_reader > m_mdt_reader
A very simple capnp::MessageReader that provides structured access to the mdt header.
Definition: msg.hpp:1145
const Body_reader & body_root() const
The Body root capnp-generated accessor object.
Definition: msg.hpp:1847
A structured out-message suitable to be sent via struc::Channel::send() (et al).
Definition: msg.hpp:340
typename Body::Builder Body_builder
Short-hand for capnp-generated mutating Builder nested class of Body. See body_root().
Definition: msg.hpp:348
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 ...
Definition: msg.hpp:720
Body_builder m_body_root
See body_root().
Definition: msg.hpp:697
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Definition: msg.hpp:1442
Native_handle native_handle_or_null() const
Returns whatever was the last word according to store_native_handle_or_null().
Definition: msg.hpp:1317
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,...
Definition: msg.hpp:1303
typename Builder::Config Builder_config
Short-hand for user-specified Struct_builder::Config.
Definition: msg.hpp:360
Builder m_builder
The guy serializing a Body, as well as storing – but not itself loading – a frame-prefix big-enough f...
Definition: msg.hpp:676
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.
Definition: msg.hpp:354
Body_builder * body_root()
The Body root capnp-generated mutator object.
Definition: msg.hpp:1283
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...
Definition: msg.hpp:1324
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().
Definition: msg.hpp:363
Orphanage orphanage()
Convenience method that returns a capnp::Orphan factory in the same capnp::MessageBuilder as body_roo...
Definition: msg.hpp:1295
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...
Definition: msg.hpp:1223
util::Own_native_handle m_hndl_or_null
The Native_handle, if any, embedded inside this message; auto-closed on destruction/replacement.
Definition: msg.hpp:723
Body_t Body
See struc::Channel::Msg_body.
Definition: msg.hpp:345
#define TEMPLATE_STRUCT_MSG_OUT
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:1208
#define CLASS_STRUCT_MSG_IN
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:1217
#define TEMPLATE_STRUCT_MSG_IN
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:1214
#define CLASS_STRUCT_MSG_OUT
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:1211
@ 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::...
Definition: classic_fwd.hpp:36
Reader< ipc::shm::classic::Pool_arena > Reader
Convenience alias: transport::struc::shm::Reader that works with boost.ipc.shm pools from ipc::shm::c...
Definition: classic_fwd.hpp:39
Sub-module of Flow-IPC module ipc::transport providing transmission of structured messages specifical...
Definition: channel.cpp:31
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...
Definition: util.hpp:71
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...
Definition: struc_fwd.hpp:247
std::vector< Split_segment > Split_segments
A simple data structure describing the segments (if any) in a Segment_bufs (or similar) structure whi...
Definition: struc_fwd.hpp:185
boost::uuids::uuid Session_token
A type used by struc::Channel for internal safety/security/auth needs.
Definition: struc_fwd.hpp:121
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...
Definition: msg_impl.cpp:43
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 ...
Definition: struc_fwd.hpp:192
std::vector< util::Blob_const > Segment_bufs
Simpler cousin of Segment_ptrs, this represents the IPC-transmissible representation of a capnp seria...
Definition: struc_fwd.hpp:171
uint64_t msg_id_t
Message ID uniquely identifying outgoing message (Msg_out, among all other Msg_outs),...
Definition: struc_fwd.hpp:215
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.
Definition: util_fwd.hpp:137
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.
Definition: util_fwd.hpp:131
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:112
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.
Definition: common.hpp:313
This is the friend facade of Msg_in that exposes private APIs hidden from public user by providing pu...
Definition: msg_impl.hpp:83
This is the friend facade of Msg_out that exposes private APIs hidden from public user by providing p...
Definition: msg_impl.hpp:46
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.