MySQL 8.4.0
Source Code Documentation
local.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2020, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef MYSQL_HARNESS_NET_TS_LOCAL_H_
27#define MYSQL_HARNESS_NET_TS_LOCAL_H_
28
29#include <cstring>
30#include <string>
31#include <system_error>
32
33#ifndef _WIN32
34#include <sys/un.h>
35#define NET_TS_HAS_UNIX_SOCKET
36#else
37#include <WinSock2.h>
38#include <Windows.h>
39
40#ifdef AF_UNIX
41#include <afunix.h>
42#define NET_TS_HAS_UNIX_SOCKET
43#endif
44#endif
45
46#ifdef NET_TS_HAS_UNIX_SOCKET
47
48#if defined(__FreeBSD__) || defined(__APPLE__)
49#include <sys/ucred.h>
50#endif
51
52#if defined(__linux__) || defined(__OpenBSD__)
53#include <sys/socket.h> // struct ucred, struct sockpeercred
54#endif
55
59
60namespace local {
61
62/**
63 * endpoint of Unix domain sockets (AF_UNIX).
64 *
65 * path may be:
66 *
67 * - empty (unnamed sockets, aka 'autobind' on Linux)
68 * - start with NUL-byte (abstract sockets, no file, used for socketpair())
69 * - a path
70 */
71template <typename Protocol>
73 public:
75
76 constexpr basic_endpoint() noexcept : data_{} {
77 data_.sun_family = protocol_type().family();
78 // unix-socket in unnamed namespace
79 }
80
81 // create a unix domain socket in the 'pathname namespace' or 'abstract
82 // namespace' (starting with \0)
83 //
84 // note: can be 'constexpr' with C++2a's http://wg21.link/P0202 applied
85 basic_endpoint(std::string_view path) : data_{} {
86 data_.sun_family = protocol_type().family();
87
88 const auto truncated_path =
89 path.substr(0, std::min(max_path_len(), path.size()));
90
91 // use std::copy() instead of std::memcpy() as it will be constexpr in C++20
92 std::copy(truncated_path.begin(), truncated_path.end(), data_.sun_path);
93
94 path_len_ = truncated_path.size();
95 }
96
97 constexpr protocol_type protocol() const noexcept { return protocol_type(); }
98
99 /**
100 * get path.
101 */
102 std::string path() const {
103 if (path_len_ > 0) {
104 return {data_.sun_path, path_len_};
105 } else {
106 return {};
107 }
108 }
109
110 const void *data() const noexcept { return &data_; }
111
112 void *data() noexcept { return &data_; }
113
114 /**
115 * bytes used data().
116 */
117 constexpr size_t size() const noexcept {
118 return offsetof(sockaddr_un, sun_path) + path_len_;
119 }
120
121 constexpr size_t capacity() const noexcept { return sizeof(data_); }
122
123 /**
124 * resize data().
125 *
126 * @param n size to resize data() too
127 *
128 * if n == 0, path() is considered empty,
129 * if n < offsetof(sockaddr_un, sun_path), behaviour is undefined,
130 * otherwise path().size() is the rest of the data()
131 */
132 void resize(size_t n) noexcept {
133 if (n >= offsetof(sockaddr_un, sun_path)) {
134 // path length: the rest of the message
135 path_len_ = std::min(capacity(), n) - offsetof(sockaddr_un, sun_path);
136
137 // ... but it may be null-terminated as long as the NUL-byte isn't at the
138 // first position
139 if (path_len_ > 0 && data_.sun_path[0] != '\0') {
140 path_len_ = strnlen(data_.sun_path, path_len_);
141 }
142 } else {
143 // socketpair's recvmsg sets the msg_namelen to 0 which implies
144 //
145 // - no path
146 // - family is the same as our socket's
147 path_len_ = 0;
148 }
149 }
150
151 private:
152 constexpr size_t max_path_len() const {
153 return capacity() - offsetof(sockaddr_un, sun_path);
154 }
155
156 sockaddr_un data_;
157 size_t path_len_{0};
158}; // namespace local
159
160template <typename Protocol>
161::std::ostream &operator<<(::std::ostream &os,
162 const basic_endpoint<Protocol> &ep) {
163 std::string path = ep.path();
164
165 // if first char is a '\0' it is abstract socket-path as used by socketpair()
166 // on Linux
167 //
168 // replace the '\0' by '@' to make it printable
169 if (path.size() > 0 && path[0] == '\0') {
170 path[0] = '@';
171 }
172 os << path;
173
174 return os;
175}
176
177template <class Protocol>
181 Protocol proto;
182 const auto res = io_ctx->socket_service()->socketpair(
183 proto.family(), proto.type(), proto.protocol());
184 if (!res) return stdx::unexpected(res.error());
185
186 const auto fds = *res;
187
188 const auto assign1_res = sock1.assign(proto, fds.first);
189 if (!assign1_res) {
190 io_ctx->socket_service()->close(fds.first);
191 io_ctx->socket_service()->close(fds.second);
192
193 return assign1_res;
194 }
195
196 const auto assign2_res = sock2.assign(proto, fds.second);
197 if (!assign2_res) {
198 sock1.close();
199 io_ctx->socket_service()->close(fds.second);
200
201 return assign2_res;
202 }
203
204 return {};
205}
206
207template <class Protocol>
209 const basic_endpoint<Protocol> &b) {
210 return a.path() == b.path();
211}
212
213template <class Protocol>
215 const basic_endpoint<Protocol> &b) {
216 return !(a == b);
217}
218
219namespace socket_option {
220#if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
221 defined(__NetBSD__) || defined(__APPLE__)
222template <int Level, int Name>
223class cred {
224 public:
225#if defined(__linux__)
226 using value_type = struct ucred;
227#elif defined(__OpenBSD__)
228 using value_type = struct sockpeercred;
229#elif defined(__FreeBSD__) || defined(__APPLE__)
230 using value_type = struct xucred;
231#elif defined(__NetBSD__)
232 using value_type = struct sockpeercred;
233#else
234#error "unsupported OS"
235#endif
236
237 constexpr cred() : value_{} {}
238
239 constexpr explicit cred(value_type v) : value_{v} {}
240
241 value_type value() const { return value_; }
242
243 template <typename Protocol>
244 constexpr int level(const Protocol & /* unused */) const noexcept {
245 return Level;
246 }
247
248 template <typename Protocol>
249 constexpr int name(const Protocol & /* unused */) const noexcept {
250 return Name;
251 }
252
253 template <typename Protocol>
254 value_type *data(const Protocol & /* unused */) {
255 return &value_;
256 }
257
258 template <typename Protocol>
259 const value_type *data(const Protocol & /* unused */) const {
260 return &value_;
261 }
262
263 /**
264 * size of data().
265 *
266 * may be smaller than sizeof(value_type) after resize() was called.
267 */
268 template <typename Protocol>
269 constexpr size_t size(const Protocol & /* unused */) const {
270 return size_;
271 }
272
273 /**
274 * resize data().
275 *
276 * called by basic_socket::get_option()
277 *
278 * @throws std::length_error if resize() would grow past sizeof(value_type)
279 */
280 template <typename Protocol>
281 void resize(const Protocol &p, size_t new_size) {
282 // freebsd/apple new_size == 4, with sizeof(xucred) == 76
283 // after socketpair(), SOCK_STREAM, LOCAL_PEERCRED
284 if (new_size > size(p)) {
285 throw std::length_error(
286 "overrun in socket_option::cred::resize(): current_size=" +
287 std::to_string(size(p)) + ", new_size=" + std::to_string(new_size));
288 }
289
290 size_ = new_size;
291 }
292
293 private:
294 value_type value_;
295
296 size_t size_{sizeof(value_)};
297};
298#endif
299} // namespace socket_option
300
302 public:
306
307 // note: to add: socket-control-message to pass credentials
308 //
309 // FreeBSD, NetBSD: LOCAL_CREDS + SCM_CREDS
310 // Linux: SO_PASSCRED + SCM_CREDENTIALS
311
312 // note: to add: socket-control-message for pass fd
313 //
314 // FreeBSD, Linux: SCM_RIGHTS
315
316 // note: to add: socket-opt LOCAL_CONNWAIT (FreeBSD)
317
318 // peer's credentials at connect()-time/listen()-time
319#if defined(__linux__) || defined(__OpenBSD__)
320 using peer_creds = socket_option::cred<SOL_SOCKET, SO_PEERCRED>;
321#elif defined(__FreeBSD__) || defined(__APPLE__)
322 using peer_creds = socket_option::cred<SOL_SOCKET, LOCAL_PEERCRED>;
323#elif defined(__NetBSD__)
324 using peer_creds = socket_option::cred<SOL_SOCKET, LOCAL_PEEREID>;
325#endif
326 // solaris uses getpeerucred(), ucred_geteuid(), ucred_getegid()
327 //
328 // windows: SIO_AF_UNIX_GETPEERPID via WSAIoctl()
329
330 constexpr int family() const noexcept { return AF_UNIX; }
331 constexpr int type() const noexcept { return SOCK_STREAM; }
332 constexpr int protocol() const noexcept { return 0; }
333};
334
335// datagram.
336//
337// SOCK_DGRAM for AF_UNIX.
338//
339// messages may be in any order when received.
341 public:
344
345 // no peer_creds on datagram_protocol as it doesn't call "connect()" nor
346 // "listen()". It needs SCM_CREDS instead
347
348 constexpr int family() const noexcept { return AF_UNIX; }
349 constexpr int type() const noexcept { return SOCK_DGRAM; }
350 constexpr int protocol() const noexcept { return 0; }
351};
352
353// seqpacket over AF_UNIX.
354//
355// seqpacket is mix between stream_protocol and datagram_protocol:
356//
357// - connection-oriented (accept(), ...)
358// - reliable (sequence order)
359//
360// like SOCK_STREAM
361//
362// - message boundaries are visible via MSG_EOR/MSG_TRUNC in recvmsg()
363//
364// like SOCK_DGRAM
365//
366// @see recvmsg()
367//
369 public:
373
374#if defined(__linux__) || defined(__OpenBSD__) || defined(__FreeBSD__) || \
375 defined(__APPLE__) || defined(__NetBSD__)
376 using peer_creds = stream_protocol::peer_creds;
377#endif
378
379 constexpr int family() const noexcept { return AF_UNIX; }
380 constexpr int type() const noexcept { return SOCK_SEQPACKET; }
381 constexpr int protocol() const noexcept { return 0; }
382};
383} // namespace local
384#endif
385
386#endif
Definition: protocol.h:33
virtual enum enum_protocol_type type() const =0
endpoint of Unix domain sockets (AF_UNIX).
Definition: local.h:72
const void * data() const noexcept
Definition: local.h:110
constexpr size_t capacity() const noexcept
Definition: local.h:121
constexpr protocol_type protocol() const noexcept
Definition: local.h:97
void * data() noexcept
Definition: local.h:112
constexpr basic_endpoint() noexcept
Definition: local.h:76
void resize(size_t n) noexcept
resize data().
Definition: local.h:132
Protocol protocol_type
Definition: local.h:74
size_t path_len_
Definition: local.h:157
constexpr size_t max_path_len() const
Definition: local.h:152
sockaddr_un data_
Definition: local.h:156
basic_endpoint(std::string_view path)
Definition: local.h:85
std::string path() const
get path.
Definition: local.h:102
constexpr size_t size() const noexcept
bytes used data().
Definition: local.h:117
Definition: local.h:340
constexpr int type() const noexcept
Definition: local.h:349
constexpr int family() const noexcept
Definition: local.h:348
constexpr int protocol() const noexcept
Definition: local.h:350
Definition: local.h:368
constexpr int protocol() const noexcept
Definition: local.h:381
constexpr int type() const noexcept
Definition: local.h:380
constexpr int family() const noexcept
Definition: local.h:379
Definition: local.h:301
constexpr int family() const noexcept
Definition: local.h:330
constexpr int type() const noexcept
Definition: local.h:331
constexpr int protocol() const noexcept
Definition: local.h:332
Definition: socket.h:911
Definition: socket.h:711
stdx::expected< void, error_type > close()
Definition: socket.h:829
stdx::expected< void, error_type > assign(const protocol_type &protocol, const native_handle_type &native_handle)
Definition: socket.h:723
Definition: socket.h:1090
virtual stdx::expected< void, error_type > close(native_handle_type native_handle) const =0
virtual stdx::expected< std::pair< native_handle_type, native_handle_type >, error_type > socketpair(int family, int sock_type, int protocol) const =0
Definition: io_context.h:61
impl::socket::SocketServiceBase * socket_service() const
Definition: io_context.h:135
Definition: expected.h:284
const char * p
Definition: ctype-mb.cc:1235
static std::string to_string(const LEX_STRING &str)
Definition: lex_string.h:50
static char * path
Definition: mysqldump.cc:149
void copy(Shards< COUNT > &dst, const Shards< COUNT > &src) noexcept
Copy the counters, overwrite destination.
Definition: ut0counter.h:354
uint16_t value_type
Definition: vt100.h:184
Definition: local.h:60
::std::ostream & operator<<(::std::ostream &os, const basic_endpoint< Protocol > &ep)
Definition: local.h:161
bool operator==(const basic_endpoint< Protocol > &a, const basic_endpoint< Protocol > &b)
Definition: local.h:208
bool operator!=(const basic_endpoint< Protocol > &a, const basic_endpoint< Protocol > &b)
Definition: local.h:214
stdx::expected< void, std::error_code > connect_pair(net::io_context *io_ctx, net::basic_socket< Protocol > &sock1, net::basic_socket< Protocol > &sock2)
Definition: local.h:178
size_t size(const char *const c)
Definition: base64.h:46
unexpected(E) -> unexpected< E >
case opt name
Definition: sslopt-case.h:29
int n
Definition: xcom_base.cc:509