Flow-IPC 1.0.1
Flow-IPC project: Full implementation reference.
Classes | Public Types | Public Member Functions | Public Attributes | Protected Member Functions | Private Types | Private Attributes | Related Functions | List of all members
ipc::session::Session_server_impl< Session_server_t, Server_session_t > Class Template Reference

Internal class template comprising API/logic common to every Session_server variant, meant to be privately sub-classed and largely forwarded. More...

#include <session_server_impl.hpp>

Inheritance diagram for ipc::session::Session_server_impl< Session_server_t, Server_session_t >:
[legend]
Collaboration diagram for ipc::session::Session_server_impl< Session_server_t, Server_session_t >:
[legend]

Classes

struct  State
 All internal mutable state of Session_server_impl. More...
 

Public Types

using Session_server_obj = Session_server_t
 See this_session_srv(). More...
 
using Server_session_obj = Server_session_t
 Useful short-hand for the concrete Server_session type emitted by async_accept(). More...
 
using Mdt_reader_ptr = typename Server_session_obj::Mdt_reader_ptr
 Short-hand for Session_mv::Mdt_reader_ptr. More...
 
using Channels = typename Server_session_obj::Channels
 Short-hand for Session_mv::Channels. More...
 

Public Member Functions

template<typename Per_app_setup_func >
 Session_server_impl (flow::log::Logger *logger_ptr, Session_server_obj *this_session_srv_arg, const Server_app &srv_app_ref, const Client_app::Master_set &cli_app_master_set_ref, Error_code *err_code, Per_app_setup_func &&per_app_setup_func)
 See Session_server ctor; it does that. More...
 
 ~Session_server_impl ()
 See Session_server dtor. More...
 
template<typename Task_err , typename N_init_channels_by_srv_req_func , typename Mdt_load_func >
void async_accept (Server_session_obj *target_session, Channels *init_channels_by_srv_req, Mdt_reader_ptr *mdt_from_cli_or_null, Channels *init_channels_by_cli_req, N_init_channels_by_srv_req_func &&n_init_channels_by_srv_req_func, Mdt_load_func &&mdt_load_func, Task_err &&on_done_func)
 See Session_server method. More...
 
void to_ostream (std::ostream *os) const
 See Server_session method. More...
 
Session_server_objthis_session_srv ()
 Returns pointer to the object that is privately sub-classing us. More...
 

Public Attributes

const Server_appm_srv_app_ref
 See Session_server public data member. More...
 

Protected Member Functions

template<typename Task >
void sub_class_set_deinit_func (Task &&task)
 Utility for sub-classes: ensures that task() is invoked near the end of *this dtor's execution, after all other (mutable) state has been destroyed, including stopping/joining any threads performing async async_accept() ops. More...
 

Private Types

using Server_session_dtl_obj = Server_session_dtl< Server_session_obj >
 Short-hand for concrete Server_session_dtl type, which each async_accept() creates internally, completes the log-in process upon, and then up-casts to Server_session_obj to emit to user via move-assignment. More...
 
using Incomplete_session = boost::shared_ptr< Server_session_dtl_obj >
 Internally used ref-counted handle to a Server_session_dtl_obj, suitable for capturing and passing around lambdas. More...
 
using Incomplete_session_observer = boost::weak_ptr< Server_session_dtl_obj >
 weak_ptr observer of an Incomplete_session. More...
 
using Incomplete_sessions = boost::unordered_set< Incomplete_session >
 Short-hand for set of Incomplete_session, with fast insertion and removal by key Incomplete_session itself. More...
 
using Mutex = flow::util::Mutex_non_recursive
 Short-hand for State::m_mutex type. More...
 
using Lock_guard = flow::util::Lock_guard< Mutex >
 Short-hand for Mutex lock. More...
 

Private Attributes

Session_server_obj *const m_this_session_srv
 See this_session_srv(). More...
 
const Client_app::Master_setm_cli_app_master_set_ref
 See ctor. More...
 
const Function< Error_code(const Client_app &client_app)> m_per_app_setup_func
 See ctor. More...
 
std::optional< Statem_state
 See State. More...
 
Function< void()> m_deinit_func_or_empty
 See sub_class_set_deinit_func(). .empty() unless that was called at least once. More...
 

