Flow-IPC 1.0.0
Flow-IPC project: Public API.
Public Types | Public Member Functions | Related Functions | List of all members
ipc::session::Client_session_mv< Client_session_impl_t > Class Template Reference

Implements Session concept on the Client_app end: a Session_mv that first achieves PEER state by connecting to an opposing Session_server_mv via Client_session_mv::sync_connect(). More...

#include <client_session.hpp>

Inheritance diagram for ipc::session::Client_session_mv< Client_session_impl_t >:
[legend]
Collaboration diagram for ipc::session::Client_session_mv< Client_session_impl_t >:
[legend]

Public Types

using Base = Session_mv< Client_session_impl_t >
 Short-hand for our base class. To the user: note its public API is inherited.
 
- Public Types inherited from ipc::session::Session_mv< Client_session_impl_t >
using Channel_obj = typename Impl::Channel_obj
 Implements Session API per contract. More...
 
using Channels = typename Impl::Channels
 Container (vector<>) of Channel_obj.
 
using Mdt_payload_obj = typename Impl::Mdt_payload_obj
 Implements Session API per contract. More...
 
using Mdt_builder = typename Impl::Mdt_builder
 Implements Session API per contract. More...
 
using Mdt_builder_ptr = typename Impl::Mdt_builder_ptr
 Implements Session API per contract. More...
 
using Mdt_reader_ptr = typename Impl::Mdt_reader_ptr
 Implements Session API per contract. More...
 
using Structured_channel = typename transport::struc::Channel_via_heap< Channel_obj, Message_body >
 Implements Session API per contract. More...
 
using Structured_msg_builder_config = typename Impl::Structured_msg_builder_config
 Implements Session API per contract. More...
 
using Structured_msg_reader_config = typename Impl::Structured_msg_builder_config
 Implements Session API per contract. More...
 

Public Member Functions

template<typename On_passive_open_channel_handler , typename Task_err >
 Client_session_mv (flow::log::Logger *logger_ptr, const Client_app &cli_app_ref, const Server_app &srv_app_ref, Task_err &&on_err_func, On_passive_open_channel_handler &&on_passive_open_channel_func)
 Constructs (passive-opens allowed form) in NULL state. More...
 
template<typename Task_err >
 Client_session_mv (flow::log::Logger *logger_ptr, const Client_app &cli_app_ref, const Server_app &srv_app_ref, Task_err &&on_err_func)
 Constructs (passive-opens disallowed form) in NULL state. More...
 
Mdt_builder_ptr mdt_builder ()
 Implements Session API per contract; plus usable to generate blank mdt argument for advanced sync_connect() overload. More...
 
bool sync_connect (Error_code *err_code=0)
 To be invoked in NULL state only, and not as-if default-cted, it synchronously and non-blockingly attempts to connect to an opposing Session_server; and synchronously reports failure or success, the latter showing *this has entered PEER state. More...
 
bool sync_connect (const typename Base::Mdt_builder_ptr &mdt, typename Base::Channels *init_channels_by_cli_req_pre_sized=0, typename Base::Mdt_reader_ptr *mdt_from_srv_or_null=0, typename Base::Channels *init_channels_by_srv_req=0, Error_code *err_code=0)
 Identical to the simpler sync_connect() overload but offers added advanced capabilities: metadata exchange; initial-channel opening. More...
 
- Public Member Functions inherited from ipc::session::Session_mv< Client_session_impl_t >
 Session_mv ()
 Implements Session API per contract. More...
 
 Session_mv (Session_mv &&src)
 Implements Session API per contract. More...
 
 Session_mv (const Session_mv &)=delete
 Copy ction is disallowed.
 
 ~Session_mv ()
 Implements Session API per contract. More...
 
Session_mvoperator= (Session_mv &&src)
 Implements Session API per contract. More...
 
Session_mvoperator= (const Session_mv &)=delete
 Copy assignment is disallowed.
 
Mdt_builder_ptr mdt_builder ()
 Implements Session API per contract. More...
 
bool open_channel (Channel_obj *target_channel, const Mdt_builder_ptr &mdt, Error_code *err_code=0)
 Implements Session API per contract. More...
 
bool open_channel (Channel_obj *target_channel, Error_code *err_code=0)
 Implements Session API per contract. More...
 
