MySQL 9.1.0
Source Code Documentation
socket.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 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_IMPL_SOCKET_H_
27#define MYSQL_HARNESS_NET_TS_IMPL_SOCKET_H_
28
29#include <algorithm> // max
30#include <array>
31#include <bitset>
32#include <cinttypes> // PRIx64
33#include <limits>
34#include <system_error>
35
36#ifdef _WIN32
37#include <WinSock2.h>
38#include <Windows.h>
39#ifdef AF_UNIX
40#include <afunix.h>
41#endif
42#else
43#include <fcntl.h>
44#include <netinet/in.h>
45#include <sys/ioctl.h>
46#include <sys/socket.h>
47#include <unistd.h> // close
48#endif
49
56
57#include "scope_guard.h"
58
59namespace net {
60namespace impl {
61namespace socket {
62
64 int sock_type,
65 int protocol) {
66 native_handle_type sock = ::socket(family, sock_type, protocol);
67
68 if (sock == kInvalidSocket) {
70 }
71
72 return sock;
73}
74
77#ifdef _WIN32
80 }
81#else
82 if (0 != ::close(native_handle)) {
84 }
85#endif
86 return {};
87}
88
90 unsigned long cmd, void *data) {
91#ifdef _WIN32
92 // use WSAIoctl() instead ?
93 if (kSocketError == ::ioctlsocket(native_handle, static_cast<long>(cmd),
94 reinterpret_cast<unsigned long *>(data))) {
96 }
97#else
98 if (kSocketError == ::ioctl(native_handle, cmd, data)) {
100 }
101#endif
102
103 return {};
104}
105
108#ifdef _WIN32
109 (void)native_handle;
110 // windows has no way to query to the blocking state
111 return stdx::unexpected(
112 std::make_error_code(std::errc::function_not_supported));
113#else
115 if (!res) return stdx::unexpected(res.error());
116
117 return (*res & O_NONBLOCK) != 0;
118#endif
119}
120
123#ifdef _WIN32
124 unsigned long nonblocking{on};
125
126 return ioctl(native_handle, FIONBIO, &nonblocking);
127#else
129 if (!res) return stdx::unexpected(res.error());
130
131 int flags = *res;
132
133 if (on) {
134 if (flags & O_NONBLOCK) return {};
135 flags |= O_NONBLOCK;
136 } else {
137 if (!(flags & O_NONBLOCK)) return {};
138 flags &= ~O_NONBLOCK;
139 }
140
141 auto set_res =
143 if (!set_res) return stdx::unexpected(set_res.error());
144
145 return {};
146#endif
147}
148
150 int backlog) {
151 if (kSocketError == ::listen(native_handle, backlog)) {
153 }
154
155 return {};
156}
157
159 native_handle_type native_handle, int level, int optname,
160 const void *optval, socklen_t optlen) {
161#ifdef _WIN32
162 int res = ::setsockopt(native_handle, level, optname,
163 reinterpret_cast<const char *>(optval), optlen);
164#else
165 int res = ::setsockopt(native_handle, level, optname, optval, optlen);
166#endif
167 if (kSocketError == res) {
169 }
170
171 return {};
172}
173
175 native_handle_type native_handle, int level, int optname, void *optval,
176 socklen_t *optlen) {
177#ifdef _WIN32
178 int res = ::getsockopt(native_handle, level, optname,
179 reinterpret_cast<char *>(optval), optlen);
180#else
181 int res = ::getsockopt(native_handle, level, optname, optval, optlen);
182#endif
183 if (kSocketError == res) {
185 }
186
187 return {};
188}
189
190/**
191 * wrap ::recv() in a portable way.
192 *
193 * @param native_handle socket handle
194 * @param buf pointer to a mutable buffer of size 'buf_len'
195 * @param buf_len size of 'buf'
196 * @param flags message flags
197 * @returns bytes transferred on success, std::error_code otherwise
198 */
200 void *buf, size_t buf_len,
202#if defined(_WIN32)
203 // recv() expects an 'int' instead of a 'size_t'.
204 // Ensure, buf_len is properly narrowed instead of wrapped around
205 auto bytes_transferred = ::recv(
206 native_handle, static_cast<char *>(buf),
207 std::min(static_cast<size_t>(std::numeric_limits<int>::max()), buf_len),
208 flags.to_ulong());
209#else
210 auto bytes_transferred =
211 ::recv(native_handle, buf, buf_len, static_cast<int>(flags.to_ulong()));
212#endif
213 if (kSocketError == bytes_transferred) {
215 }
216
217 return {static_cast<size_t>(bytes_transferred)};
218}
219
221 void *data, size_t data_len) {
222#ifdef _WIN32
223 // fallback to recv()
224 return recv(native_handle, data, data_len, 0);
225#else
226 auto bytes_transferred = ::read(native_handle, data, data_len);
227 if (kSocketError == bytes_transferred) {
229 }
230
231 return {static_cast<size_t>(bytes_transferred)};
232#endif
233}
234
237#ifdef _WIN32
238 DWORD bytes_transferred;
239 DWORD _flags = flags.to_ulong();
240
241 // WSARecvMsg() also exists, but is less flexible and is only reachable
242 // via a function-pointer-lookup via WSAID_WSARECVMSG
243 int err = ::WSARecvFrom(native_handle, msg.lpBuffers, msg.dwBufferCount,
244 &bytes_transferred, &_flags,
245 msg.name, // from
246 &msg.namelen, // from_len
247 nullptr, // overlapped
248 nullptr // completor
249 );
250 if (kSocketError == err) {
252 }
253#else
254 ssize_t bytes_transferred =
255 ::recvmsg(native_handle, &msg, static_cast<int>(flags.to_ulong()));
256 if (kSocketError == bytes_transferred) {
258 }
259#endif
260
261 return {static_cast<size_t>(bytes_transferred)};
262}
263
264/**
265 * wrap ::send() in a portable way.
266 *
267 * @param native_handle socket handle
268 * @param buf pointer to a const buffer of size 'buf_len'
269 * @param buf_len size of 'buf'
270 * @param flags message flags
271 * @returns bytes transferred on success, std::error_code otherwise
272 */
274 const void *buf, size_t buf_len,
276#if defined(_WIN32)
277 // send() expects an 'int' instead of a 'size_t'.
278 // Ensure, buf_len is properly narrowed instead of wrapped around
279 auto bytes_transferred = ::send(
280 native_handle, static_cast<const char *>(buf),
281 std::min(static_cast<size_t>(std::numeric_limits<int>::max()), buf_len),
282 flags.to_ulong());
283#else
284 // ssize_t
285 auto bytes_transferred =
286 ::send(native_handle, buf, buf_len, static_cast<int>(flags.to_ulong()));
287#endif
288 if (kSocketError == bytes_transferred) {
290 }
291
292 return {static_cast<size_t>(bytes_transferred)};
293}
294
296 native_handle_type native_handle, const void *data, size_t data_len) {
297#ifdef _WIN32
298 // fallback to send()
299 return send(native_handle, data, data_len, 0);
300#else
301 auto bytes_transferred = ::write(native_handle, data, data_len);
302 if (kSocketError == bytes_transferred) {
304 }
305
306 return {static_cast<size_t>(bytes_transferred)};
307#endif
308}
309
312#ifdef _WIN32
313 DWORD bytes_transferred;
314 DWORD _flags = flags.to_ulong();
315 int err = ::WSASendTo(native_handle, msg.lpBuffers, msg.dwBufferCount,
316 &bytes_transferred, _flags,
317 msg.name, // to
318 msg.namelen, // to_len
319 nullptr, // overlapped
320 nullptr // completor
321 );
322 if (kSocketError == err) {
324 }
325#else
326 ssize_t bytes_transferred =
327 ::sendmsg(native_handle, &msg, static_cast<int>(flags.to_ulong()));
328 if (kSocketError == bytes_transferred) {
330 }
331#endif
332
333 return {static_cast<size_t>(bytes_transferred)};
334}
335
336/**
337 * wrap ::bind() in a portable way.
338 */
340 const struct sockaddr *addr,
341 size_t addr_len) {
342 if (kSocketError ==
343 ::bind(native_handle, addr, static_cast<socklen_t>(addr_len))) {
345 }
346
347 return {};
348}
349
350/**
351 * wrap ::connect() in a portable way.
352 */
354 native_handle_type native_handle, const struct sockaddr *addr,
355 size_t addr_len) {
356 if (kSocketError ==
357 ::connect(native_handle, addr, static_cast<socklen_t>(addr_len))) {
359 }
360
361 return {};
362}
363
364/**
365 * wrap ::accept() in a portable way.
366 */
369 socklen_t *addr_len) {
370 native_handle_type fd = ::accept(native_handle, addr, addr_len);
371 if (kInvalidSocket == fd) {
373 }
374
375 return fd;
376}
377
378// freebsd and linux have accept4()
379// solaris and windows don't
382 socklen_t *addr_len, int flags = 0) {
383#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
384 defined(__NetBSD__)
385 native_handle_type fd = ::accept4(native_handle, addr, addr_len, flags);
386 if (kInvalidSocket == fd) {
388 }
389
390 return fd;
391#else
392 // static_assert(false, "operation not supported");
393 (void)native_handle;
394 (void)addr;
395 (void)addr_len;
396 (void)flags;
397
398 return stdx::unexpected(make_error_code(std::errc::operation_not_supported));
399#endif
400}
401
403 native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len) {
404#ifdef _WIN32
405 socklen_t len = static_cast<socklen_t>(*addr_len);
406#else
407 socklen_t len = *addr_len;
408#endif
409
410 if (kSocketError == ::getsockname(native_handle, addr, &len)) {
412 }
413
414#ifdef _WIN32
415 *addr_len = static_cast<size_t>(len);
416#else
417 *addr_len = len;
418#endif
419
420 return {};
421}
422
424 native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len) {
425#ifdef _WIN32
426 socklen_t len = static_cast<socklen_t>(*addr_len);
427#else
428 socklen_t len = *addr_len;
429#endif
430
431 if (kSocketError == ::getpeername(native_handle, addr, &len)) {
433 }
434
435#ifdef _WIN32
436 *addr_len = static_cast<size_t>(len);
437#else
438 *addr_len = len;
439#endif
440
441 return {};
442}
443
444/**
445 * socketpair().
446 *
447 * - wraps socketpair() on POSIX
448 * - emulates socketpair() on windows as winsock2() provides no socketpair.
449 */
452socketpair(int family, int sock_type, int protocol) {
453#if !defined(_WIN32)
454 std::array<native_handle_type, 2> fds;
455
456 if (0 != ::socketpair(family, sock_type, protocol, fds.data())) {
458 }
459
460 return std::make_pair(fds[0], fds[1]);
461#else
462 auto listener_res = impl::socket::socket(family, sock_type, protocol);
463 if (!listener_res) return stdx::unexpected(listener_res.error());
464
465 auto listener = listener_res.value();
466
467 Scope_guard listener_guard([listener]() {
468#if defined(AF_UNIX)
469 struct sockaddr_storage ss {};
470 size_t ss_len = sizeof(ss);
471
472 auto name_res = impl::socket::getsockname(
473 listener, reinterpret_cast<sockaddr *>(&ss), &ss_len);
474 if (name_res) {
475 if (ss.ss_family == AF_UNIX) {
476 struct sockaddr_un *su = reinterpret_cast<sockaddr_un *>(&ss);
477
478 // delete the named socket
479 DeleteFile(su->sun_path);
480 }
481 }
482#endif
483
484 impl::socket::close(listener);
485 });
486
488
489 switch (family) {
490 case AF_INET: {
491 int reuse = 1;
492 impl::socket::setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &reuse,
493 sizeof(reuse));
494
495 struct sockaddr_in sa {};
496 size_t sa_len = sizeof(sa);
497
498 sa.sin_family = family;
499 sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
500 sa.sin_port = 0; // pick a random port
501
502 bind_res = impl::socket::bind(listener, reinterpret_cast<sockaddr *>(&sa),
503 sa_len);
504 } break;
505#if defined(AF_UNIX)
506 case AF_UNIX: {
507 struct sockaddr_un sa {};
508 size_t sa_len = sizeof(sa);
509
510 sa.sun_family = family;
511
512 DWORD path_len = GetTempPath(UNIX_PATH_MAX, sa.sun_path);
513
514 // use the current dir if the tmppath is too long.
515 if (path_len >= UNIX_PATH_MAX - 9) path_len = 0;
516
517 LARGE_INTEGER ticks;
518 QueryPerformanceCounter(&ticks);
519
520 snprintf(sa.sun_path + path_len, UNIX_PATH_MAX - path_len,
521 "%" PRIx64 "-%lu.sok", ticks.QuadPart, GetCurrentProcessId());
522
523 bind_res = impl::socket::bind(listener, reinterpret_cast<sockaddr *>(&sa),
524 sa_len);
525 } break;
526#endif
527 default:
528 bind_res = stdx::unexpected(
529 make_error_code(std::errc::address_family_not_supported));
530 break;
531 }
532
533 if (!bind_res) return stdx::unexpected(bind_res.error());
534
535 auto listen_res = impl::socket::listen(listener, 128);
536 if (!listen_res) return stdx::unexpected(listen_res.error());
537
538 auto first_res = impl::socket::socket(family, sock_type, protocol);
539 if (!first_res) return stdx::unexpected(first_res.error());
540
541 auto first_fd = first_res.value();
542
543 Scope_guard first_fd_guard([first_fd]() { impl::socket::close(first_fd); });
544
545 auto remote_sa_res = [](auto sock_handle)
547 struct sockaddr_storage ss {};
548 size_t ss_len = sizeof(ss);
549
550 const auto name_res = impl::socket::getsockname(
551 sock_handle, reinterpret_cast<sockaddr *>(&ss), &ss_len);
552 if (!name_res) return stdx::unexpected(name_res.error());
553
554 // overwrite the address.
555 if (ss.ss_family == AF_INET) {
556 auto *sa = reinterpret_cast<sockaddr_in *>(&ss);
557
558 sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
559 }
560
561 return ss;
562 }(listener);
563
564 if (!remote_sa_res) return stdx::unexpected(remote_sa_res.error());
565 const auto remote_sa = *remote_sa_res;
566
567 const auto connect_res = impl::socket::connect(
568 first_fd, reinterpret_cast<const sockaddr *>(&remote_sa),
569 sizeof(remote_sa));
570 if (!connect_res) return stdx::unexpected(connect_res.error());
571
572 const auto second_res = impl::socket::accept(listener, nullptr, nullptr);
573 if (!second_res) return stdx::unexpected(second_res.error());
574
575 first_fd_guard.release();
576
577 auto second_fd = second_res.value();
578
579 return std::make_pair(first_fd, second_fd);
580#endif
581}
582
583#ifdef __linux__
585 native_handle_type fd_out,
586 size_t len, int flags) {
587 ssize_t written = ::splice(fd_in, nullptr, fd_out, nullptr, len, flags);
588
589 if (written == -1) {
591 }
592
593 // post-condition to ensure that we can safely convert to size_t
594 if (written < 0) {
595 return stdx::unexpected(make_error_code(std::errc::result_out_of_range));
596 }
597
598 return written;
599}
600#endif
601
603 native_handle_type fd_in, impl::file::file_handle_type fd_out, size_t len,
604 int flags) {
605#ifdef __linux__
606 return splice(fd_in, fd_out, len, flags);
607#else
608 (void)fd_in;
609 (void)fd_out;
610 (void)len;
611 (void)flags;
612
613 return stdx::unexpected(make_error_code(std::errc::operation_not_supported));
614#endif
615}
616
618 impl::file::file_handle_type fd_in, native_handle_type fd_out, size_t len,
619 int flags) {
620#ifdef __linux__
621 return splice(fd_in, fd_out, len, flags);
622#else
623 (void)fd_in;
624 (void)fd_out;
625 (void)len;
626 (void)flags;
627
628 return stdx::unexpected(make_error_code(std::errc::operation_not_supported));
629#endif
630}
631
633 wait_type wt) {
634 short events{};
635
636 switch (wt) {
638 events |= POLLIN;
639 break;
641 events |= POLLOUT;
642 break;
644 events |= POLLERR;
645 break;
646 }
647 std::array<impl::poll::poll_fd, 1> fds{{
648 {fd, events, 0},
649 }};
650
651 const auto res =
652 impl::poll::poll(fds.data(), fds.size(), std::chrono::milliseconds{-1});
653
654 if (!res) return stdx::unexpected(res.error());
655
656 return {};
657}
658
660 int how) {
661 const auto res = ::shutdown(fd, how);
662 if (kSocketError == res) {
664 }
665
666 return {};
667}
668
670#ifdef _WIN32
671 WORD wVersionRequested = MAKEWORD(2, 2);
672 WSADATA wsaData;
673 if (int err = WSAStartup(wVersionRequested, &wsaData)) {
675 }
676#endif
677 return {};
678}
679
680} // namespace socket
681} // namespace impl
682
683} // namespace net
684#endif
A Lambda to be called at scope exit.
Definition: scope_guard.h:55
Definition: expected.h:286
error_type
Definition: error.h:36
static int flags[50]
Definition: hp_test1.cc:40
#define closesocket(A)
Definition: my_io.h:178
static MYSQL * sock
Definition: mysqlcheck.cc:57
Definition: buf0block_hint.cc:30
Definition: http_server_component.cc:34
static Value err()
Create a Value object that represents an error condition.
Definition: json_binary.cc:908
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:79
stdx::expected< int, std::error_code > fcntl(file_handle_type fd, const FileControlOption &cmd)
Definition: file.h:125
int file_handle_type
Definition: file.h:53
stdx::expected< size_t, std::error_code > poll(poll_fd *fds, size_t num_fds, std::chrono::milliseconds timeout)
Definition: poll.h:53
stdx::expected< size_t, error_type > sendmsg(native_handle_type native_handle, msghdr_base &msg, message_flags flags)
Definition: socket.h:310
stdx::expected< void, error_type > listen(native_handle_type native_handle, int backlog)
Definition: socket.h:149
stdx::expected< void, error_type > getsockname(native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len)
Definition: socket.h:402
std::error_code make_error_code(int errcode)
make proper std::error_code for socket errno's
Definition: socket_error.h:96
stdx::expected< size_t, error_type > read(native_handle_type native_handle, void *data, size_t data_len)
Definition: socket.h:220
stdx::expected< native_handle_type, error_type > socket(int family, int sock_type, int protocol)
Definition: socket.h:63
stdx::expected< void, std::error_code > init()
Definition: socket.h:669
stdx::expected< std::pair< native_handle_type, native_handle_type >, error_type > socketpair(int family, int sock_type, int protocol)
socketpair().
Definition: socket.h:452
stdx::expected< void, error_type > bind(native_handle_type native_handle, const struct sockaddr *addr, size_t addr_len)
wrap bind() in a portable way.
Definition: socket.h:339
stdx::expected< size_t, error_type > send(native_handle_type native_handle, const void *buf, size_t buf_len, message_flags flags)
wrap send() in a portable way.
Definition: socket.h:273
std::error_code last_error_code()
get last std::error_code for socket-errors.
Definition: socket_error.h:107
stdx::expected< void, error_type > ioctl(native_handle_type native_handle, unsigned long cmd, void *data)
Definition: socket.h:89
stdx::expected< size_t, error_type > recvmsg(native_handle_type native_handle, msghdr_base &msg, message_flags flags)
Definition: socket.h:235
stdx::expected< size_t, error_type > splice_to_pipe(native_handle_type fd_in, impl::file::file_handle_type fd_out, size_t len, int flags)
Definition: socket.h:602
stdx::expected< void, error_type > getpeername(native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len)
Definition: socket.h:423
stdx::expected< native_handle_type, error_type > accept(native_handle_type native_handle, struct sockaddr *addr, socklen_t *addr_len)
wrap accept() in a portable way.
Definition: socket.h:367
stdx::expected< size_t, error_type > recv(native_handle_type native_handle, void *buf, size_t buf_len, message_flags flags)
wrap recv() in a portable way.
Definition: socket.h:199
stdx::expected< void, std::error_code > close(native_handle_type native_handle)
Definition: socket.h:75
stdx::expected< native_handle_type, error_type > accept4(native_handle_type native_handle, struct sockaddr *addr, socklen_t *addr_len, int flags=0)
Definition: socket.h:380
stdx::expected< size_t, error_type > write(native_handle_type native_handle, const void *data, size_t data_len)
Definition: socket.h:295
wait_type
Definition: socket_constants.h:86
stdx::expected< void, error_type > setsockopt(native_handle_type native_handle, int level, int optname, const void *optval, socklen_t optlen)
Definition: socket.h:158
stdx::expected< bool, error_type > native_non_blocking(native_handle_type native_handle)
Definition: socket.h:106
::msghdr msghdr_base
Definition: socket_constants.h:60
stdx::expected< void, error_type > connect(native_handle_type native_handle, const struct sockaddr *addr, size_t addr_len)
wrap connect() in a portable way.
Definition: socket.h:353
std::bitset< 31 > message_flags
Definition: socket_constants.h:64
stdx::expected< void, error_type > shutdown(native_handle_type fd, int how)
Definition: socket.h:659
constexpr const int kSocketError
Definition: socket_constants.h:50
int native_handle_type
Definition: socket_constants.h:51
constexpr const native_handle_type kInvalidSocket
Definition: socket_constants.h:52
stdx::expected< void, error_type > wait(native_handle_type fd, wait_type wt)
Definition: socket.h:632
stdx::expected< void, error_type > getsockopt(native_handle_type native_handle, int level, int optname, void *optval, socklen_t *optlen)
Definition: socket.h:174
stdx::expected< size_t, error_type > splice_from_pipe(impl::file::file_handle_type fd_in, native_handle_type fd_out, size_t len, int flags)
Definition: socket.h:617
Definition: buffer.h:45
native_handle_type native_handle()
Definition: process.h:56
unexpected(E) -> unexpected< E >
struct sockaddr sockaddr
Definition: sock_probe_win32.h:63
#define INADDR_LOOPBACK
Definition: types.h:94
#define SOCKET_ERROR
Definition: x_platform.h:284