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