Do not wait connection attempt delay without in progress fds (#12087)

Do not wait Connection Attempt Delay without in progress fds

Reset Connection Attempt Delay when connection fails and there is no other socket connection in progress.
This is intended to resolve an issue that was temporarily worked around in Pull Request #12062.

`TCPServer::new` (used in tests such as `TestNetHTTP_v1_2_chunked#test_timeout_during_non_chunked_streamed_HTTP_session_write`) can only connect over either IPv6 or IPv4, depending on the environment.
Since HEv2 attempts to connect over IPv6 first, environments where IPv6 connections are unavailable return ECONNREFUSED immediately.
In such cases, the client should immediately retry the connection over IPv4.
However, HEv2 includes a specification for a "Connection Attempt Delay," where it waits 250ms after the previous connection attempt before starting the next one.
This delay causes Net::OpenTimeout (100ms) to be exceeded while waiting for the next connection attempt to start.

With this change, when a connection attempt fails, if there are sockets still attempting to connect and there are addresses yet to be tried, the Connection Attempt Delay will be resetted, allowing the next connection attempt to start immediately.

---

Additionally, the following minor fixes have been made:

- The `nfds` value used for select(2) is now reset with each wait.
This commit is contained in:
Misaki Shioi 2024-11-15 00:25:59 +09:00 committed by GitHub
parent 54ff9d3525
commit fd4b27472e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
Notes: git 2024-11-14 15:26:17 +00:00
Merged-By: shioimm <shioi.mm@gmail.com>
2 changed files with 21 additions and 22 deletions

View File

@ -572,7 +572,6 @@ init_fast_fallback_inetsock_internal(VALUE v)
struct wait_fast_fallback_arg wait_arg;
struct timeval *ends_at = NULL;
struct timeval delay = (struct timeval){ -1, -1 };
wait_arg.nfds = 0;
wait_arg.writefds = NULL;
wait_arg.status = 0;
@ -916,6 +915,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
wait_arg.delay = NULL;
}
wait_arg.nfds = 0;
if (arg->connection_attempt_fds_size) {
FD_ZERO(wait_arg.writefds);
int n = 0;
@ -995,25 +995,24 @@ init_fast_fallback_inetsock_internal(VALUE v)
last_error.type = SYSCALL_ERROR;
last_error.ecode = errno;
if (any_addrinfos(&resolution_store) ||
in_progress_fds(arg->connection_attempt_fds_size) ||
!resolution_store.is_all_finised) {
if (!in_progress_fds(arg->connection_attempt_fds_size)) {
user_specified_connect_timeout_at = NULL;
}
} else {
if (local_status < 0) {
host = arg->local.host;
serv = arg->local.serv;
} else {
host = arg->remote.host;
serv = arg->remote.serv;
}
if (last_error.type == RESOLUTION_ERROR) {
rsock_raise_resolution_error(syscall, last_error.ecode);
} else {
rsock_syserr_fail_host_port(last_error.ecode, syscall, host, serv);
if (!in_progress_fds(arg->connection_attempt_fds_size)) {
if (any_addrinfos(&resolution_store)) {
connection_attempt_delay_expires_at = NULL;
} else if (resolution_store.is_all_finised) {
if (local_status < 0) {
host = arg->local.host;
serv = arg->local.serv;
} else {
host = arg->remote.host;
serv = arg->remote.serv;
}
if (last_error.type == RESOLUTION_ERROR) {
rsock_raise_resolution_error(syscall, last_error.ecode);
} else {
rsock_syserr_fail_host_port(last_error.ecode, syscall, host, serv);
}
}
user_specified_connect_timeout_at = NULL;
}
/* check for hostname resolution */

View File

@ -568,8 +568,8 @@ module TestNetHTTP_version_1_1_methods
conn.open_timeout = EnvUtil.apply_timeout_scale(0.1)
th = Thread.new do
err = !windows? ? [Net::WriteTimeout, Net::OpenTimeout] : Net::ReadTimeout
assert_raise(*err) do
err = !windows? ? Net::WriteTimeout : Net::ReadTimeout
assert_raise(err) do
assert_warning(/Content-Type did not set/) do
conn.post('/', "a"*50_000_000)
end
@ -600,7 +600,7 @@ module TestNetHTTP_version_1_1_methods
req.body_stream = StringIO.new(data)
th = Thread.new do
assert_raise(Net::WriteTimeout, Net::OpenTimeout) { conn.request(req) }
assert_raise(Net::WriteTimeout) { conn.request(req) }
end
assert th.join(10)
}