23#include "ipc/session/schema/detail/session_master_channel.capnp.h"
30#include <boost/thread/future.hpp>
82template<schema::MqType MQ_TYPE_OR_NONE,
bool TRANSMIT_NATIVE_HANDLES,
typename Mdt_payload>
84 private boost::noncopyable
90 static constexpr bool S_MQS_ENABLED = MQ_TYPE_OR_NONE != schema::MqType::NONE;
97 static_assert(MQ_TYPE_OR_NONE != schema::MqType::END_SENTINEL,
98 "Do not use the value END_SENTINEL for MQ_TYPE_OR_NONE; it is only a sentinel. Did you mean NONE?");
101 static_assert(std::is_enum_v<schema::MqType>,
102 "Sanity-checking capnp-generated MqType enum (must be an enum).");
103 static_assert(std::is_unsigned_v<std::underlying_type_t<schema::MqType>>,
104 "Sanity-checking capnp-generated MqType enum (backing type must be unsigned).");
105 static_assert((int(schema::MqType::END_SENTINEL) - 1) == 2,
106 "Code apparently must be updated -- expected exactly 2 MqType enum values plus NONE + sentinel.");
107 static_assert((int(schema::MqType::POSIX) != int(schema::MqType::BIPC))
108 && (
int(schema::MqType::POSIX) > int(schema::MqType::NONE))
109 && (
int(schema::MqType::BIPC) > int(schema::MqType::NONE))
110 && (
int(schema::MqType::POSIX) < int(schema::MqType::END_SENTINEL))
111 && (
int(schema::MqType::BIPC) < int(schema::MqType::END_SENTINEL)),
112 "Code apparently must be updated -- "
113 "expected exactly 2 particular MqType enum values plus NONE + sentinel.");
122 std::conditional_t<MQ_TYPE_OR_NONE == schema::MqType::POSIX,
129 <TRANSMIT_NATIVE_HANDLES,
133 <TRANSMIT_NATIVE_HANDLES,
351 schema::detail::SessionMasterChannelMessageBody
587 public flow::log::Log_context,
588 private boost::noncopyable
621 flow::async::Single_thread_task_loop* async_worker,
681 flow::async::Task_asio_err&& on_err_func,
879#define TEMPLATE_SESSION_BASE \
880 template<schema::MqType MQ_TYPE_OR_NONE, bool TRANSMIT_NATIVE_HANDLES, typename Mdt_payload>
882#define CLASS_SESSION_BASE \
883 Session_base<MQ_TYPE_OR_NONE, TRANSMIT_NATIVE_HANDLES, Mdt_payload>
889 flow::async::Task_asio_err&& on_err_func,
897 m_srv_app_ref(srv_app_ref),
898 m_cli_app_ptr(&cli_app_ref),
899 m_on_err_func(std::move(on_err_func)),
900 m_on_passive_open_channel_func_or_empty(std::move(on_passive_open_channel_func_or_empty_arg)),
902 m_dtor_started(false)
908CLASS_SESSION_BASE::Session_base(
const Server_app& srv_app_ref) :
917 m_srv_app_ref(srv_app_ref),
918 m_cli_app_ptr(nullptr),
920 m_srv_namespace(
Shared_name::ct(std::to_string(util::Process_credentials::own_process_id()))),
922 m_dtor_started(false)
928void CLASS_SESSION_BASE::set_cli_app_ptr(
const Client_app* cli_app_ptr_new)
930 assert(cli_app_ptr_new &&
"As of this writing cli_app_ptr should be set at most once, from null to non-null.");
933 const auto prev = m_cli_app_ptr.exchange(cli_app_ptr_new);
934 assert((!prev) &&
"As of this writing cli_app_ptr should be set at most once, from null to non-null.");
936 m_cli_app_ptr = cli_app_ptr_new;
941void CLASS_SESSION_BASE::set_srv_namespace(
Shared_name&& srv_namespace_new)
943 assert(!srv_namespace_new.empty());
945 assert(m_srv_namespace.empty() &&
"As of this writing srv_namespace should be set at most once, from empty.");
947 m_srv_namespace = std::move(srv_namespace_new);
951void CLASS_SESSION_BASE::set_cli_namespace(
Shared_name&& cli_namespace_new)
953 assert(!cli_namespace_new.empty());
955 assert(m_cli_namespace.empty() &&
"As of this writing cli_namespace should be set at most once, from empty.");
957 m_cli_namespace = std::move(cli_namespace_new);
961void CLASS_SESSION_BASE::reset_namespaces()
963 m_srv_namespace.clear();
964 m_cli_namespace.clear();
970 assert(m_on_passive_open_channel_func_or_empty.empty());
971 m_on_passive_open_channel_func_or_empty = std::move(on_passive_open_channel_func);
975void CLASS_SESSION_BASE::set_on_err_func(flow::async::Task_asio_err&& on_err_func_arg)
977 assert(!on_err_func_arg.empty());
978 assert(m_on_err_func.empty() &&
"Call set_on_err_func() once at most and only if not already set through ctor.");
980 m_on_err_func = std::move(on_err_func_arg);
986 return m_cli_app_ptr.load();
992 return m_srv_namespace;
998 return m_cli_namespace;
1002const typename CLASS_SESSION_BASE::On_passive_open_channel_func&
1003 CLASS_SESSION_BASE::on_passive_open_channel_func_or_empty()
const
1005 return m_on_passive_open_channel_func_or_empty;
1009bool CLASS_SESSION_BASE::on_err_func_set()
const
1011 return !m_on_err_func.empty();
1017 assert((!hosed()) &&
"By contract do not call unless hosed() is false.");
1019 m_peer_state_err_code_or_ok = err_code;
1020 m_on_err_func(err_code);
1024bool CLASS_SESSION_BASE::hosed()
const
1026 assert(on_err_func_set() &&
"By contract do not call until PEER state -- when on-error handler must be known.");
1027 return bool(m_peer_state_err_code_or_ok);
1031void CLASS_SESSION_BASE::set_dtor_started()
1033 assert((!m_dtor_started) &&
"By contract call at most once.");
1034 m_dtor_started =
true;
1038bool CLASS_SESSION_BASE::dtor_started()
const
1040 return m_dtor_started;
1044Shared_name CLASS_SESSION_BASE::cur_ns_store_mutex_absolute_name()
const
1046 using std::to_string;
1056 mutex_name /=
"cur_ns_store";
1067 mutex_name += to_string(m_srv_app_ref.m_user_id);
1069 mutex_name += to_string(m_srv_app_ref.m_group_id);
1071 mutex_name += to_string(
int(m_srv_app_ref.m_permissions_level_for_client_apps));
1077fs::path CLASS_SESSION_BASE::cur_ns_store_absolute_path()
const
1079 using Path = fs::path;
1081 Path path(m_srv_app_ref.m_kernel_persistent_run_dir_override.empty()
1083 : m_srv_app_ref.m_kernel_persistent_run_dir_override);
1084 path /= m_srv_app_ref.m_name;
1085 path +=
".libipc-cns.pid";
1090Shared_name CLASS_SESSION_BASE::session_master_socket_stream_acceptor_absolute_name()
const
1092 assert((!m_srv_namespace.empty()) &&
"Serv-namespace must have been set by set_srv_namespace() by now.");
1110CLASS_SESSION_BASE::Graceful_finisher::Graceful_finisher(flow::log::Logger* logger_ptr,
Session_base* this_session,
1111 flow::async::Single_thread_task_loop* async_worker,
1113 flow::log::Log_context(logger_ptr,
Log_component::S_SESSION),
1114 m_this_session(this_session),
1115 m_async_worker(async_worker),
1116 m_master_channel(master_channel)
1129 FLOW_LOG_INFO(
"Received GracefulSessionEnd from opposing Session object along session master channel "
1131 "error; and mark it down. If our Session dtor is running, it shall return soon. If it has "
1132 "not yet run, it shall return immediately upon starting to execute.");
1155void CLASS_SESSION_BASE::Graceful_finisher::on_master_channel_hosed()
1157 using boost::promise_already_satisfied;
1162 m_opposing_session_done.set_value();
1164 catch (
const promise_already_satisfied&)
1171void CLASS_SESSION_BASE::Graceful_finisher::on_dtor_start()
1173 using flow::async::Synchronicity;
1179 m_async_worker->post([&]()
1181 FLOW_LOG_INFO(
"In Session object dtor sending GracefulSessionEnd to opposing Session object along "
1182 "session master channel [" << *m_master_channel <<
"] -- if at all possible.");
1183 assert(m_this_session->dtor_started()
1184 &&
"By contract the *_session_impl dtor posts set_dtor_started() before any Graceful_finisher task.");
1186 auto msg = m_master_channel->create_msg();
1187 msg.body_root()->initGracefulSessionEnd();
1190 m_master_channel->send(&msg,
nullptr, &err_code_ignored);
1194 }, Synchronicity::S_ASYNC_AND_AWAIT_CONCURRENT_COMPLETION);
1198 FLOW_LOG_INFO(
"In Session object dtor we now await sign that the opposing Session object dtor has also started; "
1199 "only then will we proceed with destroying our Session object: e.g., maybe they hold handles "
1200 "to objects in a SHM-arena we would deinitialize. If their dtor has already been called, we will "
1201 "proceed immediately. If not, we will now wait for that. This would only block if the opposing "
1202 "side's user code neglects to destroy Session object on error; or has some kind of blocking "
1203 "operation in progress before destroying Session object. "
1204 "Session master channel: [" << *m_master_channel <<
"].");
1205 m_opposing_session_done.get_future().wait();
1206 FLOW_LOG_INFO(
"In Session object dtor: Done awaiting sign that the opposing Session object dtor has also started. "
1207 "Will now proceed with our Session object destruction.");
1211typename CLASS_SESSION_BASE::Structured_msg_reader_config
1212 CLASS_SESSION_BASE::heap_reader_config(flow::log::Logger* logger_ptr)
1217 &transport::struc::stat::Heap_serializer_global_stats::get().stats_mutable_default().m_rcv };
1220#undef CLASS_SESSION_BASE
1221#undef TEMPLATE_SESSION_BASE
Bundles access to stats from the session master channel (SMC) – the internal struc::Channel each Sess...
Optional to use by subclasses, this operates a simple state machine that carries out a graceful-sessi...
flow::async::Single_thread_task_loop * m_async_worker
The containing Session thread W loop. It shall exist until *this is gone.
Session_base *const m_this_session
The containing Session_base. It shall exist until *this is gone.
void on_master_channel_hosed()
Must be invoked if the *_session_impl detects that the master channel has emitted channel-hosing erro...
void on_dtor_start()
The reason Graceful_finisher exists, this method must be called at the start of *_session_impl dtor; ...
Graceful_finisher(flow::log::Logger *logger_ptr, Session_base *this_session, flow::async::Single_thread_task_loop *async_worker, Master_structured_channel *master_channel)
You must invoke this ctor (instantiate us) if and only if synchronized dtor execution is indeed requi...
Master_structured_channel * m_master_channel
The containing Session master channel. It shall exist until *this is gone.
boost::promise< void > m_opposing_session_done
A promise whose fulfillment is a necessary and sufficient condition for on_dtor_start() returning (le...
Internal type containing data and types common to internal types Server_session_impl and Client_sessi...
const On_passive_open_channel_func & on_passive_open_channel_func_or_empty() const
The on-passive-open handler (may be empty even in final state, meaning user wants passive-opens disab...
bool m_dtor_started
Read/written in thread W only; false until the *_session_impl dtor – as its first act – posts a task ...
static constexpr bool S_MQS_ENABLED
See Session_mv.
static constexpr util::Fine_duration S_OPEN_CHANNEL_TIMEOUT
Internal timeout for open_channel().
const Client_app * cli_app_ptr() const
See Server_session_impl, Client_session_impl.
bool on_err_func_set() const
Returns true if and only if set_on_err_func() has been called, or equivalently if error-handler was s...
bool dtor_started() const
Returns true if and only if set_dtor_started() has been called.
void reset_namespaces()
Restores srv_namespace() and cli_namespace() to the never-yet-set (empty) state.
Session_base(const Client_app &cli_app_ref, const Server_app &srv_app_ref, flow::async::Task_asio_err &&on_err_func, On_passive_open_channel_func &&on_passive_open_channel_func_or_empty_arg)
Constructs: Client_session_impl form (the user is the one constructing the object,...
void hose(const Error_code &err_code)
Marks this session as hosed for (truthy) reason err_code; and synchronously invokes on-error handler;...
Error_code m_peer_state_err_code_or_ok
Starts falsy; becomes forever truthy (with a specific Error_code that will not change thereafter) onc...
void set_cli_namespace(Shared_name &&cli_namespace_new)
Sets cli_namespace() (do not call if already set).
void set_cli_app_ptr(const Client_app *cli_app_ptr_new)
Sets cli_app_ptr() (do not call if already set).
const Shared_name & srv_namespace() const
See Server_session_impl, Client_session_impl.
std::atomic< const Client_app * > m_cli_app_ptr
See cli_app_ptr().
void set_on_passive_open_channel_func(On_passive_open_channel_func &&on_passive_open_channel_func)
Sets on_passive_open_channel_func_or_empty() (do not call if already set; do not call if user intends...
static constexpr size_t S_MQS_MAX_MSG_SZ
The default max sendable MQ message size as decided by Server_session_impl::make_channel_mqs() (and i...
std::vector< Channel_obj > Channels
See Session_mv. Note: If changed from vector please update those doc headers too.
const Shared_name & cli_namespace() const
See Server_session_impl, Client_session_impl.
bool hosed() const
Returns true if and only if hose() has been called.
boost::shared_ptr< Master_structured_channel > Master_structured_channel_ptr
Handle to Master_structured_channel.
On_passive_open_channel_func m_on_passive_open_channel_func_or_empty
See on_passive_open_channel_func_or_empty().
void set_on_err_func(flow::async::Task_asio_err &&on_err_func_arg)
Sets on_err_func() (do not call if already set).
void set_srv_namespace(Shared_name &&srv_namespace_new)
Sets srv_namespace() (do not call if already set).
fs::path cur_ns_store_absolute_path() const
Computes the absolute path to file storing (written by server, read by client) the value for srv_name...
typename transport::struc::schema::Metadata< Mdt_payload_obj >::Builder Mdt_builder
See Session_mv (or Session concept).
boost::weak_ptr< Master_structured_channel > Master_structured_channel_observer
Observer of Master_structured_channel_ptr. See its doc header.
Function< void(Channel_obj &&new_channel, Mdt_reader_ptr &&new_channel_mdt)> On_passive_open_channel_func
Concrete function type for the on-passive-open handler (if any), used for storage.
Shared_name m_srv_namespace
See srv_namespace().
boost::shared_ptr< typename transport::struc::schema::Metadata< Mdt_payload_obj >::Reader > Mdt_reader_ptr
See Session_mv (or Session concept).
flow::async::Task_asio_err m_on_err_func
See set_on_err_func().
Mdt_payload Mdt_payload_obj
See Session_mv (or Session concept).
static Structured_msg_reader_config heap_reader_config(flow::log::Logger *logger_ptr)
See Session_mv::heap_reader_config() (1-arg).
Shared_name m_cli_namespace
See cli_namespace().
boost::shared_ptr< Mdt_builder > Mdt_builder_ptr
See Session_mv (or Session concept).
void set_dtor_started()
Marks the *_session_impl dtor as having begun; from then on dtor_started() returns true,...
const Server_app & m_srv_app_ref
Reference to Server_app (referring to local process in Server_session_impl, opposing process in Clien...
static constexpr bool S_SOCKET_STREAM_ENABLED
See Session_mv.
std::conditional_t<!S_MQS_ENABLED, transport::Null_peer, std::conditional_t< MQ_TYPE_OR_NONE==schema::MqType::POSIX, transport::Posix_mq_handle, transport::Bipc_mq_handle > > Persistent_mq_handle_from_cfg
Relevant only if S_MQS_ENABLED, this is the Persistent_mq_handle-concept impl type specified by the u...
Shared_name session_master_socket_stream_acceptor_absolute_name() const
Computes the absolute name at which the server shall set up a transport::Native_socket_stream_accepto...
Shared_name cur_ns_store_mutex_absolute_name() const
Computes the name of the interprocess named-mutex used to control reading/writing to the file storing...
std::conditional_t< S_MQS_ENABLED, std::conditional_t< TRANSMIT_NATIVE_HANDLES, transport::Mqs_socket_stream_channel< true, Persistent_mq_handle_from_cfg >, transport::Mqs_channel< true, Persistent_mq_handle_from_cfg > >, std::conditional_t< TRANSMIT_NATIVE_HANDLES, transport::Socket_stream_channel< true >, transport::Socket_stream_channel_of_blobs< true > > > Channel_obj
See Session_mv (or Session concept).
Implements the Persistent_mq_handle concept by thinly wrapping bipc::message_queue,...
A Channel with at least a blobs pipe consisting of two MQs of type Persistent_mq_handle (template arg...
A Channel with a blobs pipe consisting of 2 MQs of type Persistent_mq_handle (template arg); and a ha...
static const Shared_name & S_RESOURCE_TYPE_ID
Shared_name relative-folder fragment (no separators) identifying this resource type.
Dummy type for use as a template param to Channel when either the blobs pipe or handles pipe is disab...
Implements the Persistent_mq_handle concept by wrapping the POSIX message queue API (see man mq_overv...
A Channel with a blobs pipe only (no handles pipe) that uses a Unix domain socket connection as the u...
A Channel with a handles pipe only (no blobs pipe) that uses a Unix domain socket connection as the u...
Owning and wrapping a pre-connected transport::Channel peer (an endpoint of an established channel ov...
bool expect_msg(Msg_which_in which, On_msg_handler &&on_msg_func)
Registers the expectation of up to 1 notification in-message whose Msg_which equals which.
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
static const Shared_name S_SENTINEL
A Shared_name fragment, with no S_SEPARATOR characters inside, that represents a path component that ...
static Shared_name ct(const Source &src)
Copy-constructs from a char-sequence container such as string or util::String_view.
static const Shared_name S_RESOURCE_TYPE_ID_MUTEX
Relative-folder fragment (no separators) identifying the resource type for: boost....
@ S_SESSION_FINISHED
The opposing end of the session in question has been closed gracefully by the user invoking the end-s...
Flow-IPC module providing the broad lifecycle and shared-resource organization – via the session conc...
Shared_name build_conventional_shared_name(const Shared_name &resource_type, const Shared_name &srv_app_name, const Shared_name &srv_namespace, const Shared_name &cli_app_name, const Shared_name &cli_namespace_or_sentinel)
Builds an absolute name according to the path convention explained in Shared_name class doc header; t...
Builder< ipc::shm::classic::Pool_arena > Builder
Convenience alias: transport::struc::shm::Builder that works with boost.ipc.shm pools from ipc::shm::...
Reader< ipc::shm::classic::Pool_arena > Reader
Convenience alias: transport::struc::shm::Reader that works with boost.ipc.shm pools from ipc::shm::c...
const fs::path IPC_KERNEL_PERSISTENT_RUN_DIR
Absolute path to the directory (without trailing separator) in the file system where kernel-persisten...
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
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.
flow::Function< Signature > Function
Short-hand for polymorphic functor holder which is very common. This is essentially std::function.
#define TEMPLATE_SESSION_BASE
Internally used macro; public API users should disregard (same deal as in struc/channel....
An App that is used as a client in at least one client-server IPC split.
An App that is used as a server in at least one client-server IPC split.
Implements Struct_builder::Config sub-concept.
Implements Struct_reader::Config sub-concept.