diff options
Diffstat (limited to 'ext/socket')
-rw-r--r-- | ext/socket/ipsocket.c | 105 | ||||
-rw-r--r-- | ext/socket/tcpsocket.c | 9 |
2 files changed, 68 insertions, 46 deletions
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c index e69c8b0a53..24d21a5899 100644 --- a/ext/socket/ipsocket.c +++ b/ext/socket/ipsocket.c @@ -574,7 +574,7 @@ 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.writefds = NULL; + wait_arg.writefds = &writefds; wait_arg.status = 0; struct hostname_resolution_store resolution_store; @@ -859,7 +859,6 @@ init_fast_fallback_inetsock_internal(VALUE v) } arg->connection_attempt_fds[arg->connection_attempt_fds_size] = fd; (arg->connection_attempt_fds_size)++; - wait_arg.writefds = &writefds; set_timeout_tv(&connection_attempt_delay_strage, 250, now); connection_attempt_delay_expires_at = &connection_attempt_delay_strage; @@ -922,8 +921,8 @@ init_fast_fallback_inetsock_internal(VALUE v) } wait_arg.nfds = 0; - if (arg->connection_attempt_fds_size) { - FD_ZERO(wait_arg.writefds); + FD_ZERO(wait_arg.writefds); + if (in_progress_fds(arg->connection_attempt_fds_size)) { int n = 0; for (int i = 0; i < arg->connection_attempt_fds_size; i++) { int cfd = arg->connection_attempt_fds[i]; @@ -933,8 +932,6 @@ init_fast_fallback_inetsock_internal(VALUE v) } if (n > 0) n++; wait_arg.nfds = n; - } else { - wait_arg.writefds = NULL; } FD_ZERO(wait_arg.readfds); @@ -967,14 +964,39 @@ init_fast_fallback_inetsock_internal(VALUE v) if (status > 0) { /* check for connection */ - for (int i = 0; i < arg->connection_attempt_fds_size; i++) { - int fd = arg->connection_attempt_fds[i]; - if (fd < 0 || !FD_ISSET(fd, wait_arg.writefds)) continue; + if (in_progress_fds(arg->connection_attempt_fds_size)) { + for (int i = 0; i < arg->connection_attempt_fds_size; i++) { + int fd = arg->connection_attempt_fds[i]; + if (fd < 0 || !FD_ISSET(fd, wait_arg.writefds)) continue; + + int err; + socklen_t len = sizeof(err); + + status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len); + + if (status < 0) { + last_error.type = SYSCALL_ERROR; + last_error.ecode = errno; + close(fd); - int err; - socklen_t len = sizeof(err); + if (any_addrinfos(&resolution_store)) continue; + if (in_progress_fds(arg->connection_attempt_fds_size)) break; + if (!resolution_store.is_all_finised) break; + + 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 (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len) == 0) { if (err == 0) { /* success */ remove_connection_attempt_fd( arg->connection_attempt_fds, @@ -983,42 +1005,39 @@ init_fast_fallback_inetsock_internal(VALUE v) ); connected_fd = fd; break; - }; - - /* fail */ - errno = err; - close(fd); - remove_connection_attempt_fd( - arg->connection_attempt_fds, - &arg->connection_attempt_fds_size, - fd - ); - continue; + } else { /* fail */ + close(fd); + remove_connection_attempt_fd( + arg->connection_attempt_fds, + &arg->connection_attempt_fds_size, + fd + ); + last_error.type = SYSCALL_ERROR; + last_error.ecode = err; + } } - } - if (connected_fd >= 0) break; - last_error.type = SYSCALL_ERROR; - last_error.ecode = errno; + if (connected_fd >= 0) break; - 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); + 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; } - user_specified_connect_timeout_at = NULL; } /* check for hostname resolution */ diff --git a/ext/socket/tcpsocket.c b/ext/socket/tcpsocket.c index 10b4810869..3c03e89e0d 100644 --- a/ext/socket/tcpsocket.c +++ b/ext/socket/tcpsocket.c @@ -20,14 +20,17 @@ * * Starting from Ruby 3.4, this method operates according to the * Happy Eyeballs Version 2 ({RFC 8305}[https://datatracker.ietf.org/doc/html/rfc8305]) - * algorithm with *fast_fallback:true+, except on Windows. + * algorithm by default, except on Windows. + * + * To make it behave the same as in Ruby 3.3 and earlier, + * explicitly specify the option +fast_fallback:false+. * * Happy Eyeballs Version 2 is not provided on Windows, * and it behaves the same as in Ruby 3.3 and earlier. * * [:resolv_timeout] Specifies the timeout in seconds from when the hostname resolution starts. * [:connect_timeout] This method sequentially attempts connecting to all candidate destination addresses.<br>The +connect_timeout+ specifies the timeout in seconds from the start of the connection attempt to the last candidate.<br>By default, all connection attempts continue until the timeout occurs.<br>When +fast_fallback:false+ is explicitly specified,<br>a timeout is set for each connection attempt and any connection attempt that exceeds its timeout will be canceled. - * [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (disabled by default). + * [:fast_fallback] Enables the Happy Eyeballs Version 2 algorithm (enabled by default). * * === Happy Eyeballs Version 2 * Happy Eyeballs Version 2 ({RFC 8305}[https://datatracker.ietf.org/doc/html/rfc8305]) @@ -57,7 +60,7 @@ tcp_init(int argc, VALUE *argv, VALUE sock) VALUE kwargs[4]; VALUE resolv_timeout = Qnil; VALUE connect_timeout = Qnil; - VALUE fast_fallback = Qfalse; + VALUE fast_fallback = Qtrue; VALUE test_mode_settings = Qnil; if (!keyword_ids[0]) { |