const Session_tokensession_token () const
 Implements Session API per contract. More...
 
transport::struc::Heap_fixed_builder::Config heap_fixed_builder_config ()
 Utility that obtains a heap-based (non-zero-copy) Struct_builder::Config, constructed with the most efficient yet safe values, for transport::struc::Msg_out (out-messages) compatible with Structured_channel upgraded-from Channel_obj channels opened via *this Session_mv. More...
 
transport::struc::Heap_reader::Config heap_reader_config ()
 Deserializing counterpart to non-static heap_fixed_builder_config(). More...
 
flow::log::Logger * get_logger () const
 Returns logger (possibly null). More...
 
const flow::log::Component & get_log_component () const
 Returns log component. More...
 

Related Functions

(Note that these are not member functions.)

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

Additional Inherited Members

- Static Public Member Functions inherited from ipc::session::Session_mv< Client_session_impl_t >
static transport::struc::Heap_fixed_builder::Config heap_fixed_builder_config (flow::log::Logger *logger_ptr)
 Utility that obtains a heap-based (non-zero-copy) Struct_builder::Config, constructed with the most efficient yet safe values, for transport::struc::Msg_out (out-messages) compatible with Structured_channel upgraded-from Channel_obj channels opened via this Session_mv type. More...
 
static transport::struc::Heap_reader::Config heap_reader_config (flow::log::Logger *logger_ptr)
 Deserializing counterpart to static heap_fixed_builder_config(). More...
 
- Static Public Attributes inherited from ipc::session::Session_mv< Client_session_impl_t >
static constexpr schema::ShmType S_SHM_TYPE
 Implements Session API per contract. More...
 
static constexpr bool S_SHM_ENABLED
 Implements Session API per contract. More...
 
static constexpr bool S_MQS_ENABLED
 Compile-time-known constant indicating whether Channel_obj shall use a blobs pipe over message queues (MQs).
 
static constexpr bool S_SOCKET_STREAM_ENABLED
 Compile-time-known constant indicating whether Channel_obj shall use socket stream for any type of pipe. More...
 
- Protected Types inherited from ipc::session::Session_mv< Client_session_impl_t >
using Impl = Client_session_impl_t
 Short-hand for pImpl-lite impl type. This shall be the deepest impl sub-class desired.
 
using Session_base_obj = typename Impl::Session_base_obj
 Short-hand for Impl's Session_base super-class.
 
using Impl_ptr = std::experimental::propagate_const< boost::movelib::unique_ptr< Impl > >
 Short-hand for const-respecting wrapper around Impl for the pImpl idiom. See impl().
 
- Protected Member Functions inherited from ipc::session::Session_mv< Client_session_impl_t >
const Session_base_objbase () const
 Provides const access to Session_base super-object. More...
 
Impl_ptrimpl ()
 pImpl target; particularly for sub-classes that must add to the above public API. More...
 
const Impl_ptrimpl () const
 pImpl target; particularly for sub-classes that must add to the above public API. More...
 

Detailed Description

template<typename Client_session_impl_t>
class ipc::session::Client_session_mv< Client_session_impl_t >

Implements Session concept on the Client_app end: a Session_mv that first achieves PEER state by connecting to an opposing Session_server_mv via Client_session_mv::sync_connect().

See overview of Session hierarchy in namespace ipc::session doc header; then come back here if desired.

It is unusual to use Client_session_mv template directly. If you do wish to set up a client-side session peer, and you do not require SHM support, then use Client_session alias template. The client-specific API, particularly ctor and sync_connect(), is in Client_session_mv and documented here. The side-agnostic API – active once PEER state is achieved – is described by Session (concept) doc header and implemented concretely by Session_mv which is our public, non-virtual super-class.

