Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
server_context.hpp
Go to the documentation of this file.
1/* Flow-IPC: Shared Memory
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
22#include "ipc/common.hpp"
23#include <flow/log/log.hpp>
24#include <boost/make_shared.hpp>
25#include <boost/move/unique_ptr.hpp>
26#include <boost/shared_ptr.hpp>
27
29{
30
31// Types.
32
33/**
34 * The mirror of an opposing PEER-state Client_context, as generated via successful Context_server::accept().
35 *
36 * @see ipc::transport::struc::shm::rpc namespace doc header for an overview of Flow-IPC capnp-RPC support, including
37 * how the present class relates to the others there.
38 *
39 * Client_context in PEER state (i.e., on successful `.sync_connect()`) -- therefore also Server_context -- is
40 * a bundling of:
41 * - ipc::session::Session SHM-enabled variant, also in PEER state
42 * - with no passive-channel-open abilities and
43 * - a session-hosed handler that logs about it; and
44 * - a Session_vat_network suitable to create a zero-copy-enabled #Rpc_system.
45 *
46 * In the case of Client_context session() accesses a `Client_session` in PEER state, while our session()
47 * accesses a `Server_session` in PEER state; but in PEER state they are simply a `Session` (how it was started --
48 * client, server -- does not matter).
49 *
50 * All notes in Client_context doc header relating to its semantics after successful Client_context::sync_connect()
51 * apply to a `*this` equally. A `*this` is by definition always in PEER state until destruction.
52 *
53 * @note Certain perf-knobs may be available through `this->vat_network()`. This is, along with the
54 * above-mentioned more basic notes, introduced in the Client_context doc header.
55 *
56 * @internal
57 *
58 * ### Impl notes ###
59 * There was some thought as to maybe making a `Context` with all PEER-state/common parts; have
60 * Server_context essentially equal it; and having Client_context equal it once in PEER state + the other parts
61 * like `.sync_connect()`. However that common part is so simple/short that the trouble involved would probably
62 * be costlier than the limited copy/paste-like action going on. (As of this writing this file is <250 lines
63 * including license header and comments.)
64 *
65 * @endinternal
66 *
67 * @tparam Server_session_t
68 * For a given Context_server instantiation `S`, this is `S::Session_server_obj::Server_session_obj`.
69 */
70template<typename Server_session_t>
72 public flow::log::Log_context,
73 private boost::noncopyable
74{
75public:
76 // Types.
77
78 /// Convenience alias for template arg.
79 using Session_obj = Server_session_t;
80 static_assert(Session_obj::S_SHM_ENABLED,
81 "Server_context facilitates the use of Flow-IPC zero-copy (SHM) facilities for "
82 "zero-copy performance in using capnp-RPC; therefore the supplied Server_session_t template "
83 "parameter must be a SHM-enabled Server_session variant, session::shm::*::Server_session*.");
84
85 /**
86 * The Session_vat_network concrete type -- and `capnp::VatNetwork` interface impl -- that we produce.
87 * See Session_vat_network docs; but in short, generally, once constructed this guy is used ~identically
88 * to `capnp::TwoPartyVatNetwork`.
89 */
90 using Vat_network = typename Session_obj::Vat_network;
91
92 /**
93 * Movable smart-pointer handle to a `*this`. Spiritually equivalent to `kj::Own<Server_context<...>>`.
94 *
95 * @internal
96 *
97 * Since we are going for a KJ/capnp-RPC-style API with Context_server et al, initially I (ygoldfel) went
98 * with `kj::Own<>` here, as one undoubtedly would if coding KJ/capnp itself. However I was then trying
99 * to do some internally-needed up-casting and having a really annoying time; at one point a `.release()` would
100 * have helped, but `Own` lacks it intentionally. In short I got annoyed and just reverted to the Flow-IPC-ish
101 * choice of single-ownership-ptr. They're used identically (in the mainstream), and if really required one
102 * can always make an `Own` for this after-all... so just, whatevs!
103 */
104 using Ptr = boost::movelib::unique_ptr<Server_context>;
105
106 // Constructors/destructor.
107
108 /// Identical semantics to Client_context. See that doc header.
110
111 // Methods.
112
113 /**
114 * Returns pointer to Session_vat_network established for use in your #Rpc_system.
115 * The #Vat_network is valid if and only if `*this` exists.
116 *
117 * @see `vat_network()->streaming_flow_window_ki()` is a perf-knob of potential interest accessible through here.
118 * See Session_vat_network::streaming_flow_window_ki() doc header(s).
119 *
120 * See Session_vat_network docs; but in short, generally, once constructed this guy is used ~identically
121 * to `capnp::TwoPartyVatNetwork`.
122 *
123 * @return See above.
124 */
126
127 /**
128 * Immutable counterpart to the other overload.
129 * @return See above.
130 */
131 const Vat_network* vat_network() const;
132
133 /**
134 * Returns pointer to #Session_obj (in PEER state). The #Session_obj is valid if and only if `*this` exists.
135 *
136 * @see class doc header for overview of which features accessible through this #Session_obj are available
137 * (and which are not).
138 *
139 * @return See above.
140 */
142
143 /**
144 * Immutable counterpart to the other overload.
145 * @return See above.
146 */
147 const Session_obj* session() const;
148
149private:
150 // Friends.
151
152 /// Attorney granting internal code (Context_server) access to the private ctor.
153 friend struct Server_context_dtl;
154
155 // Types.
156
157 /// Basically `shared_ptr<Session_obj>`.
158 using Session_ptr = typename Vat_network::Shm_lender_borrower_ptr;
159
160 // Constructors.
161
162 /**
163 * Constructs us in PEER state. Only callable via Server_context_dtl attorney.
164 *
165 * To the extent Session_vat_network ctor can throw: this can throw `kj::Exception`.
166 *
167 * @param logger_ptr
168 * Logger to use for logging subsequently.
169 * @param kj_io
170 * A KJ event loop context.
171 * @param session
172 * `Server_sesion` in almost-PEER state. We shall subsume this object and immediately move it
173 * to PEER state (session::Server_session::init_handlers() as of this writing).
174 * @param bidir_transport
175 * For Session_vat_network ctor (see its doc header; briefly: pre-connected stream-socket handle,
176 * as sent to us by the opposing Client_context or equivalent; subsumed and nullified by this ctor).
177 * @param enable_hndl_transport
178 * See Context_server::accept() arg of same name.
179 * @param sans_shm_transport
180 * Whether Context_server::accept() decided to forego zero-copy transport (`true`) or not.
181 */
182 explicit Server_context(flow::log::Logger* logger_ptr, kj::AsyncIoContext* kj_io,
183 Session_obj&& session, Native_handle&& bidir_transport,
184 bool enable_hndl_transport, bool sans_shm_transport);
185
186 // Methods.
187
188 /**
189 * Spiritually identical to Client_context::on_session_hosed(), including in being `static` and capturing
190 * nothing of `*this` (see #m_session).
191 *
192 * @param logger_ptr
193 * See ctor.
194 * @param session
195 * `*m_session`, which is alive whenever its own handler fires.
196 * @param err_code
197 * From error handler.
198 */
199 static void on_session_hosed(flow::log::Logger* logger_ptr, const Session_obj& session, const Error_code& err_code);
200
201 // Data.
202
203 /**
204 * Session in PEER state.
205 *
206 * Held via shared handle, as #m_network requires. Corollary: `*m_session` may outlive `*this`.
207 * See Session_vat_network doc header, "Object lifetimes." That is also why we warn about `Logger` and `App`
208 * lifetimes in our ctor doc header.
209 */
211
212 /// The established #Vat_network.
214}; // class Server_context
215
216// Template implementations.
217
218template<typename Server_session_t>
219Server_context<Server_session_t>::Server_context(flow::log::Logger* logger_ptr, kj::AsyncIoContext* kj_io,
220 Session_obj&& session, Native_handle&& bidir_transport,
221 bool enable_hndl_transport,
222 bool sans_shm_transport) :
223 flow::log::Log_context(logger_ptr, Log_component::S_RPC),
224 /* We take ownership of Session_obj... and immediately move-from it into a new Session_obj, that one
225 * wrapped in the shared_ptr handle as required by Session_vat_network m_session for its anonying lifetime
226 * reasons (see its class doc header). */
227 m_session(boost::make_shared<Session_obj>(std::move(session))),
228 m_network(get_logger(), kj_io,
229 sans_shm_transport ? Session_ptr{} : Session_ptr{m_session},
230 std::move(bidir_transport),
231 enable_hndl_transport ? Session_vat_network_base::S_N_MAX_INCOMING_FDS : 0)
232 // ^-- Can throw (unlikely).
233{
234 FLOW_LOG_INFO("rpc::Server_ctx [" << *this << "]: Created in PEER state (presumably by Context_server); "
235 "zero-copy-enabled? = [" << (!sans_shm_transport) << "].");
236
237 m_session->init_handlers([logger_ptr, session = m_session.get()](const Error_code& err_code)
238 { on_session_hosed(logger_ptr, *session, err_code); });
239}
240
241template<typename Server_session_t>
243{
244 FLOW_LOG_INFO("rpc::Server_ctx [" << *this << "]: "
245 "Shutting down. Session_vat_network shall shut down; then the ipc::session::Session. "
246 "However: straggling capnp-RPC message(s) may keep the latter alive a bit longer than immediately "
247 "following Session_vat_network's destruction.");
248}
249
250template<typename Server_session_t>
251void Server_context<Server_session_t>::on_session_hosed(flow::log::Logger* logger_ptr, const Session_obj& session,
252 const Error_code& err_code) // Static.
253{
254 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_RPC); // @todo Maybe use session.get_logger()?
255 FLOW_LOG_INFO("rpc::Server_ctx-created ipc::session::Session [" << session << "]: session-hosed handler fired "
256 "(code [" << err_code << "] [" << err_code.message() << "]). This is likely normal, as the "
257 "opposing process decided to end session; the RPC-system will have detected same, and user "
258 "RPC session should be ended or ending imminently, at which point proper user code shall "
259 "shut-down this Server_ctx which will shut down the Session_vat_network and lastly the "
260 "ipc::session::Session.");
261
262 // Why do we merely log but in no way report this to `*this` user? See Client_context equivalent; same deal here.
263}
264
265template<typename Server_session_t>
268{
269 return &m_network;
270}
271
272template<typename Server_session_t>
275{
276 return const_cast<Server_context*>(this)->vat_network();
277}
278
279template<typename Server_session_t>
282{
283 return m_session.get();
284}
285
286template<typename Server_session_t>
289{
290 return const_cast<Server_context*>(this)->session();
291}
292
293template<typename Server_session_t>
294std::ostream& operator<<(std::ostream& os, const Server_context<Server_session_t>& val)
295{
296 return os << "[session[" << *(val.session()) << "] vat_netwk[" << *(val.vat_network()) << "]]@" << &val;
297}
298
299} // namespace ipc::transport::struc::shm::rpc
The mirror of an opposing PEER-state Client_context, as generated via successful Context_server::acce...
Session_ptr m_session
Session in PEER state.
~Server_context()
Identical semantics to Client_context. See that doc header.
Vat_network * vat_network()
Returns pointer to Session_vat_network established for use in your Rpc_system.
boost::movelib::unique_ptr< Server_context > Ptr
Movable smart-pointer handle to a *this.
Session_obj * session()
Returns pointer to Session_obj (in PEER state).
Server_context(flow::log::Logger *logger_ptr, kj::AsyncIoContext *kj_io, Session_obj &&session, Native_handle &&bidir_transport, bool enable_hndl_transport, bool sans_shm_transport)
Constructs us in PEER state.
Server_session_t Session_obj
Convenience alias for template arg.
static void on_session_hosed(flow::log::Logger *logger_ptr, const Session_obj &session, const Error_code &err_code)
Spiritually identical to Client_context::on_session_hosed(), including in being static and capturing ...
typename Session_obj::Vat_network Vat_network
The Session_vat_network concrete type – and capnp::VatNetwork interface impl – that we produce.
Vat_network m_network
The established Vat_network.
typename Vat_network::Shm_lender_borrower_ptr Session_ptr
Basically shared_ptr<Session_obj>.
Provides Flow-IPC's integration with Cap'n Proto's Remote Procedure Call (RPC) layer,...
std::ostream & operator<<(std::ostream &os, const Client_context< Client_session_t > &val)
Prints string representation of the given Client_context to the given ostream.
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
Definition: common.hpp:338
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313
This is the friend facade of Server_context that exposes the internal-use private API,...
Non-template base for Session_vat_network (constants, types, and what-not).
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.