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