MySQL 8.0.37
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
112 std::make_error_code(std::errc::function_not_supported));
113#else
115 if (!res) return stdx::make_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::make_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::make_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
399 make_error_code(std::errc::operation_not_supported));
400#endif
401}
402
404 native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len) {
405#ifdef _WIN32
406 socklen_t len = static_cast<socklen_t>(*addr_len);
407#else
408 socklen_t len = *addr_len;
409#endif
410
411 if (kSocketError == ::getsockname(native_handle, addr, &len)) {
413 }
414
415#ifdef _WIN32
416 *addr_len = static_cast<size_t>(len);
417#else
418 *addr_len = len;
419#endif
420
421 return {};
422}
423
425 native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len) {
426#ifdef _WIN32
427 socklen_t len = static_cast<socklen_t>(*addr_len);
428#else
429 socklen_t len = *addr_len;
430#endif
431
432 if (kSocketError == ::getpeername(native_handle, addr, &len)) {
434 }
435
436#ifdef _WIN32
437 *addr_len = static_cast<size_t>(len);
438#else
439 *addr_len = len;
440#endif
441
442 return {};
443}
444
445/**
446 * socketpair().
447 *
448 * - wraps socketpair() on POSIX
449 * - emulates socketpair() on windows as winsock2() provides no socketpair.
450 */
453socketpair(int family, int sock_type, int protocol) {
454#if !defined(_WIN32)
455 std::array<native_handle_type, 2> fds;
456
457 if (0 != ::socketpair(family, sock_type, protocol, fds.data())) {
459 }
460
461 return std::make_pair(fds[0], fds[1]);
462#else
463 auto listener_res = impl::socket::socket(family, sock_type, protocol);
464 if (!listener_res) return stdx::make_unexpected(listener_res.error());
465
466 auto listener = listener_res.value();
467
468 Scope_guard listener_guard([listener]() {
469#if defined(AF_UNIX)
470 struct sockaddr_storage ss {};
471 size_t ss_len = sizeof(ss);
472
473 auto name_res = impl::socket::getsockname(
474 listener, reinterpret_cast<sockaddr *>(&ss), &ss_len);
475 if (name_res) {
476 if (ss.ss_family == AF_UNIX) {
477 struct sockaddr_un *su = reinterpret_cast<sockaddr_un *>(&ss);
478
479 // delete the named socket
480 DeleteFile(su->sun_path);
481 }
482 }
483#endif
484
485 impl::socket::close(listener);
486 });
487
489
490 switch (family) {
491 case AF_INET: {
492 int reuse = 1;
493 impl::socket::setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &reuse,
494 sizeof(reuse));
495
496 struct sockaddr_in sa {};
497 size_t sa_len = sizeof(sa);
498
499 sa.sin_family = family;
500 sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
501 sa.sin_port = 0; // pick a random port
502
503 bind_res = impl::socket::bind(listener, reinterpret_cast<sockaddr *>(&sa),
504 sa_len);
505 } break;
506#if defined(AF_UNIX)
507 case AF_UNIX: {
508 struct sockaddr_un sa {};
509 size_t sa_len = sizeof(sa);
510
511 sa.sun_family = family;
512
513 DWORD path_len = GetTempPath(UNIX_PATH_MAX, sa.sun_path);
514
515 // use the current dir if the tmppath is too long.
516 if (path_len >= UNIX_PATH_MAX - 9) path_len = 0;
517
518 LARGE_INTEGER ticks;
519 QueryPerformanceCounter(&ticks);
520
521 snprintf(sa.sun_path + path_len, UNIX_PATH_MAX - path_len,
522 "%" PRIx64 "-%lu.sok", ticks.QuadPart, GetCurrentProcessId());
523
524 bind_res = impl::socket::bind(listener, reinterpret_cast<sockaddr *>(&sa),
525 sa_len);
526 } break;
527#endif
528 default:
529 bind_res = stdx::make_unexpected(
530 make_error_code(std::errc::address_family_not_supported));
531 break;
532 }
533
534 if (!bind_res) return stdx::make_unexpected(bind_res.error());
535
536 auto listen_res = impl::socket::listen(listener, 128);
537 if (!listen_res) return stdx::make_unexpected(listen_res.error());
538
539 auto first_res = impl::socket::socket(family, sock_type, protocol);
540 if (!first_res) return stdx::make_unexpected(first_res.error());
541
542 auto first_fd = first_res.value();
543
544 Scope_guard first_fd_guard([first_fd]() { impl::socket::close(first_fd); });
545
546 auto remote_sa_res = [](auto sock_handle)
548 struct sockaddr_storage ss {};
549 size_t ss_len = sizeof(ss);
550
551 const auto name_res = impl::socket::getsockname(
552 sock_handle, reinterpret_cast<sockaddr *>(&ss), &ss_len);
553 if (!name_res) return stdx::make_unexpected(name_res.error());
554
555 // overwrite the address.
556 if (ss.ss_family == AF_INET) {
557 auto *sa = reinterpret_cast<sockaddr_in *>(&ss);
558
559 sa->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
560 }
561
562 return ss;
563 }(listener);
564
565 if (!remote_sa_res) return stdx::make_unexpected(remote_sa_res.error());
566 const auto remote_sa = *remote_sa_res;
567
568 const auto connect_res = impl::socket::connect(
569 first_fd, reinterpret_cast<const sockaddr *>(&remote_sa),
570 sizeof(remote_sa));
571 if (!connect_res) return stdx::make_unexpected(connect_res.error());
572
573 const auto second_res = impl::socket::accept(listener, nullptr, nullptr);
574 if (!second_res) return stdx::make_unexpected(second_res.error());
575
576 first_fd_guard.commit();
577
578 auto second_fd = second_res.value();
579
580 return std::make_pair(first_fd, second_fd);
581#endif
582}
583
584#ifdef __linux__
586 native_handle_type fd_out,
587 size_t len, int flags) {
588 ssize_t written = ::splice(fd_in, nullptr, fd_out, nullptr, len, flags);
589
590 if (written == -1) {
592 }
593
594 // post-condition to ensure that we can safely convert to size_t
595 if (written < 0) {
597 make_error_code(std::errc::result_out_of_range));
598 }
599
600 return written;
601}
602#endif
603
605 native_handle_type fd_in, impl::file::file_handle_type fd_out, size_t len,
606 int flags) {
607#ifdef __linux__
608 return splice(fd_in, fd_out, len, flags);
609#else
610 (void)fd_in;
611 (void)fd_out;
612 (void)len;
613 (void)flags;
614
616 make_error_code(std::errc::operation_not_supported));
617#endif
618}
619
621 impl::file::file_handle_type fd_in, native_handle_type fd_out, size_t len,
622 int flags) {
623#ifdef __linux__
624 return splice(fd_in, fd_out, len, flags);
625#else
626 (void)fd_in;
627 (void)fd_out;
628 (void)len;
629 (void)flags;
630
632 make_error_code(std::errc::operation_not_supported));
633#endif
634}
635
637 wait_type wt) {
638 short events{};
639
640 switch (wt) {
642 events |= POLLIN;
643 break;
645 events |= POLLOUT;
646 break;
648 events |= POLLERR;
649 break;
650 }
651 std::array<impl::poll::poll_fd, 1> fds{{
652 {fd, events, 0},
653 }};
654
655 const auto res =
656 impl::poll::poll(fds.data(), fds.size(), std::chrono::milliseconds{-1});
657
658 if (!res) return stdx::make_unexpected(res.error());
659
660 return {};
661}
662
664 int how) {
665 const auto res = ::shutdown(fd, how);
666 if (kSocketError == res) {
668 }
669
670 return {};
671}
672
674#ifdef _WIN32
675 WORD wVersionRequested = MAKEWORD(2, 2);
676 WSADATA wsaData;
677 if (int err = WSAStartup(wVersionRequested, &wsaData)) {
679 }
680#endif
681 return {};
682}
683
684} // namespace socket
685} // namespace impl
686
687} // namespace net
688#endif
Definition: scope_guard.h:28
Definition: expected.h:944
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:56
Definition: buf0block_hint.cc:30
Definition: authentication.cc:36
static Value err()
Create a Value object that represents an error condition.
Definition: json_binary.cc:910
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:403
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:673
stdx::expected< std::pair< native_handle_type, native_handle_type >, error_type > socketpair(int family, int sock_type, int protocol)
socketpair().
Definition: socket.h:453
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:604
stdx::expected< void, error_type > getpeername(native_handle_type native_handle, struct sockaddr *addr, size_t *addr_len)
Definition: socket.h:424
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:663
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:636
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:620
Definition: buffer.h:45
native_handle_type native_handle()
Definition: process.h:56
constexpr auto make_unexpected(E &&e) -> unexpected< std::decay_t< E > >
Definition: expected.h:125
struct sockaddr sockaddr
Definition: sock_probe_win32.h:63
#define INADDR_LOOPBACK
Definition: types.h:94
#define SOCKET_ERROR
Definition: x_platform.h:284