Related Functions

(Note that these are not member functions.)

template<typename Session_server_t , typename Server_session_t >
std::ostream & operator<< (std::ostream &os, const Session_server_impl< Session_server_t, Server_session_t > &val)
 Prints string representation of the given Session_server_impl to the given ostream. More...
 

Detailed Description

template<typename Session_server_t, typename Server_session_t>
class ipc::session::Session_server_impl< Session_server_t, Server_session_t >

Internal class template comprising API/logic common to every Session_server variant, meant to be privately sub-classed and largely forwarded.

In particular the vanilla Session_server (see its short Implementation doc header section) sub-classes us and makes no use of the available customization points. Contrast with, e.g., shm::classic::Session_server which uses customization points for shm::classic SHM-arena setup.

The available customization points are as follows.

Implementation design

Generally the impl should be reasonably easy to follow by reading the method bodies, at least if one understands the general ipc::session client-server paradigm.

The thing to understand strategically, as usual, is the thread design. This is an acceptor, so one might have expected it to be implemented similarly to, say, Native_socket_stream_acceptor – maintaining a thread W in which to do some/most work; including maintaining a "deficit" queue of oustanding async_accept() requests and a "surplus" queue of ready Server_sessions to emit. This was an option, but I (ygoldfel) felt that piggy-backing handling of events directly onto the unspecified handler-invoking threads of the internally used objects would produce a much simpler data structure and state machine. (As a side effect, the behavior described in "FIFO" section above occurs. Also as a side effect, the error-emission behavior described in "Error handling" above occurs. Basically: each async_accept()'s internal handling is independent of the others. They share (almost) no state; there is no single async-chain and explicit queues unlike in various other boost.asio-like classes in ipc. Each async_accept() triggers async op 1, the handler for which triggers async op 2, the handler for which emits the result to user. This is simpler to implement, but it also results in sensible API contract behavior, I feel.)

Here is how it works.

For each potential Server_session – i.e., for each async_accept() – there are 2 steps that must occur asynchronously before one is ready to emit to the user-supplied handler:

Nomenclature: We call the N_s_s_a::async_accept() handler-invoking thread: Wa. It is officially an unspecified thread or threads, but, by contract, handlers are executed non-concurrently, so it can be considered one thread (and actually it is as of this writing). We call the Server_session::async_accept_log_in() handler-invoking thread: Ws. This is really a separate thread for each Server_session, so in fact 2 different async-accept requests can cause 2 handlers to invoke simultaneously.

So each time one calls async_accept() from thread U (i.e., user thread(s) from which they must never invoke mutating stuff concurrently), that kicks off transport::Native_socket_stream_acceptor::async_accept(), which fires handler in thread Wa; we then kick off Server_session::async_accept_log_in(), which fires handler in thread Ws, where we finalize the Server_session and emit it to user. There is no cross-posting to some other worker thread W (but read on).

The obvious question is, do the handlers, some of which (as noted) may run concurrently to each other (request 1's Ws handler can co-execute with request 2's Wa handler; and request 2's Wa handler can co-execute with request 3's Wa handler), mess each other over by mutatingly accessing common data? Let's consider the state involved.

For each async-accept request, the amassed data are independent from any other's; they are passed around throughout the 2 async ops per request via lambda captures. There is, however, one caveat to this: Suppose S->accept_log_in(F) is invoked on not-yet-ready (incomplete) Server_session* S; suppose F is invoked with a truthy Error_code (it failed). We are now sitting in thread Ws: and S should be destroyed. But invoking dtor of S from within S's own handler is documented to be not-okay and results in a deadlock/infinite dtor execution, or if the system can detect it, at best an abort due to a thread trying to join itself. So:

However note that State::m_incomplete_sessions is added-to in thread Wa but removed-from in various threads Ws. Therefore it is protected by a mutex; simple enough.

Todo:
Session_server, probably in ctor or similar, should – for safety – enforce the accuracy of Server_app attributes including App::m_exec_path, App::m_user_id, App::m_group_id. As of this writing it enforces these things about each opposing Client_app and process – so for sanity it can/should do so about itself, before the sessions can begin.
Template Parameters
Server_session_tSee Server_session_obj. Its API must exactly equal (or be a superset of) that of vanilla Server_session. (Its impl may perform extra steps; for example async_accept_log_in() might set up a per-session SHM arena.)
Session_server_tThe class that is in fact privately sub-classing us. This is necessary for this_session_srv(). See its doc header for discussion.

Definition at line 143 of file session_server_impl.hpp.

Member Typedef Documentation

◆ Channels

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Channels = typename Server_session_obj::Channels

Short-hand for Session_mv::Channels.

Definition at line 160 of file session_server_impl.hpp.

◆ Incomplete_session

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Incomplete_session = boost::shared_ptr<Server_session_dtl_obj>
private

Internally used ref-counted handle to a Server_session_dtl_obj, suitable for capturing and passing around lambdas.

Rationale

It is shared_ptr, not unique_ptr, for two reasons. Primarily, it is so that it can be captured via Incomplete_session_observer to avoid a leak that would result from capturing Incomplete_session in a lambda passed-to an async op on an Incomplete_session itself. unique_ptr cannot be observed via weak_ptr; shared_ptr can.

Secondarily, a unique_ptr cannot be captured in a lambda in the first place.

Definition at line 335 of file session_server_impl.hpp.

◆ Incomplete_session_observer

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Incomplete_session_observer = boost::weak_ptr<Server_session_dtl_obj>
private

weak_ptr observer of an Incomplete_session.

Capturing this, instead of Incomplete_session itself, allows for the underlying Incomplete_session to be destroyed while the lambda still exists.

Definition at line 341 of file session_server_impl.hpp.

◆ Incomplete_sessions

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Incomplete_sessions = boost::unordered_set<Incomplete_session>
private

Short-hand for set of Incomplete_session, with fast insertion and removal by key Incomplete_session itself.

Definition at line 344 of file session_server_impl.hpp.

◆ Lock_guard

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Lock_guard = flow::util::Lock_guard<Mutex>
private

Short-hand for Mutex lock.

Definition at line 350 of file session_server_impl.hpp.

◆ Mdt_reader_ptr

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Mdt_reader_ptr = typename Server_session_obj::Mdt_reader_ptr

Short-hand for Session_mv::Mdt_reader_ptr.

Definition at line 157 of file session_server_impl.hpp.

◆ Mutex

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Mutex = flow::util::Mutex_non_recursive
private

Short-hand for State::m_mutex type.

Definition at line 347 of file session_server_impl.hpp.

◆ Server_session_dtl_obj

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Server_session_dtl_obj = Server_session_dtl<Server_session_obj>
private

Short-hand for concrete Server_session_dtl type, which each async_accept() creates internally, completes the log-in process upon, and then up-casts to Server_session_obj to emit to user via move-assignment.

Server_session_dtl_obj is equal to Server_session_obj – it adds no data – but exposes certain internally invoked APIs that the user shall not access.

Definition at line 321 of file session_server_impl.hpp.

◆ Server_session_obj

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Server_session_obj = Server_session_t

Useful short-hand for the concrete Server_session type emitted by async_accept().

Definition at line 154 of file session_server_impl.hpp.

◆ Session_server_obj

template<typename Session_server_t , typename Server_session_t >
using ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Session_server_obj = Session_server_t

See this_session_srv().

Definition at line 151 of file session_server_impl.hpp.

Constructor & Destructor Documentation

◆ Session_server_impl()

template<typename Session_server_t , typename Server_session_t >
template<typename Per_app_setup_func >
ipc::session::Session_server_impl< Session_server_t, Server_session_t >::Session_server_impl ( flow::log::Logger *  logger_ptr,
Session_server_obj this_session_srv_arg,
const Server_app srv_app_ref,
const Client_app::Master_set cli_app_master_set_ref,
Error_code err_code,
Per_app_setup_func &&  per_app_setup_func 
)
explicit

See Session_server ctor; it does that.

In addition:

takes and memorizes a functor that takes a Client_app const ref that identifies the app that wants to open the session, performs unspecified synchronous steps, and returns an Error_code indicating success or reason for failure which dooms that async_accept().

Rationale for per_app_setup_func

It is not intended for per-session setup. Server_session_dtl_obj should take care of that where it makes sense – it does after all represent the individual budding session peer. However our sub-class (e.g., shm::classic::Session_server) may need to keep track of per-distinct-Client_app resources (e.g., the per-app-scope SHM arena) which must exist before the opposing Client_session-type object completes its setup (e.g., by opening the aforementioned per-Client_app/multi-instance-scope SHM arena). It can detect a new Client_app is logging-in and set that up in the nick of time.

Template Parameters
Per_app_setup_funcSee above. Signature: Error_code F(const Client_app&).
Parameters
logger_ptrSee Session_server ctor.
srv_app_refSee Session_server ctor.
cli_app_master_set_refSee Session_server ctor.
err_codeSee Session_server ctor. Additional Error_code generated: see per_app_setup_func.
per_app_setup_funcSee above.
this_session_srv_argThe object that is, in fact, privately sub-classing *this (and calling this ctor). See this_session_srv(). The value is only saved but not dereferenced inside the ctor.

Definition at line 437 of file session_server_impl.hpp.

References ipc::session::Server_session_dtl< Server_session_t >::base(), ipc::session::build_conventional_shared_name_prefix(), ipc::util::Shared_name::ct(), ipc::session::ensure_resource_owner_is_app(), ipc::session::App::m_group_id, ipc::session::App::m_name, ipc::session::Server_app::m_permissions_level_for_client_apps, ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_srv_app_ref, ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_state, ipc::session::App::m_user_id, ipc::util::op_with_possible_bipc_exception(), ipc::util::OPEN_OR_CREATE, ipc::util::PRODUCER_CONSUMER_RESOURCE_PERMISSIONS_LVL_MAP, ipc::session::error::S_MUTEX_BIPC_MISC_LIBRARY_ERROR, ipc::session::error::S_RESOURCE_OWNER_UNEXPECTED, ipc::util::set_resource_permissions(), and ipc::util::shared_resource_permissions().

Here is the call graph for this function:

◆ ~Session_server_impl()

template<typename Session_server_t , typename Server_session_t >
ipc::session::Session_server_impl< Session_server_t, Server_session_t >::~Session_server_impl

See Session_server dtor.

Definition at line 715 of file session_server_impl.hpp.

Member Function Documentation

◆ async_accept()

template<typename Session_server_t , typename Server_session_t >
template<typename Task_err , typename N_init_channels_by_srv_req_func , typename Mdt_load_func >
void ipc::session::Session_server_impl< Session_server_t, Server_session_t >::async_accept ( Server_session_obj target_session,
Channels init_channels_by_srv_req,
Mdt_reader_ptr mdt_from_cli_or_null,
Channels init_channels_by_cli_req,
N_init_channels_by_srv_req_func &&  n_init_channels_by_srv_req_func,
Mdt_load_func &&  mdt_load_func,
Task_err &&  on_done_func 
)

See Session_server method.

In addition: invokes per_app_setup_func() (from ctor) once the connecting Client_app becomes known; if that returns truthy Error_code then this method emits that error.

Template Parameters
Task_errSee Session_server method.
N_init_channels_by_srv_req_funcSee Session_server method.
Mdt_load_funcSee Session_server method.
Parameters
target_sessionSee Session_server method.
init_channels_by_srv_reqSee Session_server method.
mdt_from_cli_or_nullSee Session_server method.
init_channels_by_cli_reqSee Session_server method.
n_init_channels_by_srv_req_funcSee Session_server method.
mdt_load_funcSee Session_server method.
on_done_funcSee Session_server method.

Definition at line 746 of file session_server_impl.hpp.

References ipc::util::Shared_name::ct(), ipc::transport::error::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER, and ipc::session::error::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER.

Here is the call graph for this function:

◆ sub_class_set_deinit_func()

template<typename Session_server_t , typename Server_session_t >
template<typename Task >
void ipc::session::Session_server_impl< Session_server_t, Server_session_t >::sub_class_set_deinit_func ( Task &&  task)
protected

Utility for sub-classes: ensures that task() is invoked near the end of *this dtor's execution, after all other (mutable) state has been destroyed, including stopping/joining any threads performing async async_accept() ops.

It may be invoked at most once.

The value it adds: A long story best told by specific example. See the original use case which is in shm::classic::Session_server; it sets up certain SHM cleanup steps to occur, when the session-server is destroyed.

Watch out!

At the time task() runs, the calling instance of the sub-class has been destroyed – thus it is, e.g., usually wrong to capture your this in the task lambda, except for logging. get_logger() and get_log_component() (which are in this super-class) are still okay to use.

Template Parameters
TaskFunction object invoked as void with no args.
Parameters
tasktask() shall execute before dtor returns.

Definition at line 987 of file session_server_impl.hpp.

◆ this_session_srv()

template<typename Session_server_t , typename Server_session_t >
Session_server_impl< Session_server_t, Server_session_t >::Session_server_obj * ipc::session::Session_server_impl< Session_server_t, Server_session_t >::this_session_srv

Returns pointer to the object that is privately sub-classing us.

In other words this equals static_cast<const Session_server_obj*>(this), where this class is the base of Session_server_obj, but up-casting from a private base is not allowed.

Rationale

I (ygoldfel) acknowledge this is somewhat odd. Why should a sub-class, per se, care or know about its super-class? This at least vaguely indicates some sort of design mistake. In fact this is needed, as of this writing, because shm::classic::Server_session_impl::async_accept_log_in() gets a Session_server_impl ptr, which it knows points to an object that's really the core of a shm::classic::Session_server, and it needs to interact with the SHM-classic-specific aspect of that guy's API. So it calls this accessor here, essentially as a way to up-cast from a private base (which is not allowed by C++). Why can't it "just" take a shm::classic::Session_server* then? Answer: because Session_server_impl uses, like, virtual-less polymorphism to invoke async_accept_log_in() regardless of which object it's calling it on.... It's hard to summarize here in words in any way that'll make sense, but if one looks at the relevant code it makes sense. Eventually. Bottom line is, this way, it can just pass-in this, and then shm::classic::Server_session_impl::async_accept_log_in() can call this_session_srv() to get at the super-class version of this.

I feel it is not criminal – internal things are working together in a way that they logically intend to – but intuitively it feels like there's a smoother way to design it. Probably.

Todo:
Reconsider the details of how classes in the non-virtual hierarchies Session_server, Server_session, Session_server_impl, Server_session_impl cooperate internally, as there is some funky stuff going on, particularly Session_server_impl::this_session_srv().
Returns
See above.

Definition at line 980 of file session_server_impl.hpp.

◆ to_ostream()

template<typename Session_server_t , typename Server_session_t >
void ipc::session::Session_server_impl< Session_server_t, Server_session_t >::to_ostream ( std::ostream *  os) const

See Server_session method.

Parameters
osSee Server_session method.

Definition at line 974 of file session_server_impl.hpp.

Friends And Related Function Documentation

◆ operator<<()

template<typename Session_server_t , typename Server_session_t >
std::ostream & operator<< ( std::ostream &  os,
const Session_server_impl< Session_server_t, Server_session_t > &  val 
)
related

Prints string representation of the given Session_server_impl to the given ostream.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 993 of file session_server_impl.hpp.

Member Data Documentation

◆ m_cli_app_master_set_ref

template<typename Session_server_t , typename Server_session_t >
const Client_app::Master_set& ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_cli_app_master_set_ref
private

See ctor.

Definition at line 412 of file session_server_impl.hpp.

◆ m_deinit_func_or_empty

template<typename Session_server_t , typename Server_session_t >
Function<void ()> ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_deinit_func_or_empty
private

See sub_class_set_deinit_func(). .empty() unless that was called at least once.

Definition at line 421 of file session_server_impl.hpp.

◆ m_per_app_setup_func

template<typename Session_server_t , typename Server_session_t >
const Function<Error_code (const Client_app& client_app)> ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_per_app_setup_func
private

See ctor.

Definition at line 415 of file session_server_impl.hpp.

◆ m_srv_app_ref

template<typename Session_server_t , typename Server_session_t >
const Server_app& ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_srv_app_ref

◆ m_state

template<typename Session_server_t , typename Server_session_t >
std::optional<State> ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_state
private

◆ m_this_session_srv

template<typename Session_server_t , typename Server_session_t >
Session_server_obj* const ipc::session::Session_server_impl< Session_server_t, Server_session_t >::m_this_session_srv
private

See this_session_srv().

Definition at line 409 of file session_server_impl.hpp.


The documentation for this class was generated from the following files: