Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
transport_fwd.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#pragma once
20
23#include <flow/util/stat/stat_fwd.hpp>
24#include <ostream>
25
26/**
27 * Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more)
28 * between pairs of processes. See namespace ::ipc doc header for an overview of Flow-IPC modules including
29 * how ipc::transport relates to the others. Then return here. A synopsis follows:
30 *
31 * @see The guided Manual chapters @ref chan_open (obtaining channels), @ref chan_struct and @ref chan_struct_advanced
32 * (structured transport), and @ref transport_core (unstructured transport) cover these topics.
33 *
34 * The main transport features of ipc::transport are: class template struc::Channel (for structured message and
35 * native handle transport) and various lower-level utilities (Channel; blob/handle streams; message queue
36 * (MQ) streams). Structured transmission facilities (struc::Channel being the main guy) are segregated in
37 * sub-namespace transport::struc.
38 *
39 * Generally speaking, to communicate (via struc::Channel and others), the two processes A and B that intend to
40 * talk must have established a broad conversation called a *session* within which all communication occurs.
41 * In fact, a transport::struc::Channel wraps a transport::Channel, and the latter can be established, in factory-ish
42 * fashion and otherwise, from an ipc::session::Session. Hence, see namespace ipc::session doc header to learn about
43 * establishing/terminating sessions. Once you have a session::Session, you can actually use main ipc::transport
44 * facilities.
45 *
46 * That said: ipc::transport does *not* require ipc::session to be used: One can instantiate all the various IPC
47 * mechanisms therein directly. ipc::session provides the lifecycle and organization to make this as simple as
48 * possible (but no simpler). In that sense ipc::transport has the essential building blocks; ipc::session provides
49 * access to those building blocks in one possible fashion -- for example by establishing a naming convention
50 * for the various required `Shared_name`s taken by the various ipc::transport constructors. Formally speaking
51 * there can certainly be other fashions of organizing ipc::transport resources. Therefore the API design of
52 * ipc::transport is not rigid.
53 */
54namespace ipc::transport
55{
56
57// Types.
58
59// Find doc headers near the bodies of these compound types.
60
61class Native_socket_stream_cfg;
62class Native_socket_stream;
63class Native_socket_stream_acceptor;
64template<typename Msg_resource_t>
65class Native_socket_stream_msg_batch_in;
66class Posix_mq_handle;
67class Bipc_mq_handle;
68template<typename Persistent_mq_handle>
69class Blob_stream_mq_sender;
70template<typename Persistent_mq_handle>
71class Blob_stream_mq_receiver;
72class Null_peer;
73template<typename Blob_sender_t, typename Blob_receiver_t,
74 typename Native_handle_sender_t, typename Native_handle_receiver_t>
75class Channel;
76template<bool SIO>
77class Socket_stream_channel;
78template<bool SIO>
79class Socket_stream_channel_of_blobs;
80template<bool SIO,
81 typename Persistent_mq_handle,
82 typename Native_handle_sender_t = Null_peer, typename Native_handle_receiver_t = Null_peer>
83class Mqs_channel;
84template<bool SIO,
85 typename Persistent_mq_handle>
86class Mqs_socket_stream_channel;
87class Protocol_negotiator;
88template<typename Msg_resource_t, bool NO_HNDLS = true>
89class Generic_msg_batch_in;
90
91/// Convenience alias for the commonly used type util::Native_handle.
93
94/// Convenience alias for the commonly used type util::Shared_name.
96
97/**
98 * Convenience alias: Blob_sender via unidirectional POSIX MQ (message queue).
99 *
100 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
101 */
103
104/**
105 * Convenience alias: Blob_receiver via unidirectional POSIX MQ (message queue).
106 *
107 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
108 */
110
111/**
112 * Convenience alias: Blob_sender via unidirectional bipc MQ (message queue).
113 *
114 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
115 */
117
118/**
119 * Convenience alias: Blob_receiver via unidirectional bipc MQ (message queue).
120 *
121 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
122 */
124
125/**
126 * Convenience alias: Channel peer (Blob_sender, Blob_receiver) at one end of full-duplex (bidirectional) pipe
127 * composed of 2 opposite-facing unidirectional POSIX MQs (message queues).
128 *
129 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
130 */
132
133/**
134 * Convenience alias: Channel peer (Blob_sender, Blob_receiver) at one end of full-duplex (bidirectional) pipe
135 * composed of 2 opposite-facing unidirectional POSIX MQs (message queues).
136 *
137 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
138 */
140
141/**
142 * Convenience alias: Channel peer (Blob_sender, Blob_receiver, Native_handle_sender, Native_handle_receiver)
143 * at one end of a full-duplex (bidirectional) pipe composed of 2 opposite-facing unidirectional POSIX MQs
144 * (message queues), transmitting blobs only; and a full-duplex pipe over a Unix domain stream connection,
145 * transmitting native-handle-and/or-meta-blob messages.
146 *
147 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
148 */
150
151/**
152 * Convenience alias: Channel peer (Blob_sender, Blob_receiver, Native_handle_sender, Native_handle_receiver)
153 * at one end of a full-duplex (bidirectional) pipe composed of 2 opposite-facing unidirectional bipc MQs
154 * (message queues), transmitting blobs only; and a full-duplex pipe over a Unix domain stream connection,
155 * transmitting native-handle-and/or-meta-blob messages.
156 *
157 * Tip: In `sync_io` sub-namespace there is the `sync_io`-pattern counterpart.
158 */
160
161// Free functions.
162
163/**
164 * Prints string representation of the given `Native_socket_stream` to the given `ostream`.
165 *
166 * @relatesalso Native_socket_stream
167 *
168 * @param os
169 * Stream to which to write.
170 * @param val
171 * Object to serialize.
172 * @return `os`.
173 */
174std::ostream& operator<<(std::ostream& os, const Native_socket_stream& val);
175
176/**
177 * Prints string representation of the given `Native_socket_stream_msg_batch_in` to the given `ostream`.
178 *
179 * @relatesalso Native_socket_stream_msg_batch_in
180 *
181 * @param os
182 * Stream to which to write.
183 * @param val
184 * Object to serialize.
185 * @return `os`.
186 */
187template<typename Msg_resource_t>
188std::ostream& operator<<(std::ostream& os, const Native_socket_stream_msg_batch_in<Msg_resource_t>& val);
189
190/**
191 * Prints string representation of the given `Native_socket_stream_acceptor` to the given `ostream`.
192 *
193 * @relatesalso Native_socket_stream_acceptor
194 *
195 * @param os
196 * Stream to which to write.
197 * @param val
198 * Object to serialize.
199 * @return `os`.
200 */
201std::ostream& operator<<(std::ostream& os, const Native_socket_stream_acceptor& val);
202
203/**
204 * Prints string representation of the given `Blob_stream_mq_receiver` to the given `ostream`.
205 *
206 * If object is default-cted (or moved-from), this will output something graceful indicating this.
207 *
208 * @relatesalso Blob_stream_mq_receiver
209 *
210 * @param os
211 * Stream to which to write.
212 * @param val
213 * Object to serialize.
214 * @return `os`.
215 */
216template<typename Persistent_mq_handle>
217std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_receiver<Persistent_mq_handle>& val);
218
219/**
220 * Prints string representation of the given `Blob_stream_mq_sender` to the given `ostream`.
221 *
222 * If object is default-cted (or moved-from), this will output something graceful indicating this.
223 *
224 * @relatesalso Blob_stream_mq_sender
225 *
226 * @param os
227 * Stream to which to write.
228 * @param val
229 * Object to serialize.
230 * @return `os`.
231 */
232template<typename Persistent_mq_handle>
233std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_sender<Persistent_mq_handle>& val);
234
235/**
236 * Prints string representation of the given Bipc_mq_handle to the given `ostream`.
237 *
238 * @relatesalso Bipc_mq_handle
239 *
240 * @param os
241 * Stream to which to write.
242 * @param val
243 * Object to serialize.
244 * @return `os`.
245 */
246std::ostream& operator<<(std::ostream& os, const Bipc_mq_handle& val);
247
248/**
249 * Prints string representation of the given Posix_mq_handle to the given `ostream`.
250 *
251 * @relatesalso Posix_mq_handle
252 *
253 * @param os
254 * Stream to which to write.
255 * @param val
256 * Object to serialize.
257 * @return `os`.
258 */
259std::ostream& operator<<(std::ostream& os, const Posix_mq_handle& val);
260
261/**
262 * Prints string representation of the given `Channel` to the given `ostream`.
263 *
264 * @relatesalso Channel
265 *
266 * @param os
267 * Stream to which to write.
268 * @param val
269 * Object to serialize.
270 * @return `os`.
271 */
272template<typename Blob_sender_t, typename Blob_receiver_t,
273 typename Native_handle_sender_t, typename Native_handle_receiver_t>
274std::ostream& operator<<(std::ostream& os,
275 const Channel<Blob_sender_t, Blob_receiver_t,
276 Native_handle_sender_t, Native_handle_receiver_t>& val);
277
278/**
279 * Dummy that is never invoked. It must still exist in order for Channel to build successfully with at least 1
280 * Null_peer template arg.
281 *
282 * Assertion may trip if this is invoked. Formally behavior is undefined.
283 *
284 * @relatesalso Null_peer
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 Null_peer& val);
293
294/**
295 * Prints string representation of the given `Generic_msg_batch_in` to the given `ostream`.
296 *
297 * @relatesalso Generic_msg_batch_in
298 *
299 * @param os
300 * Stream to which to write.
301 * @param val
302 * Object to serialize.
303 * @return `os`.
304 */
305template<typename Msg_resource_t, bool NO_HNDLS>
306std::ostream& operator<<(std::ostream& os, const Generic_msg_batch_in<Msg_resource_t, NO_HNDLS>& val);
307
308/**
309 * Implements Persistent_mq_handle related concept: Swaps two objects.
310 *
311 * @relatesalso Bipc_mq_handle
312 *
313 * @param val1
314 * Object.
315 * @param val2
316 * Object.
317 */
318void swap(Bipc_mq_handle& val1, Bipc_mq_handle& val2);
319
320/**
321 * Implements Persistent_mq_handle related concept: Swaps two objects.
322 *
323 * @relatesalso Posix_mq_handle
324 *
325 * @param val1
326 * Object.
327 * @param val2
328 * Object.
329 */
330void swap(Posix_mq_handle& val1, Posix_mq_handle& val2);
331
332} // namespace ipc::transport
333
334/// Stats-related sub-namespace, for ADL segregation and general organization.
335namespace ipc::transport::stat
336{
337
338// Types.
339
340// Find doc headers near the bodies of these compound types.
341
342struct Blob_snd_stats;
343struct Blob_rcv_stats;
344
345// Free functions.
346
347/**
348 * Declares the stats for Blob_snd_stats. Not invoked directly except by `flow::util::stat` internals,
349 * or when composing this stat-set into another.
350 * @see `flow::util::stat` namespace doc header for background on the declare/visit mechanism.
351 *
352 * @tparam Visitor
353 * See above.
354 * @param name_prefix
355 * See above.
356 * @param src_stats
357 * See above.
358 * @param target_stats
359 * See above.
360 * @param visitor
361 * See above.
362 */
363template<typename Visitor>
364void declare_stats(const flow::util::stat::Stat_name& name_prefix,
365 const Blob_snd_stats* src_stats, Blob_snd_stats* target_stats,
366 Visitor&& visitor);
367
368/**
369 * Maps a stats `struct` type to its core Blob_snd_stats; identity for Blob_snd_stats itself.
370 * See Blob_sender::Blob_snd_stats and Native_handle_sender::Native_handle_snd_stats concept doc headers
371 * for context. Both concepts require this same function (the core send-stats type is shared).
372 *
373 * Generic use with proper ADL (let `Cool_sender` be a Blob_sender or Native_handle_sender impl instance).
374 * ~~~
375 * using ipc::transport::stat::blob_snd_stats;
376 * Cool_sender::Blob_snd_stats total_stats = ...;
377 * const auto& core_stats = blob_snd_stats(total_stats);
378 * // core_stats has type Blob_snd_stats.
379 * // If Cool_sender::Blob_snd_stats is Blob_snd_stats, then the present free function was invoked.
380 * // Otherwise an actual mapping function in `Cool_sender`s namespace was invoked via ADL.
381 * ~~~
382 *
383 * @param stats
384 * Thing.
385 * @return `stats`.
386 */
387const Blob_snd_stats& blob_snd_stats(const Blob_snd_stats& stats);
388
389/**
390 * Non-`const` wrapper around blob_snd_stats(). Safe because the input is non-`const`, so the
391 * `const_cast` merely undoes the `const` added by delegating to the `const` overload.
392 *
393 * @tparam Stats_t
394 * `Blob_snd_stats`, or an extended stats type with a `blob_snd_stats(const Stats_t&)` ADL overload.
395 * @param stats
396 * Stats to map.
397 * @return See blob_snd_stats(); but non-`const`.
398 */
399template<typename Stats_t>
400Blob_snd_stats& blob_snd_stats_mutable(Stats_t& stats);
401
402/**
403 * Declares the stats for Blob_rcv_stats. Not invoked directly except by `flow::util::stat` internals,
404 * or when composing this stat-set into another.
405 * @see `flow::util::stat` namespace doc header for background on the declare/visit mechanism.
406 *
407 * @tparam Visitor
408 * See above.
409 * @param name_prefix
410 * See above.
411 * @param src_stats
412 * See above.
413 * @param target_stats
414 * See above.
415 * @param visitor
416 * See above.
417 */
418template<typename Visitor>
419void declare_stats(const flow::util::stat::Stat_name& name_prefix,
420 const Blob_rcv_stats* src_stats, Blob_rcv_stats* target_stats,
421 Visitor&& visitor);
422
423/**
424 * Maps a stats `struct` type to its core Blob_rcv_stats; identity for Blob_rcv_stats itself.
425 * See Blob_receiver::Blob_rcv_stats and Native_handle_receiver::Native_handle_rcv_stats concept doc headers
426 * for context. Both concepts require this same function (the core receive-stats type is shared).
427 *
428 * Generic use with proper ADL (let `Cool_receiver` be a Blob_receiver or Native_handle_receiver impl instance).
429 * ~~~
430 * using ipc::transport::stat::blob_rcv_stats;
431 * Cool_receiver::Blob_rcv_stats total_stats = ...;
432 * const auto& core_stats = blob_rcv_stats(total_stats);
433 * // core_stats has type Blob_rcv_stats.
434 * // If Cool_receiver::Blob_rcv_stats is Blob_rcv_stats, then the present free function was invoked.
435 * // Otherwise an actual mapping function in `Cool_receiver`s namespace was invoked via ADL.
436 * ~~~
437 *
438 * @param stats
439 * Thing.
440 * @return `stats`.
441 */
442const Blob_rcv_stats& blob_rcv_stats(const Blob_rcv_stats& stats);
443
444/**
445 * Non-`const` wrapper around blob_rcv_stats(). Safe because the input is non-`const`, so the
446 * `const_cast` merely undoes the `const` added by delegating to the `const` overload.
447 *
448 * @tparam Stats_t
449 * `Blob_rcv_stats`, or an extended stats type with a `blob_rcv_stats(const Stats_t&)` ADL overload.
450 * @param stats
451 * Stats to map.
452 * @return See blob_rcv_stats(); but non-`const`.
453 */
454template<typename Stats_t>
455Blob_rcv_stats& blob_rcv_stats_mutable(Stats_t& stats);
456
457} // namespace ipc::transport::stat
458
459/**
460 * `sync_io`-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
461 * For example transport::sync_io::Native_socket_stream <=> transport::Native_socket_stream.
462 *
463 * @see util::sync_io doc header -- describes the general `sync_io` pattern we are following.
464 */
466{
467
468// Types.
469
470// Find doc headers near the bodies of these compound types.
471class Native_socket_stream;
472class Native_socket_stream_acceptor;
473template<typename Persistent_mq_handle>
474class Blob_stream_mq_sender;
475template<typename Persistent_mq_handle>
476class Blob_stream_mq_receiver;
477
478/// Convenience alias: sync_io::Blob_sender via unidirectional POSIX MQ (message queue).
480/// Convenience alias: sync_io::Blob_receiver via unidirectional POSIX MQ (message queue).
482/// Convenience alias: sync_io::Blob_sender via unidirectional bipc MQ (message queue).
484/// Convenience alias: sync_io::Blob_receiver via unidirectional bipc MQ (message queue).
486
487/**
488 * Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver) at one end of full-duplex
489 * (bidirectional) pipe composed of 2 opposite-facing unidirectional POSIX MQs (message queues).
490 */
492
493/**
494 * Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver) at one end of full-duplex
495 * (bidirectional) pipe composed of 2 opposite-facing unidirectional POSIX MQs (message queues).
496 */
498
499/**
500 * Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver, sync_io::Native_handle_sender,
501 * sync_io::Native_handle_receiver) at one end of a full-duplex (bidirectional) pipe composed of 2 opposite-facing
502 * unidirectional POSIX MQs (message queues), transmitting blobs only; and a full-duplex pipe over a Unix domain
503 * stream connection, transmitting native-handle-and/or-meta-blob messages.
504 */
506
507/**
508 * Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver, sync_io::Native_handle_sender,
509 * sync_io::Native_handle_receiver) at one end of a full-duplex (bidirectional) pipe composed of 2 opposite-facing
510 * unidirectional bipc MQs (message queues), transmitting blobs only; and a full-duplex pipe over a Unix domain
511 * stream connection, transmitting native-handle-and/or-meta-blob messages.
512 */
514
515// Free functions.
516
517/**
518 * Implements `{Native_handle|Blob}_receiver::async_receive_*_batch()` by emulating batch-receiving as a
519 * series of single-message receive-ops.
520 *
521 * ### How to use ###
522 * Just call us; we'll do it. The main requirement is to provide a proper `async_rcv_impl_func()` which shall
523 * perform a regular one-message receive.
524 *
525 * The formal requirements for `async_rcv_impl_func()` are as follows. It shall be called in a `void` context
526 * and have the following arguments, in order:
527 * - (If and only if `NO_HNDLS == false`) `Native_handle*`: Target handle object.
528 * - `bool`: If `true`, your function may assume the pipe is in would-block state already
529 * which may help it be more efficient in doing its task; otherwise it must make no such assumption.
530 * (This will *not* simply always equal the eponymous argument to async_receive_batch_emulation()!)
531 * - util::Blob_mutable: Target memory area for the async-read.
532 * - `Error_code*`: The error-code object for the op. This shall *not* be null (you do *not* need to throw
533 * an exception to emit an error).
534 * - `size_t*`: Set the pointee to the received in-blob's size, unless an error is emitted.
535 * - Function-object of the specific type `flow::async::Task_asio_err_sz`, a/k/a
536 * `Function<void (const Error_code& err_code, size_t n_rcvd)>`.
537 * Attention! This may, or may not, be `.empty()`. See below.
538 *
539 * It shall act as-if `{Native_handle|Blob}_receiver::async_receive_{native_handle|blob}()` was called, except:
540 * - Which one it is: it must act consistently with `NO_HNDLS`.
541 * - It shall take the extra leading `Native_handle*` arg (see above) if `NO_HNDLS == false`.
542 * - It may assume the following checks have all passed: in PEER state, `start_*_ops()` has been called, no
543 * pipe-hosing error recorded yet from prior ops, no `async_receive_*()` already outstanding,
544 * `batch->initialized() && (!batch->full())`.
545 * - May act differently (probably for perf savings) depending on the `bool` arg (assume-would-block; see above).
546 * - If it emits non-success, non-would-block (in-pipe-hosing) error `E`, *and* the desired outcome *if* 1+
547 * in-messages have already been received successfully into `*batch` is *delayed error* (emit no error for this
548 * batch-receive, but next async-receive on that in-pipe shall instantly yield `E`), then `E` *must* be one of the
549 * following:
550 * - error::Code::S_RECEIVES_FINISHED_CANNOT_RECEIVE,
551 * - `boost::asio::error::eof`.
552 * - Any other `E` in that situation will cause the batch-receive to emit `E` (and therefore leave
553 * `batch->n_used()` unchanged); 1+ in-messages shall be eaten. (Promise: any `Native_handle`s received
554 * with the eaten in-messages shall be closed -- returned to the OS -- not leaked.)
555 * - The on-done handler may be non-empty (as required for normal user-triggered calls) or `.empty()`.
556 * If it's non-empty, act normally. If it's empty, and no would-block is encountered, act normally; which is
557 * to say synchronously emit the result, and that's that (on-done handler ignored). If it's empty, and
558 * would-block *is* encountered then there are 2 possibilities.
559 * - If would-block is encountered immediately (no partial message is read/non-steady state reached):
560 * Emit would-block as normal; but *end the async-receive op*. Do not issue an async-wait for readability;
561 * do not save on-done handler (which is empty anyway).
562 * - If would-block is encountered after receiving part of an in-message/a non-steady state is reached:
563 * Do the same; plus:
564 * - Memorize the partial-message payload/non-steady state, so that if another
565 * async-receive is issued by something/someone later, your state machine starts from the point as-if
566 * the partial-message payload/state had already been received/reached. (After all: it *had* already been
567 * received/reached -- it just ended up irrelevant to the previous async-receive; namely us.)
568 *
569 * Unfortunately that last bullet point can be tricky to implement (or even understand what it means),
570 * so we must discuss. Firstly the (potential) good news: If your protocol
571 * combined with the underlying transport is such that reading a partial in-message
572 * is impossible, and (non-hosed) pipe state is the same regardless of where a would-block occurs,
573 * then the bullet point cannot apply, and things (your code) remain simple.
574 *
575 * Example: Native_socket_stream, when operating (and this is determined at compile-time, not run-time) in
576 * datagram mode (asio_local_stream_socket::Protocol_pkt_stream, not `Protocol_byte_stream`; a/k/a
577 * in Linux `SOCK_SEQPACKET`, not `SOCK_STREAM`) can (and in our impl as of this writing does) map each in-message
578 * to one in-datagram, and the pipe is always in the same state (barring being hosed) upon receiving any in-dgram.
579 *
580 * However if it possible to read a payload which encodes (potentially) part of an in-message/non-steady state,
581 * then the bullet point may apply, and you must code for it.
582 *
583 * Example: Blob_stream_mq_receiver is essentially dgram-based too, so each in-message maps to one lower-level
584 * dgram (MQ message), *but* as of this writing our internal protocol is (for certain boring logical/technical reasons)
585 * such that some (non-user-in-message) messages are represented by 2 dgrams (MQ messages), not 1: a CONTROL
586 * message like an auto-ping is represented by an empty in-message (enters CONTROL state) and then a particular
587 * enumeration-value-encoding message (indicates auto-ping; goes back to normal state). So, the start of
588 * async-receive cannot assume normal state; it might be in CONTROL state because of the above. Of course this
589 * is pretty easy to handle; just keep a CONTROL-or-not state flag; and resume the state machine based on its value.
590 * There's no need to store any user payload copy.
591 *
592 * Example: Native_socket_stream, when operating in stream mode (asio_local_stream_socket::Protocol_byte_stream
593 * a/k/a `SOCK_STREAM` unlike the earlier example) might hit would-block after any given byte whatsoever; right down
594 * to the "worst case" of, say, reading all of a 60K-long payload except for the very last expected byte. Then you'd
595 * have to copy it from the would-be user buffer; and feed that part to the next async-receive's user buffer (another
596 * copy). Fortunately this eventuality should not be frequent enough to affect overall perf.
597 *
598 * In that case you'll need to do somehow save any partial-read results and apply them to the next async-read
599 * *of any type* at the start of that async-read, before reading any further potential low-level data. Usually
600 * this isn't a matter of performance, as at worst it's part of only 1 in-message, but you'll need some extra code,
601 * and the support for emulated batch-receiving will impact code not-itself-necessarily-related to batch-receiving.
602 *
603 * @warning It is important that `async_rcv_impl_func()` cache any new pipe-hosing error it encounters
604 * (and therefore emits via `Error_code*` -- but note it may emit non-pipe-hosing error(s) too, most notably
605 * would-block; that is different); so that if an async-receive is attempted subsequently, it knows to
606 * immediately emit it. We mention this, because async_receive_batch_emulation() will -- in the case of
607 * encountering 1+ in-messages followed by error (e.g., graceful close
608 * error::Code::S_RECEIVES_FINISHED_CANNOT_RECEIVE) -- *only* emit the 1+ messages and not any error; it will
609 * stop but ignore the error itself. `{Native_handle|Blob}_receiver::async_receive_*()`
610 * contract is to emit the error next time in that
611 * case -- and async_receive_batch_emulation() shall take no steps of its own to make that happen.
612 * Your `async_rcv_impl_func()` must take care of that.
613 *
614 * ### Rationale / use-cases ###
615 * @see Native_handle_receiver concept doc header "Batch-receiving" section for background.
616 *
617 * As of this writing Native_socket_stream and Blob_stream_mq_receiver use it internally. The latter does so, since
618 * (as of now anyway) there is no built-in batch-receiving OS support for POSIX MQs (nor bipc MQs). The former does
619 * so if and only if Native_socket_stream_cfg::S_USE_OS_DGRAM_BATCH_SUPPORT is `false`. In English -- in both
620 * cases there's no low-level batch-receiving, so to provide that higher-level interface it has to be emulated
621 * based on normal receiving.
622 *
623 * The same task would be faced by any potential Blob_receiver or Native_handle_receiver concept implementer,
624 * including when a Flow-IPC user wants to do so; an advanced type of work but entirely supported. Therefore it would
625 * be relatively rare that a user would call this... but definitely possible. Hence it is public.
626 *
627 * @tparam NO_HNDLS
628 * `true` if implementing Blob_receiver::async_receive_blob_batch().
629 * `false` if Native_handle_receiver::async_receive_native_handle_batch().
630 * @tparam Batch
631 * Blob_receiver::Blob_batch_in or Native_handle_receiver::Native_handle_batch_in (see `NO_HNDLS`).
632 * In addition, it must have the APIs with identical names/semantics to
633 * `Generic_msg_batch_in::clear_used(size_t)`, Generic_msg_batch_in::emulate_result(),
634 * Generic_msg_batch_in::next_target_blob(), and -- if `NO_HNDLS == false` --
635 * Generic_msg_batch_in::next_target_hndl(). (Rationale: We could have instead simply required that
636 * `Batch` be an instance of `Generic_msg_batch_in<Msg_resource, NO_HNDLS>`. Decided to formally allow
637 * any type, as long as it has the required behavior -- for freedom in custom scenarios.)
638 * @tparam Task_err
639 * As for `{Native_handle|Blob}_receiver::async_receive_*_batch()`.
640 * @tparam Async_rcv_impl_func
641 * See above.
642 * @param logger_ptr
643 * Logger to use for logging in this op, including its async-continuation if applicable.
644 * @param batch
645 * As for `{Native_handle|Blob}_receiver::async_receive_*_batch()`.
646 * @param assume_would_block
647 * As for `{Native_handle|Blob}_receiver::async_receive_*_batch()`.
648 * @param sync_err_code
649 * As for `{Native_handle|Blob}_receiver::async_receive_*_batch()`.
650 * @param on_done_func
651 * As for `{Native_handle|Blob}_receiver::async_receive_*_batch()`.
652 * @param async_rcv_impl_func
653 * Your `*_receiver`'s single-message receive op. See above.
654 */
655template<bool NO_HNDLS, typename Batch, typename Task_err, typename Async_rcv_impl_func>
656void async_receive_batch_emulation(flow::log::Logger* logger_ptr,
657 Batch* batch, bool assume_would_block,
658 Error_code* sync_err_code, Task_err&& on_done_func,
659 Async_rcv_impl_func&& async_rcv_impl_func);
660
661/**
662 * Prints string representation of the given `Native_socket_stream` to the given `ostream`.
663 *
664 * @relatesalso Native_socket_stream
665 *
666 * @param os
667 * Stream to which to write.
668 * @param val
669 * Object to serialize.
670 * @return `os`.
671 */
672std::ostream& operator<<(std::ostream& os, const Native_socket_stream& val);
673
674/**
675 * Prints string representation of the given `Native_socket_stream_acceptor` to the given `ostream`.
676 *
677 * @relatesalso Native_socket_stream_acceptor
678 *
679 * @param os
680 * Stream to which to write.
681 * @param val
682 * Object to serialize.
683 * @return `os`.
684 */
685std::ostream& operator<<(std::ostream& os, const Native_socket_stream_acceptor& val);
686
687/**
688 * Prints string representation of the given `Blob_stream_mq_sender` to the given `ostream`.
689 *
690 * If object is default-cted (or moved-from), this will output something graceful indicating this.
691 *
692 * @relatesalso Blob_stream_mq_sender
693 *
694 * @param os
695 * Stream to which to write.
696 * @param val
697 * Object to serialize.
698 * @return `os`.
699 */
700template<typename Persistent_mq_handle>
701std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_sender<Persistent_mq_handle>& val);
702
703/**
704 * Prints string representation of the given `Blob_stream_mq_receiver` to the given `ostream`.
705 *
706 * If object is default-cted (or moved-from), this will output something graceful indicating this.
707 *
708 * @relatesalso Blob_stream_mq_receiver
709 *
710 * @param os
711 * Stream to which to write.
712 * @param val
713 * Object to serialize.
714 * @return `os`.
715 */
716template<typename Persistent_mq_handle>
717std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_receiver<Persistent_mq_handle>& val);
718
719} // namespace ipc::transport::sync_io
Implements the Persistent_mq_handle concept by thinly wrapping bipc::message_queue,...
Implements Blob_receiver concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message...
Implements Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message q...
Peer to a bundle of 1-2 full-duplex pipe(s), one for transmitting unstructured binary blobs; the othe...
Definition: channel.hpp:285
Straightforward Msg_batch_in concept implementation (as taken by API {Blob|Native_handle}_receiver::a...
Definition: batch.hpp:88
A Channel with at least a blobs pipe consisting of two MQs of type Persistent_mq_handle (template arg...
Definition: channel.hpp:1351
A Channel with a blobs pipe consisting of 2 MQs of type Persistent_mq_handle (template arg); and a ha...
Definition: channel.hpp:1449
A server object that binds to a Shared_name and listens for incoming Native_socket_stream connect att...
Msg_batch_in concept implementation for at least sync_io::Native_socket_stream (as taken by APIs Nati...
Implements both Native_handle_sender and Native_handle_receiver concepts by using a Unix domain socke...
Dummy type for use as a template param to Channel when either the blobs pipe or handles pipe is disab...
Definition: channel.hpp:1137
Implements the Persistent_mq_handle concept by wrapping the POSIX message queue API (see man mq_overv...
Implements sync_io::Blob_receiver concept by using an adopted Persistent_mq_handle MQ handle to an MQ...
Implements sync_io::Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (...
sync_io-pattern counterpart to async-I/O-pattern transport::Native_socket_stream_acceptor.
Implements both sync_io::Native_handle_sender and sync_io::Native_handle_receiver concepts by using a...
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
Stats-related sub-namespace, for ADL segregation and general organization.
const Blob_rcv_stats & blob_rcv_stats(const Blob_rcv_stats &stats)
Maps a stats struct type to its core Blob_rcv_stats; identity for Blob_rcv_stats itself.
void declare_stats(const flow::util::stat::Stat_name &name_prefix, const Blob_snd_stats *src_stats, Blob_snd_stats *target_stats, Visitor &&visitor)
Declares the stats for Blob_snd_stats.
Blob_snd_stats & blob_snd_stats_mutable(Stats_t &stats)
Non-const wrapper around blob_snd_stats().
const Blob_snd_stats & blob_snd_stats(const Blob_snd_stats &stats)
Maps a stats struct type to its core Blob_snd_stats; identity for Blob_snd_stats itself.
Blob_rcv_stats & blob_rcv_stats_mutable(Stats_t &stats)
Non-const wrapper around blob_rcv_stats().
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
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
std::ostream & operator<<(std::ostream &os, const Native_socket_stream_impl &val)
Prints string representation of the given Native_socket_stream_impl to the given ostream.
void async_receive_batch_emulation(flow::log::Logger *logger_ptr, Batch *batch, bool assume_would_block, Error_code *sync_err_code, Task_err &&on_done_func, Async_rcv_impl_func &&async_rcv_impl_func)
Implements {Native_handle|Blob}_receiver::async_receive_*_batch() by emulating batch-receiving as a s...
Definition: batch.hpp:33
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
std::ostream & operator<<(std::ostream &os, const Generic_msg_batch_in< Msg_resource_t, NO_HNDLS > &val)
Prints string representation of the given Generic_msg_batch_in to the given ostream.
Definition: batch.hpp:431
util::Shared_name Shared_name
Convenience alias for the commonly used type util::Shared_name.
util::Native_handle Native_handle
Convenience alias for the commonly used type util::Native_handle.
void swap(Bipc_mq_handle &val1, Bipc_mq_handle &val2)
Implements Persistent_mq_handle related concept: Swaps two objects.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.