Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
native_socket_stream.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
28#include <flow/log/log.hpp>
29#include <flow/async/util.hpp>
30#include <boost/move/unique_ptr.hpp>
31#include <experimental/propagate_const>
32#include <iosfwd>
33#include <string>
34#include <utility>
35
37{
38
39// Types.
40
41/**
42 * Implements both sync_io::Native_handle_sender and sync_io::Native_handle_receiver concepts by using
43 * a Unix domain socket, allowing high-performance but non-zero-copy transmission of
44 * discrete messages, each containing a native handle, a binary blob, or both. This is the `sync_io`-pattern
45 * counterpart to transport::Native_socket_stream -- and in fact the latter use an instance of the present
46 * class as its core.
47 *
48 * @see transport::Native_socket_stream and util::sync_io doc headers. The latter describes the general pattern which
49 * we implement here; it also contrasts it with the async-I/O pattern, which the former implements.
50 * Which of the two to use depends on your needs, as summarized in the util::sync_io doc header.
51 *
52 * ### Quick note on naming ###
53 * Notes for transport::Native_socket_stream apply.
54 *
55 * ### sync_io::Blob_sender and sync_io::Blob_receiver concept compatibility ###
56 * Notes for transport::Native_socket_stream apply analogously.
57 *
58 * ### Informal comparison to other core transport mechanisms ###
59 * Notes for transport::Native_socket_stream apply.
60 *
61 * ### Cleanup ###
62 * Notes for transport::Native_socket_stream apply.
63 *
64 * ### How to use ###
65 * Notes for transport::Native_socket_stream apply. The differences (some of which are quite important) are as
66 * follows.
67 *
68 * As described by the concepts being implemented -- one must use `start_send_*_ops()` before
69 * the send API (`send_*()`, `*end_sending()`, auto_ping()) and/or `start_receive_*_ops()` before
70 * the receive API (`async_receive_*()`, idle_timer_run()).
71 *
72 * Before `start_*_ops()`, it may be required to call replace_event_wait_handles() (depending on your use case).
73 *
74 * Regarding ctors: Naturally the transport::Native_socket_stream `sync_io`-core-adopting ctor does not exist here,
75 * as we *are* a `sync_io` core. (Or I suppose it's just the move ctor.)
76 *
77 * Thread safety
78 * -------------
79 * Boring stuff out of the way first: It is safe to concurrently act on 2 separate objects of this type.
80 * nickname() and `ostream<<` are always safe to call, and they always yield the same value (modulo
81 * across move-assignment).
82 *
83 * Now as to invoking operation X concurrently with operation Y on the same `*this`, where at least X is non-`const`:
84 *
85 * Firstly let us define operation: Unlike with most APIs in the library, operations don't merely comprise methods
86 * (or related free functions). Rather, in addition, invoking
87 * util::sync_io::Event_wait_func `(*on_active_ev_func)()` -- to inform `*this` of an active
88 * event due to an earlier async-wait requested by `*this` -- is formally an operation on `*this`. It can be
89 * thought of as a member of its (non-`const`) API. For the below discussion we shall pretend these methods
90 * actually exist, to simplify discussion of these operations:
91 * - `send_on_active_ev()` (`on_active_ev_func` originating from `start_send_*_ops()`).
92 * - Recall this may synchronously trigger async_end_sending()-passed completion handler.
93 * - `receive_on_active_ev()` (`on_active_ev_func` originating from `start_receive_*_ops()`).
94 * - Recall this may synchronously trigger `async_receive_*()`-passed completion handler.
95 *
96 * Objects of most types simply declare it to be unsafe to invoke (on one `*this`) non-`const` operation X
97 * concurrently with operation Y (whether X or Y are the same op or differ). `Native_socket_stream`, however,
98 * works as follows: By *default* that is indeed the rule...
99 * with the exception of the following specific exceptions, wherein it *is* **intentionally** safe.
100 *
101 * ### In PEER state ###
102 * Firstly, let's assume `*this` is in PEER state, which is achieved either by using the PEER-state ctor form
103 * (where a pre-connected `Native_handle` is subsumed), or else by successfully completing `*_connect()`.
104 * Cool? Cool. We are in PEER state. Then:
105 *
106 * Boring ones first: sync_connect() simply returns `false` and is always safe to call (it is meant for NULL state).
107 * `*_max_size()` always return the same respective constant values and are always safe to call.
108 *
109 * Much more significantly, we now list two specific categories of operations:
110 * - Send-ops:
111 * - `send_*()`, end_sending(), async_end_sending(), auto_ping();
112 * and `send_on_active_ev()` (reminder: not a real method but a real op/see definition above).
113 * - Receive-ops:
114 * - `async_receive_*()`, `idle_timer_run()`;
115 * and `receive_on_active_ev()` (reminder: not a real method but a real op/see definition above).
116 *
117 * Now then: It is safe to invoke (even on the same `*this`) any 1 operation from the "send-ops" list concurrently
118 * with any 1 operation from the "receive-ops" list.
119 *
120 * Formally that's simply the case.
121 *
122 * Additionally: The remote_peer_process_credentials() accessor (not the mutator) may be invoked concurrently with
123 * any 1 operation from the "send-ops" list and/or any 1 operation from the "receive-ops" list.
124 *
125 * Informally: it may be highly significant to performance of the user code
126 * that this is the case. It means that the two mutually-opposing pipes can operate concurrently, despite the
127 * fact they're operating on the same socket. E.g., an upload and download being highly active simultaneously
128 * will proceed in parallel on separate processor cores if possible. If your event loop is single-threaded in
129 * any case, then this does not matter; but if 2+ threads are involved, then it may well matter quite a bit.
130 * (For example: non-`sync_io` transport::Native_socket_stream is internally built on a sync_io::Native_socket_stream.
131 * It starts a thread (internally dubbed thread W) in which to perform significant incoming-direction work, while most
132 * -- but not all -- outgoing-direction work is done synchronously from its user's calling thread (dubbed thread U).
133 * Therefore it can keep 2 separate mutexes (one for each direction) and lock only 1 when doing in-work
134 * (in either thread U/W); and lock the other when doing out-work, in either thread U/W. So if a send can
135 * complete synchronously in thread U, while a receive does stuff in the background in thread W, the two
136 * may execute concurrently as opposed to serially. Running concurrently would decrease latency latency in
137 * sending and/or receipt.)
138 *
139 * ### In NULL state ###
140 * Nothing interesting here.
141 *
142 * @internal
143 * ### Implementation design/rationale ###
144 * Notes for transport::Native_socket_stream apply: the pImpl-lite stuff; and the fact that:
145 *
146 * The rest of the implementation is inside sync_io::Native_socket_stream_impl and is discussed in that class's
147 * doc header.
148 *
149 * @see sync_io::Native_socket_stream_impl doc header.
150 *
151 * @endinternal
152 *
153 * @see sync_io::Native_handle_sender: implemented concept.
154 * @see sync_io::Native_handle_receiver: implemented concept.
155 * @see sync_io::Blob_sender: alternatively implemented concept.
156 * @see sync_io::Blob_receiver: alternatively implemented concept.
157 */
159{
160private:
161 // Types.
162
163 /// Short-hand for the impl type we're wrapping. Cannot simply forward-declare as in pImpl; we do pImpl-lite.
165
166public:
167 // Types.
168
169 /// Useful for generic programming, the async-I/O-pattern counterpart to `*this` type.
171 /// You may disregard.
173
174 /// Implements Native_handle_receiver concept API.
175 template<typename Msg_resource>
177 /// Implements Blob_receiver concept API.
178 template<typename Msg_resource>
179 using Blob_batch_in = typename Impl::template Blob_batch_in<Msg_resource>;
180
181 /// Implements sync_io::Blob_sender concept API.
183 /// Implements sync_io::Native_handle_sender concept API. Identical to #Blob_snd_stats for this impl.
185 /// Implements sync_io::Blob_receiver concept API.
187 /// Implements sync_io::Native_handle_receiver concept API. Identical to #Blob_rcv_stats for this impl.
189
190 // Constants.
191
192 /// Implements concept API.
194
195 /**
196 * Implements concept API; namely it is `true`. Notes for transport::Native_socket_stream apply.
197 *
198 * @see Native_handle_receiver::S_META_BLOB_UNDERFLOW_ALLOWED: implemented concept. Accordingly also see
199 * "Blob underflow semantics" in transport::Native_handle_receiver doc header.
200 */
201 static constexpr bool S_META_BLOB_UNDERFLOW_ALLOWED = true;
202
203 /**
204 * Implements concept API; namely it is `true`. Notes for transport::Native_socket_stream apply.
205 *
206 * @see Native_handle_receiver::S_BLOB_UNDERFLOW_ALLOWED: implemented concept. Accordingly also see
207 * "Blob underflow semantics" in transport::Native_handle_receiver doc header.
208 */
210
211 /**
212 * Implements concept API. As of this writing this value depends on
213 * Native_socket_stream_cfg::S_USE_OS_DGRAM_BATCH_SUPPORT and `S_USE_OS_DGRAM_SUPPORT`; iff and only if both are
214 * `true`, then this value is `> 1`; otherwise it is `1`.
215 *
216 * @internal
217 * ### Value to choose ###
218 * This paragraph is a quote from the concept doc:
219 * This is "only" a recommendation, though other parts of Flow-IPC may well take it to heart
220 * (struc::Channel does in particular, as of this writing, when deciding whether to even use the batching code
221 * path -- when this is not set to 1 -- and if so then the batch-size value is taken from here).
222 *
223 * It is hopefully straightforward why the conservative decision is to set this to 1, unless
224 * `USE_OS_DGRAM_SUPPORT` is in effect. As for what value (at least 2) to use, when it *is* in effect:
225 *
226 * In typical code out there one tends to see 32 or 64 in this context. Larger values would not be particularly
227 * wasteful, as proper full use of Msg_batch_in concept (most importantly: reuse from receive call to receive call)
228 * means zero cost (other than some memory) for unused slots. However in practice such large in-batches are rare
229 * in our experience, and 64 (or 32) is a nice vanilla choice for "big batch."
230 */
233 ? 64 : 1;
234
235 /**
236 * Implements concept API.
237 *
238 * @see Blob_receiver::S_RCV_BLOB_BATCH_SZ_RECOMMENDATION: implemented concept. One transport, one value:
239 * it serves both of our receiver-concept personas equally (batch-receiving mechanics do not depend on
240 * whether native handles ride along).
241 */
243
244 /**
245 * Useful for generic programming: `true` to indicate a `*this` has a send_native_handle()
246 * and an async_receive_native_handle().
247 *
248 * @todo Shouldn't Native_socket_stream::S_TRANSMIT_NATIVE_HANDLES and its peer concept impls
249 * be formally generalized in the appopriate concept? E.g., as of this writing the Async_adapter_receiver impl
250 * relies on it, so trying to use that guy to implement a custom `..._receiver` in terms of a custom
251 * `sync_io::..._receiver` would cause a build error, unless the writer of the latter hypothetical custom guy
252 * added a `S_TRANSMIT_NATIVE_HANDLES` member. In practice they'd probably know to do so upon seeing the error
253 * and the present code; but formally a relevant concept should specify it, so the custom-guy writer would've known
254 * to do so from the start.
255 */
256 static constexpr bool S_TRANSMIT_NATIVE_HANDLES = true;
257
258 // Constructors/destructor.
259
260 /**
261 * Default ctor (object is in NULL state). Notes for transport::Native_socket_stream apply.
262 *
263 * @see Native_handle_sender::Native_handle_sender(): implemented concept.
264 * @see Native_handle_receiver::Native_handle_receiver(): implemented concept.
265 * @see Blob_sender::Blob_sender(): implemented concept.
266 * @see Blob_receiver::Blob_receiver(): implemented concept.
267 */
269
270 /**
271 * Creates a Native_socket_stream in NULL (not connected) state.
272 * Notes for transport::Native_socket_stream apply.
273 *
274 * @param logger_ptr
275 * See above.
276 * @param nickname_str
277 * See above.
278 */
279 explicit Native_socket_stream(flow::log::Logger* logger_ptr, util::String_view nickname_str);
280
281 /**
282 * Constructs the socket-and-meta-blob stream by taking over an already-connected native Unix domain socket handle.
283 * Notes for transport::Native_socket_stream apply.
284 *
285 * @param logger_ptr
286 * See above.
287 * @param native_peer_socket_moved
288 * See above.
289 * @param nickname_str
290 * See above.
291 */
292 explicit Native_socket_stream(flow::log::Logger* logger_ptr, util::String_view nickname_str,
293 Native_handle&& native_peer_socket_moved);
294
295 /**
296 * Move-constructs from `src`; `src` becomes as-if default-cted (therefore in NULL state).
297 * Notes for transport::Native_socket_stream apply.
298 *
299 * @param src
300 * See above.
301 *
302 * @see Native_handle_sender::Native_handle_sender(): implemented concept.
303 * @see Native_handle_receiver::Native_handle_receiver(): implemented concept.
304 * @see Blob_sender::Blob_sender(): implemented concept.
305 * @see Blob_receiver::Blob_receiver(): implemented concept.
306 */
308
309 /// Copy construction is disallowed.
311
312 /**
313 * Implements Native_handle_sender *and* Native_handle_receiver APIs at the same time, per their concept contracts.
314 * (Also implements Blob_sender *and* Blob_receiver APIs; they are identical.)
315 */
317
318 // Methods.
319
320 /**
321 * Move-assigns from `src`; `*this` acts as if destructed; `src` becomes as-if default-cted (therefore in NULL state).
322 * No-op if `&src == this`.
323 *
324 * Notes for transport::Native_socket_stream apply.
325 *
326 * @param src
327 * See above.
328 * @return `*this`.
329 *
330 * @see Native_handle_sender move assignment: implemented concept.
331 * @see Native_handle_receiver move assignment: implemented concept.
332 * @see Blob_sender move assignment: implemented concept.
333 * @see Blob_receiver move assignment: implemented concept.
334 */
336
337 /// Copy assignment is disallowed.
339
340 /**
341 * Returns nickname, a brief string suitable for logging. Notes for transport::Native_socket_stream apply.
342 *
343 * @return See above.
344 */
345 const std::string& nickname() const;
346
347 /**
348 * Returns logger (possibly null).
349 * @return See above.
350 */
351 flow::log::Logger* get_logger() const;
352
353 /**
354 * Implements Native_handle_sender *and* Native_handle_receiver APIs at the same time, per their concept contracts.
355 * (Also implements Blob_sender *and* Blob_receiver APIs; they are identical.)
356 *
357 * @param create_ev_wait_hndl_func
358 * See above.
359 * @return See above.
360 */
361 template<typename Create_ev_wait_hndl_func>
362 bool replace_event_wait_handles(const Create_ev_wait_hndl_func& create_ev_wait_hndl_func);
363
364 // Connect-ops API.
365
366 /**
367 * Identical to #Async_io_obj counterpart.
368 *
369 * @param absolute_name
370 * See above.
371 * @param err_code
372 * See above.
373 * @return See above.
374 */
375 bool sync_connect(const Shared_name& absolute_name, Error_code* err_code = nullptr);
376
377 // Send-ops API.
378
379 /**
380 * Implements Native_handle_sender API per contract. Notes for transport::Native_handle_sender apply.
381 *
382 * @return See above.
383 */
384 size_t send_meta_blob_max_size() const;
385
386 /**
387 * Implements Blob_sender API per contract. Notes for transport::Blob_sender apply.
388 *
389 * @return See above.
390 */
391 size_t send_blob_max_size() const;
392
393 /**
394 * Implements Native_handle_sender API per contract. See also start_send_blob_ops().
395 *
396 * @tparam Event_wait_func_t
397 * See above.
398 * @param ev_wait_func
399 * See above.
400 * @return See above. In addition return `false`/WARNING/no-op, if start_send_blob_ops() earlier succeeded;
401 * same if `*this` is not in PEER state.
402 */
403 template<typename Event_wait_func_t>
404 bool start_send_native_handle_ops(Event_wait_func_t&& ev_wait_func);
405
406 /**
407 * Implements Blob_sender API per contract. In this implementation start_send_native_handle_ops()
408 * and start_send_blob_ops() are interchangeable: calling either one gets the job done, and calling the other
409 * subsequently is harmless but would return `false` and no-op/log WARNING.
410 *
411 * @tparam Event_wait_func_t
412 * See above.
413 * @param ev_wait_func
414 * See above.
415 * @return See above. In addition return `false`/WARNING/no-op, if start_send_native_handle_ops() earlier succeeded;
416 * same if `*this` is not in PEER state.
417 */
418 template<typename Event_wait_func_t>
419 bool start_send_blob_ops(Event_wait_func_t&& ev_wait_func);
420
421 /**
422 * Implements Native_handle_sender API per contract. Reminder: Please peruse "Thread safety" in class doc header.
423 *
424 * @param hndl_or_null
425 * See above.
426 * @param meta_blob
427 * See above.
428 * @param err_code
429 * See above. Reminder: In rare circumstances, an error emitted here may represent something
430 * detected during handling of a *preceding* send_native_handle() call but after it returned.
431 * #Error_code generated: See #Async_io_obj counterpart doc header.
432 * @return See above.
433 */
434 bool send_native_handle(Native_handle hndl_or_null, const util::Blob_const& meta_blob,
435 Error_code* err_code = nullptr);
436
437 /**
438 * Implements Blob_sender API per contract. Reminder: Please peruse "Thread safety" in class doc header.
439 *
440 * @param blob
441 * See above.
442 * @param err_code
443 * See above. Reminder: In rare circumstances, an error emitted here may represent something
444 * detected during handling of a *preceding* send_native_handle() call but after it returned.
445 * #Error_code generated: See #Async_io_obj counterpart doc header.
446 * @return See above.
447 */
448 bool send_blob(const util::Blob_const& blob, Error_code* err_code = nullptr);
449
450 /**
451 * Implements Native_handle_sender, Blob_sender API per contract.
452 * Reminder: Please peruse "Thread safety" in class doc header.
453 *
454 * #Error_code generated and passed to `on_done_func()` or emitted synchronously:
455 * See #Async_io_obj counterpart doc header.
456 *
457 * Reminder: In rare circumstances, an error emitted there may represent something
458 * detected during handling of a preceding send_native_handle() or send_blob() call but after it returned.
459 *
460 * @tparam Task_err
461 * See above.
462 * @param sync_err_code
463 * See above.
464 * Do realize error::Code::S_SYNC_IO_WOULD_BLOCK *is* still an error, so if this pointer is null, then
465 * would-block *will* make this throw.
466 * @param on_done_func
467 * See above.
468 * @return See above. Reminder: If and only if it returns `false`, we're in NULL state, or `*end_sending()` has
469 * already been called; and `on_done_func()` will never be called, nor will an error be emitted.
470 */
471 template<typename Task_err>
472 bool async_end_sending(Error_code* sync_err_code, Task_err&& on_done_func);
473
474 /**
475 * Implements Native_handle_sender, Blob_sender API per contract.
476 *
477 * @return See above.
478 */
479 bool end_sending();
480
481 /**
482 * Implements Native_handle_sender, Blob_sender API per contract.
483 *
484 * @param period
485 * See above.
486 * @return See above.
487 */
488 bool auto_ping(util::Fine_duration period = boost::chrono::seconds{2});
489
490 /**
491 * Implements sync_io::Blob_sender API per contract. Notes for transport::Native_socket_stream apply.
492 * @return See above.
493 */
495
496 /// Implements sync_io::Blob_sender API per contract.
498
499 /**
500 * Implements sync_io::Native_handle_sender API per contract. Identical to blob_send_stats() for this impl.
501 * @return See above.
502 */
504
505 /// Implements sync_io::Native_handle_sender API per contract. Identical to blob_send_stats_reset().
507
508 // Receive-ops API.
509
510 /**
511 * Implements Native_handle_receiver API per contract. Notes for transport::Native_handle_receiver apply.
512 *
513 * @return See above.
514 */
515 size_t receive_meta_blob_max_size() const;
516
517 /**
518 * Implements Blob_receiver API per contract. Notes for transport::Blob_receiver apply.
519 *
520 * @return See above.
521 */
522 size_t receive_blob_max_size() const;
523
524 /**
525 * Implements Native_handle_receiver API per contract. See also start_receive_blob_ops().
526 *
527 * @tparam Event_wait_func_t
528 * See above.
529 * @param ev_wait_func
530 * See above.
531 * @return See above. In addition return `false`/WARNING/no-op, if start_receive_blob_ops() earlier succeeded;
532 * same if `*this` is not in PEER state.
533 */
534 template<typename Event_wait_func_t>
535 bool start_receive_native_handle_ops(Event_wait_func_t&& ev_wait_func);
536
537 /**
538 * Implements Blob_receiver API per contract. In this implementation start_receive_native_handle_ops()
539 * and start_receive_blob_ops() are interchangeable: calling either one gets the job done, and calling the other
540 * subsequently is harmless but would return `false` and no-op/log WARNING.
541 *
542 * @tparam Event_wait_func_t
543 * See above.
544 * @param ev_wait_func
545 * See above.
546 * @return See above. In addition return `false`/WARNING/no-op, if start_receive_native_handle_ops() earlier
547 * succeeded; same if `*this` is not in PEER state.
548 */
549 template<typename Event_wait_func_t>
550 bool start_receive_blob_ops(Event_wait_func_t&& ev_wait_func);
551
552 /**
553 * Implements Native_handle_receiver API per contract. Reminder: Please peruse "Thread safety" in class doc header.
554 *
555 * #Error_code generated and passed to `on_done_func()` or emitted synchronously:
556 * See `Async_io_obj::async_receive_native_handle()` doc header
557 * (but not `S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER`; and add `S_SYNC_IO_WOULD_BLOCK`).
558 *
559 * @tparam Task_err_sz
560 * See above.
561 * @param target_hndl
562 * See above.
563 * @param target_meta_blob
564 * See above.
565 * @param sync_err_code
566 * See above.
567 * Do realize error::Code::S_SYNC_IO_WOULD_BLOCK *is* still an error, so if this pointer is null, then
568 * would-block *will* make this throw.
569 * @param sync_sz
570 * See above.
571 * @param on_done_func
572 * See above.
573 * @return See above.
574 */
575 template<typename Task_err_sz>
576 bool async_receive_native_handle(Native_handle* target_hndl, const util::Blob_mutable& target_meta_blob,
577 Error_code* sync_err_code, size_t* sync_sz,
578 Task_err_sz&& on_done_func);
579
580 /**
581 * Implements Blob_receiver API per contract. Reminder: Please peruse "Thread safety" in class doc header.
582 *
583 * #Error_code generated and passed to `on_done_func()` or emitted synchronously:
584 * See `Async_io_obj::async_receive_blob()` doc header
585 * (but not `S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER`; and add `S_SYNC_IO_WOULD_BLOCK`).
586 *
587 * @tparam Task_err_sz
588 * See above.
589 * @param target_blob
590 * See above.
591 * @param sync_err_code
592 * See above.
593 * Do realize error::Code::S_SYNC_IO_WOULD_BLOCK *is* still an error, so if this pointer is null, then
594 * would-block *will* make this throw.
595 * @param sync_sz
596 * See above.
597 * @param on_done_func
598 * See above.
599 * @return See above.
600 */
601 template<typename Task_err_sz>
602 bool async_receive_blob(const util::Blob_mutable& target_blob, Error_code* sync_err_code, size_t* sync_sz,
603 Task_err_sz&& on_done_func);
604
605 /**
606 * Implements Native_handle_receiver API per contract. Reminder: Please peruse "Thread safety" in class doc header.
607 *
608 * #Error_code generated and passed to `on_done_func()` or emitted synchronously:
609 * See `Async_io_obj::async_receive_native_handle_batch()` doc header
610 * (but not `S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER`; and add `S_SYNC_IO_WOULD_BLOCK`).
611 *
612 * @tparam Msg_resource
613 * See above.
614 * @tparam Task_err
615 * See above.
616 * @param batch
617 * See above.
618 * @param assume_would_block
619 * See above.
620 * @param sync_err_code
621 * See above.
622 * Do realize error::Code::S_SYNC_IO_WOULD_BLOCK *is* still an error, so if this pointer is null, then
623 * would-block *will* make this throw.
624 * @param on_done_func
625 * See above.
626 * @return See above.
627 */
628 template<typename Msg_resource, typename Task_err>
629 bool async_receive_native_handle_batch(Native_handle_batch_in<Msg_resource>* batch, bool assume_would_block,
630 Error_code* sync_err_code, Task_err&& on_done_func);
631
632 /**
633 * Implements Blob_receiver API per contract. Reminder: Please peruse "Thread safety" in class doc header.
634 *
635 * #Error_code generated and passed to `on_done_func()` or emitted synchronously:
636 * See `Async_io_obj::async_receive_blob_batch()` doc header
637 * (but not `S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER`; and add `S_SYNC_IO_WOULD_BLOCK`).
638 *
639 * @tparam Msg_resource
640 * See above.
641 * @tparam Task_err
642 * See above.
643 * @param batch
644 * See above.
645 * @param assume_would_block
646 * See above.
647 * @param sync_err_code
648 * See above.
649 * Do realize error::Code::S_SYNC_IO_WOULD_BLOCK *is* still an error, so if this pointer is null, then
650 * would-block *will* make this throw.
651 * @param on_done_func
652 * See above.
653 * @return See above.
654 */
655 template<typename Msg_resource, typename Task_err>
656 bool async_receive_blob_batch(Blob_batch_in<Msg_resource>* batch, bool assume_would_block, Error_code* sync_err_code,
657 Task_err&& on_done_func);
658
659 /**
660 * Implements Native_handle_receiver, Blob_receiver API per contract. Reminder: Please peruse "Thread safety"
661 * in class doc header.
662 *
663 * @param timeout
664 * See above.
665 * @return See above.
666 */
667 bool idle_timer_run(util::Fine_duration timeout = boost::chrono::seconds{5});
668
669 /**
670 * Implements sync_io::Blob_receiver API per contract.
671 * @return See above.
672 */
674
675 /// Implements sync_io::Blob_receiver API per contract.
677
678 /**
679 * Implements sync_io::Native_handle_receiver API per contract. Identical to blob_receive_stats() for this impl.
680 * @return See above.
681 */
683
684 /// Implements sync_io::Native_handle_receiver API per contract. Identical to blob_receive_stats_reset().
686
687 // Misc API.
688
689 /**
690 * See transport::Native_socket_stream counterpart.
691 *
692 * @param err_code
693 * See transport::Native_socket_stream counterpart.
694 * @return See transport::Native_socket_stream counterpart.
695 */
697
698 /**
699 * See transport::Native_socket_stream counterpart.
700 *
701 * @param creds
702 * See transport::Native_socket_stream counterpart.
703 * @return See transport::Native_socket_stream counterpart.
704 */
706
707private:
708 // Types.
709
710 /// Short-hand for `const`-respecting wrapper around #Impl for the pImpl-lite idiom.
711 using Impl_ptr = std::experimental::propagate_const<boost::movelib::unique_ptr<Impl>>;
712
713 // Friends.
714
715 /// Friend of Native_socket_stream.
716 friend std::ostream& operator<<(std::ostream& os, const Native_socket_stream& val);
717
718 // Methods.
719
720 /**
721 * Helper that simply returns #m_impl while guaranteeing that #m_impl is non-null upon return. All
722 * forwarding-to-#m_impl methods (including `const` ones) shall access #m_impl through this impl() method only.
723 *
724 * ### Design/rationale ###
725 * Notes from transport::Native_socket_stream apply.
726 *
727 * @return Reference to #m_impl.
728 */
729 Impl_ptr& impl() const;
730
731 // Please see transport::Native_socket_stream_impl similar doc header; explains why this is dead code but remains.
732#if 0
733 /**
734 * In PEER state only, with no prior send or receive ops, returns an object of this same type
735 * (as-if just constructed) operating on `*this` underlying low-level transport `Native_handle`; while
736 * `*this` becomes as-if default-cted. It is similar to returning `Native_socket_stream(std::move(*this))`,
737 * except that any replace_event_wait_handles() and `start_*_ops()` -- generally irreversible publicly
738 * otherwise -- are as-if undone on the returned object.
739 *
740 * Rationale: To be perfectly honest this was originally written in order to allow for
741 * async-I/O-pattern transport::Native_socket_stream::release() to be writable.
742 *
743 * Behavior is undefined if `*this` is not in PEER state, or if it is, but you've invoked `async_receive_*()`,
744 * `send_*()`, `*end_sending()`, auto_ping(), or idle_timer_run() in the past. (`start_*_ops()` and
745 * replace_event_wait_handles() are fine.) Please be careful.
746 *
747 * @return See above.
748 */
749 Native_socket_stream release();
750#endif
751
752 // Data.
753
754 /**
755 * The true implementation of this class. See also our class doc header; and impl() (in particular explaining
756 * why this is `mutable`).
757 *
758 * Do not access directly but only via impl().
759 */
761}; // class Native_socket_stream
762
763// Free functions: in *_fwd.hpp.
764
765// Template implementations.
766
767template<typename Create_ev_wait_hndl_func>
768bool Native_socket_stream::replace_event_wait_handles(const Create_ev_wait_hndl_func& create_ev_wait_hndl_func)
769{
770 return impl()->replace_event_wait_handles(create_ev_wait_hndl_func);
771}
772
773template<typename Event_wait_func_t>
774bool Native_socket_stream::start_send_native_handle_ops(Event_wait_func_t&& ev_wait_func)
775{
776 return impl()->start_send_native_handle_ops(std::move(ev_wait_func));
777}
778
779template<typename Event_wait_func_t>
780bool Native_socket_stream::start_send_blob_ops(Event_wait_func_t&& ev_wait_func)
781{
782 return impl()->start_send_blob_ops(std::move(ev_wait_func));
783}
784
785template<typename Task_err>
786bool Native_socket_stream::async_end_sending(Error_code* sync_err_code, Task_err&& on_done_func)
787{
788 return impl()->async_end_sending(sync_err_code, std::move(on_done_func));
789}
790
791template<typename Event_wait_func_t>
792bool Native_socket_stream::start_receive_native_handle_ops(Event_wait_func_t&& ev_wait_func)
793{
794 return impl()->start_receive_native_handle_ops(std::move(ev_wait_func));
795}
796
797template<typename Event_wait_func_t>
798bool Native_socket_stream::start_receive_blob_ops(Event_wait_func_t&& ev_wait_func)
799{
800 return impl()->start_receive_blob_ops(std::move(ev_wait_func));
801}
802
803template<typename Task_err_sz>
805 const util::Blob_mutable& target_meta_blob,
806 Error_code* sync_err_code, size_t* sync_sz,
807 Task_err_sz&& on_done_func)
808{
809 /* Perf note: In all cases, as of this writing, Native_socket_stream_impl would wrap the various handler
810 * parameterized args in concrete Function<>s anyway for its own impl ease; so we change nothing by
811 * (implicitly, if needed) constructing flow::async::Task_asio_err_sz higher up in the call stack in this
812 * template and its siblings below. */
813
814 return impl()->async_receive_native_handle(target_hndl, target_meta_blob, sync_err_code, sync_sz,
815 std::move(on_done_func));
816}
817
818template<typename Task_err_sz>
820 Error_code* sync_err_code, size_t* sync_sz, Task_err_sz&& on_done_func)
821{
822 return impl()->async_receive_blob(target_blob, sync_err_code, sync_sz, std::move(on_done_func));
823}
824
825template<typename Msg_resource, typename Task_err>
827 bool assume_would_block,
828 Error_code* sync_err_code, Task_err&& on_done_func)
829{
830 return impl()->async_receive_native_handle_batch<Msg_resource>(batch, assume_would_block, sync_err_code,
831 std::move(on_done_func));
832}
833
834template<typename Msg_resource, typename Task_err>
836 Error_code* sync_err_code, Task_err&& on_done_func)
837{
838 return impl()->async_receive_blob_batch<Msg_resource>(batch, assume_would_block, sync_err_code,
839 std::move(on_done_func));
840}
841
842} // namespace ipc::transport::sync_io
static constexpr bool S_USE_OS_DGRAM_BATCH_SUPPORT
Whether the OS provides, and we shall use for sync_io::Native_socket_stream and derivative(s),...
static constexpr bool S_USE_OS_DGRAM_SUPPORT
Whether the OS provides, and we shall use for sync_io::Native_socket_stream and derivative(s),...
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
Internal, non-movable pImpl-lite implementation of sync_io::Native_socket_stream class.
Implements both sync_io::Native_handle_sender and sync_io::Native_handle_receiver concepts by using a...
bool async_receive_native_handle(Native_handle *target_hndl, const util::Blob_mutable &target_meta_blob, Error_code *sync_err_code, size_t *sync_sz, Task_err_sz &&on_done_func)
Implements Native_handle_receiver API per contract.
transport::stat::Blob_snd_stats Blob_snd_stats
Implements sync_io::Blob_sender concept API.
static constexpr size_t S_RCV_NATIVE_HANDLE_BATCH_SZ_RECOMMENDATION
Implements concept API.
Native_socket_stream(Native_socket_stream &&src)
Move-constructs from src; src becomes as-if default-cted (therefore in NULL state).
bool send_native_handle(Native_handle hndl_or_null, const util::Blob_const &meta_blob, Error_code *err_code=nullptr)
Implements Native_handle_sender API per contract.
static constexpr size_t S_RCV_BLOB_BATCH_SZ_RECOMMENDATION
Implements concept API.
const util::Process_credentials & remote_peer_process_credentials(Error_code *err_code=nullptr) const
See transport::Native_socket_stream counterpart.
bool start_send_blob_ops(Event_wait_func_t &&ev_wait_func)
Implements Blob_sender API per contract.
bool start_send_native_handle_ops(Event_wait_func_t &&ev_wait_func)
Implements Native_handle_sender API per contract.
static const Shared_name S_RESOURCE_TYPE_ID
Implements concept API.
Native_socket_stream()
Default ctor (object is in NULL state).
Native_socket_stream & operator=(const Native_socket_stream &)=delete
Copy assignment is disallowed.
Blob_snd_stats blob_send_stats() const
Implements sync_io::Blob_sender API per contract.
std::experimental::propagate_const< boost::movelib::unique_ptr< Impl > > Impl_ptr
Short-hand for const-respecting wrapper around Impl for the pImpl-lite idiom.
void blob_send_stats_reset()
Implements sync_io::Blob_sender API per contract.
bool auto_ping(util::Fine_duration period=boost::chrono::seconds{2})
Implements Native_handle_sender, Blob_sender API per contract.
bool async_receive_blob_batch(Blob_batch_in< Msg_resource > *batch, bool assume_would_block, Error_code *sync_err_code, Task_err &&on_done_func)
Implements Blob_receiver API per contract.
Native_socket_stream(const Native_socket_stream &)=delete
Copy construction is disallowed.
bool end_sending()
Implements Native_handle_sender, Blob_sender API per contract.
static constexpr bool S_BLOB_UNDERFLOW_ALLOWED
Implements concept API; namely it is true.
bool idle_timer_run(util::Fine_duration timeout=boost::chrono::seconds{5})
Implements Native_handle_receiver, Blob_receiver API per contract.
transport::stat::Blob_rcv_stats Blob_rcv_stats
Implements sync_io::Blob_receiver concept API.
const std::string & nickname() const
Returns nickname, a brief string suitable for logging.
Blob_rcv_stats native_handle_receive_stats() const
Implements sync_io::Native_handle_receiver API per contract.
typename Impl::template Blob_batch_in< Msg_resource > Blob_batch_in
Implements Blob_receiver concept API.
bool async_receive_blob(const util::Blob_mutable &target_blob, Error_code *sync_err_code, size_t *sync_sz, Task_err_sz &&on_done_func)
Implements Blob_receiver API per contract.
bool sync_connect(const Shared_name &absolute_name, Error_code *err_code=nullptr)
Identical to Async_io_obj counterpart.
void native_handle_send_stats_reset()
Implements sync_io::Native_handle_sender API per contract. Identical to blob_send_stats_reset().
Impl_ptr & impl() const
Helper that simply returns m_impl while guaranteeing that m_impl is non-null upon return.
Native_socket_stream & operator=(Native_socket_stream &&src)
Move-assigns from src; *this acts as if destructed; src becomes as-if default-cted (therefore in NULL...
bool start_receive_blob_ops(Event_wait_func_t &&ev_wait_func)
Implements Blob_receiver API per contract.
size_t send_meta_blob_max_size() const
Implements Native_handle_sender API per contract.
Impl_ptr m_impl
The true implementation of this class.
Blob_rcv_stats blob_receive_stats() const
Implements sync_io::Blob_receiver API per contract.
size_t receive_blob_max_size() const
Implements Blob_receiver API per contract.
static constexpr bool S_META_BLOB_UNDERFLOW_ALLOWED
Implements concept API; namely it is true.
size_t send_blob_max_size() const
Implements Blob_sender API per contract.
flow::log::Logger * get_logger() const
Returns logger (possibly null).
typename Impl::template Native_handle_batch_in< Msg_resource > Native_handle_batch_in
Implements Native_handle_receiver concept API.
friend std::ostream & operator<<(std::ostream &os, const Native_socket_stream &val)
Friend of Native_socket_stream.
bool start_receive_native_handle_ops(Event_wait_func_t &&ev_wait_func)
Implements Native_handle_receiver API per contract.
bool send_blob(const util::Blob_const &blob, Error_code *err_code=nullptr)
Implements Blob_sender API per contract.
size_t receive_meta_blob_max_size() const
Implements Native_handle_receiver API per contract.
bool async_receive_native_handle_batch(Native_handle_batch_in< Msg_resource > *batch, bool assume_would_block, Error_code *sync_err_code, Task_err &&on_done_func)
Implements Native_handle_receiver API per contract.
~Native_socket_stream()
Implements Native_handle_sender and Native_handle_receiver APIs at the same time, per their concept c...
void native_handle_receive_stats_reset()
Implements sync_io::Native_handle_receiver API per contract. Identical to blob_receive_stats_reset().
void blob_receive_stats_reset()
Implements sync_io::Blob_receiver API per contract.
static constexpr bool S_TRANSMIT_NATIVE_HANDLES
Useful for generic programming: true to indicate a *this has a send_native_handle() and an async_rece...
bool replace_event_wait_handles(const Create_ev_wait_hndl_func &create_ev_wait_hndl_func)
Implements Native_handle_sender and Native_handle_receiver APIs at the same time, per their concept c...
Blob_snd_stats native_handle_send_stats() const
Implements sync_io::Native_handle_sender API per contract.
bool async_end_sending(Error_code *sync_err_code, Task_err &&on_done_func)
Implements Native_handle_sender, Blob_sender API per contract.
A process's credentials (PID, UID, GID as of this writing).
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
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::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:112
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313
Cumulative stats from the incoming-direction (receive) pipe of a Blob_receiver or Native_handle_recei...
Cumulative stats from the outgoing-direction (send) pipe of a Blob_sender or Native_handle_sender con...
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.