If you do wish to set up a client-side session peer, but you do require SHM support, then use shm::classic::Client_session or similar (for other SHM-provider(s)). However Client_session (hence Client_session_mv to which it aliases) is its super-class, and until PEER state is reached its API remains the only relevant API to use. Once Client_session_mv::sync_connect() puts *this into PEER state, super-class Session_mv (= Session concept) API continues to be relevant. Also in PEER state SHM-relevant additional API members (e.g., shm::classic::Session_mv::app_shm()`) become of interest.

Summary hierarchy:

We may refer to Client_session_mv as Client_session below; particularly since it is likeliest used in that form by the user.

How to use

Per the Session concept a Client_session is open/capable of operation when in PEER state only. A Client_session object is always in one of 2 states:

To get from NULL state to PEER state: Use Session_server on the other side. On this side construct a Client_session (always in NULL state) and invoke sync_connect() which will synchronously and non-blockingly try to move to PEER state (mission accomplished). If the connect fails, it will stay in NULL state. Being moved-from makes a *this as-if default-cted; therefore also moves to NULL state.

Once in PEER state Client_session simply follows Session concept semantics. At this stage our super-class Session_mv implements that concept in particular. See either doc header (Session, Session_mv).

A related reminder:

Why no async-connect method, only sync-connect?

Without networking, the other side (Session_server) either exists/is listening; or no. Connecting is a synchronous, non-blocking operation; so an async_connect() API in this context only makes life harder for the user. (However, there are some serious plans to add a networking-capable counterpart (probably via TCP at least) to Native_socket_stream and therefore Client_session_mv; such a networky-client-session class will almost certainly have an async_connect(), while its sync_connect() will probably become potentially blocking.)

Note
Impl detail for exposition purposes: transport::Native_socket_stream is used internally by ipc::session to establish internal session-related IPC. That is a Unix domain socket: local stream connection. This can be extended, relatively cheaply in terms of effort, to work over networked-TCP sockets. Based on that work, Client_session and Session_server hierarchies can be relatively cheaply extended to also be network-enabled in some form.
If some form of *this becomes network-enabled, open_channel() too will need an async form most likely, while existing open_channel() would become potentially-blocking.

Thread safety and handler invocation semantics

These follow the Session concept policies.

Error handling

Once in PEER state, error handling follows the Session concept (= Session_mv concrete class) doc header. Up to that point (in NULL state) there are no public asynchronous operations; there is just sync_connect() which succeeds or fails synchronously and quickly.

See also
Session: implemented concept.
Template Parameters
Client_session_impl_tAn implementation detail. Use one of the aliases prescribed near the top of this doc header to set this correctly.

Constructor & Destructor Documentation

◆ Client_session_mv() [1/2]

template<typename Client_session_impl_t >
template<typename On_passive_open_channel_handler , typename Task_err >
ipc::session::Client_session_mv< Client_session_impl_t >::Client_session_mv ( flow::log::Logger *  logger_ptr,
const Client_app cli_app_ref,
const Server_app srv_app_ref,
Task_err &&  on_err_func,
On_passive_open_channel_handler &&  on_passive_open_channel_func 
)
explicit

Constructs (passive-opens allowed form) in NULL state.

To be useful, invoke sync_connect() next.

Parameters
logger_ptrLogger to use for logging subsequently.
cli_app_refProperties of this client application. The address is copied; the object is not copied.
srv_app_refProperties of the opposing server application. The address is copied; the object is not copied.
on_err_funcOn-error handler. See Session concept doc header for semantics.
on_passive_open_channel_funcOn-passive-open handler. See Session concept doc header for semantics.
Template Parameters
On_passive_open_channel_handlerSee Session concept doc header for semantics.
Task_errSee Session concept doc header for semantics.

◆ Client_session_mv() [2/2]

template<typename Client_session_impl_t >
template<typename Task_err >
ipc::session::Client_session_mv< Client_session_impl_t >::Client_session_mv ( flow::log::Logger *  logger_ptr,
const Client_app cli_app_ref,
const Server_app srv_app_ref,
Task_err &&  on_err_func 
)
explicit

Constructs (passive-opens disallowed form) in NULL state.

To be useful, invoke sync_connect() next.

Parameters
logger_ptrLogger to use for logging subsequently.
cli_app_refProperties of this client application. The address is copied; the object is not copied.
srv_app_refProperties of the opposing server application. The address is copied; the object is not copied.
on_err_funcOn-error handler. See Session concept doc header for semantics.
Template Parameters
Task_errSee Session concept doc header for semantics.

Member Function Documentation

◆ mdt_builder()

template<typename Client_session_impl_t >
Mdt_builder_ptr ipc::session::Client_session_mv< Client_session_impl_t >::mdt_builder ( )

Implements Session API per contract; plus usable to generate blank mdt argument for advanced sync_connect() overload.

That is: can additionally be invoked in NULL state (before sync_connect() or between a failed attempt and the next attempt). The return value can be used only as follows; otherwise undefined behavior results:

Returns
See above.
See also
Session::mdt_builder(): implemented concept.

◆ sync_connect() [1/2]

template<typename Client_session_impl_t >
bool ipc::session::Client_session_mv< Client_session_impl_t >::sync_connect ( const typename Base::Mdt_builder_ptr mdt,
typename Base::Channels init_channels_by_cli_req_pre_sized = 0,
typename Base::Mdt_reader_ptr mdt_from_srv_or_null = 0,
typename Base::Channels init_channels_by_srv_req = 0,
Error_code err_code = 0 
)

Identical to the simpler sync_connect() overload but offers added advanced capabilities: metadata exchange; initial-channel opening.

The other overload is identical to sync_connect(mdt_builder(), nullptr, nullptr, nullptr, err_code) and requires the opposing async_accept() to similarly not use the corresponding features.

Client->server metadata exchange

Client may wish to provide information in some way, but without a structured channel – or any channel – yet available, this provides an opportunity to do so in a structured way with a one-off message available at session open, together with the opposing Session object itself.

Similarly to how it is optionally done on a per-channel-open basis (open_channel()): call mdt = mdt_builder(); fill out the resulting capnp structure *mdt; then pass mdt to sync_connect(). Opposing async_accept() shall receive deserializable Mdt_reader together with the freshly-opened Session, though they may choose to ignore it.

To omit using this feature, skip the "fill out the resulting capnp structure" step. You must still call mdt_builder() and pass-in the result. (The other overload does so.)

Server->client metadata exchange

This is the reverse of the above. Whatever the opposing server chose to supply as server->client metadata shall be deserializable at *mdt_from_srv_or_null on successful return from sync_connect(). If mdt_from_srv_or_null is null, the srv->cli metadata shall be ignored.

Init-channels by client request

Once the session is open, open_channel() and the on-passive-open handler may be used to open channels at will. In many use cases, however, a certain number of channels is required immediately before work can really begin (and, frequently, no further channels are even needed). For convenience (to avoid asynchrony/boiler-plate) the init-channels feature will pre-open a requested # of channels making them available right away, together with the freshly-open session – to both sides.

The client may request 0 or more init-channels. They shall be opened and placed into *init_channels_by_cli_req_pre_sized; its ->size() at entry to the method indicates the number of channels requested. If null, it is treated as if ->size() == 0, meaning no init-channels-by-client-request are opened.

Init-channels by server request

This is the reverse of the above. The opposing side shall request 0 or more init-channels-by-server-request; that number of channels shall be opened; and they will be placed into *init_channels_by_srv_req which shall be ->resize()d accordingly on successful return from sync_connect().

init_channels_by_srv_req being null is allowed, but only if the opposing server requests 0 init-channels-by-server-request. Otherwise an error shall be emitted (see below).

Parameters
mdtSee above.
init_channels_by_cli_req_pre_sizedSee above: null or pointer to container of Channel_obj with .size() specifying how many channels this side is requesting to be opened on its behalf; each element will be move-assigned a PEER-state Channel_obj on success. Recommend simply ct-ing with (n) or .resize(n) which loads it with default-cted (NULL-state) objects to be replaced. null is treated same as .empty().
mdt_from_srv_or_nullSee above: null or pointer to Reader of metadata which shall be set for access on success.
init_channels_by_srv_reqSee above: null or pointer to container of Channel_obj which shall be .clear()ed and replaced by a container of PEER-state Channel_obj on success the number being specified by the opposing (server) side. The number may be zero. null is allowed if and only if the number is zero; otherwise error::Code::S_INVALID_ARGUMENT is emitted.
err_codeSee other sync_connect() overload. Note the above target (pointer) args are touched only if no error is emitted via this standard Flow error reporting mechanism.
Returns
See other sync_connect() overload.

◆ sync_connect() [2/2]

template<typename Client_session_impl_t >
bool ipc::session::Client_session_mv< Client_session_impl_t >::sync_connect ( Error_code err_code = 0)

To be invoked in NULL state only, and not as-if default-cted, it synchronously and non-blockingly attempts to connect to an opposing Session_server; and synchronously reports failure or success, the latter showing *this has entered PEER state.

Failure means *this remains in NULL state.

If invoked outside of NULL state, or if it is as-if default-cted (i.e., default-cted or moved-from), this returns false and otherwise does nothing.

Note that *this (modulo moves) that has entered PEER state can never change state subsequently (even on transmission error); once a PEER, always a PEER.

How does it know "where" the Session_server is listening?

While details are internal, abstractly speaking this is determined by the Server_app passed to the ctor. Internal detail (for exposition/general knowledge):

  • The server application maintains a CNS (Current Namespace Store, a/k/a PID) file. Only at most 1 server instance (a/k/a process) shall be active at a time. The CNS contents – which are simply the active server app process's PID – determine "where" this Client_session will connect, and all other internally used cross-process resources (sockets, MQs, SHM pools...) are similarly segregated among different instances of the Server_app-described application.
  • The location of this file is determined by Server_app contents. Namely, Server_app::m_name, at least, is unique per Server_app in the universe, and most of the PID file's name comprises it; and its location comprises Server_app::m_kernel_persistent_run_dir_override and/or /var/run (or equivalent).
  • sync_connect() reads the CNS (PID) file at that location, unique among Server_apps. Now it knows "where" to connect in order to open the session; so it won't accidentally connect to some old zombie instance of the Server_app (its PID wouldn't be in the CNS file any longer) or another application entirely (its PID file would be located elsewhere and never accessed by this sync_connect()).

What if the CNS (PID) file does not exist? What if server is inactive?

Then sync_connect() will quickly fail (file-not-found or connection-refused error). Shouldn't we supply some API to await its appearance and actively listening? Answer: Probably not. Why? Answer: Consider the situation where the PID file is there, but it belongs to a now-exited instance of the Server_app; let's say it is currently suspended or restarting. sync_connect() will fail then too: There is nothing listening (anymore) at the advertised PID. So it'll quickly fail (connection-refused error). So then we'd also need an API to await an active server's appearance whether or not the PID exists. That leads to the following to-do:

Todo:
Consider adding an optional mode/feature to allow to wait through the condition wherein CNS (PID) file does not exist, or it does but the initial session-open connect op would be refused; instead it detects these relatively common conditions (server not yet up and/or is restarting and/or is operationally suspended for now, etc.) as normal and waits until the condition is cleared. Without this mode, a typical user would probably do something like: oh, sync_connect() failed; let's sleep 1 sec and try again (rinse/repeat). It's not awful, but we might as well make it easier and more responsive out of the box (optionally). Upon resolving this to-do please update the Manual section Sessions: Setting Up an IPC Context accordingly.
See also
Class doc header, section "Why no async-connect method, only sync-connect?" for potentially interesting context.
Returns
false if and only if invoked outside of NULL state; or if *this is as-if default-cted.
Parameters
err_codeSee flow::Error_code docs for error reporting semantics. Error_code generated: session::error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER (destructor called, canceling all pending ops; spiritually identical to boost::asio::error::operation_aborted), interprocess-mutex-related errors (probably from boost.interprocess) w/r/t reading the CNS (PID file), file-related system errors w/r/t reading the CNS (PID file) (see Session_server doc header for background), error::Code::S_CLIENT_NAMESPACE_STORE_BAD_FORMAT (bad CNS contents), those emitted by transport::Native_socket_stream::sync_connect(), those emitted by transport::struc::Channel::send(), those emitted by transport::struc::Channel via on-error handler (most likely transport::error::Code::S_RECEIVES_FINISHED_CANNOT_RECEIVE indicating graceful shutdown of opposing process coincidentally during log-in procedure, prematurely ending session while it was starting), error::Code::S_CLIENT_MASTER_LOG_IN_RESPONSE_BAD, error::Code::S_INVALID_ARGUMENT (other side expected other sync_connect() overload with non-null init_channels_by_srv_req arg).

Friends And Related Function Documentation

◆ operator<<()

template<typename Client_session_impl_t >
std::ostream & operator<< ( std::ostream &  os,
const Client_session_mv< Client_session_impl_t > &  val 
)
related

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

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

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