-
Notifications
You must be signed in to change notification settings - Fork 251
Experimental support for IPv6 #7671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 8 commits
501271c
5fd593b
1a727ae
b889d2b
d461997
c903926
8ce7afa
1ae1a18
05af854
262f563
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,9 @@ | |
|
|
||
| #include <netinet/in.h> | ||
| #include <optional> | ||
| #ifndef _WIN32 | ||
| # include <unistd.h> | ||
| #endif | ||
|
|
||
| namespace asynchost | ||
| { | ||
|
|
@@ -192,6 +195,13 @@ namespace asynchost | |
| } | ||
| else | ||
| { | ||
| if (!set_connection_timeout_on_uv_handle()) | ||
| { | ||
| assert_status(BINDING, BINDING_FAILED); | ||
| behaviour->on_bind_failed(); | ||
| return; | ||
| } | ||
|
|
||
| assert_status(BINDING, CONNECTING_RESOLVING); | ||
| if (addr_current != nullptr) | ||
| { | ||
|
|
@@ -411,37 +421,8 @@ namespace asynchost | |
| return false; | ||
| } | ||
|
|
||
| if (is_client) | ||
| { | ||
| uv_os_sock_t sock = 0; | ||
| if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) | ||
| { | ||
| LOG_FAIL_FMT( | ||
| "socket creation failed: {}", | ||
| std::strerror(errno)); // NOLINT(concurrency-mt-unsafe) | ||
| return false; | ||
| } | ||
|
|
||
| if (connection_timeout.has_value()) | ||
| { | ||
| const unsigned int ms = connection_timeout->count(); | ||
| const auto ret = | ||
| setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &ms, sizeof(ms)); | ||
| if (ret != 0) | ||
| { | ||
| LOG_FAIL_FMT( | ||
| "Failed to set socket option (TCP_USER_TIMEOUT): {}", | ||
| std::strerror(errno)); // NOLINT(concurrency-mt-unsafe) | ||
| return false; | ||
| } | ||
| } | ||
|
|
||
| if ((rc = uv_tcp_open(&uv_handle, sock)) < 0) | ||
| { | ||
| LOG_FAIL_FMT("uv_tcp_open failed: {}", uv_strerror(rc)); | ||
| return false; | ||
| } | ||
| } | ||
| // Client socket creation is deferred to connect_resolved(), where | ||
| // the resolved address family (AF_INET or AF_INET6) is known. | ||
|
|
||
| if ((rc = uv_tcp_keepalive(&uv_handle, 1, 30)) < 0) | ||
| { | ||
|
|
@@ -544,6 +525,50 @@ namespace asynchost | |
|
|
||
| bool connect_resolved() | ||
| { | ||
| // Create the client socket with the correct address family, but only | ||
| // if client_bind() hasn't already created one via uv_tcp_bind(). | ||
| if (is_client && !client_host.has_value() && addr_current != nullptr) | ||
| { | ||
|
achamayou marked this conversation as resolved.
|
||
| int rc = 0; | ||
|
achamayou marked this conversation as resolved.
|
||
| uv_os_fd_t existing_fd = {}; | ||
| const auto uv_fileno_rc = uv_fileno( | ||
| reinterpret_cast<const uv_handle_t*>(&uv_handle), &existing_fd); | ||
| if (uv_fileno_rc < 0 && uv_fileno_rc != UV_EBADF) | ||
| { | ||
| LOG_FAIL_FMT( | ||
| "uv_fileno returned unexpected error while checking TCP handle " | ||
| "state: {}", | ||
| uv_strerror(uv_fileno_rc)); | ||
| return false; | ||
| } | ||
|
|
||
| if (uv_fileno_rc == UV_EBADF) | ||
| { | ||
| const int family = addr_current->ai_family; | ||
| uv_os_sock_t sock = 0; | ||
| if ((sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) == -1) | ||
| { | ||
| LOG_FAIL_FMT( | ||
| "socket creation failed: {}", | ||
| std::strerror(errno)); // NOLINT(concurrency-mt-unsafe) | ||
| return false; | ||
| } | ||
|
|
||
| if (!set_connection_timeout(sock)) | ||
| { | ||
| close_socket_before_uv_ownership(sock); | ||
| return false; | ||
| } | ||
|
|
||
| if ((rc = uv_tcp_open(&uv_handle, sock)) < 0) | ||
| { | ||
| LOG_FAIL_FMT("uv_tcp_open failed: {}", uv_strerror(rc)); | ||
| close_socket_before_uv_ownership(sock); | ||
| return false; | ||
| } | ||
| } | ||
| } | ||
|
|
||
| auto* req = new uv_connect_t; // NOLINT(cppcoreguidelines-owning-memory) | ||
| int rc = 0; | ||
|
|
||
|
|
@@ -573,6 +598,76 @@ namespace asynchost | |
| return false; | ||
| } | ||
|
|
||
| bool set_connection_timeout(uv_os_sock_t sock) | ||
| { | ||
| if (!connection_timeout.has_value()) | ||
| { | ||
| return true; | ||
| } | ||
|
|
||
| const unsigned int ms = connection_timeout->count(); | ||
| const auto ret = | ||
| setsockopt(sock, IPPROTO_TCP, TCP_USER_TIMEOUT, &ms, sizeof(ms)); | ||
| if (ret != 0) | ||
| { | ||
| #ifdef _WIN32 | ||
| const auto err = WSAGetLastError(); | ||
| LOG_FAIL_FMT("Failed to set socket option (TCP_USER_TIMEOUT): {}", err); | ||
| #else | ||
| const auto err = errno; | ||
| LOG_FAIL_FMT( | ||
| "Failed to set socket option (TCP_USER_TIMEOUT): {}", | ||
| std::strerror(err)); // NOLINT(concurrency-mt-unsafe) | ||
| #endif | ||
| return false; | ||
| } | ||
|
|
||
| return true; | ||
| } | ||
|
|
||
| static void close_socket_before_uv_ownership(uv_os_sock_t sock) | ||
| { | ||
| // Socket ownership is transferred to libuv only if uv_tcp_open succeeds. | ||
| // Before that, this socket must be closed by the caller. | ||
| // This is best-effort cleanup on an existing failure path: we only log | ||
| // close() errors (including EINTR). We intentionally do not retry | ||
| // close(), since retrying may close a reused fd. | ||
| #ifdef _WIN32 | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drop all WIN32 include guards, we don't want them.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done in 262f563: removed the remaining |
||
| const auto rc = closesocket(sock); | ||
| #else | ||
| const auto rc = close(sock); | ||
| #endif | ||
| if (rc != 0) | ||
| { | ||
| #ifdef _WIN32 | ||
| const auto err = WSAGetLastError(); | ||
| LOG_FAIL_FMT("Failed to close socket {}: {}", sock, err); | ||
| #else | ||
| const auto err = errno; | ||
| LOG_FAIL_FMT( | ||
| "Failed to close socket {}: {}", | ||
| sock, | ||
| std::strerror(err)); // NOLINT(concurrency-mt-unsafe) | ||
| #endif | ||
| } | ||
| } | ||
|
|
||
| bool set_connection_timeout_on_uv_handle() | ||
| { | ||
| uv_os_fd_t existing_fd = {}; | ||
| const auto rc = uv_fileno( | ||
| reinterpret_cast<const uv_handle_t*>(&uv_handle), &existing_fd); | ||
| if (rc < 0) | ||
| { | ||
| LOG_FAIL_FMT( | ||
| "uv_fileno failed while applying TCP_USER_TIMEOUT: {}", | ||
| uv_strerror(rc)); | ||
| return false; | ||
| } | ||
|
|
||
| return set_connection_timeout(existing_fd); | ||
| } | ||
|
|
||
| void assert_status(Status from, Status to) | ||
| { | ||
| if (status != from) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot we don't support WIN32, please remove this include guard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in 05af854: removed the
_WIN32include guard around<unistd.h>insrc/host/tcp.h.