Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
util_fwd.hpp
Go to the documentation of this file.
1/* Flow-IPC: Core
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 <flow/async/util.hpp>
25#include <flow/util/util_fwd.hpp>
26#include <boost/asio.hpp>
27#include <boost/interprocess/permissions.hpp>
28#include <boost/interprocess/creation_tags.hpp>
29#include <cstdint>
30#include <string>
31
32/**
33 * Flow-IPC module containing miscellaneous general-use facilities that are ubiquitously used by ~all Flow-IPC modules
34 * and/or do not fit into any other Flow-IPC module.
35 *
36 * Each symbol therein is typically used by at least 1 other Flow-IPC module; but all public symbols (except ones
37 * under a detail/ subdirectory) are intended for use by Flow-IPC user as well. Some particulars to note:
38 *
39 * ipc::util::Shared_name is a universally used shared-resource name class, conceptually similar to
40 * `boost::filesystem::path`. It is used in ipc::transport APIs -- namely to name endpoints when establishing channels,
41 * and more -- but also in other Flow-IPC modules. For example `Shared_name` is used to name certain SHM entities
42 * in ipc::shm and in ipc::session when connecting to conversation partner process(es).
43 *
44 * ipc::util::Native_handle is a commonly used native-handle (FD in POSIX parlance) wrapper (so thin it doesn't add
45 * a single bit on top of the actual FD). These are ~always passed around by value (copied), as they are very small
46 * in practice.
47 *
48 * There are of course various other things; just check them out as they are referenced, or just look around.
49 * Note there are free functions providing various niceties; and more types including classes and scoped `enum`s.
50 */
51namespace ipc::util
52{
53
54// Types.
55
56/* Normally we'd try to forward-declare the following only, but doing so means (1) having to specify `: size_t`
57 * in two places, here and the definition; and (2) ::S_END_SENTINEL cannot be used in _fwd.hpp to, say,
58 * set a compile-time array<> size. So just make an exception and define the enum fully here. It's not
59 * "really" an aggregate type (class), so it's all right. */
60
61#ifndef FLOW_OS_LINUX
62static_assert(false, "Design of Permissions_level assumes a POSIX-y security model with users and groups; "
63 "we have not yet considered whether it can apply to Windows in its current form. "
64 "Should work in non-Linux POSIX OS (like macOS) but must be checked/tested.");
65#endif
66
67/**
68 * Simple specifier of desired access permissions, usually but not necessarily translated into
69 * a `Permissions` value (though even then different value in different contexts). May be used to map, say,
70 * from a Permissions_level to a #Permissions value in an
71 * `array<Permissions, size_t(Permissions_level::S_END_SENTINEL)>`.
72 *
73 * While, unlike #Permissions, this `enum` intends not to be overtly based on a POSIX RWXRWXRWX model, it does
74 * still assume the 3 user groupings are "user themselves," "user's group," and "everyone." The 1st and 3rd
75 * are likely universal, but the 2nd may not apply to all OS -- though probably all POSIX/Unix ones --
76 * and even for something like Linux there could be different groupings such as ones based on OS ACL.
77 * As of this writing it's fine, as this is a POSIX-targeted library at least (in fact Linux as of this writing,
78 * but that could change to include, say, macOS/similar).
79 *
80 * @internal
81 *
82 * ### Maintenance ###
83 * Do *not* change the order of these constants unless absolutely necessary. In general any change here
84 * means updating any `array<>`s (etc.) that map implicitly from a `size_t` representing
85 * Permissions_level. By convention they are named `*_PERMISSIONS_LVL_MAP` as of this writing.
86 *
87 * The `array<>` mapping scheme is for max performance; if one uses an `unordered_map` or similar, then there is no
88 * similar issue.
89 */
90enum class Permissions_level : size_t
91{
92 /// Forbids all access, even by the creator's user. Most likely this would be useful for testing or debugging.
94
95 /// Allows access by resource-owning user (in POSIX/Unix identified by UID) and no one else.
97
98 /**
99 * Allows access by resource-owning user's containing group(s) (in POSIX/Unix identified by GID) and no one else.
100 * This implies, as well, at least as much access as `S_USER_ACCESS`.
101 */
103
104 /// Allows access by all. Implies, as well, at least as much access as `S_GROUP_ACCESS` and thus `S_USER_ACCESS`.
106
107 /// Sentinel: not a valid value. May be used to, e.g., size an `array<>` mapping from Permissions_level.
109}; // enum class Permissions_level
110
111/// Short-hand for Flow's `String_view`.
113/// Short-hand for Flow's `Fine_duration`.
115/// Short-hand for Flow's `Fine_time_pt`.
117
118/// Short-hand for polymorphic function (a-la `std::function<>`) that takes no arguments and returns nothing.
120
121/**
122 * Short-hand for an immutable blob somewhere in memory, stored as exactly a `void const *` and a `size_t`.
123 *
124 * ### How to use ###
125 * We provide this alias as a stylistic short-hand, as it better suits various interfaces especially in
126 * ipc::transport. Nevertheless it's not meant to be more than that; it's not an attempt to abstract it away.
127 *
128 * That is to say, to work with these (create them, access them, etc.), do use the highly convenient
129 * boost.asio buffer APIs which are well documented in boost.asio's docs.
130 */
131using Blob_const = boost::asio::const_buffer;
132
133/**
134 * Short-hand for a mutable blob somewhere in memory, stored as exactly a `void*` and a `size_t`.
135 * @see ipc::util::Blob_const; usability notes in that doc header apply similarly here.
136 */
137using Blob_mutable = boost::asio::mutable_buffer;
138
139/// Syntactic-sugary type for POSIX process ID (integer).
140using process_id_t = ::pid_t;
141
142/// Syntactic-sugary type for POSIX user ID (integer).
143using user_id_t = ::uid_t;
144
145/// Syntactic-sugary type for POSIX group ID (integer).
146using group_id_t = ::gid_t;
147
148/// Tag type indicating an atomic open-if-exists-else-create operation. @see #OPEN_OR_CREATE.
149using Open_or_create = bipc::open_or_create_t;
150
151/// Tag type indicating an ideally-atomic open-if-exists-else-fail operation. @see #OPEN_ONLY.
152using Open_only = bipc::open_only_t;
153
154/// Tag type indicating a create-unless-exists-else-fail operation. @see #CREATE_ONLY.
155using Create_only = bipc::create_only_t;
156
157/// Short-hand for Unix (POSIX) permissions class.
158using Permissions = bipc::permissions;
159
160// Constants.
161
162/// Tag value indicating an open-if-exists-else-create operation.
163extern const Open_or_create OPEN_OR_CREATE;
164
165/// Tag value indicating an atomic open-if-exists-else-fail operation.
166extern const Open_only OPEN_ONLY;
167
168/// Tag value indicating an atomic create-unless-exists-else-fail operation.
169extern const Create_only CREATE_ONLY;
170
171/// A (default-cted) string. May be useful for functions returning `const std::string&`.
172extern const std::string EMPTY_STRING;
173
174// Free functions.
175
176/**
177 * Maps general Permissions_level specifier to low-level #Permissions value, when the underlying resource
178 * is in the file-system and is either accessible (read-write in terms of file system) or inaccessible.
179 * Examples of such resources are SHM pools (e.g., shm::classic::Pool_arena), bipc MQs (transport::Bipc_mq_handle),
180 * POSIX MQs (transport::Posix_mq_handle).
181 *
182 * Please do not confuse this setting with the read-only/read-write dichotomy potentially specified each time such
183 * a resource is opened for access (as is the case for SHM pools): the present mapping applies to a persistent
184 * protection in the file system, not at runtime at the code writer's discretion. The present permissions check
185 * is performed at opening time; the runtime writability check each time a datum is written into the resource.
186 *
187 * @param permissions_lvl
188 * The value to translate.
189 * @return The result.
190 */
192
193/**
194 * Utility that sets the permissions of the given resource (at the supplied file system path) to specified
195 * POSIX value. If the resource cannot be accessed (not found, permissions...), that system Error_code shall be
196 * emitted.
197 *
198 * ### Rationale ###
199 * It may seem unnecessary, particularly given that it sometimes (in our internal code, but I mention it
200 * publicly for exposition purposes) is placed right after the creation of the resource (file, SHM pool,
201 * POSIX MQ, shared mutex, etc.) -- where the same `perms` is supplied to the creation-API, whichever is
202 * applicable. The reason is that those APIs tend to make the corresponding OS call (e.g., `open()`)
203 * which is bound by the "process umask" in POSIX/Linux; so for example if it's set to the typical
204 * 022 (octal), then it's impossible to make the resource group- or all-writable, regardless of
205 * `perms`. set_resource_permissions() uses a technique that bypasses the umask thing. Note that it does not make
206 * any calls to change the umask to accomplish this.
207 *
208 * Note 1: Sometimes there is not even the creation-API argument for `perms`; in which case the rationale is even
209 * more straightforward.
210 *
211 * Note 2: Sometimes there *is* that API... and (namely in boost.ipc at least) they actually took care to do this
212 * (what we do here) themselves (via `fchmod()` and such)... so we don't need to; in fact I (ygoldfel) treated
213 * it as valuable confirmation of the correctness of this maneuver.
214 *
215 * @note The resource must be readable by the calling process: this overload opens it (read-only) to obtain a
216 * descriptor and then acts as the other overload. So, e.g., an owner cannot use it to loosen the permissions of
217 * a resource it has made unreadable to itself; in that case open it yourself by other means (if possible) and
218 * use the other overload.
219 *
220 * @param logger_ptr
221 * Logger to use for logging (WARNING, on error only). Caller can themselves log further info if desired.
222 * @param path
223 * Path to resource. Symlinks are followed, and the target is the resource in question (not the symlink).
224 * @param perms
225 * The permissions to set.
226 * @param err_code
227 * See `flow::Error_code` docs for error reporting semantics. #Error_code generated:
228 * see other overload; note that in addition file-not-found and the like are possible errors (in fact
229 * arguably the likeliest).
230 */
231void set_resource_permissions(flow::log::Logger* logger_ptr, const fs::path& path,
232 const Permissions& perms, Error_code* err_code = nullptr);
233
234/**
235 * Identical to the other set_resource_permissions() overload but operates on a pre-opened Native_handle
236 * (a/k/a handle, socket, file descriptor) to the resource in question.
237 *
238 * @param logger_ptr
239 * See other overload.
240 * @param handle
241 * See above. `handle.null() == true` causes undefined behavior (assertion may trip).
242 * Closed/invalid/etc. handle will yield civilized Error_code emission.
243 * @param perms
244 * See other overload.
245 * @param err_code
246 * See `flow::Error_code` docs for error reporting semantics. #Error_code generated:
247 * system error codes if permissions cannot be set (invalid descriptor, un-opened descriptor, etc.).
248 */
249void set_resource_permissions(flow::log::Logger* logger_ptr, Native_handle handle,
250 const Permissions& perms, Error_code* err_code = nullptr);
251
252/**
253 * Returns `true` if and only if the given process (by PID) is reported as running by the OS.
254 * Caution: It may be running, but it may be a zombie; and/or it may be running now but dead shortly after
255 * this function returns. Use defensively.
256 *
257 * @note PID recycling is also possible. In most contexts this happens on a much larger time scale than is
258 * practically relevant, but we advise verifying your exact situation.
259 *
260 * Implementation (normally avoided in contract docs, but we'd like to be as useful as we can here):
261 * It invokes POSIX `kill()` with the fake zero "signal"; success or failure-due-to-identity/permissions indicates
262 * the process *can* be signaled (by someone with proper identity/permissions anyway) and therefore exists. Otherwise
263 * it does not exist.
264 *
265 * @param process_id
266 * The process ID of the process in question. If it is not positive, then `false` is returned (no single
267 * process can have such a PID).
268 * @return See above.
269 */
270bool process_running(process_id_t process_id);
271
272/**
273 * Syntactic-sugary helper that returns pointer to first byte in an immutable buffer, as `const uint8_t*`.
274 *
275 * @param blob
276 * The buffer.
277 * @return See above.
278 */
279const uint8_t* blob_data(const Blob_const& blob);
280
281/**
282 * Syntactic-sugary helper that returns pointer to first byte in a mutable buffer, as `uint8_t*`.
283 *
284 * @param blob
285 * The buffer.
286 * @return See above.
287 */
288uint8_t* blob_data(const Blob_mutable& blob);
289
290} // namespace ipc::util
291
292/// Stats-related sub-namespace of ipc::util, for general organization (and ADL segregation if needed).
293namespace ipc::util::stat
294{
295
296// Types.
297
298// Find doc headers near the bodies of these compound types.
299
300struct Info_dump_format;
301
302} // namespace ipc::util::stat
Stats-related sub-namespace of ipc::util, for general organization (and ADL segregation if needed).
Definition: util.hpp:24
Flow-IPC module containing miscellaneous general-use facilities that are ubiquitously used by ~all Fl...
Definition: util.cpp:31
::pid_t process_id_t
Syntactic-sugary type for POSIX process ID (integer).
Definition: util_fwd.hpp:140
bipc::permissions Permissions
Short-hand for Unix (POSIX) permissions class.
Definition: util_fwd.hpp:158
const uint8_t * blob_data(const Blob_const &blob)
Syntactic-sugary helper that returns pointer to first byte in an immutable buffer,...
Definition: util.cpp:181
Permissions_level
Simple specifier of desired access permissions, usually but not necessarily translated into a Permiss...
Definition: util_fwd.hpp:91
@ S_UNRESTRICTED
Allows access by all. Implies, as well, at least as much access as S_GROUP_ACCESS and thus S_USER_ACC...
@ S_USER_ACCESS
Allows access by resource-owning user (in POSIX/Unix identified by UID) and no one else.
@ S_GROUP_ACCESS
Allows access by resource-owning user's containing group(s) (in POSIX/Unix identified by GID) and no ...
@ S_NO_ACCESS
Forbids all access, even by the creator's user. Most likely this would be useful for testing or debug...
flow::async::Task Task
Short-hand for polymorphic function (a-la std::function<>) that takes no arguments and returns nothin...
Definition: util_fwd.hpp:119
bipc::open_only_t Open_only
Tag type indicating an ideally-atomic open-if-exists-else-fail operation.
Definition: util_fwd.hpp:152
::gid_t group_id_t
Syntactic-sugary type for POSIX group ID (integer).
Definition: util_fwd.hpp:146
const Open_or_create OPEN_OR_CREATE
Tag value indicating an open-if-exists-else-create operation.
Definition: util.cpp:36
::uid_t user_id_t
Syntactic-sugary type for POSIX user ID (integer).
Definition: util_fwd.hpp:143
const Open_only OPEN_ONLY
Tag value indicating an atomic open-if-exists-else-fail operation.
Definition: util.cpp:37
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
Definition: util_fwd.hpp:137
bool process_running(process_id_t process_id)
Returns true if and only if the given process (by PID) is reported as running by the OS.
Definition: util.cpp:140
bipc::open_or_create_t Open_or_create
Tag type indicating an atomic open-if-exists-else-create operation.
Definition: util_fwd.hpp:149
bipc::create_only_t Create_only
Tag type indicating a create-unless-exists-else-fail operation.
Definition: util_fwd.hpp:155
flow::Fine_time_pt Fine_time_pt
Short-hand for Flow's Fine_time_pt.
Definition: util_fwd.hpp:116
Permissions shared_resource_permissions(Permissions_level permissions_lvl)
Maps general Permissions_level specifier to low-level Permissions value, when the underlying resource...
Definition: util.cpp:43
void set_resource_permissions(flow::log::Logger *logger_ptr, const fs::path &path, const Permissions &perms, Error_code *err_code)
Utility that sets the permissions of the given resource (at the supplied file system path) to specifi...
Definition: util.cpp:52
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
Definition: util_fwd.hpp:114
const std::string EMPTY_STRING
A (default-cted) string. May be useful for functions returning const std::string&.
Definition: util.cpp:39
const Create_only CREATE_ONLY
Tag value indicating an atomic create-unless-exists-else-fail operation.
Definition: util.cpp:38
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
Definition: util_fwd.hpp:131
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:112
@ S_END_SENTINEL
CAUTION – see ipc::Log_component doc header for directions to find actual members of this enum class.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.