Flow-IPC 1.0.0
Flow-IPC project: Full implementation reference.
struc_fwd.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 <flow/util/blob.hpp>
30#include <capnp/message.h>
31#include <boost/uuid/uuid.hpp>
32
33/**
34 * Sub-module of Flow-IPC module ipc::transport providing transmission of structured messages specifically.
35 * See ipc::transport doc header. As that notes, the big daddy here is struc::Channel.
36 *
37 * Be aware of sub-namespace ipc::transport::struc::shm which concerns itself with end-to-end-zero-copyable
38 * messages leveraging in-SHM storage. Normally there's no need for the user to know or worry about it,
39 * but for advanced applications, particularly extensions and customizations, one might delve into this area of
40 * the code. Otherwise it'll be used silently as important glue between various systems. Your journey would
41 * like start with the struc::Builder concept doc header which would then lead you to
42 * struc::shm::Builder impl. That might lead you to specific SHM-providers like ipc::shm::classic.
43 */
45{
46
47// Types.
48
49// Find doc headers near the bodies of these compound types.
50
51template<typename Message_body, typename Struct_builder_config>
52class Msg_out;
53template<typename Message_body, typename Struct_reader_config>
54class Msg_in;
55
56class Channel_base;
57template<typename Channel_obj, typename Message_body,
58 typename Struct_builder_config, typename Struct_reader_config>
59class Channel;
60
61class Heap_fixed_builder;
62class Heap_reader;
63
64struct Null_session;
65
66/// Alias for capnp's MessageBuilder interface. Rationale: as part of our API, we use our identifier style.
67using Capnp_msg_builder_interface = ::capnp::MessageBuilder;
68
69/**
70 * A type used by struc::Channel for internal safety/security/auth needs. See in particular
71 * struc::Channel constructors, both the regular-channel one and the session-master-channel one.
72 * That said: The user of ipc::transport (aided by ipc::session) structured layer shall generally be unconcerned
73 * with this, in practice, as ipc::session machinery will take care of:
74 * - setting up the session master struc::Channel which will generate this token during initial setup (log-in);
75 * and
76 * - setting up further `struc::Channel`s as requested by the user (the preceding bullet's token shall be
77 * passed to each new struc::Channel and expected internally in all messages).
78 *
79 * However, if one plans to *create* a struc::Channel directly (as ipc::session does), then one must have some
80 * limited understanding of this guy's existence (if not the internal details).
81 *
82 * @internal
83 * As you can see: internally it is a UUID (RFC 4122 Universally Unique IDentifier) which is 128 bits (16 bytes)
84 * in size. It's also a POD (Plain Old Data object), meaning it's ctor-free (direct-initialized) and can be
85 * `memcpy()`d around and such. See boost.uuid docs (which are simple).
86 *
87 * ### Use and rationale thereof ###
88 * A session master channel struc::Channel, operating in server mode during the log-in phase, will (as of
89 * this writing anyway) generate this using the boost.uuid random UUID generator. From that point on all
90 * channels spawned through that guy (by ipc::session) will be cted with that token value; and all messages both
91 * in those channels and the original master channel (after the log-in message exchange) will send this value
92 * and ensure any in-message has that value (or immediately hose the channel -- auth failure). This is a
93 * safety (not really security, due to the lack of token invalidation at least) measure. It will reduce chances
94 * that "wires get crossed," and a message goes into the wrong channel somehow.
95 *
96 * That's how it's used. Is the random-generator method of UUID generation acceptable for this use?
97 *
98 * A bit of research (starting in the RFC perhaps; or Wikipedia) shows that collisions are so cosmically rare as to
99 * make it, quite officially, a non-concern. Even if one does not accept that, however, suppose a collision does
100 * occur: two channels happen to generate the same UUID on the same machine around the same time. This (essentially
101 * impossible) scenario would not cause either channel to break; it would only allow (in theory) a token check
102 * to succeed where it shouldn't, if the fabled wires-crossed scenario occurred. This is an acceptable level of risk.
103 *
104 * Conversely, perhaps using UUIDs for this is overkill. 128 bits isn't heavy, but perhaps something smaller --
105 * maybe even much smaller, like 32 bits or even 16 -- would improve perf without really reducing effectiveness
106 * given the above rationale. Indeed that's worth considering but only in the phase where perf optimization is
107 * the explicit goal. Until then (if that even happens) the ability to use the nice boost.uuid library instead
108 * of rolling our own jankier/smaller UUID-like thing (or whatever) is well worth the alleged perf cost.
109 *
110 * @todo Look into whether something smaller that RFC 4122 UUIDs can and should be used for #Session_token.
111 * This would be for perf but may well be unnecessary. See discussion near this to-do.
112 */
113using Session_token = boost::uuids::uuid;
114
115/**
116 * Sequence of 1+ `Blob` *pointers* to blobs which must stay alive while these pointers may be dereferenced,
117 * intended here to refer to a capnp serialization of a capnp-`struct`. In each `Blob` [`begin()`, `end()`)
118 * is the serialization itself; and space before `begin()` and starting with `end()` may
119 * be reserved for framing prefix/postfix to preserve zero-copy when transmitting such serializations over
120 * an IPC "wire."
121 */
122using Segment_ptrs = std::vector<flow::util::Blob*>;
123
124/**
125 * Message ID uniquely identifying outgoing message (Msg_out, among all other `Msg_out`s), per channel; and
126 * similarly incoming message (Msg_in, among `Msg_in`s), per channel. 0 is a sentinel value and not a valid
127 * user message ID. A message ID pertains to a *sent* or *received* *instance* of a user-created Msg_out
128 * (and its in-message countrepart Msg_in). A given Msg_out can be sent 2+ times through a given
129 * struc::Channel and even a *different* struc::Channel; a different message ID will pertain to each
130 * of those times for a given struc::Channel. Therefore there is no #msg_id_t *inside* a user Msg_out.
131 *
132 * This type is in the public API, as the message ID is made available in certain contexts for:
133 * - referring to an earlier-sent message, such as in struc::Channel::undo_expect_responses(); and
134 * - logging/reporting.
135 *
136 * @internal
137 * It can also be used as a sequence number and is therefore assigned from sequence 1, 2, ... (0 is sentinel).
138 *
139 * ### Rationale for type used ###
140 * Needs to be big enough to where there's no chance it overflows in a given channel for a given direction.
141 * Assume 1 billion messages per second, or about 2^30 msg/s. That would take 2^(64-30), or 2^34, seconds,
142 * or over 500 years, to overflow. So this should be fine. Moreover overflow is fine in that case, in practice,
143 * if this is used only as a unique ID; it would however in theory present problems if used as a sequence number.
144 */
145using msg_id_t = uint64_t;
146
147// Constants.
148
149/// A value for which `.is_nil()` is true.
151
152/// The only necessary value of empty-type Null_session.
153extern const Null_session NULL_SESSION;
154
155// Free functions.
156
157/**
158 * Prints string representation of the given struc::Channel to the given `ostream`.
159 *
160 * @relatesalso struc::Channel
161 *
162 * @param os
163 * Stream to which to write.
164 * @param val
165 * Object to serialize.
166 * @return `os`.
167 */
168template<typename Channel_obj, typename Message_body,
169 typename Struct_builder_config, typename Struct_reader_config>
170std::ostream& operator<<(std::ostream& os,
171 const Channel<Channel_obj, Message_body,
172 Struct_builder_config, Struct_reader_config>& val);
173
174/**
175 * Prints string representation of the given `Msg_out` to the given `ostream`.
176 * Namely it prints via Msg_out::to_ostream()`; be sure to read perf notes on that!
177 *
178 * @relatesalso Msg_out
179 *
180 * @param os
181 * Stream to which to write.
182 * @param val
183 * Object to serialize.
184 * @return `os`.
185 */
186template<typename Message_body, typename Struct_builder_t>
187std::ostream& operator<<(std::ostream& os, const Msg_out<Message_body, Struct_builder_t>& val);
188
189/**
190 * Prints string representation of the given `Msg_in` to the given `ostream`.
191 *
192 * @relatesalso Msg_in
193 *
194 * @param os
195 * Stream to which to write.
196 * @param val
197 * Object to serialize.
198 * @return `os`.
199 */
200template<typename Message_body, typename Struct_reader_config>
201std::ostream& operator<<(std::ostream& os, const Msg_in<Message_body, Struct_reader_config>& val);
202
203/**
204 * Prints string representation of the given `Heap_fixed_builder` to the given `ostream`.
205 *
206 * @relatesalso Heap_fixed_builder
207 *
208 * @param os
209 * Stream to which to write.
210 * @param val
211 * Object to serialize.
212 * @return `os`.
213 */
214std::ostream& operator<<(std::ostream& os, const Heap_fixed_builder& val);
215
216/**
217 * Prints string representation of the given `Heap_reader` to the given `ostream`.
218 *
219 * @relatesalso Heap_reader
220 *
221 * @param os
222 * Stream to which to write.
223 * @param val
224 * Object to serialize.
225 * @return `os`.
226 */
227std::ostream& operator<<(std::ostream& os, const Heap_reader& val);
228
229} // namespace ipc::transport::struc
230
231/**
232 * `sync_io`-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport::struc.
233 * Namely transport::struc::sync_io::Channel <=> transport::struc::Channel.
234 *
235 * @see util::sync_io doc header -- describes the general `sync_io` pattern we are following.
236 */
238{
239
240// Types.
241
242template<typename Channel_obj, typename Message_body,
243 typename Struct_builder_config, typename Struct_reader_config>
244class Channel;
245
246// Free functions.
247
248/**
249 * Prints string representation of the given struc::sync_io::Channel to the given `ostream`.
250 *
251 * @relatesalso struc::sync_io::Channel
252 *
253 * @param os
254 * Stream to which to write.
255 * @param val
256 * Object to serialize.
257 * @return `os`.
258 */
259template<typename Channel_obj, typename Message_body,
260 typename Struct_builder_config, typename Struct_reader_config>
261std::ostream& operator<<(std::ostream& os,
262 const Channel<Channel_obj, Message_body,
263 Struct_builder_config, Struct_reader_config>& val);
264
265} // namespace ipc::transport::struc::sync_io
266
267/**
268 * Small group of miscellaneous utilities to ease work with capnp (Cap'n Proto), joining its `capnp` namespace.
269 * As of this writing circumstances have to very particular and rare indeed for something to actually be added
270 * by us to this namespace. As I write this, it contains only `oparator<<(std::ostream&, capnp::Text::Reader&)`.
271 */
272namespace capnp
273{
274
275/**
276 * Prints string representation of the given `capnp::Text::Reader` to the given `ostream`.
277 *
278 * ### Rationale for existence ###
279 * Well, capnp does not provide it, even though it provides a conversion operator to `string` and such; and
280 * it's nice to be able to print these (particularly when logging with `FLOW_LOG_*()`).
281 * For whatever reason the auto-conversion operator does not "kick in" when placed in a
282 * an `ostream<<` context; so such printing does not compile (nor does `lexical_cast<string>`).
283 *
284 * It won't be forced on anyone that doesn't include the present detail/ header.
285 *
286 * @param os
287 * Stream to which to write.
288 * @param val
289 * Object to serialize.
290 * @return `os`.
291 */
292std::ostream& operator<<(std::ostream& os, const Text::Reader& val);
293
294} // namespace capnp
Owning and wrapping a pre-connected transport::Channel peer (an endpoint of an established channel ov...
Definition: channel.hpp:589
std::ostream & operator<<(std::ostream &os, const Channel< Channel_obj, Message_body, Struct_builder_config, Struct_reader_config > &val)
Prints string representation of the given struc::Channel to the given ostream.
typename Sync_io_obj::Msg_in Msg_in
Encapsulation of any in-message instance received by a *this of this type.
Definition: channel.hpp:639
typename Sync_io_obj::Msg_out Msg_out
Encapsulation of any out-message payload sent or meant to be sent via send() (et al) by a *this of th...
Definition: channel.hpp:630
Implements Struct_builder concept by straightforwardly allocating fixed-size segments on-demand in th...
Implements Struct_reader concept by straightforwardly interpreting a serialization by Heap_fixed_buil...
sync_io-pattern counterpart to async-I/O-pattern transport::struc::Channel.
Definition: channel.hpp:326
Small group of miscellaneous utilities to ease work with capnp (Cap'n Proto), joining its capnp names...
std::ostream & operator<<(std::ostream &os, const Text::Reader &val)
Prints string representation of the given capnp::Text::Reader to the given ostream.
struc::Channel< Channel_obj, Message_body, Builder::Config, Reader::Config > Channel
Convenience alias: Use this when constructing a struc::Channel with tag Channel_base::S_SERIALIZE_VIA...
Definition: classic.hpp:42
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
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport::st...
Definition: struc_fwd.hpp:238
std::ostream & operator<<(std::ostream &os, const Channel< Channel_obj, Message_body, Struct_builder_config, Struct_reader_config > &val)
Prints string representation of the given struc::sync_io::Channel to the given ostream.
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
const Null_session NULL_SESSION
The only necessary value of empty-type Null_session.
const Session_token NULL_SESSION_TOKEN
A value for which .is_nil() is true.
Definition: channel.cpp:35
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
Value for Struct_builder::Session when no extra information is needed when serializing Struct_builder...