Flow-IPC 1.0.2
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"
33#include <boost/endian.hpp>
34#include <boost/move/make_unique.hpp>
35
37{
38
39// Types.
40
41/**
42 * A structured out-message suitable to be sent via struc::Channel::send() (et al). Publicly this can be constructed
43 * directly; or via struc::Channel::create_msg(). The latter has the advantage of reusing the serialization
44 * engine knobs registered with the channel and hence is simply easier to write. If one uses the direction-construction
45 * route, the builder (serialization) engine type -- Struct_builder #Builder -- must match that of the
46 * struc::Channel used to `send()` a `*this`; otherwise it simply will not compile.
47 *
48 * @see "Lifecycle of an out-message" section of struc::Channel class doc header for useful context.
49 *
50 * As explained in that doc section, a Msg_out (struc::Channel::Msg_out) is akin to a container,
51 * like `vector<uint8_t>`; and the #Builder template param + ctor arg are akin to the allocator
52 * used by such a container. A given `*this` represents the message payload; it does not represent a particular
53 * `send()`t (past/present/future) *instance* of that payload. Modifying it is akin to modifying the
54 * `vector<uint8_t>`, albeit in structured-schema fashion -- available API controlled by `Message_body` template
55 * param -- and with an optionally attached #Native_handle.
56 *
57 * As explained in that doc section, like any container, once another process has access to it -- which is
58 * only possible in read-only fashion as of this writing -- modifying it must be done with concurrency/synchronization
59 * considered. If the compile-time-chosen #Builder is SHM-based, then this is a concern.
60 * If it is heap-based (notably Heap_fixed_builder), then it is not: the serialization is *copied* into
61 * and out of the transport.
62 *
63 * After construction, one mutates the message via body_root() and/or store_native_handle_or_null().
64 * You may also use orphanage() to build the message in bottom-up fashion, eventually grafting pieces in via
65 * `body_root()->....adopt...()`. See orphanage() doc header for more information on this technique.
66 * Lastly consider the following section for another, more holistic bottom-up appraoch (or perhaps
67 * taking the orphanage technique further).
68 *
69 * ### Advanced technique: Construction from earlier-prepared raw #Capnp_msg_builder_interface ###
70 * To enable the straightforward operation implied above, one uses the 1st/simple ctor form which
71 * by definition necessitates specifying the root schema, #Body (as to contruct one must know the type).
72 * This is typically perfectly natural: a module knows it's building a message of schema #Body, so they
73 * construct a `Msg_out<Body>` (which already auto-creates a blank #Body via
74 * `initRoot<Body>()`), then fills it out via body_root() (which points to what `initRoot()` returned).
75 * The orphanage technique above is a slight complication, in that things can be built bottom-up, but in any case
76 * by then the root schema already had to be specified, even if it's actually mutated only somewhat later, once
77 * the component orphan(s) can be plugged in.
78 *
79 * When working with capnp outside of ::ipc, users typically do basically the same thing:
80 * start with `M.initRoot<Body>()`, then set stuff in its tree; or in more complex cases maybe use
81 * `M.getOrphanage()` from the same `MessageBuilder M` to help build bottom-up.
82 *
83 * However consider a complex schema `Huge_body` built by collaboration between modules A and B.
84 * Now module A may be aware the ultimate product is rooted at
85 * `Huge_body`, while module B has no idea, and yet they work together to build parts of the final
86 * thing. In that case B does not necessarily think of any particular overall `Huge_body` tree but only the
87 * sub-schema types it cares about; so to it the `MessageBuilder M` is just a memory pool or heap of sorts;
88 * it makes whatever structures it wants (via `M.getOrphanage()`) from it but does
89 * not call or know about `initRoot<Huge_body>()`. Conceivably, even, module B is first to run its
90 * procedures (before module A) and to create `M` in the first place; and only later module A perhaps
91 * finally sets the root (`initRoot<HugeBody>()`) and attaches whatever orphan values module B produces,
92 * hooking them into the `HugeBody`.
93 *
94 * The straightforward use of Msg_out, as described before, does in fact force one (from the start) to
95 * specify `HugeBody` by definition (it's -- again -- a template argument to the class template), and that may not
96 * be desirable in this module A-B scenario. So to support it: use the 2nd/advanced ctor form which
97 * takes over (via `std::move()`) an already-created #Builder -- not templated on any schema `Body`.
98 * The #Builder exposes the direct `MessageBuilder`, so the tree can be built using whatever features in whatever
99 * order one desires... and only *then* create the Msg_out. The only constraint is that
100 * by ctor time, the `MessageBuilder` (a/k/a #Capnp_msg_builder_interface) *is* initialized to be rooted at `Body`;
101 * but this could be done anytime up to that point; so module B need not do it, while module A might ultimately
102 * do it and then construct the `Msg_out<Body>`. Alternatively, the user can omit performing
103 * `initRoot<Body>()`, and it will be done as needed by the ctor, resulting in a blank message at that point
104 * which then can be filled-out via body_root() mutations. (Note: This is just an example. The point is
105 * with this technique one can use a `MessageBuilder` in any fashion desired, and the only constraint is
106 * it is in fact rooted at some structure ``S`, at which point `Msg_out<S>` can be cted. In that
107 * sense it removes any -- albeit typically simplifying -- ipc::transport constraints on how one builds a message,
108 * allowing one to use the full builder API provided by capnp without any stylistic concessions.)
109 *
110 * ### Resource use: RAM ###
111 * Creating a `*this`, and mutating it via body_root(), uses proportionally large RAM resources; e.g.,
112 * if you successfully store a multi-megabyte blob, `*this` will allocate RAM accordingly. Conversely,
113 * destroying `*this` returns such resources. However, if #Builder is SHM-based, then a process-counting
114 * ref-count (conceptually) exists. It is 1 after construction. It is incremented each time
115 * it is `struc::Channel::send()`t. For each such increment, there is a decrement when the receiving
116 * process's counterpart Msg_in, which is always passed-around by `shared_ptr`, is no longer
117 * owned by that process (when that `shared_ptr` group's ref-count drops to zero). Once `*this` is destroyed,
118 * *and* each `send()` target process has both yielded the struc::Channel::Msg_in_ptr and let that
119 * `shared_ptr` drop to ref-count-zero, the backing RAM is released.
120 *
121 * ### Resource use: the #Native_handle (if any) ###
122 * It is returned to the OS by our destructor. This does not, necessarily, destroy whatever resource it references:
123 * presumably the idea is to send it, via IPC, to the opposing process. The handle (FD) that process receives
124 * is really a new one in that process's table; there are at that point two *descriptors* referencing one
125 * resource *description*, and the latter disappears in the kernel only once both descriptors go away.
126 * If you do not wish to let the local handle (FD) be destroyed by `*this` destructor, consider (in Unix-type OS)
127 * passing-in `dup(your_hndl)` instead of `your_hndl` itself.
128 *
129 * The #Native_handle, if any, stored via store_native_handle_or_null() is not a part of the
130 * serialization/deserialization/sharing schema described above. It just sits in `*this` until `*this` dtor runs
131 * (or it is replaced/unloaded via store_native_handle_or_null()). If at send() time there's one in `*this`,
132 * then a copy is transmitted to the recipient process. store_native_handle_or_null() on `*this` will never
133 * have any direct effect on any received copy.
134 *
135 * @internal
136 * ### Impl notes ###
137 * Some important aspects of this class template's API, which must be accessed by the ipc::transport (structured
138 * layer) internals only, are `protected`. struc::Channel then sub-classes this guy and exposes them publicly
139 * (to itself). This avoids `friend` which would would be not quite as clean, since `private` parts would be
140 * exposed too, and so on. In other words this is a class an API -- not a mere data-store -- but there is
141 * an internally used API which is left `protected`. As of this writing it's essentially emit_serialization()
142 * which the user does not access directly (struc::Channel::send() internals do).
143 *
144 * The internally-used APIs are reasonably self-explanatory, so just see their doc headers.
145 * @endinternal
146 *
147 * @tparam Message_body
148 * See struc::Channel.
149 * @tparam Struct_builder_t
150 * See struc::Channel.
151 */
152template<typename Message_body, typename Struct_builder_t>
154{
155public:
156 // Types.
157
158 /// See struc::Channel::Msg_body.
159 using Body = Message_body;
160
161 /// Short-hand for capnp-generated mutating `Builder` nested class of #Body. See body_root().
162 using Body_builder = typename Body::Builder;
163
164 /**
165 * Short-hand for user-specified Struct_builder type. An internally stored instance of this contains the user
166 * payload.
167 */
168 using Builder = Struct_builder_t;
169
170 /**
171 * Short-hand for user-specified Struct_builder::Config. One can construct a #Builder via
172 * `Builder(const Builder_config&)`.
173 */
174 using Builder_config = typename Builder::Config;
175
176 /// Short-hand for capnp orphan factory. See orphanage().
177 using Orphanage = ::capnp::Orphanage;
178
179 // Constructors/destructor.
180
181 /**
182 * Creates blank #Body-bearing out-message message, with no native handle,
183 * all of which can be modified via body_root() and the ancillary mutator store_native_handle_or_null().
184 *
185 * See also the alternate (advanced-technique) ctor form which may be more suitable in more complex scenarios.
186 * This is discussed in our class doc header.
188 * ### Obtaining the #Builder_config object ###
189 * In the first place it is often easier/better to not invoke this ctor directly but rather
190 * invoke struc::Channel::create_msg() which will do so for you and supply the proper #Builder_config.
191 * However it is definitely possible for a Msg_out to be constructed orthogonally to a
192 * particular struc::Channel -- or even to a particular ipc::Session (if even applicable). How to get
193 * the `struct_builder_config` arg for this ctor then? Informally: if you're constructing the #Builder_config
194 * directly, you're probably not doing the right thing. The following places are available to obtain one
195 * for safety and efficiency (and code maintainability):
196 * - From another, compatible, struc::Channel via struc::Channel::struct_builder_config().
197 * - Heap-backed:
198 * - If you have a target struc::Channel::Owned_channel: via `static`
199 * struc::Channel::heap_fixed_builder_config().
200 * - Otherwise: session::Session_mv::heap_fixed_builder_config() (`static` or non-`static`).
201 * - SHM-backed (e.g., SHM-classic):
202 * - session::shm::classic::Session_mv::session_shm_builder_config(),
203 * session::shm::classic::Session_mv::app_shm_builder_config(). Requires a `Session` object.
204 * - session::shm::classic::Session_server::app_shm_builder_config() (requires session::Client_app).
205 * Server-only; if a `Session` is not available or applicable.
206 *
207 * @param struct_builder_config
208 * See above. This is neither memorized nor copied.
209 */
210 explicit Msg_out(const Builder_config& struct_builder_config);
211
212 /**
213 * Advanced technique: Creates message by subsuming the provided already-prepared
214 * `Capnp_msg_builder_interface`-bearing, root-initialized-to-#Body #Builder object (which is moved-to `*this`),
215 * with no native handle, all of which can be (further) modified via body_root() and the ancillary
216 * mutator store_native_handle_or_null().
217 *
218 * The advanced technique revolving around the use of this ctor form is discussed in our class doc header.
219 * That said:
220 * - `*struct_builder.payload_msg_builder()` -- a #Capnp_msg_builder_interface -- *must* already have
221 * been root-initialized, and the root type *must* be #Body; or *must* not have been root-initialized
222 * at all (in which case the ctor will perform `initRoot<Body>()`).
223 * - If it was already root-initialized, but not with `<Body>`, then behavior is undefined, and the trouble
224 * may only be detected on the opposing side upon receipt of `*this` message, in trying to
225 * deserialize it in Msg_in.
226 * - If you chose to not root-initialize before this ctor, and therefore it performs `initRoot<Body>()`,
227 * then naturally the message root tree shall be blank, similarly to the other/vanilla ctor.
228 * - This is typically accomplished via `struct_builder.payload_msg_builder()->initRoot<Body>()`, although
229 * there are other techniques available. See capnp docs for `capnp::MessageBuilder`
230 * (#Capnp_msg_builder_interface).
231 * - That having been guaranteed, the message may be further mutated via body_root().
232 * - Naturally it may also have already been mutated (beyond `initRoot()`/etc.), possibly to its final intended
233 * form.
234 * - Conversely, in practice, if you chose to not root-initialize `struct_builder`, you'll want to in fact
235 * use body_root() mutations to actually load the message with something useful.
236 *
237 * For exposition purposes: note that the other ctor form, which takes a `Builder::Config`, behaves as-if
238 * delegating to the present ctor: `Msg_out(Builder(struct_builder_config))`.
239 * When creating a straightforward message in ~one place in the user code, using that other ctor form is
240 * usually therefore more convenient, avoiding some boiler-plate.
241 *
242 * @param struct_builder
243 * See above. Note the requirements listed.
244 */
245 explicit Msg_out(Builder&& struct_builder);
246
247 /// Creates non-message; any operation except move-to or destruction results in undefined behavior subsequently.
249
250 /**
251 * Move ctor: Make `*this` equal to `src`, while `src` becomes as-if default-cted (in that any operation
252 * except move-to or destruction results in undefined behavior subsequently).
253 *
254 * @param src
255 * Source object.
256 */
258
259 /// Disallow copying.
260 Msg_out(const Msg_out&) = delete;
261
262 /**
263 * Returns resources, including potentially significant RAM resources and native_handle_or_null(), taken throughout;
264 * in the case of SHM-based RAM resources their return may be delayed until counterpart `Msg_in`s
265 * are also destroyed. See class doc header for discussion.
266 */
268
269 // Methods.
270
271 /**
272 * Move assignment: Destroy `*this` contents; make `*this` equal to `src`, while `src` becomes as-if
273 * default-cted (in that any operation except move-to or destruction results in undefined behavior subsequently).
274 * no-op if `&src == this`.
275 *
276 * @param src
277 * Source object.
278 * @return `*this`.
279 */
281
282 /// Disallow copying.
283 Msg_out& operator=(const Msg_out&) = delete;
284
285 /**
286 * The #Body root capnp-generated mutator object. E.g.: `this->body_root()->initSomeStruct().setSomeField(123)`
287 * will create the capnp-`struct`-typed root field `someStruct` and set the value `someField` -- presumably an
288 * integer -- within it. The pointer returned shall always be the same value until `*this` is destroyed.
289 *
290 * #Body_builder is light-weight, so you may make a copy and then mutate via that, if desired. However
291 * whether `*(body_root())` or such a copy, such a `Builder` object may not be accessed after `*this` is destroyed.
292 *
293 * Informally we recommend against copying `*(body_root())`: Light-weight or not, it's a copy, and copying a pointer
294 * is cheaper; and it may not live past `*this` anyway; and body_root() always returns the same pointer. So just
295 * store the pointer (or reference from it).
296 *
297 * ### Quick capnp tips ###
298 * You should really read all of capnp docs at its web site. They are very useful and well written and not
299 * overly formal despite being quite comprehensive. That said a couple of gotchas/tips:
300 * - On a `Builder`, `.getX()` and `.setX()` are lightning-fast, like accessing `struct` members directly --
301 * but only when `X` is of a scalar type. Compound types, where `.getX()` returns not a native type
302 * but another `Builder`, need to perform some pointer checking and are slower. Therefore,
303 * if you plan to `.getX()` and then `.setA()` and `.setB()` (and similar) on that `X`, you should
304 * save the result (`auto x = ....getX();`); then mutate via the saved result (`x.setA(...); x.setB(...)`).
305 * - Let `X` be a compound field, particularly `List`, `Text` (string/list-of-characters),
306 * `Data` (list-of-bytes). It is usually, to begin, null; you must perform `.initX(size_t n)` or equivalent
307 * to initialize it (fill it with `n` zeroes). However, suppose you are mutating a message, such as
308 * a previously-sent message, and wish to *modify* the `X`. If the new value might have the same length (which is
309 * common), the correct thing to do is: check `.hasX()`; if `true`, modify `.getX()`;
310 * but if `false` then `.initX(n)` (as `X` was null after all). Performing `.initX()` on an already-`.initX()`ed
311 * value works but has a nasty invisible effect: the existing datum continues taking space in the
312 * serialization; the new datum takes a new chunk of the serialization segments (and might even cause
313 * the allocation of a new segment if needed). As of this writing capnp does not reuse such orphaned
314 * space. If the new `n` equals the old `n`, this is a straight waste of RAM; and can lead to pathologically
315 * growing memory leaks if done many times.
316 * - However, if the new `n` is different from the preceding, then there is no choice but to
317 * re-`.initX()`. A list/blob/string's size cannot be modified in capnp.
318 * - It is best to avoid any situation where the `n` would change; try to design your protocol differently.
319 *
320 * @return See above.
321 */
323
324 /**
325 * Equivalent to the other body_root() overload but immutable version. May be useful for, say, pretty-printing it
326 * to log (e.g.: `capnp::prettyPrint(M.body_root()->asReader()).flatten().cStr()`).
327 *
328 * @return See above.
329 */
330 const Body_builder* body_root() const;
331
332 /**
333 * Convenience method that returns a `capnp::Orphan` factory in the same `capnp::MessageBuilder` as body_root().
334 * Therefore `Orphan`s generated via the returned #Orphanage can be `adopt...()`ed by the `Builder` `*(body_root())`
335 * and its various sub-fields' `Builder`s (at any depth).
336 *
337 * ### Suggested technique ###
338 * In general, the orphan concept is discussed briefly but usefully in the "C++ serialization" section of
339 * capnp docs (the web site). We do not attempt to get into all these topics. However consider the following
340 * pattern.
341 *
342 * In general the Flow-IPC system places almost no constraints on #Body (the schema), but there is one:
343 * Generally there must be an anonymous capnp-`union` at the top of #Body, and in practice any message will
344 * eventually load the root (body_root()) with one of the `union` choices. (This is to operate within the
345 * struc::Channel::expect_msg() and struc::Channel::expect_msgs() APIs.) The vanilla approach to building
346 * the message is top-down: body_root() is pre-initialized to be a #Body; then, say, if your plan is to
347 * load it with the `union` choice `someChoice`, then you'd do `body_root()->initSomeChoice()`; then
348 * mutate stuff inside the `Builder` returned by that. There could be an arbitrarily complex sub-tree within that,
349 * built top-down in the same fashion.
350 *
351 * Instead you may choose to build it bottom-up. For this discussion let's assume `struct SomeChoice`
352 * has a number of scalars. You would first obtain and save an `Orphanage`:
353 * `auto orphan_factory = M.orphanage()`. Next you would create an orphan, not yet connected to the root
354 * body_root(), like so:
355 * `auto some_choice_orphan = orphan_factory.newOrphan<SomeChoice>(); some_choice_builder = some_choice_orphan.get()`.
356 * Next you'd set the scalars within it: `some_choice_builder.set...(...)`. Lastly, when it's ready, graft it into
357 * the actual root: `body_root()->adoptSomeChoice(some_choice_orphan)`.
358 *
359 * Due to the simplicity of this example one might wonder why not simply build it top-down in the first place.
360 * Indeed. However, if `struct SomeChoice` is a complex tree of `struct`s within `List`s within (...),
361 * it would be reasonable to build the lowest levels of that tree by generating intermediate orphans
362 * (via `orphan_factory.newOrphan<LowerLevelStructOrListOrWhatever>()`), adopting them into higher-level
363 * orphans, and so on, finishing it via the top-level `body_root()->adoptSomeChoice()` call.
364 *
365 * ### Similar technique ###
366 * See also the 2nd (advanced) ctor form. It allows one to do the above but takes it further by not even
367 * needing a Msg_out until the time comes to actually struc::Channel::send() the message.
368 * I.e., one would work with essentially a #Capnp_msg_builder_interface directly, including
369 * invoking `Capnp_msg_builder_interface.getOrphanage()`.
370 *
371 * @return See above.
372 */
374
375 /**
376 * Store the `Native_handle` (potentially `.null()`, meaning none) in this out-message; no-ops if the same
377 * `.m_native_handle` already stored; otherwise returns the previously stored native handle to the OS
378 * (similarly to dtor).
379 *
380 * @param native_handle_or_null
381 * The `Native_handle` (`.null() == true` if none) to move into `*this`. Made `.null() == true` upon return.
382 */
384
385 /**
386 * Returns whatever was the last word according to store_native_handle_or_null(). Note it is a copy;
387 * `*this` retains ownership of the OS resource.
388 *
389 * @return See ctor (which stores no handle), store_native_handle_or_null().
390 */
392
393 /**
394 * Prints string representation to the given `ostream`. This representation lacks newlines/indentation;
395 * includes a (potentially truncated) pretty-printed representation of `body_root()` contents; and includes
396 * native_handle_or_null().
397 *
398 * Caution: This could be an operation expensive in processor cycles and, temporarily, RAM; and thus should
399 * be used judiciously. To help drive your decision-making: This method, internally,
400 * -# uses capnp `kj::str(*(this->body_root))` to generate a *full* pretty-print of body_root() contents;
401 * -# truncates the result of the latter, as needed for a reasonably short output, and prints the result;
402 * -# adds native_handle_or_null() and possibly a few other small information items.
403 *
404 * Because there is no reasonably-available way to stop generating the pretty-print in step 1 upon reaching
405 * a certain number of characters, the operation may take a while, if many non-default bytes have been
406 * mutated-in; and before truncation the resulting string may take significant RAM accordingly.
407 *
408 * @param os
409 * Stream to which to write.
410 */
411 void to_ostream(std::ostream* os) const;
412
413protected:
414 // Methods.
415
416 /**
417 * Returns the serialization in the form of a sequence of 1+ `Blob`s.
418 * It is meant to be invoked at struc::Channel::send() time.
419 *
420 * It can be invoked repeatedly: `session` can specify a different destination each time; or the same
421 * destination each time; or an arbitrary mix thereof. In particular struc::Channel::send() (and its
422 * derivatives struc::Channel::sync_request(), struc::Channel::async_request()) shall each time specify the
423 * channel's opposing process as the destination -- regardless of which struc::Channel's
424 * struc::Channel::create_msg() originally generated `*this` (assuming that method was even used for
425 * construction of `*this` -- in no way required, just often convenient).
426 *
427 * @see our class doc header and/or "Lifecycle of an out-message" section of struc::Channel class doc
428 * header. Recall that where it mentions struc::Channel::send(), you can understand
429 * there a 1-1 relationship with a synchronous call to `this->emit_serialization()`.
430 *
431 * ### Errors ###
432 * See Struct_builder::emit_serialization(). This essentially forwards to that and emits its errors if any.
433 * Out-arg `native_handle_or_null` is untouched on error.
434 *
435 * @param target_blobs
436 * On success (no error emitted) this is cleared and replaced with the sequence of segments as `Blob`s.
437 * @param session
438 * Specifies the opposing recipient for which the serialization is intended.
439 * If `Builder::Session` is Null_session, then `Session()` is the only value to supply here. Otherwise more
440 * information is necessary.
441 * @param err_code
442 * See `flow::Error_code` docs for error reporting semantics. See above.
443 */
444 void emit_serialization(Segment_ptrs* target_blobs, const typename Builder::Session& session,
445 Error_code* err_code) const;
446
447 /**
448 * Returns what `target_blobs.size()` would return after calling `emit_serialization(&target_blobs)` (with
449 * an empty `target_blobs` going-in), right now.
450 *
451 * @return See above.
452 */
454
455private:
456 // Data.
457
458 /// The guy serializing a #Body. Underlying serialization potentially futher mutated by user via body_root().
460
461 /**
462 * See body_root().
463 *
464 * ### Rationale ###
465 * We don't strictly need to save this; we could have body_root() return the #Body_builder, not a pointer to
466 * it. This would not be out of line; it is a general capnp-documented tip to act on a given `Builder` repeatedly
467 * as opposed to accessing it via an accessor each time; so we could encourage the user to do that -- not
468 * our problem. (Though I (ygoldfel) am not positive that perf tip applies to the root capnp-`struct`; maybe
469 * look into it sometime for education.) It would also reduce `*this` footprint a bit and simplify/speed-up
470 * the move-ctor and move-assignment somewhat (a capnp `Builder` is light-weight but not totally tiny, consisting
471 * of a few pointers and integers). So why do this?
472 *
473 * Honestly keeping it this way is firstly a historic artifact from an earlier situation where keeping a
474 * pointer made sense in a no-longer-relevant sense (explaining how here would be uninteresting).
475 * That said it's a fairly cheap little optimization that allows the repeated use of body_root() with no perf
476 * penalty, and it is nice and expressive to have a non-`const` accessor returning a pointer to *the*
477 * thing that would mutate `*this`. Similarly it's nice to have a `const` accessor returning pointer-to-`const`
478 * suitable for pretty-printing. Throw in now having to change existing call sites, and voila, this decision.
479 */
481
482 /// The `Native_handle`, if any, embedded inside this message.
484}; // class Msg_out
485
486/**
487 * A structured in-message *instance* suitable as received and emittable (to user) by struc::Channel. Publicly
488 * these are never constructed but emitted into `Channel`-passed handlers, wrapped into `shared_ptr`
489 * struc::Channel::Msg_in_ptr. These handlers include struc::Channel::expect_msg(),
490 * struc::Channel::expect_msgs(), and struc::Channel::async_request() and struc::Channel::sync_request().
491 * Once available to the user, one accesses the in-place (zero-copy) capnp serialization via body_root(),
492 * via which one can access the message's read-only contents.
493 *
494 * @see Msg_out
495 * @see "Lifecycle of an out-message" section of struc::Channel class doc header for useful context.
496 * Note that for each Msg_out, there will exist 0+ `Msg_in`s, one per
497 * successful `send()` (et al) paired with emission to user via aformentioned handlers. The latter represent
498 * each instance of the original message being received; the former represents the original message.
499 * Hence Msg_in access is read-only (`Reader` access only); Msg_out access
500 * is read/write (`Builder` access).
501
502 * ### Resource use: RAM ###
503 * If #Reader_config is non-SHM-based, then a `*this` is analogous to a Msg_out; the
504 * RAM used is released once `*this` is destroyed. If it *is* SHM-based, then the cross-process ref-count
505 * scheme explained in Msg_out doc header is in force.
506 *
507 * ### Resource use: the #Native_handle (if any) ###
508 * Firstly see similarly named section in Msg_out doc header. In particular note that
509 * the `*this`-stored descriptor is not the same descriptor as the one in the out-message object;
510 * rather it's a descriptor in a different process referring to the the same description, with an OS/kernel-held
511 * ref-count.
512 *
513 * Even if `*this` stores a non-null #Native_handle, it will never return it to the OS on your behalf.
514 * You may do so if and when desired. This is different from Msg_out which "owns" its copy
515 * and will return it to the OS at destruction.
516 *
517 * @internal
518 * ### Impl notes ###
519 * This follows the same facade-API pattern as Msg_out; see similar place in its doc header.
520 * Same applies here. However: Msg_in represents an *instance* of a received message. Therefore it
521 * contains *both*
522 * - metadata-message about the associated user-message, if any, or the internal message; message ID,
523 * originating message ID, etc.; and
524 * - the user message (if any).
525 *
526 * So, in fact, on the sender side struc::Channel maintains the user's Msg_out (if any) and
527 * a user-invisible (created at send() time) Msg_mdt_out, which is just a somewhat-decorated-API
528 * Msg_out over an internal-use schema. On the receiver side Msg_in stores
529 * *both* counterpart read-only deserializations.
530 * - body_root() provides `public` user access to the user body;
531 * - `protected` accessors provide access to the other stuff, like id_or_none() and originating_msg_id_or_none(),
532 * which struc::Channel uses to maintain operation. These are `public`ly exposed via Msg_out_impl.
533 *
534 * In the case of an internal message, a `*this` is never emitted to the user. In that case
535 * internal_msg_body_root() provides internal access to the message.
536 *
537 * @endinternal
538 *
539 * @tparam Message_body
540 * See Msg_in: this is the counterpart.
541 * @tparam Struct_reader_config
542 * See Msg_out: this is the counterpart.
543 */
544template<typename Message_body, typename Struct_reader_config>
545class Msg_in :
546 private boost::noncopyable
547{
548public:
549 // Types.
550
551 /// See struc::Channel::Msg_body.
552 using Body = Message_body;
553
554 /// Short-hand for capnp-generated read-only-accessing `Reader` nested class of #Body. See body_root().
555 using Body_reader = typename Body::Reader;
556
557 /// See struc::Channel::Reader_config.
558 using Reader_config = Struct_reader_config;
559
560 // Constructors/destructor.
561
562 /**
563 * Returns resources, potentially including potentially significant RAM resources, taken before emitting to the user.
564 * native_handle_or_null(), even if not `.null()`, is not returned to the OS.
565 *
566 * See class doc header for discussion.
567 */
569
570 // Methods.
571
572 /**
573 * The #Body root capnp-generated accessor object. E.g.: `this->body_root().getSomeStruct().setSomeField()`
574 * will access the capnp-`struct`-typed root field `someStruct` and pluck out the value `someField` -- presumably an
575 * integer -- within it. The ref returned shall always be to the same address until `*this` is destroyed.
576 *
577 * #Body_reader is light-weight, so you may make a copy and then access via that, if desired. However
578 * whether `body_root()` itself or such a copy, such a `Reader` object may not be accessed after `*this` is destroyed.
579 *
580 * Informally we recommend against value-copying body_root(): Light-weight or not, it's a copy, and copying a
581 * pointer/cref is cheaper; and it may not live past `*this` anyway; and body_root() always returns the same address.
582 * So just store the cref (or pointer-to-`const` with the same addr).
583 *
584 * ### Quick capnp tips ###
585 * You should really read all of capnp docs at its web site. They are very useful and well written and not
586 * overly formal despite being quite comprehensive. That said a couple of gotchas/tips:
587 * - On a `Reader`, `.getX()` is lightning-fast, like accessing `struct` members directly --
588 * but only when `X` is of a scalar type. Compount types, where `.getX()` returns not a native type
589 * but another `Reader`, need to perform some pointer checking and are slower. Therefore,
590 * if you plan to `.getX()` and then `.getA()` and `.getB()` (and similar) on that `X`, you should
591 * save the result (`auto x = ....getX();`); then access via the saved result
592 * (`a = x.getA(...); b = x.getB(...)`).
593 *
594 * To pretty-print (with indent/newlines) you can use: `capnp::prettyPrint(M.body_root()).flatten().cStr()`.
595 *
596 * @return See above.
597 */
598 const Body_reader& body_root() const;
599
600 /**
601 * The #Native_handle -- potentially null meaning none -- embedded in this message.
602 *
603 * @return See above.
604 */
606
607 /**
608 * Prints string representation to the given `ostream`. This representation lacks newlines/indentation;
609 * includes a (potentially truncated) pretty-printed representation of `body_root()` contents; and includes
610 * native_handle_or_null().
611 *
612 * Caution: This could be an operation expensive in processor cycles and, temporarily, RAM; and thus should
613 * be used judiciously. To help drive your decision-making: This method, internally,
614 * -# uses capnp `kj::str(this->body_root)` to generate a *full* pretty-print of body_root() contents;
615 * -# truncates the result of the latter, as needed for a reasonably short output, and prints the result;
616 * -# adds native_handle_or_null() and possibly a few other small information items.
617 *
618 * Because there is no reasonably-available way to stop generating the pretty-print in step 1 upon reaching
619 * a certain number of characters, the operation may take a while, if many non-default bytes have been
620 * mutated-in; and before truncation the resulting string may take significant RAM accordingly.
621 *
622 * @internal
623 * If used by internal code before successful deserialize_mdt() and/or before successful deserialize_body()
624 * (if one would even be possible in the first place -- not so with internal messages), this method will print
625 * useful things. Moreover the above public-facing description is no longer complete in that case.
626 * In any case the method remains suitable for TRACE-logging but not INFO-logging by internal code, at least
627 * in the per-message common code path.
628 * @endinternal
629 *
630 * @param os
631 * Stream to which to write.
632 */
633 void to_ostream(std::ostream* os) const;
634
635protected:
636 // Types.
637
638 /// `Reader` counterpart to Msg_mdt_out::Internal_msg_body_builder.
640
641 /// Same as `Msg_mdt_out::Body`.
642 using Mdt = schema::detail::StructuredMessage;
643
644 /// Same as `Msg_mdt_out::Body_builder` but the `Reader` instead.
645 using Mdt_reader = typename Mdt::Reader;
646
647 // Constructors/destructor.
648
649 /**
650 * Constructs a not-ready-for-public-consumption in-message which awaits serialization-storing segments to be
651 * added via add_serialization_segment() and then finalized with deserialize_mdt() and possibly deserialize_body().
652 * After the latter 1-2: body_root() or internal_msg_body_root() can be used to access the deserialized data; as can
653 * id_or_none() and similar accessors.
654 *
655 * @param struct_reader_config
656 * See struc::Channel ctors. This is copied, memorized.
657 */
658 explicit Msg_in(const Reader_config& struct_reader_config);
659
660 // Methods.
661
662 /**
663 * Store the #Native_handle (potentially `.null()`, meaning none) in this in-message. Call this at most once;
664 * or behavior undefined (assertion may trip).
665 *
666 * @param native_handle_or_null
667 * The #Native_handle (`.null() == true` if none) to move into `*this`. Made `.null() == true` upon return.
668 */
670
671 /**
672 * Prior to `deserialization_*()` obtains a memory area `max_sz` bytes long into which the user may write-to
673 * until the next add_serialization_segment(), `deserialization_*()`, or dtor call (whichever happens first);
674 * returns a pointer to that area as described by the pointed-to `Blob`'s [`begin()`, `end()`) range.
675 * If the reader impl decides `max_sz` bytes are not available, returns null. `*this` shall not be used
676 * subsequent to such an eventuality.
677 *
678 * This essentially forwards to the appropriate Struct_reader::add_serialization_segment(); hence the same
679 * requirements, including w/r/t alignment and subsequent storing-into and modification of returned `Blob`,
680 * apply as described in that doc header. That said:
681 * - The first add_serialization_segment() call must be the *sole* segment of the metadata
682 * message (corresponding to Msg_mdt_out). After the returned `Blob` is filled-out and `.resize()`d,
683 * you must invoke deserialize_mdt() which shall return the number of additional
684 * add_serialization_segment() calls to make. If that number is 0 (<=> id_or_none() is 0 <=> there is an
685 * internal message in the Msg_mdt_out), then there shall be no further add_serialization_segment() calls;
686 * internal_msg_body_root() can be used. Otherwise:
687 * - The following add_serialization_segment() calls (the 2nd, 3rd, ...) ones shall be, in order, comprised by
688 * the user-message serialization (corresponding to `Msg_out<Message_body>`). After each call
689 * fill-out and `.resize()` the returned `Blob`. After the last call call deserialize_body(); then
690 * body_root() can be used.
691 *
692 * @param max_sz
693 * See Struct_reader::add_serialization_segment().
694 * @return See Struct_reader::add_serialization_segment().
695 */
696 flow::util::Blob* add_serialization_segment(size_t max_sz);
697
698 /**
699 * To be invoked after exactly one successful add_serialization_segment() call (and that `Blob` being filled-out
700 * and `.resize()`d): finalizes the deserialization of everything except the potential user-message body.
701 * This must be called strictly before any calls to internal_msg_body_root(), id_or_none(),
702 * originating_msg_id_or_none(), or session_token(); and any subsequent add_serialization_segment()
703 * calls (if any).
704 *
705 * The value this returns (sans error) dictates the exact # of further add_serialization_segment() calls to make.
706 * - If 0: You may use the accessor API immediately. internal_msg_body_root() is OK; `id_or_none() == 0`;
707 * body_root() may not be used.
708 * - Else: You may use the accessor API immediately. `id_or_none() != 0`; internal_msg_body_root() may not be
709 * used; body_root() may not be used *yet* until successful deserialize_body().
710 *
711 * If called before add_serialization_segment(), behavior is undefined (assertion may trip).
712 *
713 * If called more than once, behavior is undefined (assertion may trip).
714 *
715 * If it fails (emits truthy #Error_code), it is pointless to use `*this`. Recommend destruction.
716 *
717 * @param logger_ptr
718 * Logger to use for logging within this method.
719 * @param err_code
720 * Caution: Unlike user-facing methods, this does not throw (except capnp-generated exceptions);
721 * and `err_code` may not be null. Other than that:
722 * #Error_code generated: falsy on success, else:
723 * error::Code::S_STRUCT_CHANNEL_INTERNAL_PROTOCOL_MISUSED_SCHEMA (opposing Msg_out code
724 * filled out the fields in an unexpected way),
725 * anything emitted by Struct_reader::deserialization().
726 * @return See above.
727 */
728 size_t deserialize_mdt(flow::log::Logger* logger_ptr, Error_code* err_code);
729
730 /**
731 * To be invoked after `deserialize_mdt() == N`, and add_serialization_segment() was called N times (with all
732 * N `Blob`s filled-out and `.resize()`d): finalizes the deserialization of the user-message body.
733 * This must be called strictly before any calls to body_root().
734 *
735 * If called before a post-deserialize_mdt() add_serialization_segment(), behavior is undefined (assertion may trip).
736 *
737 * If called more than once, behavior is undefined (assertion may trip).
738 *
739 * If it fails (emits truthy #Error_code), it is pointless to use `*this`. Recommend destruction.
740 *
741 * @param err_code
742 * See deserialize_mdt().
743 */
744 void deserialize_body(Error_code* err_code);
745
746 /**
747 * To be called only after deserialize_mdt(), returns the message ID of this in-message; 0 means it's an internal
748 * message (internal_msg_body_root() applies), else it's a user message (body_root() applies).
749 *
750 * @return See above.
751 */
752 msg_id_t id_or_none() const;
753
754 /**
755 * To be called only after deserialize_mdt(), returns the message ID of the out-message to which this in-message
756 * claims to be responding; or 0 if it is not a response.
757 *
758 * @return See above.
759 */
761
762 /**
763 * To be called only after deserialize_mdt(), similar to body_root() but for the internal-message root.
764 * See #Internal_msg_body_reader doc header.
765 *
766 * @return See above.
767 */
769
770 /**
771 * To be called only after deserialize_mdt(), returns session token tagging this in-message.
772 *
773 * @return See above.
774 */
775 const Session_token& session_token() const;
776
777 /**
778 * The #Mdt root capnp-generated accessor object. May be useful for, say, pretty-printing it
779 * to log (e.g.: `capnp::prettyPrint(M.mdt_root()).flatten().cStr()`). We do not recommend its use for
780 * other purposes; stylistically it is better to access items via individual accessors like session_token()
781 * or internal_msg_body_root().
782 *
783 * @return See above.
784 */
785 const Mdt_reader& mdt_root() const;
786
787private:
788 // Types.
789
790 /**
791 * Same as Msg_out::Builder but the reader that can decode what that serializing `Builder` did.
792 * This deserializes the metadata and (if any) user message.
793 */
795
796 // Data.
797
798 /// See ctor.
800
801 /**
802 * Deserializes the metadata sub-message, invisible to user: the thing describing the user message
803 * (if any) or describing and containing the internal message (otherwise).
804 * Essentially: the first add_serialization_segment() forwards to the same
805 * method on this #m_mdt_reader. (We ensure on the opposing side the metadata structure is always 1 segment, no
806 * more.) This stores a few things like message ID; plus possibly an internal-body; otherwise the #
807 * of times add_serialization_segment() must be called to complete #m_body_reader serialization. In the former
808 * case #m_body_reader is left null: there is no user message.
809 *
810 * deserialize_mdt() forwards to `.deserialization()` on #m_mdt_reader. Then the post-deserialization accessors
811 * become available except body_root().
812 */
813 std::optional<Reader> m_mdt_reader;
814
815 /**
816 * Like #m_mdt_reader but for the user message if any. Essentially: the 2nd, 3rd, ... add_serialization_segment()
817 * forward to the same method on this #m_body_reader. This stores the user-message payload if any. If none this
818 * is left null: there is no user message.
819 *
820 * deserialize_body() forwards to the same method on #m_body_reader. Then body_root() becomes available.
821 */
822 std::optional<Reader> m_body_reader;
823
824 /// Starts `false`; becomes `true` immutably once deserialize_mdt() succeeds.
826
827 /// Starts `false`; becomes `true` immutably once deserialize_body() succeeds (never if it's an internal message).
829
830 /// See internal_msg_body_root(); meaningless until #m_mdt_deserialized_ok.
832
833 /// See body_root(); meaningless until #m_body_deserialized_ok.
835
836 /**
837 * Starts uninitialized, this is assigned exactly once by deserialize_mdt(), storing the session-token that
838 * was embedded in the in-message. This is cached from the encoding in the tree accessed via #m_mdt_root.
839 * It is cached for session_token() perf only.
840 */
842
843 /// See store_native_handle_or_null().
845}; // class Msg_in
846
847// Free functions: in *_fwd.hpp.
848
849// Template implementations.
850
851/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
852#define TEMPLATE_STRUCT_MSG_OUT \
853 template<typename Message_body, typename Struct_builder_t>
854/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
855#define CLASS_STRUCT_MSG_OUT \
856 Msg_out<Message_body, Struct_builder_t>
857/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
858#define TEMPLATE_STRUCT_MSG_IN \
859 template<typename Message_body, typename Struct_reader_config>
860/// Internally used macro; public API users should disregard (same deal as in struc/channel.hpp).
861#define CLASS_STRUCT_MSG_IN \
862 Msg_in<Message_body, Struct_reader_config>
863
864// Msg_out template implementations.
865
867CLASS_STRUCT_MSG_OUT::Msg_out() :
868 m_body_root(nullptr) // capnp deletes default ctor to "discourage incorrect usage" but makes this available.
869{
870 // OK then. Useless *this until moved-to.
871}
872
874CLASS_STRUCT_MSG_OUT::Msg_out
875 (const Builder_config& struct_builder_config) :
876
877 /* As promised, in this simple (typical) form we create the new capnp::MessageBuilder and initRoot<Body>() it
878 * for them. Simply delegating as follows causes getRoot<Body>() to act as-if initRoot<Body>() due to lacking
879 * an initialized root at that point. */
880 Msg_out(Builder(struct_builder_config))
881{
882 // OK then. Mutate away, user.
883}
884
886CLASS_STRUCT_MSG_OUT::Msg_out(Builder&& struct_builder) :
887
888 /* In this more advanced (from user's PoV) ctor form they already are giving us m_builder and guaranteeing
889 * its getRoot<Body>() is either already a thing... or it is not root-initialized at all.
890 * getRoot<Body>() by us will thus not modify the tree, if it is initialized; or create a blank tree
891 * (same as the other ctor), if it is not. The only problematic situation -- as advertised -- is
892 * if they root-initialized it to something other than Body (e.g., initRoot<SomeOtherThing>()); then getRoot<Body>()
893 * will try to treat non-Body as Body, and something will probably blow up at some point
894 * (possibly during deserialization). */
895 m_builder(std::move(struct_builder)), // Eat theirs!
896 m_body_root(m_builder.payload_msg_builder()->template getRoot<Body>()) // Pluck out theirs, or initialize if needed!
897{
898 // OK then. Mutate away, user (though they may well have finalized m_body_root tree already).
899}
900
902CLASS_STRUCT_MSG_OUT::Msg_out(Msg_out&& src) :
903 Msg_out()
904{
905 operator=(std::move(src));
906
907 /* (This comment is by ygoldfel, original author of this code -- here and all of this class template and file.)
908 * This implementation is clearly correct (functionally); one can see a similar pattern used in many places in,
909 * e.g., STL/Boost. However the original, and all else being equal (which it's not; read on), my preferred
910 * implementation of this move ctor is simply: `= default;`. In that original state I tested this guy and
911 * ran into the following.
912 *
913 * As of this writing, to test this (and all of Msg_out and much else besides), I've been using the
914 * transport_test.exec exercise-mode section; and the unit_test.exec test suite (both in the `ipc` meta-project,
915 * though most of the relevant .../test/... code for unit_test.exec is in `ipc_shm_arena_lend` project therein).
916 * (Normally we don't speak of test code inside source code proper like this, but read on to see why the
917 * exception.) transport_test has passed in all configurations (build/run envs) without issue.
918 * unit_test.exec has passed in at least the following (all Linux) except the *asterisked* one:
919 * - gcc-9, -O0 or: (-O3 + LTO disabled or LTO (with fat-object-generation on) enabled (for all of libflow
920 * and libipc_* and the test code proper)).
921 * - clang-17 + libc++ (LLVM-10) (note: not GNU stdc++), -O0 or: (-O3 + LTO disabled or LTO (-flto=thin) enabled*
922 * (for all of libflow and libipc_* and the test code proper)).
923 *
924 * The *asterisk* there denotes the one config where a problem was observed. Namely,
925 * Shm_session_test.In_process_array unit_test failed, seg-faulting before the test could complete (no actual
926 * test-failed assertions had triggered up to the seg-fault point). The seg-fault was completely consistent
927 * (at least given a particular machine): in session::Client_session_impl::mdt_builder(), just near the end
928 * of the method, a Msg_out was being move-cted (presumably using this ctor here) from another Msg_out
929 * that had just been constructed a few lines above. Granted, that source Msg_out was constructed and
930 * populated (rather straightforwardly) in another thread, but a synchronization mechanism was used to ensure
931 * this happened synchronously before the code that seg-faulted (this move-ctor) would proceed to be called.
932 * (I verified quite studiously that nothing untoward was happening there; clearly the source object was
933 * created cleanly before signaling the thread waiting to proceed with this move-ct to quit waiting and proceed.)
934 * (In addition note that this Msg_out ctor was, as seen in debugger, clearly getting auto-inlined; since the prob
935 * occurred with LTO but not without -- though gcc's LTO had no issue, but I digress -- this may be significant.)
936 *
937 * First I labored to isolate where the problem occurred; there was no corrupted memory or anything strange like
938 * that; and it fairly clearly really was in the move ctor (which, again, was just `= default;` at the time).
939 * Since the move ctor was auto-generated, it was somewhat challenging to see where the problem happened, though
940 * admittedly due to time pressure I did not delve into the move ctors *that* would've invoked: for
941 * m_builder, m_body_root, m_hndl_or_null (doing so might be a good idea; but keep reading).
942 *
943 * At that point, just to see what's up, I "jiggled" the implementation into its current form. Empirically
944 * speaking the problem went away, and everything passed swimmingly with no instability. Hence I left the
945 * work-around in place. So where does it leave us?
946 *
947 * 1, in terms of correctness and generated-code quality: As noted, the new impl is clearly correct. In terms of
948 * generated-code quality, it is potentially a few instructions slower than the auto-generated ctor:
949 * the three m_* are first initialized to their null states and then move-assigned; plus
950 * store_native_handle_or_null() checks m_hndl_or_null for null (which it is, so that `if` no-ops).
951 * It's simple/quick stuff, and it might even get optimized away with -O3, but nevertheless skipping to
952 * move-ction of the members would be more certain to not do that unneeded zeroing stuff. Subjectively: it's
953 * probably fine (undoubtedly there are far heavier perf concerns than a few extra zeroings).
954 *
955 * 2, there's the mystery. I.e., sure, the replacement code is fine and is unlikely to be a perf problem;
956 * but why isn't the preferred `= default;` the one in actual use? Why did it cause the failure, though only
957 * in a very particular build/run environment (clang-17, LLVM-10 libc++, with thin-LTO), when similar ones
958 * (such as same but without LTO) were fine? At this stage I honestly do not know and will surely file a
959 * ticket to investigate/solve. Briefly the culprit candidates are:
960 * - Msg_out code itself. Is there some unseen uninitialized datum? Some basic assumption being ignored or
961 * C++ rule being broken? ###
962 * - Something in capnp-generated move-ctor (as of this writing capnp version = 1.0.1, from late 2023) or
963 * m_builder move-ctor.
964 * - Something in clang-17 + thin-LTO optimizer improperly reordering instructions.
965 *
966 * I cannot speculate much about which it is; can only say after a few hours of contemplating possibilities:
967 * no candidates for ### (see above) being at fault has jumped out at me. That said, no run-time sanitizer
968 * has run through this code as of this writing (though the code analyzer, Coverity, has not complained);
969 * that could help. Sanitizer or not, generally:
970 * given 0-2 days of investigation by an experienced person surely we can narrow this down to a
971 * minimal repro case, etc. etc. So it is solvable: just needs to be done.
972 *
973 * Until then: (1) this remains a mystery; and (2) there is an acceptable work-around. (Though the mystery
974 * is personally disconcerting to me; e.g., as of this writing, I cannot name another such mystery in this
975 * entire code base.) */
976} // CLASS_STRUCT_MSG_OUT::Msg_out(Msg_out&&)
977
979CLASS_STRUCT_MSG_OUT::~Msg_out()
980{
981 // As promised return it (if any) to OS.
982 store_native_handle_or_null(Native_handle());
983
984 // The rest of cleanup is automatic.
985}
986
988CLASS_STRUCT_MSG_OUT& CLASS_STRUCT_MSG_OUT::operator=(Msg_out&& src)
989{
990 m_builder = std::move(src.m_builder);
991
992 /* I was a bit worried about this (and note this of course similarly auto-occurs in the =default-ed move ctor) but
993 * I (ygoldfel) did some due diligence on it:
994 * - It is after all move()able (or this wouldn't compile), with implicitly-default move ops.
995 * This doesn't "nullify" src.m_body_root, but that is perfectly fine; m_builder sure is made as-if
996 * default-cted, and anyway using (other than move-to) of a moved-from `*this` is advertised as undefined
997 * behavior.
998 * - `Builder`s are generally treated as light-weight in capnp docs.
999 * - Looking inside the current (version 0.10) code shows that a capnp-`struct` Builder is, internally,
1000 * entirely consisting of something called StructBuilder, and the latter consists of 4 pointers and 2
1001 * integers.
1002 * So it is fine (and so is the move ctor). */
1003 m_body_root = std::move(src.m_body_root);
1004
1005 // The following is why we didn't simply do =default.
1006 if (m_hndl_or_null != src.m_hndl_or_null)
1007 {
1008 // As promised return it (if any) to OS, as that is what would happen if *this were destroyed.
1009 store_native_handle_or_null(Native_handle());
1010 }
1011
1012 m_hndl_or_null = std::move(src.m_hndl_or_null);
1013
1014 return *this;
1015} // Msg_out::operator=(move)
1016
1018typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root()
1019{
1020 return &m_body_root;
1021}
1022
1024const typename CLASS_STRUCT_MSG_OUT::Body_builder* CLASS_STRUCT_MSG_OUT::body_root() const
1025{
1026 return const_cast<Msg_out*>(this)->body_root();
1027}
1028
1030typename CLASS_STRUCT_MSG_OUT::Orphanage CLASS_STRUCT_MSG_OUT::orphanage()
1031{
1032 return m_builder.payload_msg_builder()->getOrphanage();
1033 /* Aside: Per capnp docs ("C++ serialization") one can also do:
1034 * return ::capnp::Orphanage::getForMessageContaining(*(body_root())); */
1035}
1036
1038void CLASS_STRUCT_MSG_OUT::store_native_handle_or_null (Native_handle&& native_handle_or_null)
1039{
1040 if (native_handle_or_null == m_hndl_or_null)
1041 {
1042 return;
1043 }
1044 // else
1045 if (!m_hndl_or_null.null())
1046 {
1047 asio_local_stream_socket::release_native_peer_socket(std::move(m_hndl_or_null)); // OK if it is .null().
1048 }
1049 m_hndl_or_null = std::move(native_handle_or_null);
1050}
1051
1053Native_handle CLASS_STRUCT_MSG_OUT::native_handle_or_null() const
1054{
1055 return m_hndl_or_null;
1056}
1057
1059void CLASS_STRUCT_MSG_OUT::emit_serialization(Segment_ptrs* target_blobs, const typename Builder::Session& session,
1060 Error_code* err_code) const
1061{
1062 m_builder.emit_serialization(target_blobs, session, err_code); // Let it emit error or not.
1063}
1064
1066size_t CLASS_STRUCT_MSG_OUT::n_serialization_segments() const
1067{
1068 return m_builder.n_serialization_segments();
1069}
1070
1072void CLASS_STRUCT_MSG_OUT::to_ostream(std::ostream* os_ptr) const
1073{
1074 using util::String_view;
1075
1076 constexpr size_t MAX_SZ = 256;
1077 constexpr String_view TRUNC_SUFFIX = "... )"; // Fake the end to look like the end of the real pretty-print.
1078
1079 auto& os = *os_ptr;
1080
1081 // This is not a public API but OK to output publicly methinks.
1082 os << "[n_serialization_segs[" << n_serialization_segments() << "] ";
1083
1084 const auto hndl_or_null = native_handle_or_null();
1085 if (!hndl_or_null.null())
1086 {
1087 // As of this writing it's, like, "native_hndl[<the FD>]" -- that looks pretty good and pithy.
1088 os << hndl_or_null << ' ';
1089 }
1090 // else { No need to output anything; pithier. }
1091
1092 /* prettyPrint() gives an indented multi-line version; this gives a single-line one. Seems there's no way to
1093 * truncate it "on the fly"; a full-printout string must be made first (which is too bad; @todo revisit). */
1094 const kj::String capnp_str = kj::str(*(body_root()));
1095 if (capnp_str.size() > MAX_SZ)
1096 {
1097 os << String_view(capnp_str.begin(), MAX_SZ - TRUNC_SUFFIX.size()) << TRUNC_SUFFIX;
1098 }
1099 else
1100 {
1101 os << capnp_str.cStr();
1102 }
1103
1104 os << "]@" << this;
1105} // Msg_out::to_ostream()
1106
1108std::ostream& operator<<(std::ostream& os, const CLASS_STRUCT_MSG_OUT& val)
1109{
1110 val.to_ostream(&os);
1111 return os;
1112}
1113
1114// Msg_in template implementations.
1115
1117CLASS_STRUCT_MSG_IN::Msg_in(const Reader_config& struct_reader_config) :
1118 m_reader_config(struct_reader_config),
1119 m_mdt_deserialized_ok(false),
1120m_body_deserialized_ok(false)
1121 // m_session_token is uninitialized garbage.
1122{
1123 // That's it: need to feed segments into m_*_reader before can deserialize anything.
1124}
1125
1127void CLASS_STRUCT_MSG_IN::store_native_handle_or_null(Native_handle&& native_handle_or_null)
1128{
1129 assert(m_hndl_or_null.null() && "Call this at most once (probably upon finalizing 1st segment as well).");
1130
1131 m_hndl_or_null = std::move(native_handle_or_null);
1132}
1133
1135CLASS_STRUCT_MSG_IN::~Msg_in() = default;
1136
1138flow::util::Blob* CLASS_STRUCT_MSG_IN::add_serialization_segment(size_t max_sz)
1139{
1140 using boost::movelib::make_unique;
1141
1142 assert((!m_body_deserialized_ok)
1143 && "Do not call add_serialization_segment() after both deserialize_*().");
1144
1145 // Fill them out in the order described in their doc headers.
1146
1147 if (!m_mdt_reader)
1148 {
1149 m_mdt_reader.emplace(m_reader_config);
1150 return m_mdt_reader->add_serialization_segment(max_sz);
1151 }
1152 // else
1153 if (!m_body_reader)
1154 {
1155 m_body_reader.emplace(m_reader_config);
1156 }
1157 return m_body_reader->add_serialization_segment(max_sz);
1158} // Msg_in::add_serialization_segment()
1159
1161size_t CLASS_STRUCT_MSG_IN::deserialize_mdt(flow::log::Logger* logger_ptr, Error_code* err_code)
1162{
1163 using util::String_view;
1164 using boost::endian::little_to_native;
1165
1166 assert(err_code);
1167 assert((!m_mdt_deserialized_ok) && "Do not call deserialize_mdt() after it returns.");
1168 assert(m_mdt_reader && "Must call add_serialization_segment() exactly 1x before deserialize_mdt().");
1169
1170 m_mdt_root = m_mdt_reader->template deserialization<Mdt>(err_code);
1171 if (*err_code)
1172 {
1173 return 0;
1174 }
1175 // else: Now the accessors will work (including for us below).
1176 m_mdt_deserialized_ok = true;
1177
1178 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT); // Log on errors (at least).
1179
1180 /* Refer to structured_msg.capnp StructuredMessage. m_mdt_reader has initialized it for us. Now to fill it in:
1181 * Let's go over it:
1182 * - authHeader.sessionToken: We decode it here and save it (for accessor perf).
1183 * - id: It's accessible through accessor id_or_none() (perf is good enough to not need caching).
1184 * However we check it for correctness and emit error if bad.
1185 * - originatingMessageOrNull: Basically there's a msg_id_t in there too (ditto, originating_msg_id_or_none()).
1186 * However we check it for correctness and emit error if bad.
1187 * - internalMessageBody: Present if and only if there will be no m_body_reader. */
1188
1189 // Deal with sessionToken. Decode as mandated in .capnp Uuid doc header. @todo Factor this out into a util method.
1190
1191 // Error helper.
1192 const auto error_out = [&](String_view msg) -> size_t
1193 {
1195 FLOW_LOG_WARNING(msg);
1196 m_mdt_deserialized_ok = false; // Mark us as failed again.
1197 return 0;
1198 }; // const auto error_out =
1199
1200 if (!m_mdt_root.hasAuthHeader())
1201 {
1202 return error_out("In-mdt-message has null .authHeader. Other side misbehaved?");
1203 }
1204 // else
1205 const auto auth_header = m_mdt_root.getAuthHeader();
1206
1207 if (!auth_header.hasSessionToken())
1208 {
1209 return error_out("In-mdt-message has null .authHeader. Other side misbehaved?");
1210 }
1211 // else
1212
1213 const auto capnp_uuid = auth_header.getSessionToken();
1214 static_assert(decltype(m_session_token)::static_size() == 2 * sizeof(uint64_t),
1215 "World is broken: UUIDs expected to be 16 bytes!");
1216 auto& first8 = *(reinterpret_cast<uint64_t*>(m_session_token.data)); // m_session_token is aligned, so this is too.
1217 auto& last8 = *(reinterpret_cast<uint64_t*>(m_session_token.data + sizeof(uint64_t))); // As is this.
1218 first8 = little_to_native(capnp_uuid.getFirst8()); // Reminder: Likely no-op + copy of uint64_t.
1219 last8 = little_to_native(capnp_uuid.getLast8()); // Ditto.
1220
1221 // As planned check .originatingMessageOrNull for basic correctness.
1222 if (m_mdt_root.hasOriginatingMessageOrNull() && (originating_msg_id_or_none() == 0))
1223 {
1224 return error_out("In-mdt-message top union specifies .originatingMessageOrNull.id but it is 0. Responses to "
1225 "internal messages (with .id=sentinel) are not allowed. Other side misbehaved?");
1226 }
1227 // else: no problem there.
1228
1229 const auto id_or_0 = id_or_none();
1230 if (m_mdt_root.isInternalMessageBody())
1231 {
1232 if (id_or_0 != 0)
1233 {
1234 return error_out("In-mdt-message top union specifies .internalMessageBody; but .id=/=0, the sentinel value. "
1235 "Other side misbehaved?");
1236 }
1237 // else
1238
1239 /* And that's that. Stuff like IDs may still be wrong compared to preceding messages, which we can't check yet.
1240 * struc::Channel will before any emission to user. */
1241 assert(!*err_code);
1242 return 0;
1243 }
1244 // else if (!.isInternalMessageBody())
1245
1246 if (id_or_0 == 0)
1247 {
1248 return error_out("In-mdt-message top union specifies no .internalMessageBody; but .id=0, the sentinel value. "
1249 "Other side misbehaved?");
1250 }
1251 // else
1252
1253 const size_t n_body_segs = m_mdt_root.getNumBodySerializationSegments();
1254 if (n_body_segs == 0)
1255 {
1256 return error_out("In-mdt-message top union specifies no .internalMessageBody; and .id=0, the sentinel value; "
1257 "but body-segment-count is 0 which is illegal. Other side misbehaved?");
1258 }
1259 // else
1260
1261 // And that's that. (Same comment as above.)
1262 return n_body_segs;
1263} // Msg_in::deserialize_mdt()
1264
1266void CLASS_STRUCT_MSG_IN::deserialize_body(Error_code* err_code)
1267{
1268 assert(err_code);
1269 assert(m_mdt_deserialized_ok && "Do not call deserialize_body() until deserialize_mdt() succeeds.");
1270 assert((id_or_none() != 0) && "Do not call deserialize_body() on internal messages.");
1271 assert((!m_body_deserialized_ok) && "Do not call deserialize_body() after it returns.");
1272 assert(m_body_reader && "Must call add_serialization_segment() at least once after deserialize_mdt() but before "
1273 "deserialize_body().");
1274
1275 m_body_root = m_body_reader->template deserialization<Body>(err_code);
1276 if (*err_code)
1277 {
1278 return;
1279 }
1280 // else: Now body_root() works.
1281 m_body_deserialized_ok = true;
1282} // Msg_in::deserialize_body()
1283
1285msg_id_t CLASS_STRUCT_MSG_IN::id_or_none() const
1286{
1287 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1288 return m_mdt_root.getId();
1289}
1290
1292msg_id_t CLASS_STRUCT_MSG_IN::originating_msg_id_or_none() const
1293{
1294 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1295 return m_mdt_root.hasOriginatingMessageOrNull()
1296 ? m_mdt_root.getOriginatingMessageOrNull().getId()
1297 : 0;
1298}
1299
1301const Session_token& CLASS_STRUCT_MSG_IN::session_token() const
1302{
1303 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1304 return m_session_token;
1305}
1306
1308typename CLASS_STRUCT_MSG_IN::Internal_msg_body_reader CLASS_STRUCT_MSG_IN::internal_msg_body_root() const
1309{
1310 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling accessors.");
1311 assert((!m_body_reader) && "Access internal_msg_body_root() only if `id_or_none() == 0`.");
1312 return m_mdt_root.getInternalMessageBody();
1313}
1314
1316const typename CLASS_STRUCT_MSG_IN::Body_reader& CLASS_STRUCT_MSG_IN::body_root() const
1317{
1318 assert(m_body_deserialized_ok && "Call deserialize_body() successfully before calling body_root() accessor.");
1319 return m_body_root;
1320}
1321
1323const typename CLASS_STRUCT_MSG_IN::Mdt_reader& CLASS_STRUCT_MSG_IN::mdt_root() const
1324{
1325 assert(m_mdt_deserialized_ok && "Call deserialize_mdt() successfully before calling mdt_root() accessor.");
1326 return m_mdt_root;
1327}
1328
1330Native_handle CLASS_STRUCT_MSG_IN::native_handle_or_null() const
1331{
1332 return m_hndl_or_null;
1333}
1334
1336void CLASS_STRUCT_MSG_IN::to_ostream(std::ostream* os_ptr) const
1337{
1338 using util::String_view;
1339
1340 constexpr size_t MAX_SZ = 256;
1341 constexpr String_view TRUNC_SUFFIX = "... )"; // Fake the end to look like the end of the real pretty-print.
1342
1343 auto& os = *os_ptr;
1344
1345 os << '[';
1346
1347 const auto hndl_or_null = native_handle_or_null();
1348 if (!hndl_or_null.null())
1349 {
1350 // As of this writing it's, like, "native_hndl[<the FD>]" -- that looks pretty good and pithy.
1351 os << hndl_or_null << ' ';
1352 }
1353 // else { No need to output anything; pithier. }
1354
1355 if (m_mdt_deserialized_ok)
1356 {
1357 const auto id_or_0 = id_or_none();
1358 if (id_or_0 == 0)
1359 {
1360 /* Internal message. Might as well simply print the entire metadata-header; it's all interesting, and
1361 * an internal message never reaches the user; so internal code may well want to print all this.
1362 * Plus there's simply nothing else to print, at all, so it's complete.
1363 * As in Msg_out::to_ostream() use the non-indent/newline pretty-print but no truncation needed. */
1364 os << ::kj::str(internal_msg_body_root()).cStr();
1365 }
1366 else // if (id_or_0 != 0)
1367 {
1368 /* User message. We should be somewhat judicious as to what to print; it does not strictly have to be
1369 * stuff available via public APIs -- but don't go overboard either. E.g., session token is of low interest
1370 * and takes space more than anything and is an internal detail; but message ID and originating message ID
1371 * (if any) both help correlate messages versus other messages. */
1372 os << "id[" << id_or_0 << "] ";
1373 const auto originating_msg_id_or_0 = originating_msg_id_or_none();
1374 if (originating_msg_id_or_0 != 0)
1375 {
1376 os << "rsp_to_id[" << originating_msg_id_or_0 << "] ";
1377 }
1378
1379 if (m_body_deserialized_ok)
1380 {
1381 // Similarly to Msg_out::to_ostream() print the body but truncated if needed. @todo Code reuse?
1382 const kj::String capnp_str = kj::str(body_root());
1383 if (capnp_str.size() > MAX_SZ)
1384 {
1385 os << String_view(capnp_str.begin(), MAX_SZ - TRUNC_SUFFIX.size()) << TRUNC_SUFFIX;
1386 }
1387 else
1388 {
1389 os << capnp_str.cStr();
1390 }
1391 }
1392 else // if (!m_body_deserialized_ok)
1393 {
1394 os << " ( incomplete )"; // Perhaps we're being printed internally, before deserialize_body().
1395 }
1396 } // else if (id_or_0 != 0)
1397 }
1398 else // if (!m_mdt_deserialized_ok)
1399 {
1400 os << "( incomplete )"; // Perhaps we're being printed internally, before deserialize_mdt().
1401 }
1402
1403 os << "]@" << this;
1404} // Msg_in::to_ostream()
1405
1407std::ostream& operator<<(std::ostream& os, const CLASS_STRUCT_MSG_IN& val)
1408{
1409 val.to_ostream(&os);
1410 return os;
1411}
1412
1413#undef TEMPLATE_STRUCT_MSG_OUT
1414#undef CLASS_STRUCT_MSG_OUT
1415#undef TEMPLATE_STRUCT_MSG_IN
1416#undef CLASS_STRUCT_MSG_IN
1417
1418} // namespace ipc::transport::struc
A structured in-message instance suitable as received and emittable (to user) by struc::Channel.
Definition: msg.hpp:547
Mdt_reader m_mdt_root
See internal_msg_body_root(); meaningless until m_mdt_deserialized_ok.
Definition: msg.hpp:831
~Msg_in()
Returns resources, potentially including potentially significant RAM resources, taken before emitting...
flow::util::Blob * add_serialization_segment(size_t max_sz)
Prior to deserialization_*() obtains a memory area max_sz bytes long into which the user may write-to...
Definition: msg.hpp:1138
bool m_mdt_deserialized_ok
Starts false; becomes true immutably once deserialize_mdt() succeeds.
Definition: msg.hpp:825
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Definition: msg.hpp:1336
const Mdt_reader & mdt_root() const
The Mdt root capnp-generated accessor object.
Definition: msg.hpp:1323
const Body_reader & body_root() const
The Body root capnp-generated accessor object.
Definition: msg.hpp:1316
Native_handle m_hndl_or_null
See store_native_handle_or_null().
Definition: msg.hpp:844
typename Body::Reader Body_reader
Short-hand for capnp-generated read-only-accessing Reader nested class of Body. See body_root().
Definition: msg.hpp:555
std::optional< Reader > m_mdt_reader
Deserializes the metadata sub-message, invisible to user: the thing describing the user message (if a...
Definition: msg.hpp:813
Reader_config m_reader_config
See ctor.
Definition: msg.hpp:799
Internal_msg_body_reader internal_msg_body_root() const
To be called only after deserialize_mdt(), similar to body_root() but for the internal-message root.
Definition: msg.hpp:1308
Body_reader m_body_root
See body_root(); meaningless until m_body_deserialized_ok.
Definition: msg.hpp:834
typename Mdt::Reader Mdt_reader
Same as Msg_mdt_out::Body_builder but the Reader instead.
Definition: msg.hpp:645
const Session_token & session_token() const
To be called only after deserialize_mdt(), returns session token tagging this in-message.
Definition: msg.hpp:1301
Message_body Body
See struc::Channel::Msg_body.
Definition: msg.hpp:552
Session_token m_session_token
Starts uninitialized, this is assigned exactly once by deserialize_mdt(), storing the session-token t...
Definition: msg.hpp:841
schema::detail::StructuredMessage Mdt
Same as Msg_mdt_out::Body.
Definition: msg.hpp:642
Native_handle native_handle_or_null() const
The Native_handle – potentially null meaning none – embedded in this message.
Definition: msg.hpp:1330
msg_id_t originating_msg_id_or_none() const
To be called only after deserialize_mdt(), returns the message ID of the out-message to which this in...
Definition: msg.hpp:1292
void store_native_handle_or_null(Native_handle &&native_handle_or_null)
Store the Native_handle (potentially .null(), meaning none) in this in-message.
Definition: msg.hpp:1127
void deserialize_body(Error_code *err_code)
To be invoked after deserialize_mdt() == N, and add_serialization_segment() was called N times (with ...
Definition: msg.hpp:1266
size_t deserialize_mdt(flow::log::Logger *logger_ptr, Error_code *err_code)
To be invoked after exactly one successful add_serialization_segment() call (and that Blob being fill...
Definition: msg.hpp:1161
typename Reader_config::Reader Reader
Same as Msg_out::Builder but the reader that can decode what that serializing Builder did.
Definition: msg.hpp:794
msg_id_t id_or_none() const
To be called only after deserialize_mdt(), returns the message ID of this in-message; 0 means it's an...
Definition: msg.hpp:1285
Msg_in(const Reader_config &struct_reader_config)
Constructs a not-ready-for-public-consumption in-message which awaits serialization-storing segments ...
Definition: msg.hpp:1117
std::optional< Reader > m_body_reader
Like m_mdt_reader but for the user message if any.
Definition: msg.hpp:822
bool m_body_deserialized_ok
Starts false; becomes true immutably once deserialize_body() succeeds (never if it's an internal mess...
Definition: msg.hpp:828
Struct_reader_config Reader_config
See struc::Channel::Reader_config.
Definition: msg.hpp:558
typename schema::detail::StructuredMessage::InternalMessageBody::Reader Internal_msg_body_reader
Reader counterpart to Msg_mdt_out::Internal_msg_body_builder.
Definition: msg.hpp:639
A structured out-message suitable to be sent via struc::Channel::send() (et al).
Definition: msg.hpp:154
typename Builder::Config Builder_config
Short-hand for user-specified Struct_builder::Config.
Definition: msg.hpp:174
Native_handle m_hndl_or_null
The Native_handle, if any, embedded inside this message.
Definition: msg.hpp:483
Msg_out(Msg_out &&src)
Move ctor: Make *this equal to src, while src becomes as-if default-cted (in that any operation excep...
Definition: msg.hpp:902
Msg_out & operator=(const Msg_out &)=delete
Disallow copying.
const Body_builder * body_root() const
Equivalent to the other body_root() overload but immutable version.
Definition: msg.hpp:1024
typename Body::Builder Body_builder
Short-hand for capnp-generated mutating Builder nested class of Body. See body_root().
Definition: msg.hpp:162
Msg_out & operator=(Msg_out &&src)
Move assignment: Destroy *this contents; make *this equal to src, while src becomes as-if default-cte...
Definition: msg.hpp:988
~Msg_out()
Returns resources, including potentially significant RAM resources and native_handle_or_null(),...
Definition: msg.hpp:979
void to_ostream(std::ostream *os) const
Prints string representation to the given ostream.
Definition: msg.hpp:1072
Body_builder m_body_root
See body_root().
Definition: msg.hpp:480
void emit_serialization(Segment_ptrs *target_blobs, const typename Builder::Session &session, Error_code *err_code) const
Returns the serialization in the form of a sequence of 1+ Blobs.
Definition: msg.hpp:1059
Msg_out()
Creates non-message; any operation except move-to or destruction results in undefined behavior subseq...
Definition: msg.hpp:867
Orphanage orphanage()
Convenience method that returns a capnp::Orphan factory in the same capnp::MessageBuilder as body_roo...
Definition: msg.hpp:1030
Msg_out(Builder &&struct_builder)
Advanced technique: Creates message by subsuming the provided already-prepared Capnp_msg_builder_inte...
Definition: msg.hpp:886
Body_builder * body_root()
The Body root capnp-generated mutator object.
Definition: msg.hpp:1018
Msg_out(const Builder_config &struct_builder_config)
Creates blank Body-bearing out-message message, with no native handle, all of which can be modified v...
Definition: msg.hpp:875
Msg_out(const Msg_out &)=delete
Disallow copying.
Builder m_builder
The guy serializing a Body. Underlying serialization potentially futher mutated by user via body_root...
Definition: msg.hpp:459
Message_body Body
See struc::Channel::Msg_body.
Definition: msg.hpp:159
Struct_builder_t Builder
Short-hand for user-specified Struct_builder type.
Definition: msg.hpp:168
::capnp::Orphanage Orphanage
Short-hand for capnp orphan factory. See orphanage().
Definition: msg.hpp:177
void store_native_handle_or_null(Native_handle &&native_handle_or_null)
Store the Native_handle (potentially .null(), meaning none) in this out-message; no-ops if the same ....
Definition: msg.hpp:1038
size_t n_serialization_segments() const
Returns what target_blobs.size() would return after calling emit_serialization(&target_blobs) (with a...
Definition: msg.hpp:1066
Native_handle native_handle_or_null() const
Returns whatever was the last word according to store_native_handle_or_null().
Definition: msg.hpp:1053
#define TEMPLATE_STRUCT_MSG_OUT
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:852
#define CLASS_STRUCT_MSG_IN
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:861
#define TEMPLATE_STRUCT_MSG_IN
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:858
#define CLASS_STRUCT_MSG_OUT
Internally used macro; public API users should disregard (same deal as in struc/channel....
Definition: msg.hpp:855
void release_native_peer_socket(Native_handle &&peer_socket_native_or_null)
Little utility that returns the raw Native_handle suitable for Peer_socket to the OS.
@ S_STRUCT_CHANNEL_INTERNAL_PROTOCOL_MISUSED_SCHEMA
Structured channel: received structured message with invalid internally-set/used fields.
Builder< ipc::shm::classic::Pool_arena > Builder
Convenience alias: transport::struc::shm::Builder that works with boost.ipc.shm pools from ipc::shm::...
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
boost::uuids::uuid Session_token
A type used by struc::Channel for internal safety/security/auth needs.
Definition: struc_fwd.hpp:113
std::vector< flow::util::Blob * > Segment_ptrs
Sequence of 1+ Blob pointers to blobs which must stay alive while these pointers may be dereferenced,...
Definition: struc_fwd.hpp:122
std::ostream & operator<<(std::ostream &os, const Heap_fixed_builder &val)
Prints string representation of the given Heap_fixed_builder to the given ostream.
uint64_t msg_id_t
Message ID uniquely identifying outgoing message (Msg_out, among all other Msg_outs),...
Definition: struc_fwd.hpp:145
util::Native_handle Native_handle
Convenience alias for the commonly used type util::Native_handle.
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:115
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:298
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.