24#include <flow/error/error.hpp>
25#include <flow/common.hpp>
26#include <boost/move/make_unique.hpp>
44 flow::log::Log_context(logger_ptr,
Log_component::S_TRANSPORT),
45 m_absolute_name(absolute_name_arg),
46 m_worker(get_logger(),
49 flow::util::ostream_op_string(
"NSSA-", m_absolute_name.str())),
50 m_next_peer_socket(*(m_worker.task_engine()))
59 using flow::error::Runtime_error;
60 using flow::async::reset_thread_pinning;
61 using boost::system::system_error;
69 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Awaiting initial setup/listening in worker thread.");
72 reset_thread_pinning(get_logger());
74 auto const asio_engine =
m_worker.task_engine();
76 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: Starting (am in worker thread).");
78 const auto local_endpoint = endpoint_at_shared_name<Protocol>(get_logger(),
m_absolute_name, &sys_err_code);
79 assert((local_endpoint ==
Endpoint{}) ==
bool(sys_err_code));
94 catch (
const system_error& exc)
97 FLOW_LOG_WARNING(
"Acceptor [" << *
this <<
"]: Unable to open/bind/listen native local stream socket; could "
98 "be due to address/name clash; details logged below.");
99 sys_err_code = exc.code();
100 FLOW_ERROR_SYS_ERROR_LOG_WARNING();
104 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: "
105 "Successfully made endpoint and open/bind/listen-ed on it. Ready for connections.");
119 assert(!sys_err_code);
132 *err_code = sys_err_code;
136 throw Runtime_error{sys_err_code, FLOW_UTIL_WHERE_AM_I_STR()};
139 assert(!sys_err_code);
140 err_code && (*err_code = {});
142 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: Ready for incoming connections.");
147 using flow::async::Single_thread_task_loop;
148 using flow::async::reset_thread_pinning;
149 using flow::util::ostream_op_string;
153 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: Shutting down. Next acceptor socket will close; all our internal "
154 "async handlers will be canceled; and worker thread will be joined.");
162 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: Continuing shutdown. Next we will run pending handlers from some "
163 "other thread. In this user thread we will await those handlers' completion and then return.");
164 Single_thread_task_loop one_thread{get_logger(), ostream_op_string(
"NSSADeinit-",
m_absolute_name.
str())};
166 one_thread.start([&]()
168 reset_thread_pinning(get_logger());
170 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: "
171 "In transient finisher thread: Shall run all pending internal handlers (typically none).");
173 const auto task_engine =
m_worker.task_engine();
174 task_engine->restart();
175 const auto count = task_engine->poll();
178 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: "
179 "In transient finisher thread: Ran [" << count <<
"] internal handlers after all.");
183 FLOW_LOG_INFO(
"Acceptor [" << *
this <<
"]: "
184 "In transient finisher thread: Shall run all pending user handlers (feeding operation-aborted).");
188 FLOW_LOG_TRACE(
"Running a queued async-accept completion handler.");
192 FLOW_LOG_TRACE(
"User accept handler finished. Popped from user request deficit queue.");
195 FLOW_LOG_INFO(
"Transient finisher exiting.");
202 using flow::util::ostream_op_string;
203 using std::holds_alternative;
206 if (sys_err_code == boost::asio::error::operation_aborted)
211 assert(sys_err_code != boost::asio::error::would_block);
213 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Incoming connection, or error when trying to accept one.");
220 if (sys_err_code == boost::asio::error::connection_aborted)
222 FLOW_LOG_WARNING(
"Incoming connection aborted halfway during connection; this is quite weird but "
223 "should not be fatal. Ignoring. Still listening.");
228 FLOW_LOG_WARNING(
"Acceptor [" << *
this <<
"]: The background accept failed fatally. "
229 "Closing acceptor; no longer listening. Details follow.");
230 FLOW_ERROR_SYS_ERROR_LOG_WARNING();
283 static_assert(
false,
"Should not have gotten to this line; should have required Linux; "
284 "the next thing assumes not-Win-<8.1.");
289 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: "
290 "Ejected ownership of new incoming peer socket [" << native_peer_socket <<
"].");
293 = boost::movelib::make_unique<Peer>
297 std::move(native_peer_socket));
299 assert(native_peer_socket.null());
319 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Starting the next background accept.");
330 using boost::movelib::make_unique;
332 using std::holds_alternative;
345 m_worker.post([
this, target_peer, on_done_func = std::move(on_done_func)]
350 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Handling async-accept request.");
352 auto new_req = make_unique<User_request>();
353 new_req->m_target_peer = target_peer;
354 new_req->m_on_done_func = std::move(on_done_func);
362 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: New async-accept request pushed onto deficit queue; "
363 "but there is no surplus (no pending results). Will await results.");
373 if (holds_alternative<Error_code>(peer_or_err_code))
376 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: New async-request pushed onto deficit queue; "
377 "and there is surplus in the form of a fatal error code. Will feed error to the request "
378 "*without* popping it from surplus queue (size remains 1).");
383 assert(holds_alternative<Peer_ptr>(peer_or_err_code));
385 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: New async-request pushed onto deficit queue; "
386 "and there is surplus in the form of a new peer handle. Will feed handle to the request. "
389 Peer_ptr peer{std::move(get<Peer_ptr>(peer_or_err_code))};
399 using std::holds_alternative;
407 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Fatal error pushed onto surplus queue; "
408 "but there is no deficit (no pending requests). Will await async-accept request(s).");
418 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Fatal error pushed onto surplus queue; "
419 "and there is deficit (1+ pending requests). Will feed error to all pending requests *without* "
420 "popping surplus queue, whose size remains 1.");
427 using std::holds_alternative;
435 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: New peer socket handle pushed onto surplus queue; "
436 "but there is no deficit (no pending requests). Will await async-accept request(s).");
447 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: New peer socket handle pushed onto surplus queue; "
448 "and there is deficit (1+ pending requests). Will feed to next pending request, having "
449 "popped it from surplus queue (size is now 0).");
460 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Feeding to user async-accept request handler [" << idx <<
"]: "
461 "Error code [" << err_code <<
"] [" << err_code.message() <<
"].");
474 FLOW_LOG_TRACE(
"Acceptor [" << *
this <<
"]: Feeding to user async-accept request handler: "
475 "Socket stream [" << *peer <<
"]. User request queue size post-pop is "
478 *head_request->m_target_peer = std::move(*peer);
490 return os <<
"sh_name[" << val.
absolute_name() <<
"]@" <<
static_cast<const void*
>(&val);
A server object that binds to a Shared_name and listens for incoming Native_socket_stream connect att...
asio_local_stream_socket::Peer_socket< Native_socket_stream_cfg::Protocol > m_next_peer_socket
Unix domain peer socket, always empty/unconnected while a background m_acceptor.async_accept() is pro...
static const Shared_name & S_RESOURCE_TYPE_ID
Shared_name relative-folder fragment (no separators) identifying this resource type.
void async_accept_impl(Peer *target_peer, On_peer_accepted_func &&on_done_func)
Non-template impl of async_accept().
flow::async::Single_thread_task_loop m_worker
A single-threaded async task loop that starts in constructor and ends in destructor.
const Shared_name m_absolute_name
See absolute_name().
boost::movelib::unique_ptr< Peer > Peer_ptr
Short-hand for internally stored PEER-state sync_io::Native_socket_stream in m_pending_results_q.
std::queue< User_request::Ptr > m_pending_user_requests_q
Queue storing deficit async-accept requests queued up due to lacking pending ready peer socket handle...
void finalize_q_surplus_on_error()
In thread W, in steady state except for an Error_code just pushed to the back of m_pending_results_q ...
~Native_socket_stream_acceptor()
Destroys this acceptor which will stop listening in the background and cancel any pending completion ...
void feed_error_result_to_deficit(const Error_code &err_code)
In thread W, gets back to steady state by feeding the given Error_code (which must be the sole elemen...
boost::movelib::unique_ptr< asio_local_stream_socket::Acceptor< Native_socket_stream_cfg::Protocol > > m_acceptor
Unix domain socket acceptor.
flow::async::Task_asio_err On_peer_accepted_func
Short-hand for callback called on new peer-to-peer connection; or on unrecoverable error.
void finalize_q_surplus_on_success()
In thread W, in steady state, introduces the just-established peer socket handle into the state machi...
std::queue< std::variant< Peer_ptr, Error_code > > m_pending_results_q
Queue storing surplus finalized async-accept results queued up due to lacking async_accept() requests...
Native_socket_stream_acceptor(flow::log::Logger *logger_ptr, const Shared_name &absolute_name, Error_code *err_code=nullptr)
Creates the Native_socket_stream_acceptor and immediately begins listening in the background,...
const Shared_name & absolute_name() const
Returns the full name/address to which the constructor bound, or attempted to bind,...
void feed_success_result_to_deficit(Peer_ptr &&peer)
In thread W, gets back to steady state by feeding the given just-connected peer socket (which must ha...
void on_next_peer_socket_or_error(const Error_code &sys_err_code)
Handler for incoming connection on m_acceptor.
std::conditional_t< S_USE_OS_DGRAM_SUPPORT, asio_local_stream_socket::Protocol_pkt_stream, asio_local_stream_socket::Protocol_byte_stream > Protocol
sync_io::Native_socket_stream and derivative(s) shall internally use a boost.asio socket type of this...
Implements both sync_io::Native_handle_sender and sync_io::Native_handle_receiver concepts by using a...
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
const std::string & str() const
Returns (sans copying) ref to immutable entire wrapped name string, suitable to pass into sys calls w...
Endpoint< Protocol > endpoint_at_shared_name(flow::log::Logger *logger_ptr, const Shared_name &absolute_name, Error_code *err_code)
Returns an Endpoint corresponding to the given absolute Shared_name, so that an Acceptor or Peer_sock...
typename Protocol::endpoint Endpoint
Short-hand for boost.asio Unix domain peer stream-socket endpoint.
typename Protocol::acceptor Acceptor
Short-hand for boost.asio Unix domain stream-socket acceptor (listening guy) socket.
@ S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER
Async completion handler is being called prematurely, because underlying object is shutting down,...
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
std::ostream & operator<<(std::ostream &os, const Generic_msg_batch_in< Msg_resource_t, NO_HNDLS > &val)
Prints string representation of the given Generic_msg_batch_in to the given ostream.
util::Shared_name Shared_name
Convenience alias for the commonly used type util::Shared_name.
flow::util::String_view String_view
Short-hand for Flow's String_view.
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.