MySQL 8.3.0
Source Code Documentation
socket.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2019, 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_IMPL_SOCKET_H_
26#define MYSQL_HARNESS_NET_TS_IMPL_SOCKET_H_
27
28#include <algorithm> // max
29#include <array>
30#include <bitset>
31#include <cinttypes> // PRIx64
32#include <limits>
33#include <system_error>
34
35#ifdef _WIN32
36#include <WinSock2.h>
37#include <Windows.h>
38#ifdef AF_UNIX
39#include <afunix.h>
40#endif
41#else
42#include <fcntl.h>
43#include <netinet/in.h>
44#include <sys/ioctl.h>
45#include <sys/socket.h>
46#include <unistd.h> // close
47#endif
48
55
56#include "scope_guard.h"
57
58namespace net {
59namespace impl {
60namespace socket {
61
63 int sock_type,
64 int protocol) {
65 native_handle_type sock = ::socket(family, sock_type, protocol);
66
67 if (sock == kInvalidSocket) {
69 }
70
71 return sock;
72}
73
76#ifdef _WIN32
79 }
80#else
81 if (0 != ::close(native_handle)) {
83 }
84#endif
85 return {};
86}
87
89 unsigned long cmd, void *data) {
90#ifdef _WIN32
91 // use WSAIoctl() instead ?
92 if (kSocketError == ::ioctlsocket(native_handle, static_cast<long>(cmd),
93 reinterpret_cast<unsigned long *>(data))) {
95 }
96#else
97 if (kSocketError == ::ioctl(native_handle, cmd, data)) {
99 }
100#endif
101
102 return {};
103}
104
107#ifdef _WIN32
108 (void)native_handle;
109 // windows has no way to query to the blocking state
111 std::make_error_code(std::errc::function_not_supported));
112#else
114 if (!res) return stdx::make_unexpected(res.error());
115
116 return (*res & O_NONBLOCK) != 0;
117#endif
118}
119
122#ifdef _WIN32
123 unsigned long nonblocking{on};
124
125 return ioctl(native_handle, FIONBIO, &nonblocking);
126#else
128 if (!res) return stdx::make_unexpected(res.error());
129
130 int flags = *res;
131
132 if (on) {
133 if (flags & O_NONBLOCK) return {};
134 flags |= O_NONBLOCK;
135 } else {
136 if (!(flags & O_NONBLOCK)) return {};
137 flags &= ~O_NONBLOCK;
138 }
139
140 auto set_res =
142 if (!set_res) return stdx::make_unexpected(set_res.error());
143
144 return {};
145#endif
146}
147
149 int backlog) {
150 if (kSocketError == ::listen(native_handle, backlog)) {
152 }
153
154 return {};
155}
156
158 native_handle_type native_handle, int level, int optname,
159 const void *optval, socklen_t optlen) {
160#ifdef _WIN32
161 int res = ::setsockopt(native_handle, level, optname,
162 reinterpret_cast<const char *>(optval), optlen);
163#else
164 int res = ::setsockopt(native_handle, level, optname, optval, optlen);
165#endif
166 if (kSocketError == res) {
168 }
169
170 return {};
171}
172
174 native_handle_type native_handle, int level, int optname, void *optval,
175 socklen_t *optlen) {
176#ifdef _WIN32
177 int res = ::getsockopt(native_handle, level, optname,
178 reinterpret_cast<char *>(optval), optlen);
179#else
180 int res = ::getsockopt(native_handle, level, optname, optval, optlen);
181#endif
182 if (kSocketError == res) {
184 }
185
186 return {};
187}
188
189/**
190 * wrap ::recv() in a portable way.
191 *
192 * @param native_handle socket handle
193 * @param buf pointer to a mutable buffer of size 'buf_len'
194 * @param buf_len size of 'buf'
195 * @param flags message flags
196 * @returns bytes transferred on success, std::error_code otherwise
197 */
199 void *buf, size_t buf_len,
201#if defined(_WIN32)
202 // recv() expects an 'int' instead of a 'size_t'.
203 // Ensure, buf_len is properly narrowed instead of wrapped around
204 auto bytes_transferred = ::recv(
205 native_handle, static_cast<char *>(buf),
206 std::min(static_cast<size_t>(std::numeric_limits<int>::max()), buf_len),
207 flags.to_ulong());
208#else
209 auto bytes_transferred =
210 ::recv(native_handle, buf, buf_len, static_cast<int>(flags.to_ulong()));
211#endif
212 if (kSocketError == bytes_transferred) {
214 }
215
216 return {static_cast<size_t>(bytes_transferred)};
217}
218
220 void *data, size_t data_len) {
221#ifdef _WIN32
222 // fallback to recv()
223 return recv(native_handle, data, data_len, 0);
224#else
225 auto bytes_transferred = ::read(native_handle, data, data_len);
226 if (kSocketError == bytes_transferred) {
228 }
229
230 return {static_cast<size_t>(bytes_transferred)};
231#endif
232}
233
236#ifdef _WIN32
237 DWORD bytes_transferred;
238 DWORD _flags = flags.to_ulong();
239
240 // WSARecvMsg() also exists, but is less flexible and is only reachable
241 // via a function-pointer-lookup via WSAID_WSARECVMSG
242 int err = ::WSARecvFrom(native_handle, msg.lpBuffers, msg.dwBufferCount,
243 &bytes_transferred, &_flags,
244 msg.name, // from
245 &msg.namelen, // from_len
246 nullptr, // overlapped
247 nullptr // completor
248 );
249 if (kSocketError == err) {
251 }
252#else
253 ssize_t bytes_transferred =
254 ::recvmsg(native_handle, &msg, static_cast<int>(flags.to_ulong()));
255 if (kSocketError == bytes_transferred) {
257 }
258#endif
259
260 return {static_cast<size_t>(bytes_transferred)};
261}
262
263/**
264 * wrap ::send() in a portable way.
265 *
266 * @param native_handle socket handle
267 * @param buf pointer to a const buffer of size 'buf_len'
268 * @param buf_len size of 'buf'
269 * @param flags message flags
270 * @returns bytes transferred on success, std::error_code otherwise
271 */
273 const void *buf, size_t buf_len,
275#if defined(_WIN32)
276 // send() expects an 'int' instead of a 'size_t'.
277 // Ensure, buf_len is properly narrowed instead of wrapped around
278 auto bytes_transferred = ::send(
279 native_handle, static_cast<const char *>(buf),
280 std::min(static_cast<size_t>(std::numeric_limits<int>::max()), buf_len),
281 flags.to_ulong());
282#else
283 // ssize_t
284 auto bytes_transferred =
285 ::send(native_handle, buf, buf_len, static_cast<int>(flags.to_ulong()));
286#endif
287 if (kSocketError == bytes_transferred) {
289 }
290
291 return {static_cast<size_t>(bytes_transferred)};
292}
293
295 native_handle_type native_handle, const void *data, size_t data_len) {
296#ifdef _WIN32
297 // fallback to send()
298 return send(native_handle, data, data_len, 0);
299#else
300 auto bytes_transferred = ::write(native_handle, data, data_len);
301 if (kSocketError == bytes_transferred) {
303 }
304
305 return {static_cast<size_t>(bytes_transferred)};
306#endif
307}
308
311#ifdef _WIN32
312 DWORD bytes_transferred;
313 DWORD _flags = flags.to_ulong();
314 int err = ::WSASendTo(native_handle, msg.lpBuffers, msg.dwBufferCount,
315 &bytes_transferred, _flags,
316 msg.name, // to
317 msg.namelen, // to_len
318 nullptr, // overlapped
319 nullptr // completor
320 );
321 if (kSocketError == err) {
323 }
324#else
325 ssize_t bytes_transferred =
326 ::sendmsg(native_handle, &msg, static_cast<int>(flags.to_ulong()));
327 if (kSocketError == bytes_transferred) {
329 }
330#endif
331
332 return {static_cast<size_t>(bytes_transferred)};
333}
334
335/**
336 * wrap ::bind() in a portable way.
337 */
339 const struct sockaddr *addr,
340 size_t addr_len) {
341 if (kSocketError ==
342 ::bind(native_handle, addr, static_cast<socklen_t>(addr_len))) {
344 }
345
346 return {};
347}
348
349/**
350 * wrap ::connect() in a portable way.
351 */
353 native_handle_type native_handle, const struct sockaddr *addr,
354 size_t addr_len) {
355 if (kSocketError ==
356 ::connect(native_handle, addr, static_cast<socklen_t>(addr_len))) {
358 }
359
360 return {};
361}
362
363/**
364 * wrap ::accept() in a portable way.
365 */
368 socklen_t *addr_len) {
369 native_handle_type fd = ::accept(native_handle, addr, addr_len);
370 if (kInvalidSocket == fd) {
372 }
373
374 return fd;
375}
376
377// freebsd and linux have accept4()
378// solaris and windows don't
381 socklen_t *addr_len, int flags = 0) {
382#if defined(__linux__) || defined(__FreeBSD__) || defined(__OpenBSD__) || \
383 defined(__NetBSD__)
384 native_handle_type fd = ::accept4(native_handle, addr, addr_len, flags);
385 if (kInvalidSocket == fd) {
387 }
388
389 return fd;
390#else
391 // static_assert(false, "operation not supported");
392 (void)native_handle;
393 (void)addr;
394 (void)addr_len;
395 (void)flags;
396
398 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::make_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::make_unexpected(
529 make_error_code(std::errc::address_family_not_supported));
530 break;
531 }
532
533 if (!bind_res) return stdx::make_unexpected(bind_res.error());
534
535 auto listen_res = impl::socket::listen(listener, 128);
536 if (!listen_res) return stdx::make_unexpected(listen_res.error());
537
538 auto first_res = impl::socket::socket(family, sock_type, protocol);
539 if (!first_res) return stdx::make_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::make_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::make_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::make_unexpected(connect_res.error());
571
572 const auto second_res = impl::socket::accept(listener, nullptr, nullptr);
573 if (!second_res) return stdx::make_unexpected(second_res.error());
574
575 first_fd_guard.commit();
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) {
596 make_error_code(std::errc::result_out_of_range));
597 }
598
599 return written;
600}
601#endif
602
604 native_handle_type fd_in, impl::file::file_handle_type fd_out, size_t len,
605 int flags) {
606#ifdef __linux__
607 return splice(fd_in, fd_out, len, flags);
608#else
609 (void)fd_in;
610 (void)fd_out;
611 (void)len;
612 (void)flags;
613
615 make_error_code(std::errc::operation_not_supported));
616#endif
617}
618
620 impl::file::file_handle_type fd_in, native_handle_type fd_out, size_t len,
621 int flags) {
622#ifdef __linux__
623 return splice(fd_in, fd_out, len, flags);
624#else
625 (void)fd_in;
626 (void)fd_out;
627 (void)len;
628 (void)flags;
629
631 make_error_code(std::errc::operation_not_supported));
632#endif
633}
634
636 wait_type wt) {
637 short events{};
638
639 switch (wt) {
641 events |= POLLIN;
642 break;
644 events |= POLLOUT;
645 break;
647 events |= POLLERR;
648 break;
649 }
650 std::array<impl::poll::poll_fd, 1> fds{{
651 {fd, events, 0},
652 }};
653
654 const auto res =
655 impl::poll::poll(fds.data(), fds.size(), std::chrono::milliseconds{-1});
656
657 if (!res) return stdx::make_unexpected(res.error());
658
659 return {};
660}
661
663 int how) {
664 const auto res = ::shutdown(fd, how);
665 if (kSocketError == res) {
667 }
668
669 return {};
670}
671
673#ifdef _WIN32
674 WORD wVersionRequested = MAKEWORD(2, 2);
675 WSADATA wsaData;
676 if (int err = WSAStartup(wVersionRequested, &wsaData)) {
678 }
679#endif
680 return {};
681}
682
683} // namespace socket
684} // namespace impl
685
686} // namespace net
687#endif
Definition: scope_guard.h:27
Definition: expected.h:943
error_type
Definition: error.h:35
static int flags[50]
Definition: hp_test1.cc:39
#define closesocket(A)
Definition: my_io.h:177
static MYSQL * sock
Definition: mysqlcheck.cc:56
Definition: buf0block_hint.cc:29
Definition: authentication.cc:35
static Value err()
Create a Value object that represents an error condition.
Definition: json_binary.cc:926
std::error_code make_error_code(DynamicLoaderErrc ec)
make error_code from a DynamicLoaderErrc.
Definition: dynamic_loader.cc:78
stdx::expected< int, std::error_code > fcntl(file_handle_type fd, const FileControlOption &cmd)
Definition: file.h:124
int file_handle_type
Definition: file.h:52
stdx::expected< size_t, std::error_code > poll(poll_fd *fds, size_t num_fds, std::chrono::milliseconds timeout)
Definition: poll.h:52
stdx::expected< size_t, error_type > sendmsg(native_handle_type native_handle, msghdr_base &msg, message_flags flags)
Definition: socket.h:309
stdx::expected< void, error_type > listen(native_handle_type native_handle, int backlog)
Definition: socket.h:148
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:95
stdx::expected< size_t, error_type > read(native_handle_type native_handle, void *data, size_t data_len)
Definition: socket.h:219
stdx::expected< native_handle_type, error_type > socket(int family, int sock_type, int protocol)
Definition: socket.h:62
stdx::expected< void, std::error_code > init()
Definition: socket.h:672
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:338
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:272
std::error_code last_error_code()
get last std::error_code for socket-errors.
Definition: socket_error.h:106
stdx::expected< void, error_type > ioctl(native_handle_type native_handle, unsigned long cmd, void *data)
Definition: socket.h:88
stdx::expected< size_t, error_type > recvmsg(native_handle_type native_handle, msghdr_base &msg, message_flags flags)
Definition: socket.h:234
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:603
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:366
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:198
stdx::expected< void, std::error_code > close(native_handle_type native_handle)
Definition: socket.h:74
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:379
stdx::expected< size_t, error_type > write(native_handle_type native_handle, const void *data, size_t data_len)
Definition: socket.h:294
wait_type
Definition: socket_constants.h:85
stdx::expected< void, error_type > setsockopt(native_handle_type native_handle, int level, int optname, const void *optval, socklen_t optlen)
Definition: socket.h:157
stdx::expected< bool, error_type > native_non_blocking(native_handle_type native_handle)
Definition: socket.h:105
::msghdr msghdr_base
Definition: socket_constants.h:59
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:352
std::bitset< 31 > message_flags
Definition: socket_constants.h:63
stdx::expected< void, error_type > shutdown(native_handle_type fd, int how)
Definition: socket.h:662
constexpr const int kSocketError
Definition: socket_constants.h:49
int native_handle_type
Definition: socket_constants.h:50
constexpr const native_handle_type kInvalidSocket
Definition: socket_constants.h:51
stdx::expected< void, error_type > wait(native_handle_type fd, wait_type wt)
Definition: socket.h:635
stdx::expected< void, error_type > getsockopt(native_handle_type native_handle, int level, int optname, void *optval, socklen_t *optlen)
Definition: socket.h:173
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:619
Definition: buffer.h:44
native_handle_type native_handle()
Definition: process.h:55
constexpr auto make_unexpected(E &&e) -> unexpected< std::decay_t< E > >
Definition: expected.h:124
struct sockaddr sockaddr
Definition: sock_probe_win32.h:62
#define INADDR_LOOPBACK
Definition: types.h:93
#define SOCKET_ERROR
Definition: x_platform.h:283