Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
blob_transport.hpp
Go to the documentation of this file.
1/* Flow-IPC: Core
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19
20// Not compiled: for documentation only. Contains concept docs as of this writing.
21#ifndef IPC_DOXYGEN_ONLY
22static_assert(false, "As of this writing this is a documentation-only \"header\" "
23 "(the \"source\" is for humans and Doxygen only).");
24#else // ifdef IPC_DOXYGEN_ONLY
25
26namespace ipc::transport
27{
28
29// Types.
30
31/**
32 * A documentation-only *concept* defining the behavior of an object capable of reliably/in-order *sending* of
33 * discrete messages, each containing a binary blob. This is paired with
34 * the Blob_receiver concept which defines reception of such messages.
35 *
36 * The concept is exactly identical to Native_handle_sender except that in the latter each message consists
37 * of 0-1 native handles and 0-1 binary blobs; whereas here it is always exactly 1 of the latter. More precisely,
38 * each message contains 1 binary blob, whose length must be at least 1 byte. You may interpret notes in common-sense
39 * fashion; for example send_blob_max_size() here corresponds to `send_meta_blob_max_size()` there.
40 *
41 * Therefore we keep the documentation very light, only pointing out the differences against Native_handle_sender --
42 * which are summarized in the preceding paragraph. All other notes from Native_handle_sender apply here.
43 *
44 * @see Native_handle_sender, an identical concept with 1 feature (native handle transmission) added.
45 */
47{
48public:
49 // Constants.
50
51 /// Shared_name relative-folder fragment (no separators) identifying this resource type. Equals `_receiver`'s.
53
54 // Types.
55
56 /**
57 * Return type, typically a `struct`, for blob_send_stats().
58 *
59 * In addition: the impl must choose one of the following paths. Note that stat::Blob_snd_stats defines statistics
60 * relevant to any concept impl of Blob_sender.
61 * -# This type *is* stat::Blob_snd_stats. Therefore, given a value `S` of this type, you can count on this:
62 * `using ipc::transport::stat::blob_snd_stats; assert(&(blob_snd_stats(S)) == &S)`.
63 * - That is: your impl adds no stats beyond the concept-level ones.
64 * -# This type *is not* stat::Blob_snd_stats but contains one via some type of composition. Therefore your
65 * Blob_sender impl must be accompanied (in the same namespace, for ADL) with a
66 * free function such that this works:
67 * `using ipc::transport::stat::blob_snd_stats; const stat::Blob_snd_stats& core_stats = blob_snd_stats(S)`.
68 * - That is: your impl adds some stats on top of the concept-level ones.
69 */
70 using Blob_snd_stats = value;
71
72 // Constructors/destructor.
73
74 /**
75 * Default ctor: Creates a peer object in NULL (neither connected nor connecting) state.
76 *
77 * All notes from Native_handle_sender() default ctor doc header apply.
78 */
80
81 /**
82 * `sync_io`-core-adopting ctor: Creates a peer object in PEER state by subsuming a `sync_io` core in that state.
83 *
84 * @param sync_io_core_in_peer_state_moved
85 * See Native_handle_sender concept.
86 */
87 Blob_sender(sync_io::Blob_sender&& sync_io_core_in_peer_state_moved);
88
89 /**
90 * Move-constructs from `src`; `src` becomes as-if default-cted (therefore in NULL state).
91 *
92 * @param src
93 * Source object. For reasonable uses of `src` after this ctor returns: see default ctor doc header.
94 */
96
97 /// Disallow copying.
98 Blob_sender(const Blob_sender&) = delete;
99
100 /**
101 * Destroys this peer endpoint which will end the conceptual outgoing-direction pipe (in PEER state, and if it
102 * is still active) and cancels any pending completion handlers by invoking them ASAP with
103 * error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER.
104 *
105 * All notes from ~Native_handle_sender() doc header apply.
106 */
108
109 // Methods.
110
111 /**
112 * Move-assigns from `src`; `*this` acts as if destructed; `src` becomes as-if default-cted (therefore in NULL state).
113 * No-op if `&src == this`.
114 *
115 * @see ~Blob_sender().
116 *
117 * @param src
118 * Source object. For reasonable uses of `src` after this ctor returns: see default ctor doc header.
119 * @return `*this`.
120 */
122
123 /// Disallow copying.
125
126 /**
127 * In PEER state: Returns max `blob.size()` such that send_blob() shall not fail due to too-long
128 * payload with error::Code::S_INVALID_ARGUMENT. Always the same value once in PEER state. The opposing
129 * Blob_receiver::receive_blob_max_size() shall return the same value (in the opposing object potentially
130 * in a different process).
131 *
132 * If `*this` is not in PEER state (in particular if it is default-cted or moved-from), returns zero; else
133 * a positive value.
134 *
135 * @return See above.
136 */
137 size_t send_blob_max_size() const;
138
139 /**
140 * In PEER state: Synchronously, non-blockingly sends one discrete message, reliably and in-order, to the opposing
141 * peer; the message consists of the provided binary blob (of length at least 1 byte). Providing a null blob
142 * results in undefined behavior (assertion may trip).
143 *
144 * All notes from Native_handle_sender::send_native_handle() doc header apply.
145 *
146 * @param blob
147 * A binary blob to send; behavior undefined unless `blob.size() >= 1`.
148 * @param err_code
149 * See above.
150 * @return See above.
151 */
152 bool send_blob(const util::Blob_const& blob, Error_code* err_code = nullptr);
153
154 /**
155 * Equivalent to send_blob() but sends a graceful-close message instead of the usual payload; the opposing
156 * peer's Blob_receiver shall receive it reliably and in-order via Blob_receiver::async_receive_blob() in the form of
157 * #Error_code = error::Code::S_RECEIVES_FINISHED_CANNOT_RECEIVE.
158 *
159 * All notes from Native_handle_sender::async_end_sending() doc header apply.
160 *
161 * @tparam Task_err
162 * See above.
163 * @param on_done_func
164 * See above.
165 * @return See above.
166 */
167 template<typename Task_err>
168 bool async_end_sending(Task_err&& on_done_func);
169
170 /**
171 * Equivalent to `async_end_sending(F)` wherein `F()` does nothing.
172 *
173 * All notes from Native_handle_sender::end_sending() doc header apply.
174 *
175 * @return See above.
176 */
178
179 /**
180 * In PEER state: Irreversibly enables periodic auto-pinging of opposing receiver with low-level messages that
181 * are ignored except that they reset any idle timer as enabled via Blob_receiver::idle_timer_run()
182 * (or similar).
183 *
184 * All notes from Native_handle_sender::auto_ping() doc header apply.
185 *
186 * @param period
187 * See above.
188 * @return See above.
189 */
190 bool auto_ping(util::Fine_duration period = default_value);
191
192 /**
193 * Returns the accumulated transport statistics as of this call.
194 * If not in PEER state returns a zeroed-out stats object.
195 *
196 * @see #Blob_snd_stats doc header about how to obtain a transport::stat::Blob_snd_stats core
197 * from the returned `struct`.
198 *
199 * Thread-safe: can be called concurrently with any other method including `send_*()`.
200 * The returned copy is a consistent snapshot.
201 *
202 * @return Stats snapshot by value.
203 */
205
206 /**
207 * Resets the transport statistics as of this call. The formal meaning of a reset is discussed in
208 * `flow::util::stat` doc header. If not in PEER state this is a no-op.
209 *
210 * Thread-safe: can be called concurrently with any other method including `send_*()`.
211 */
213}; // class Blob_sender
214
215/**
216 * A documentation-only *concept* defining the behavior of an object capable of reliably/in-order *receiving* of
217 * discrete messages, each containing a binary blob. This is paired with
218 * the Blob_sender concept which defines sending of such messages.
219 *
220 * The concept is exactly identical to Native_handle_receiver except that in the latter each message consists
221 * of 0-1 native handles and 0-1 binary blobs; whereas here it is always exactly 1 of the latter. More precisely,
222 * each message contains 1 binary blob, whose length must be at least 1 byte. You may interpret notes in common-sense
223 * fashion; for example receive_blob_max_size() here corresponds to `receive_meta_blob_max_size()` there.
224 *
225 * Therefore we keep the documentation very light, only pointing out the differences against Native_handle_receiver --
226 * which are summarized in the preceding paragraph. All other notes from Native_handle_receiver apply here.
227 *
228 * @see Native_handle_receiver, an identical concept with 1 feature (native handle transmission) added.
229 */
231{
232public:
233 // Constants.
234
235 /// Shared_name relative-folder fragment (no separators) identifying this resource type. Equals `_sender`'s.
237
238 /**
239 * If `false` then `blob.size() < receive_blob_max_size()` in PEER-state async_receive_blob()
240 * or `batch->target_payload_size() < receive_blob_max_size()` in PEER-state async_receive_blob_batch()
241 * shall yield non-pipe-hosing error::Code::INVALID_ARGUMENT, and it shall never yield
242 * pipe-hosing error::Code::S_MESSAGE_SIZE_EXCEEDS_USER_STORAGE; else the latter may occur, while the former
243 * shall never occur for that reason.
244 *
245 * @see "Blob underflow semantics" in Native_handle_receiver concept doc header; they apply equally here.
246 */
247 static constexpr bool S_BLOB_UNDERFLOW_ALLOWED = value;
248
249 /// All notes from Native_handle_receiver::S_RCV_NATIVE_HANDLE_BATCH_SZ_RECOMMENDATION doc header apply.
250 static constexpr size_t S_RCV_BLOB_BATCH_SZ_RECOMMENDATION = value;
251
252 // Types.
253
254 /// See `async_receive_*_batch()` argument `batch`.
255 template<typename Msg_resource>
257
258 /**
259 * Return type, typically a `struct`, for blob_receive_stats().
260 *
261 * In addition: the impl must choose one of the following paths. Note that stat::Blob_rcv_stats defines statistics
262 * relevant to any concept impl of Blob_receiver.
263 * -# This type *is* stat::Blob_rcv_stats. Therefore, given a value `S` of this type, you can count on this:
264 * `using ipc::transport::stat::blob_rcv_stats; assert(&(blob_rcv_stats(S)) == &S)`.
265 * - That is: your impl adds no stats beyond the concept-level ones.
266 * -# This type *is not* stat::Blob_rcv_stats but contains one via some type of composition. Therefore your
267 * Blob_receiver impl must be accompanied (in the same namespace, for ADL) with a
268 * free function such that this works:
269 * `using ipc::transport::stat::blob_rcv_stats; const stat::Blob_rcv_stats& core_stats = blob_rcv_stats(S)`.
270 * - That is: your impl adds some stats on top of the concept-level ones.
271 */
272 using Blob_rcv_stats = value;
273
274 // Constructors/destructor.
275
276 /**
277 * Default ctor: Creates a peer object in NULL (neither connected nor connecting) state.
278 *
279 * All notes from Native_handle_receiver() default ctor doc header apply.
280 */
282
283 /**
284 * `sync_io`-core-adopting ctor: Creates a peer object in PEER state by subsuming a `sync_io` core in that state.
285 *
286 * @param sync_io_core_in_peer_state_moved
287 * See Native_handle_sender concept.
288 */
289 Blob_receiver(sync_io::Blob_receiver&& sync_io_core_in_peer_state_moved);
290
291 /**
292 * Move-constructs from `src`; `src` becomes as-if default-cted (therefore in NULL state).
293 *
294 * @param src
295 * Source object. For reasonable uses of `src` after this ctor returns: see default ctor doc header.
296 */
298
299 /// Disallow copying.
300 Blob_receiver(const Blob_receiver&) = delete;
301
302 /**
303 * Destroys this peer endpoint which will end the conceptual incoming-direction pipe (in PEER state, and if it
304 * is still active) and cancels any pending completion handlers by invoking them ASAP with
305 * error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER.
306 *
307 * All notes from ~Native_handle_receiver() doc header apply.
308 */
310
311 // Methods.
312
313 /**
314 * Move-assigns from `src`; `*this` acts as if destructed; `src` becomes as-if default-cted (therefore in NULL state).
315 * No-op if `&src == this`.
316 *
317 * @see ~Blob_receiver().
318 *
319 * @param src
320 * Source object. For reasonable uses of `src` after this ctor returns: see default ctor doc header.
321 * @return `*this`.
322 */
324
325 /// Disallow copying.
327
328 /**
329 * In PEER state: Returns min target-blob size such that (1) async_receive_blob() shall not fail
330 * with error::Code::S_INVALID_ARGUMENT (only if #S_BLOB_UNDERFLOW_ALLOWED is `false`; otherwise not relevant),
331 * and (2) async_receive_blob_batch() shall not similarly fail,
332 * and (3) neither shall *ever* fail with error::Code::S_MESSAGE_SIZE_EXCEEDS_USER_STORAGE. Please see
333 * "Blob underflow semantics" (for Native_handle_receiver, but applied in common-sense fashion to us) for
334 * explanation of these semantics.
335 *
336 * Always the same value once in PEER state. The opposing
337 * Blob_sender::send_blob_max_size() shall return the same value (in the opposing object potentially
338 * in a different process).
339 *
340 * If `*this` is not in PEER state (in particular if it is default-cted or moved-from), returns zero; else
341 * a positive value.
342 *
343 * @return See above.
344 */
345 size_t receive_blob_max_size() const;
346
347 /**
348 * In PEER state: Asynchronously awaits one discrete message -- as sent by the opposing peer via
349 * Blob_sender::send_blob() or `"Blob_sender::*end_sending()"` -- and
350 * receives it into the given target locations, reliably and in-order.
351 *
352 * All notes from Native_handle_receiver::async_receive_native_handle() doc header apply. In particular
353 * watch out for the semantics regarding `target_blob.size()` and potential resulting errors.
354 *
355 * Additionally, a corollary to counterpart concept Blob_sender requirements: this method shall never yield
356 * `size_t n_rcvd = 0` to `on_done_func()`, as it is not allowed to send an empty message (blob).
357 * (Native_handle_sender is allowed to do so, but only if such an empty meta-blob is paired with
358 * a non-null `Native_handle`.)
359 *
360 * ### Informal suggestion w/r/t a `Native_handle_sender` that is also a `Blob_sender` ###
361 * Suppose you have class `X` (e.g., Native_socket_stream is such a class) that implements *both*
362 * concepts. Suppose an `X` is on the opposing side of a `*this`. Then we informally recommend that
363 * this async_receive_blob() detect the situation wherein the opposing `X`:
364 * - used `send_native_handle(hndl, blob, ...)` or equivalent; and
365 * - that method or equivalent sent no `hndl` (e.g., the above method was passed `hndl` that contained
366 * no handle: `hndl.null() == true`).
367 *
368 * It should emit an error in that case. Flow-IPC itself uses error::Code::S_BLOB_RECEIVER_GOT_NON_BLOB.
369 *
370 * This is technically not a formal requirement. It's just nice, as it detects a user misbehavior as opposed
371 * to an internal impl bug.
372 *
373 * @tparam Task_err_sz
374 * See above.
375 * @param target_blob
376 * `target_blob.data()...` shall be written to by the time `on_done_func()` is executed with a falsy
377 * code, bytes numbering `N`, where `N` is passed to that callback. `N` shall not exceed
378 * `target_blob.size()`. See above.
379 * @param on_done_func
380 * See above.
381 * @return See above.
382 */
383 template<typename Task_err_sz>
384 bool async_receive_blob(const util::Blob_mutable& target_blob, Task_err_sz&& on_done_func);
385
386 /**
387 * In PEER state: Asynchronously awaits 1+ discrete message(s) -- as sent by the opposing peer via
388 * Blob_sender::send_blob() or `"Blob_sender::*end_sending()"` -- and
389 * receives them into the target locations as described by `*batch` slots, reliably and in-order.
390 *
391 * All notes from Native_handle_receiver::async_receive_native_handle_batch() doc header apply.
392 *
393 * Additionally, a corollary to counterpart concept Blob_sender requirements: this method shall never yield
394 * a slot (index `idx`) such that `batch->result_payload_blob(idx) == 0`; meaning an empty blob was received.
395 * That is because it is not allowed to send an empty message (blob).
396 * (Native_handle_sender is allowed to do so, but only if such an empty meta-blob is paired with
397 * a non-null `Native_handle`.)
398 *
399 * @tparam Msg_resource
400 * See above.
401 * @tparam Task_err
402 * See above.
403 * @param batch
404 * See above. However note that Blob_batch_in<Msg_resource>::result_payload_hndl() (the would-be method
405 * itself) shall not exist, as `Blob_batch_in<M>` is `Msg_batch_in<M, true>`; note the `NO_HNDLS = true`.
406 * @param assume_would_block
407 * See above.
408 * @param on_done_func
409 * See above.
410 * @return Same notes as for async_receive_blob().
411 */
412 template<typename Msg_resource, typename Task_err>
413 bool async_receive_blob_batch(Blob_batch_in<Msg_resource>* batch, bool assume_would_block, Task_err&& on_done_func);
414
415 /**
416 * In PEER state: Irreversibly enables a conceptual idle timer whose potential side effect is, once at least
417 * the specified time has passed since the last received low-level traffic (or this call, whichever most
418 * recently occurred), to emit the pipe-hosing error error::Code::S_RECEIVER_IDLE_TIMEOUT.
419 *
420 * All notes from Native_handle_receiver::idle_timer_run() doc header apply.
421 *
422 * @param timeout
423 * See above.
424 * @return See above.
425 */
426 bool idle_timer_run(util::Fine_duration timeout = default_value);
427
428 /**
429 * Returns the accumulated transport statistics as of this call.
430 * If not in PEER state returns a zeroed-out stats object.
431 *
432 * @see #Blob_rcv_stats doc header about how to obtain a transport::stat::Blob_rcv_stats core
433 * from the returned `struct`.
434 *
435 * Thread-safe: can be called concurrently with any other method including `async_receive_*()`.
436 * The returned copy is a consistent snapshot.
437 *
438 * @return Stats snapshot by value.
439 */
441
442 /**
443 * Resets the transport statistics as of this call. The formal meaning of a reset is discussed in
444 * `flow::util::stat` doc header. If not in PEER state this is a no-op.
445 *
446 * Thread-safe: can be called concurrently with any other method including `async_receive_*()`.
447 */
449}; // class Blob_receiver
450
451} // namespace ipc::transport
452
453#endif // ifdef IPC_DOXYGEN_ONLY
A documentation-only concept defining the behavior of an object capable of reliably/in-order receivin...
Blob_receiver()
Default ctor: Creates a peer object in NULL (neither connected nor connecting) state.
Blob_receiver(const Blob_receiver &)=delete
Disallow copying.
Blob_rcv_stats blob_receive_stats() const
Returns the accumulated transport statistics as of this call.
size_t receive_blob_max_size() const
In PEER state: Returns min target-blob size such that (1) async_receive_blob() shall not fail with er...
bool idle_timer_run(util::Fine_duration timeout=default_value)
In PEER state: Irreversibly enables a conceptual idle timer whose potential side effect is,...
Blob_receiver & operator=(const Blob_receiver &)=delete
Disallow copying.
void blob_receive_stats_reset()
Resets the transport statistics as of this call.
Blob_receiver & operator=(Blob_receiver &&src)
Move-assigns from src; *this acts as if destructed; src becomes as-if default-cted (therefore in NULL...
Blob_receiver(sync_io::Blob_receiver &&sync_io_core_in_peer_state_moved)
sync_io-core-adopting ctor: Creates a peer object in PEER state by subsuming a sync_io core in that s...
static const Shared_name S_RESOURCE_TYPE_ID
Shared_name relative-folder fragment (no separators) identifying this resource type....
value Blob_rcv_stats
Return type, typically a struct, for blob_receive_stats().
bool async_receive_blob_batch(Blob_batch_in< Msg_resource > *batch, bool assume_would_block, Task_err &&on_done_func)
In PEER state: Asynchronously awaits 1+ discrete message(s) – as sent by the opposing peer via Blob_s...
bool async_receive_blob(const util::Blob_mutable &target_blob, Task_err_sz &&on_done_func)
In PEER state: Asynchronously awaits one discrete message – as sent by the opposing peer via Blob_sen...
static constexpr size_t S_RCV_BLOB_BATCH_SZ_RECOMMENDATION
All notes from Native_handle_receiver::S_RCV_NATIVE_HANDLE_BATCH_SZ_RECOMMENDATION doc header apply.
Blob_receiver(Blob_receiver &&src)
Move-constructs from src; src becomes as-if default-cted (therefore in NULL state).
static constexpr bool S_BLOB_UNDERFLOW_ALLOWED
If false then blob.size() < receive_blob_max_size() in PEER-state async_receive_blob() or batch->targ...
~Blob_receiver()
Destroys this peer endpoint which will end the conceptual incoming-direction pipe (in PEER state,...
A documentation-only concept defining the behavior of an object capable of reliably/in-order sending ...
Blob_sender()
Default ctor: Creates a peer object in NULL (neither connected nor connecting) state.
bool send_blob(const util::Blob_const &blob, Error_code *err_code=nullptr)
In PEER state: Synchronously, non-blockingly sends one discrete message, reliably and in-order,...
void blob_send_stats_reset()
Resets the transport statistics as of this call.
value Blob_snd_stats
Return type, typically a struct, for blob_send_stats().
bool end_sending()
Equivalent to async_end_sending(F) wherein F() does nothing.
Blob_sender(sync_io::Blob_sender &&sync_io_core_in_peer_state_moved)
sync_io-core-adopting ctor: Creates a peer object in PEER state by subsuming a sync_io core in that s...
bool async_end_sending(Task_err &&on_done_func)
Equivalent to send_blob() but sends a graceful-close message instead of the usual payload; the opposi...
Blob_sender(Blob_sender &&src)
Move-constructs from src; src becomes as-if default-cted (therefore in NULL state).
Blob_sender & operator=(const Blob_sender &)=delete
Disallow copying.
bool auto_ping(util::Fine_duration period=default_value)
In PEER state: Irreversibly enables periodic auto-pinging of opposing receiver with low-level message...
~Blob_sender()
Destroys this peer endpoint which will end the conceptual outgoing-direction pipe (in PEER state,...
Blob_sender & operator=(Blob_sender &&src)
Move-assigns from src; *this acts as if destructed; src becomes as-if default-cted (therefore in NULL...
static const Shared_name S_RESOURCE_TYPE_ID
Shared_name relative-folder fragment (no separators) identifying this resource type....
Blob_snd_stats blob_send_stats() const
Returns the accumulated transport statistics as of this call.
size_t send_blob_max_size() const
In PEER state: Returns max blob.size() such that send_blob() shall not fail due to too-long payload w...
Blob_sender(const Blob_sender &)=delete
Disallow copying.
A documentation-only concept defining the behavior of an object that is a key aspect of batch-receivi...
A documentation-only concept: what transport::Blob_receiver is to transport::Native_handle_receiver (...
A documentation-only concept: what transport::Blob_sender is to transport::Native_handle_sender (name...
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
Definition: util_fwd.hpp:137
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
Definition: util_fwd.hpp:114
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
Definition: util_fwd.hpp:131
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313