Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
native_socket_stream_impl.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 <cstddef>
26#include <flow/async/single_thread_task_loop.hpp>
27#include <boost/noncopyable.hpp>
28#include <optional>
29#include <string>
30#include <utility>
31
32namespace ipc::transport
33{
34
35// Types.
36
37/**
38 * Internal, non-movable pImpl-lite implementation of Native_socket_stream class.
39 * In and of itself it would have been directly and publicly usable; however Native_socket_stream adds move semantics
40 * which are essential to cooperation with Native_socket_stream_acceptor and overall consistency with the rest
41 * of ipc::transport API and, arguably, boost.asio API design.
42 *
43 * @see All discussion of the public API is in Native_socket_stream doc header; that class forwards to this one.
44 * All discussion of pImpl-related notions is also there. See that doc header first please. Then come back here.
45 *
46 * Impl design
47 * -----------
48 * ### Intro / history ###
49 * Native_socket_stream_impl is (or perhaps was, and now sync_io::Native_socket_stream_impl is, as you'll see),
50 * one could argue, the core class of this entire library, Flow-IPC.
51 * Beyond that, even the closest alternatives (which, in the first place, cannot do some of what it can -- namely the
52 * `Blob_stream_mq_*` guys cannot transmit native handles) tend to use many of the same techniques.
53 * So, like, this impl design is important -- for performance on behalf of the ipc::transport use and ipc::session
54 * internals (which bases its session master channel on a single-`Native_socket_stream` Channel); and as
55 * a conceptual template for how various other things are implemented (at least in part).
56 *
57 * Truthfully, in some cases historically speaking I (ygoldfel) tweaked aspects of the concept APIs it
58 * implements (Native_handle_sender, Native_handle_receiver, Blob_sender, Blob_receiver) based on lessons
59 * learned in writing this impl. (Yes, it "should" be the other way around -- concept should be maximally
60 * useful, impl should fulfill it, period -- but I am just being real.)
61 *
62 * That said: at some point during the initial development of Flow-IPC, the `sync_io` pattern emerged as a
63 * necessary alternative API -- alternative to the async-I/O pattern of `*_sender` and `*_receiver` concepts.
64 * (See util::sync_io doc header. It describes the pattern and the rationale for it.) It was of course possible,
65 * at that point, to have the 2 be decoupled: Native_socket_stream (async-I/O pattern) is implemented like so,
66 * and sync_io::Native_socket_stream (`sync_io` pattern) is implemented separate like *so*. Historically speaking,
67 * Native_socket_stream was already written and working great, with a stable API and insides;
68 * but sync_io::Native_socket_stream didn't exist and needed to be written -- in fact, the 1st `sync_io` guy to
69 * be written.
70 *
71 * Naturally I scrapped the idea of simply writing the new guy from scratch and leaving existing guy as-is.
72 * Instead I moved the relevant aspects of the old guy into the new guy, and (re)wrote the formerly-old guy
73 * (that's the present class Native_socket_stream_impl) *in terms of* the new guy. (I then repeated this for
74 * its peers Blob_stream_mq_sender -- which is like `*this` but for blobs-only and outgoing-only -- and
75 * Blob_stream_mq_receiver, which is (same) but incoming-only.) Any other approach would have resulted in 2x
76 * the code and 2x the bug potential and maintenance going forward. (Plus it allowed for the nifty
77 * concept of being able to construct a Native_socket_stream from a sync_io::Native_socket_stream "core";
78 * this was immediately standardized to all the relevant concepts.) Note -- however -- that as Native_socket_stream
79 * underwent this bifurcation into Native_socket_stream and sync_io::Native_socket_stream, its API did not change
80 * *at all* (modulo the addition of the `sync_io`-core-subsuming constructor).
81 *
82 * As a result -- whether that was a good or bad design (I say, good) -- at least the following is true:
83 * Understanding the impl of `*this` class means: understanding the `sync_io` core sync_io::Native_socket_stream
84 * *as a black box* (!); and then understanding the (actually quite limited) work necessary to build on top of that
85 * to provide the desired API (as largely mandated by Native_handle_sender and Native_handle_receiver concept
86 * APIs). Moreover, given a `sync_op::_*sender` the PEER-state logic for `*_sender` is always the same;
87 * and similarly for `*_receiver`. Because of that I factored out this adapter logic into
88 * sync_io::Async_adapter_sender and sync_io::Async_adapter_receiver; so 49.5% of Native_socket_stream PEER-state
89 * logic forwards to `Async_adapter_sender`, 49.5% to `Async_adapter_receiver`; and accordingly
90 * 99% of each of `Blob_stream_mq_sender/receiver` forwards to `Async_adapter_sender/receiver`. If more
91 * sender/receiver types were to be written they could do the same. So only the `sync_io::X` core is different.
92 *
93 * So... actually... it is pretty straightforward now! Pre-decoupling it was much more of a challenge.
94 * Of course, you may want to change its insides; in that case you might need to get into
95 * sync_io::Native_socket_stream_impl. Though, that guy is simpler too, as its mission is much reduced --
96 * no more "thread W" or async-handlers to invoke.
97 *
98 * That said you'll need to in fact understand how sync_io::Native_socket_stream (as a black box) works which means
99 * getting comfortable with the `sync_io` pattern. (See util::sync_io doc header.)
100 *
101 * ### Threads and thread nomenclature ###
102 * *Thread U* refers to the user "meta-thread" from which the public APIs are invoked after construction.
103 * Since ("Thread safety" in Native_socket_stream doc header) they are to protect from any concurrent API
104 * calls on a given `*this`, all access to the APIs can be thought of as coming from a single "thread" U. There is a
105 * caveat: User-supplied completion handler callbacks are explicitly said to be invoked from an unspecified
106 * thread that is *not* U, and the user is generally explicitly allowed to call public APIs directly from these
107 * callbacks. *Thread W* (see below) is the "unspecified thread that is not U" -- the worker thread. Therefore, at
108 * the top of each public API body, we write the internal comment "We are in thread U *or* thread W (but always
109 * serially)." or similar.
110 *
111 * Generally speaking the threads are used as follows internally by `*this`:
112 * - User invokes `this->f()` in thread U. We ask, immediately if possible, for `m_sync_io` (the `sync_io` core)
113 * to finish `m_sync_io.f()` as synchronously as it can. If it can, wonderful. If it cannot, it will
114 * (per `sync_io` pattern) ask to async-wait on an event (readable or writable) on some FD of its choice.
115 * We `.async_wait(F)` on it -- and as a result, on ready event, `F()` executes in thread W.
116 * - In thread W, `F()` eventually executes, so *within* `F()` we (1) tell `m_sync_io` of the ready event
117 * by calling into an `m_sync_io` API.
118 * - Into thread W, we `post()` user completion handlers, namely from `async_receive_*()` and async_end_sending().
119 * As promised that's the "unspecified thread" from which we do this.
120 *
121 * The thread-W `post()`ing does not require locking. It does need to happen in a separate boost.asio task, as
122 * otherwise recursive mayhem can occur (we want to do A-B synchronously, but then between A and B they invoke
123 * `this->something()`, which starts something else => mayhem).
124 *
125 * However: the other 2 bullet points (first one and the sub-bullet under it) do operate on the same data
126 * from threads U and W potentially concurrently. (Note: usually it is not necessary to engage thread W,
127 * except for receive-ops. A receive-op may indeed commonly encounter would-block, simply because no data have
128 * arrived yet. Otherwise: For send-ops, `m_sync_io` will synchronously succeed in each send, including that of
129 * graceful-close due to `*end_sending()`, unless the kernel buffer is full and gives would-block -- only if the
130 * opposing side is not reading in timely fashion. The sparing use of multi-threading, instead completing stuff
131 * synchronously whenever humanly possible, is a good property of this design that uses a `sync_io` core.)
132 *
133 * That brings us to:
134 *
135 * ### Locking ###
136 * All receive logic is bracketed by a lock, sync_io::Async_adapter_receiver::m_mutex.
137 * Lock contention occurs only if more `async_receive_*()` requests are made while one is in progress.
138 * This is, we guess, relatively rare.
139 *
140 * All send logic is similarly bracketed by a different lock, sync_io::Async_adapter_sender::m_mutex. Lock
141 * contention occurs only if (1) `send_*()` (or, one supposes, `*end_sending()`, but that's negligible) encounters
142 * would-block inside `m_sync_io.send_*()`; *and* (2) more `send_*()` (+ `*end_sending()`) requests are made
143 * during this state. (1) should be infrequent-to-non-existent assuming civilized opposing-side receiving behavior.
144 * Therefore lock contention should be rare.
145 *
146 * ### Outgoing-direction impl design ###
147 * @see sync_io::Async_adapter_sender where all that is encapsulated.
148 *
149 * ### Incoming-direction impl design ###
150 * @see sync_io::Async_adapter_receiver where all that is encapsulated.
151 */
153 public flow::log::Log_context,
154 private boost::noncopyable // And not movable.
155{
156public:
157 // Types.
158
159 /**
160 * See Native_socket_stream counterpart. Or, just go to where that'll ultimately point you:
161 * transport::Native_handle_receiver::Native_handle_batch_in concept doc header.
162 */
163 template<typename Msg_resource>
164 using Native_handle_batch_in = sync_io::Native_socket_stream::template Native_handle_batch_in<Msg_resource>;
165
166 /// See Native_socket_stream counterpart / transport::Blob_receiver::Blob_batch_in.
167 template<typename Msg_resource>
168 using Blob_batch_in = typename sync_io::Native_socket_stream::template Blob_batch_in<Msg_resource>;
169
170 /// Implements Blob_sender concept API.
172 /// Implements Native_handle_sender concept API. Identical to #Blob_snd_stats for this impl.
174 /// Implements Blob_receiver concept API.
176 /// Implements Native_handle_receiver concept API. Identical to #Blob_rcv_stats for this impl.
178
179 // Constructors/destructor.
180
181 /**
182 * See Native_socket_stream counterpart.
183 *
184 * @param logger_ptr
185 * See Native_socket_stream counterpart.
186 * @param nickname_str
187 * See Native_socket_stream counterpart.
188 */
189 explicit Native_socket_stream_impl(flow::log::Logger* logger_ptr, util::String_view nickname_str);
190
191 /**
192 * See Native_socket_stream counterpart.
193 *
194 * @param logger_ptr
195 * See Native_socket_stream counterpart.
196 * @param native_peer_socket_moved
197 * See Native_socket_stream counterpart.
198 * @param nickname_str
199 * See Native_socket_stream counterpart.
200 */
201 explicit Native_socket_stream_impl(flow::log::Logger* logger_ptr, util::String_view nickname_str,
202 Native_handle&& native_peer_socket_moved);
203
204 /**
205 * See Native_socket_stream counterpart.
206 *
207 * @param sync_io_core_in_peer_state_moved
208 * See Native_socket_stream counterpart.
209 */
210 explicit Native_socket_stream_impl(sync_io::Native_socket_stream&& sync_io_core_in_peer_state_moved);
211
212 /**
213 * See Native_socket_stream counterpart.
214 *
215 * @internal
216 * The unspecified thread from which remaining handlers are potentially invoked, as of this writing,
217 * is not the usual thread W. There is rationale discussion and detail in the body, but it seemed prudent to
218 * point it out here.
219 * @endinternal
220 */
222
223 // Methods.
224
225 /* The following dead code is intentionally left-in; in fact this doc header (or close to it) could live
226 * in transport::Native_socket_stream and an identical signature in `*this` would implement it. Why is it around?
227 * Answer: There is currently no public async_connect(), only private; the public-facing reason for this
228 * is briefly given in the Native_socket_stream class doc header (TL;DR: there's no point, as locally it's always
229 * a quick operation); the internal reason that async_connect() does exist, but not publicly, is given at length
230 * in the sync_io::Native_socket_stream_impl doc header. release() would be quite helpful, if async_connect()
231 * were public: As then one could construct an async-I/O-pattern transport::Native_socket_stream; .async_connect()
232 * it; then .release() the sync_io-pattern core; and various things elsewhere require sync_io-pattern cores
233 * rather than the heavier-weight, thread-assisted async-I/O wrappers like a *this. So one could .release() a core
234 * and then feed it to whatever needs it. Thing is, as noted elsewhere, there are serious plans to extend
235 * the Unix-domain-socket locally-focused Native_socket_stream to a TCP-networked version whose code would mostly
236 * be reusing us (a stream socket is a stream socket, in many ways, whether local or TCP). At that point
237 * we'd like this release() to be immediately visible to the developer. So that's why this is around. Naturally,
238 * its code might diverge over time, but at least as of this writing we suspect it's useful to keep this around,
239 * it doesn't get in the way too much. (Historically, it has not always been dead code and worked nicely.) */
240#if 0
241 /**
242 * In PEER state only, with no prior send or receive ops, returns a sync_io::Native_socket_stream core
243 * (as-if just constructed) operating on `*this` underlying low-level transport `Native_handle`; while
244 * `*this` becomes as-if default-cted.
245 *
246 * This can be useful if one desires a `sync_io` core -- e.g., to bundle into a Channel to then feed to
247 * a struc::Channel ctor -- after a successful async-I/O-style async_connect() advanced `*this`
248 * from NULL to CONNECTING to PEER state.
249 *
250 * In a sense it's the reverse of `*this` `sync_io`-core-adopting ctor.
251 *
252 * Behavior is undefined if `*this` is not in PEER state, or if it is, but you've invoked `async_receive_*()`,
253 * `send_*()`, `*end_sending()`, auto_ping(), or idle_timer_run() in the past. Please be careful.
254 *
255 * @return See above.
256 */
258#endif
259
260 /**
261 * See Native_socket_stream counterpart.
262 * @return See Native_socket_stream counterpart.
263 */
264 const std::string& nickname() const;
265
266 /**
267 * See Native_socket_stream counterpart.
268 *
269 * @param absolute_name
270 * See Native_socket_stream counterpart.
271 * @param err_code
272 * See Native_socket_stream counterpart.
273 * @return See Native_socket_stream counterpart.
274 */
275 bool sync_connect(const Shared_name& absolute_name, Error_code* err_code);
276
277 /**
278 * See Native_socket_stream counterpart.
279 *
280 * @param err_code
281 * See Native_socket_stream counterpart.
282 * @return See Native_socket_stream counterpart.
283 */
285
286 /**
287 * See Native_socket_stream counterpart.
288 *
289 * @param creds
290 * See Native_socket_stream counterpart.
291 * @return See Native_socket_stream counterpart.
292 */
294
295 /**
296 * See Native_socket_stream counterpart.
297 * @return See Native_socket_stream counterpart.
298 */
299 size_t send_meta_blob_max_size() const;
300
301 /**
302 * See Native_socket_stream counterpart.
303 * @return See Native_socket_stream counterpart.
304 */
305 size_t send_blob_max_size() const;
306
307 /**
308 * See Native_socket_stream counterpart.
309 *
310 * @param hndl_or_null
311 * See Native_socket_stream counterpart.
312 * @param meta_blob
313 * See Native_socket_stream counterpart.
314 * @param err_code
315 * See Native_socket_stream counterpart.
316 * @return See Native_socket_stream counterpart.
317 */
318 bool send_native_handle(Native_handle hndl_or_null, const util::Blob_const& meta_blob, Error_code* err_code);
319
320 /**
321 * See Native_socket_stream counterpart.
322 *
323 * @param blob
324 * See Native_socket_stream counterpart.
325 * @param err_code
326 * See Native_socket_stream counterpart.
327 * @return See Native_socket_stream counterpart.
328 */
329 bool send_blob(const util::Blob_const& blob, Error_code* err_code);
330
331 /**
332 * See Native_socket_stream counterpart.
333 *
334 * @param on_done_func
335 * See Native_socket_stream counterpart.
336 * @return See Native_socket_stream counterpart.
337 */
338 bool async_end_sending(flow::async::Task_asio_err&& on_done_func);
339
340 /// See Native_socket_stream counterpart. @return Ditto.
341 bool end_sending();
342
343 /**
344 * See Native_socket_stream counterpart.
345 *
346 * @param period
347 * See Native_socket_stream counterpart.
348 * @return See Native_socket_stream counterpart.
349 */
350 bool auto_ping(util::Fine_duration period);
351
352 /**
353 * See Native_socket_stream counterpart.
354 * @return See Native_socket_stream counterpart.
355 */
357
358 /// See Native_socket_stream counterpart.
360
361 /**
362 * See Native_socket_stream counterpart.
363 * @return See Native_socket_stream counterpart.
364 */
366
367 /// See Native_socket_stream counterpart.
369
370 /**
371 * See Native_socket_stream counterpart.
372 * @return See Native_socket_stream counterpart.
373 */
374 size_t receive_meta_blob_max_size() const;
375
376 /**
377 * See Native_socket_stream counterpart.
378 * @return See Native_socket_stream counterpart.
379 */
380 size_t receive_blob_max_size() const;
381
382 /**
383 * See Native_socket_stream counterpart.
384 *
385 * @param target_hndl
386 * See Native_socket_stream counterpart.
387 * @param target_meta_blob
388 * See Native_socket_stream counterpart.
389 * @param on_done_func
390 * See Native_socket_stream counterpart.
391 * @return See Native_socket_stream counterpart.
392 */
394 const util::Blob_mutable& target_meta_blob,
395 flow::async::Task_asio_err_sz&& on_done_func);
396
397 /**
398 * See Native_socket_stream counterpart.
399 *
400 * @param target_blob
401 * See Native_socket_stream counterpart.
402 * @param on_done_func
403 * See Native_socket_stream counterpart.
404 * @return See Native_socket_stream counterpart.
405 */
406 bool async_receive_blob(const util::Blob_mutable& target_blob,
407 flow::async::Task_asio_err_sz&& on_done_func);
408
409 /**
410 * See Native_socket_stream counterpart.
411 *
412 * @param batch
413 * See Native_socket_stream counterpart.
414 * @param assume_would_block
415 * See Native_socket_stream counterpart.
416 * @param on_done_func
417 * See Native_socket_stream counterpart.
418 * @return See Native_socket_stream counterpart.
419 */
420 template<typename Msg_resource>
422 flow::async::Task_asio_err&& on_done_func);
423
424 /**
425 * See Native_socket_stream counterpart.
426 *
427 * @param batch
428 * See Native_socket_stream counterpart.
429 * @param assume_would_block
430 * See Native_socket_stream counterpart.
431 * @param on_done_func
432 * See Native_socket_stream counterpart.
433 * @return See Native_socket_stream counterpart.
434 */
435 template<typename Msg_resource>
436 bool async_receive_blob_batch(Blob_batch_in<Msg_resource>* batch, bool assume_would_block,
437 flow::async::Task_asio_err&& on_done_func);
438
439 /**
440 * See Native_socket_stream counterpart.
441 *
442 * @param timeout
443 * See Native_socket_stream counterpart.
444 * @return See Native_socket_stream counterpart.
445 */
447
448 /**
449 * See Native_socket_stream counterpart.
450 * @return See Native_socket_stream counterpart.
451 */
453
454 /// See Native_socket_stream counterpart.
456
457 /**
458 * See Native_socket_stream counterpart.
459 * @return See Native_socket_stream counterpart.
460 */
462
463 /// See Native_socket_stream counterpart.
465
466private:
467 // Constructors.
468
469 /**
470 * Core delegated-to ctor: does everything except `m_sync_io.start_*_ops()`.
471 * Delegating ctor shall do nothing further if starting in NULL state;
472 * else (starting directly in PEER state) it will delegate `m_sync_io.start_receive/send_*_ops()`
473 * to #m_snd_sync_io_adapter and #m_rcv_sync_io_adapter which it will initialize.
474 *
475 * Therefore if entering PEER state due to successful `*_connect()`, #m_snd_sync_io_adapter and
476 * #m_rcv_sync_io_adapter will be created at that time.
477 *
478 * `get_logger()` and nickname() values are obtained from `sync_io_core_moved`.
479 *
480 * @param sync_io_core_moved
481 * A freshly constructed sync_io::Native_socket_stream subsumed by `*this` (this object
482 * becomes as-if-default-cted). It can be in NULL or PEER state.
483 * @param tag
484 * Ctor-selecting tag.
485 */
486 explicit Native_socket_stream_impl(sync_io::Native_socket_stream&& sync_io_core_moved, std::nullptr_t tag);
487
488 // Data.
489
490 // General data (both-direction pipes, not connect-ops-related).
491
492 /**
493 * Single-thread worker pool for all internal async work in both directions. Referred to as thread W in comments.
494 * See doc header impl section for discussion.
495 *
496 * Ordering: Must be either declared after mutex(es), or `.stop()`ed explicitly in dtor: Thread must be joined,
497 * before mutex possibly-locked-in-it destructs.
498 */
499 flow::async::Single_thread_task_loop m_worker;
500
501 /**
502 * The core `Native_socket_stream` engine, implementing the `sync_io` pattern (see util::sync_io doc header).
503 * See our class doc header for overview of how we use it (the aforementioned `sync_io` doc header talks about
504 * the `sync_io` pattern generally).
505 *
506 * Thus, #m_sync_io is the synchronous engine that we use to perform our work in our asynchronous boost.asio
507 * loop running in thread W (#m_worker) while collaborating with user thread(s) a/k/a thread U.
508 * (Recall that the user may choose to set up their own event loop/thread(s) --
509 * boost.asio-based or otherwise -- and use their own equivalent of an #m_sync_io instead.)
510 *
511 * ### Order subtlety versus `m_worker` ###
512 * When constructing #m_sync_io, we need the `Task_engine` from #m_worker. On the other hand tasks operating
513 * in #m_worker access #m_sync_io. So in destructor it is important to `m_worker.stop()` explicitly, so that
514 * the latter is no longer a factor. Then when automatic destruction occurs in the opposite order of
515 * creation, the fact that #m_sync_io is destroyed before #m_worker has no bad effect.
516 */
518
519 // Send-ops data.
520
521 /**
522 * Null until PEER state, this handles ~all send-ops logic in that state. sync_io::Async_adapter_sender adapts
523 * any sync_io::Native_handle_sender and makes available ~all necessary async-I/O Native_handle_sender APIs.
524 * So in PEER state we forward ~everything to this guy.
525 *
526 * ### Creation ###
527 * By its contract, this guy's ctor will handle what it needs to, as long as #m_worker (to which it stores a pointer)
528 * has been `.start()`ed by that time, and #m_sync_io (to which it stores... ditto) has been
529 * `.replace_event_wait_handles()`ed as required.
530 *
531 * ### Destruction ###
532 * By its contract, this guy's dtor will handle what it needs to, as long as #m_worker (to which it stores a pointer)
533 * has been `.stop()`ed by that time, and any queued-up (ready to execute) handlers on it have been
534 * `Task_engine::poll()`ed-through by that time as well.
535 */
537
538 // Receive-ops data.
539
540 /**
541 * Null until PEER state, this handles ~all receive-ops logic in that state. sync_io::Async_adapter_receiver adapts
542 * any sync_io::Native_handle_receiver and makes available ~all necessary async-I/O Native_handle_receiver APIs.
543 * So in PEER state we forward ~everything to this guy.
544 *
545 * ### Creation ###
546 * See #m_snd_sync_io_adapter -- same stuff.
547 *
548 * ### Destruction ###
549 * See #m_snd_sync_io_adapter -- same stuff.
550 */
552}; // class Native_socket_stream_impl
553
554// Free functions: in *_fwd.hpp.
555
556// Template implementations.
557
558template<typename Msg_resource>
560 bool assume_would_block,
561 flow::async::Task_asio_err&& on_done_func)
562{
564 ? (m_rcv_sync_io_adapter->async_receive_native_handle_batch
565 (batch, assume_would_block, std::move(on_done_func)),
566 true) // It's void.
567 : false;
568}
569
570template<typename Msg_resource>
572 bool assume_would_block,
573 flow::async::Task_asio_err&& on_done_func)
574{
576 ? (m_rcv_sync_io_adapter->async_receive_blob_batch
577 (batch, assume_would_block, std::move(on_done_func)),
578 true) // It's void.
579 : false;
580}
581
582} // namespace ipc::transport
Internal, non-movable pImpl-lite implementation of Native_socket_stream class.
bool sync_connect(const Shared_name &absolute_name, Error_code *err_code)
See Native_socket_stream counterpart.
void native_handle_receive_stats_reset()
See Native_socket_stream counterpart.
const std::string & nickname() const
See Native_socket_stream counterpart.
bool send_native_handle(Native_handle hndl_or_null, const util::Blob_const &meta_blob, Error_code *err_code)
See Native_socket_stream counterpart.
Blob_rcv_stats native_handle_receive_stats() const
See Native_socket_stream counterpart.
const util::Process_credentials & remote_peer_process_credentials(Error_code *err_code) const
See Native_socket_stream counterpart.
Blob_snd_stats blob_send_stats() const
See Native_socket_stream counterpart.
bool auto_ping(util::Fine_duration period)
See Native_socket_stream counterpart.
void blob_send_stats_reset()
See Native_socket_stream counterpart.
sync_io::Native_socket_stream::template Native_handle_batch_in< Msg_resource > Native_handle_batch_in
See Native_socket_stream counterpart.
Blob_rcv_stats blob_receive_stats() const
See Native_socket_stream counterpart.
bool idle_timer_run(util::Fine_duration timeout)
See Native_socket_stream counterpart.
typename sync_io::Native_socket_stream::template Blob_batch_in< Msg_resource > Blob_batch_in
See Native_socket_stream counterpart / transport::Blob_receiver::Blob_batch_in.
sync_io::Native_socket_stream m_sync_io
The core Native_socket_stream engine, implementing the sync_io pattern (see util::sync_io doc header)...
bool async_end_sending(flow::async::Task_asio_err &&on_done_func)
See Native_socket_stream counterpart.
void blob_receive_stats_reset()
See Native_socket_stream counterpart.
bool async_receive_blob_batch(Blob_batch_in< Msg_resource > *batch, bool assume_would_block, flow::async::Task_asio_err &&on_done_func)
See Native_socket_stream counterpart.
std::optional< sync_io::Async_adapter_sender< decltype(m_sync_io)> > m_snd_sync_io_adapter
Null until PEER state, this handles ~all send-ops logic in that state.
bool async_receive_native_handle_batch(Native_handle_batch_in< Msg_resource > *batch, bool assume_would_block, flow::async::Task_asio_err &&on_done_func)
See Native_socket_stream counterpart.
size_t receive_blob_max_size() const
See Native_socket_stream counterpart.
Blob_snd_stats native_handle_send_stats() const
See Native_socket_stream counterpart.
size_t send_blob_max_size() const
See Native_socket_stream counterpart.
void native_handle_send_stats_reset()
See Native_socket_stream counterpart.
std::optional< sync_io::Async_adapter_receiver< decltype(m_sync_io)> > m_rcv_sync_io_adapter
Null until PEER state, this handles ~all receive-ops logic in that state.
size_t receive_meta_blob_max_size() const
See Native_socket_stream counterpart.
Native_socket_stream_impl(flow::log::Logger *logger_ptr, util::String_view nickname_str)
See Native_socket_stream counterpart.
bool end_sending()
See Native_socket_stream counterpart.
bool async_receive_blob(const util::Blob_mutable &target_blob, flow::async::Task_asio_err_sz &&on_done_func)
See Native_socket_stream counterpart.
bool async_receive_native_handle(Native_handle *target_hndl, const util::Blob_mutable &target_meta_blob, flow::async::Task_asio_err_sz &&on_done_func)
See Native_socket_stream counterpart.
~Native_socket_stream_impl()
See Native_socket_stream counterpart.
bool send_blob(const util::Blob_const &blob, Error_code *err_code)
See Native_socket_stream counterpart.
size_t send_meta_blob_max_size() const
See Native_socket_stream counterpart.
flow::async::Single_thread_task_loop m_worker
Single-thread worker pool for all internal async work in both directions.
Type that adapts a given PEER-state sync_io::Native_handle_receiver or sync_io::Blob_receiver core in...
Type that adapts a given PEER-state sync_io::Native_handle_sender or sync_io::Blob_sender core into t...
Implements both sync_io::Native_handle_sender and sync_io::Native_handle_receiver concepts by using a...
A process's credentials (PID, UID, GID as of this writing).
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
Definition: util_fwd.hpp:137
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
Definition: util_fwd.hpp:114
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
Definition: util_fwd.hpp:131
flow::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.