Flow-IPC 1.0.2
Flow-IPC project: Full implementation reference.
native_handle.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
21#include <ostream>
22#include <flow/common.hpp>
23
24namespace ipc::util
25{
26
27#ifndef FLOW_OS_LINUX
28static_assert(false, "Flow-IPC supports transmitting native handles in Linux only; a core feature. "
29 "Build in Linux only.");
30#endif
31// From this point on (in #including .cpp files as well) POSIX is assumed; and in a few spots specifically Linux.
32
33// Types.
34
35/* Note: We lack a native_handle_fwd.hpp, as it's such a thin wrapper around an FD (int) that there's no point
36 * forward-declaring it, as it's ~always referred to by value. */
37
38/**
39 * A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.
40 * It would have been acceptable to simply use an alias
41 * to the native handle type (in POSIX, `int`), but this way is better stylistically with exactly zero performance
42 * overhead. Initialize it, e.g., `Native_handle hndl(some_fd);`, where
43 * `some_fd` might be some POSIX-y FD (network socket, Unix domain socket, file descriptor, etc.).
44 * Or initialize via no-arg construction which results in an `null() == true` object. Copy construction, assignment,
45 * equality, total ordering, and hashing all work as one would expect and essentially the same as on the underlying
46 * native handles.
47 *
48 * It is either null() or stores a native handle. In the former case, null() being `true` means explicitly
49 * that `m_native_handle == Native_handle::S_NULL_HANDLE`.
50 *
51 * ### Rationale ###
52 * Originally we tried to make it aggregate-initializable, like `Native_handle hndl = {some_fd}`; for example see
53 * standard `array<>`. This is reassuring perf-wise; and it involves less (i.e., no) code to boot.
54 * However, it really is just one light-weight scalar, and there's 0% chance explicit construction is any slower.
55 * So, perf isn't an issue. Still, why not make it aggregate-initializable though? I (ygoldfel) gave up, eventually,
56 * because I wanted *some* non-default-behavior constructors to be available, namely no-args (`Native_handle()` that
57 * makes an `null() == true` one) and move (`Native_handle(Native_handle&&)` that nullifies the source object).
58 * This isn't allowed in aggregate-initializable classes; so then I made some `static` "constructors" instead; but
59 * those aren't sufficient for containers... and on it went. This way, though verbose, just works out better for the
60 * API.
61 */
63{
64 // Types.
65
66 /// The native handle type. Much logic relies on this type being light-weight (fast to copy).
67 using handle_t = int;
68
69 // Constants.
70
71 /**
72 * The value for #m_native_handle such that `null() == true`; else it is `false`.
73 * No valid handle ever equals this.
74 */
75 static const handle_t S_NULL_HANDLE;
76
77 // Data.
78
79 /**
80 * The native handle (possibly equal to #S_NULL_HANDLE), the exact payload of this Native_handle.
81 * It can, of course, be assigned and accessed explicitly. The best way to initialize a
82 * new Native_handle is, therefore: `Native_handle{some_native_handle}`. You may also use the
83 * null() "constructor" to create a null() handle.
84 */
86
87 // Constructors/destructor.
88
89 /**
90 * Constructs with given payload; also subsumes no-args construction to mean constructing an object with
91 * `null() == true`.
92 *
93 * @param native_handle
94 * Payload.
95 */
96 Native_handle(handle_t native_handle = S_NULL_HANDLE);
97
98 /**
99 * Constructs object equal to `src`, while making `src == null()`.
100 *
101 * ### Rationale ###
102 * This is move construction, but it's not about performance at all (as this is all quite cheap anyway);
103 * more to allow for the pattern of making an object from another object without propagating more copies of the
104 * underlying handle. Won't the default move ctor take care of it? No, because it'll just copy the handle and not
105 * nullify it.
106 *
107 * @param src
108 * Source object which will be made `null() == true`.
109 */
111
112 /**
113 * Copy constructor.
114 * @param src
115 * Source object.
116 */
118
119 // Methods.
120
121 /**
122 * Move assignment; acts similarly to move ctor; but no-op if `*this == src`.
123 * @param src
124 * Source object which will be made `null() == true`, unles `*this == src`.
125 * @return `*this`.
126 */
128
129 /**
130 * Copy assignment; acts similarly to copy ctor.
131 * @param src
132 * Source object.
133 * @return `*this`.
134 */
136
137 /**
138 * Returns `true` if and only if #m_native_handle equals #S_NULL_HANDLE.
139 * @return See above.
140 */
141 bool null() const;
142}; // struct Native_handle
143
144// Free functions.
145
146/**
147 * Returns `true` if and only if the two Native_handle objects are the same underlying handle.
148 *
149 * @relatesalso Native_handle
150 *
151 * @param val1
152 * Object.
153 * @param val2
154 * Object.
155 * @return See above.
156 */
157bool operator==(Native_handle val1, Native_handle val2);
158
159/**
160 * Negation of similar `==`.
161 *
162 * @relatesalso Native_handle
163 *
164 * @param val1
165 * Object.
166 * @param val2
167 * Object.
168 * @return See above.
169 */
170bool operator!=(Native_handle val1, Native_handle val2);
171
172/**
173 * Returns a less-than comparison of two Native_handle objects, with the usual total ordering guarantees.
174 *
175 * @relatesalso Native_handle
176 *
177 * @param val1
178 * Left-hand side object.
179 * @param val2
180 * Right-hand side object.
181 * @return Whether left side is considered strictly less-than right side.
182 */
183bool operator<(Native_handle val1, Native_handle val2);
184
185/**
186 * Hasher of Native_handle for boost.unordered et al.
187 *
188 * @relatesalso Native_handle
189 *
190 * @param val
191 * Object to hash.
192 * @return See above.
193 */
194size_t hash_value(Native_handle val);
195
196/**
197 * Prints string representation of the given Native_handle to the given `ostream`.
198 *
199 * @relatesalso Native_handle
200 *
201 * @param os
202 * Stream to which to write.
203 * @param val
204 * Object to serialize.
205 * @return `os`.
206 */
207std::ostream& operator<<(std::ostream& os, const Native_handle& val);
208
209} // namespace ipc::util
Flow-IPC module containing miscellaneous general-use facilities that ubiquitously used by ~all Flow-I...
std::ostream & operator<<(std::ostream &os, const Native_handle &val)
Prints string representation of the given Native_handle to the given ostream.
bool operator<(Native_handle val1, Native_handle val2)
Returns a less-than comparison of two Native_handle objects, with the usual total ordering guarantees...
bool operator!=(Native_handle val1, Native_handle val2)
Negation of similar ==.
size_t hash_value(Native_handle val)
Hasher of Native_handle for boost.unordered et al.
bool operator==(Native_handle val1, Native_handle val2)
Returns true if and only if the two Native_handle objects are the same underlying handle.
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.
bool null() const
Returns true if and only if m_native_handle equals S_NULL_HANDLE.
Native_handle(const Native_handle &src)
Copy constructor.
Native_handle(handle_t native_handle=S_NULL_HANDLE)
Constructs with given payload; also subsumes no-args construction to mean constructing an object with...
static const handle_t S_NULL_HANDLE
The value for m_native_handle such that null() == true; else it is false.
Native_handle & operator=(Native_handle &&src)
Move assignment; acts similarly to move ctor; but no-op if *this == src.
int handle_t
The native handle type. Much logic relies on this type being light-weight (fast to copy).
handle_t m_native_handle
The native handle (possibly equal to S_NULL_HANDLE), the exact payload of this Native_handle.
Native_handle & operator=(const Native_handle &src)
Copy assignment; acts similarly to copy ctor.