mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 12:14:51 +00:00
Fix: Specifying 0 should cause an immediate timeout (#15641)
This change fixes a bug in which specifying 0 for timeout-related options (such as the `timeout` option of `Addrinfo.getaddrinfo`) incorrectly results in an infinite wait. (This change overwrites https://github.com/ruby/ruby/pull/15626 .)
This commit is contained in:
parent
f81c62be3d
commit
47244b0f30
Notes:
git
2025-12-19 06:45:03 +00:00
Merged-By: shioimm <shioi.mm@gmail.com>
@ -83,15 +83,13 @@ init_inetsock_internal(VALUE v)
|
||||
VALUE open_timeout = arg->open_timeout;
|
||||
VALUE timeout;
|
||||
VALUE starts_at;
|
||||
unsigned int timeout_msec;
|
||||
|
||||
timeout = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
|
||||
timeout_msec = NIL_P(timeout) ? 0 : rsock_value_timeout_to_msec(timeout);
|
||||
starts_at = current_clocktime();
|
||||
|
||||
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
|
||||
family, SOCK_STREAM,
|
||||
(type == INET_SERVER) ? AI_PASSIVE : 0, timeout_msec);
|
||||
(type == INET_SERVER) ? AI_PASSIVE : 0, timeout);
|
||||
|
||||
/*
|
||||
* Maybe also accept a local address
|
||||
@ -99,7 +97,7 @@ init_inetsock_internal(VALUE v)
|
||||
|
||||
if (type != INET_SERVER && (!NIL_P(arg->local.host) || !NIL_P(arg->local.serv))) {
|
||||
arg->local.res = rsock_addrinfo(arg->local.host, arg->local.serv,
|
||||
family, SOCK_STREAM, 0, 0);
|
||||
family, SOCK_STREAM, 0, timeout);
|
||||
}
|
||||
|
||||
VALUE io = Qnil;
|
||||
@ -630,14 +628,7 @@ init_fast_fallback_inetsock_internal(VALUE v)
|
||||
arg->getaddrinfo_shared = NULL;
|
||||
|
||||
int family = arg->families[0];
|
||||
unsigned int t;
|
||||
if (!NIL_P(open_timeout)) {
|
||||
t = rsock_value_timeout_to_msec(open_timeout);
|
||||
} else if (!NIL_P(resolv_timeout)) {
|
||||
t = rsock_value_timeout_to_msec(resolv_timeout);
|
||||
} else {
|
||||
t = 0;
|
||||
}
|
||||
VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
|
||||
|
||||
arg->remote.res = rsock_addrinfo(
|
||||
arg->remote.host,
|
||||
@ -1337,15 +1328,7 @@ rsock_init_inetsock(
|
||||
* Maybe also accept a local address
|
||||
*/
|
||||
if (!NIL_P(local_host) || !NIL_P(local_serv)) {
|
||||
unsigned int t;
|
||||
if (!NIL_P(open_timeout)) {
|
||||
t = rsock_value_timeout_to_msec(open_timeout);
|
||||
} else if (!NIL_P(resolv_timeout)) {
|
||||
t = rsock_value_timeout_to_msec(resolv_timeout);
|
||||
} else {
|
||||
t = 0;
|
||||
}
|
||||
|
||||
VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout;
|
||||
local_res = rsock_addrinfo(
|
||||
local_host,
|
||||
local_serv,
|
||||
@ -1609,7 +1592,7 @@ static VALUE
|
||||
ip_s_getaddress(VALUE obj, VALUE host)
|
||||
{
|
||||
union_sockaddr addr;
|
||||
struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, 0);
|
||||
struct rb_addrinfo *res = rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, 0, Qnil);
|
||||
socklen_t len = res->ai->ai_addrlen;
|
||||
|
||||
/* just take the first one */
|
||||
|
||||
@ -293,7 +293,7 @@ rb_freeaddrinfo(struct rb_addrinfo *ai)
|
||||
xfree(ai);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
static int
|
||||
rsock_value_timeout_to_msec(VALUE timeout)
|
||||
{
|
||||
double seconds = NUM2DBL(timeout);
|
||||
@ -308,7 +308,7 @@ rsock_value_timeout_to_msec(VALUE timeout)
|
||||
#if GETADDRINFO_IMPL == 0
|
||||
|
||||
static int
|
||||
rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int _timeout)
|
||||
rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
|
||||
{
|
||||
return getaddrinfo(hostp, portp, hints, ai);
|
||||
}
|
||||
@ -346,7 +346,7 @@ fork_safe_getaddrinfo(void *arg)
|
||||
}
|
||||
|
||||
static int
|
||||
rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int _timeout)
|
||||
rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int _timeout)
|
||||
{
|
||||
struct getaddrinfo_arg arg;
|
||||
MEMZERO(&arg, struct getaddrinfo_arg, 1);
|
||||
@ -367,11 +367,11 @@ struct getaddrinfo_arg
|
||||
int err, gai_errno, refcount, done, cancelled, timedout;
|
||||
rb_nativethread_lock_t lock;
|
||||
rb_nativethread_cond_t cond;
|
||||
unsigned int timeout;
|
||||
int timeout;
|
||||
};
|
||||
|
||||
static struct getaddrinfo_arg *
|
||||
allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, unsigned int timeout)
|
||||
allocate_getaddrinfo_arg(const char *hostp, const char *portp, const struct addrinfo *hints, int timeout)
|
||||
{
|
||||
size_t hostp_offset = sizeof(struct getaddrinfo_arg);
|
||||
size_t portp_offset = hostp_offset + (hostp ? strlen(hostp) + 1 : 0);
|
||||
@ -465,8 +465,11 @@ wait_getaddrinfo(void *ptr)
|
||||
struct getaddrinfo_arg *arg = (struct getaddrinfo_arg *)ptr;
|
||||
rb_nativethread_lock_lock(&arg->lock);
|
||||
while (!arg->done && !arg->cancelled) {
|
||||
unsigned long msec = arg->timeout;
|
||||
if (msec > 0) {
|
||||
long msec = arg->timeout;
|
||||
if (msec == 0) {
|
||||
arg->cancelled = 1;
|
||||
arg->timedout = 1;
|
||||
} else if (msec > 0) {
|
||||
rb_native_cond_timedwait(&arg->cond, &arg->lock, msec);
|
||||
if (!arg->done) {
|
||||
arg->cancelled = 1;
|
||||
@ -549,7 +552,7 @@ fork_safe_do_getaddrinfo(void *ptr)
|
||||
}
|
||||
|
||||
static int
|
||||
rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, unsigned int timeout)
|
||||
rb_getaddrinfo(const char *hostp, const char *portp, const struct addrinfo *hints, struct addrinfo **ai, int timeout)
|
||||
{
|
||||
int retry;
|
||||
struct getaddrinfo_arg *arg;
|
||||
@ -1021,7 +1024,7 @@ rb_scheduler_getaddrinfo(VALUE scheduler, VALUE host, const char *service,
|
||||
}
|
||||
|
||||
struct rb_addrinfo*
|
||||
rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, unsigned int timeout)
|
||||
rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout)
|
||||
{
|
||||
struct rb_addrinfo* res = NULL;
|
||||
struct addrinfo *ai;
|
||||
@ -1056,7 +1059,8 @@ rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_h
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
error = rb_getaddrinfo(hostp, portp, hints, &ai, timeout);
|
||||
int t = NIL_P(timeout) ? -1 : rsock_value_timeout_to_msec(timeout);
|
||||
error = rb_getaddrinfo(hostp, portp, hints, &ai, t);
|
||||
if (error == 0) {
|
||||
res = (struct rb_addrinfo *)xmalloc(sizeof(struct rb_addrinfo));
|
||||
res->allocated_by_malloc = 0;
|
||||
@ -1089,7 +1093,7 @@ rsock_fd_family(int fd)
|
||||
}
|
||||
|
||||
struct rb_addrinfo*
|
||||
rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, unsigned int timeout)
|
||||
rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout)
|
||||
{
|
||||
struct addrinfo hints;
|
||||
|
||||
@ -1380,8 +1384,7 @@ call_getaddrinfo(VALUE node, VALUE service,
|
||||
hints.ai_flags = NUM2INT(flags);
|
||||
}
|
||||
|
||||
unsigned int t = NIL_P(timeout) ? 0 : rsock_value_timeout_to_msec(timeout);
|
||||
res = rsock_getaddrinfo(node, service, &hints, socktype_hack, t);
|
||||
res = rsock_getaddrinfo(node, service, &hints, socktype_hack, timeout);
|
||||
|
||||
if (res == NULL)
|
||||
rb_raise(rb_eSocket, "host not found");
|
||||
|
||||
@ -327,8 +327,8 @@ void rb_freeaddrinfo(struct rb_addrinfo *ai);
|
||||
VALUE rsock_freeaddrinfo(VALUE arg);
|
||||
int rb_getnameinfo(const struct sockaddr *sa, socklen_t salen, char *host, size_t hostlen, char *serv, size_t servlen, int flags);
|
||||
int rsock_fd_family(int fd);
|
||||
struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, unsigned int timeout);
|
||||
struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, unsigned int timeout);
|
||||
struct rb_addrinfo *rsock_addrinfo(VALUE host, VALUE port, int family, int socktype, int flags, VALUE timeout);
|
||||
struct rb_addrinfo *rsock_getaddrinfo(VALUE host, VALUE port, struct addrinfo *hints, int socktype_hack, VALUE timeout);
|
||||
|
||||
VALUE rsock_fd_socket_addrinfo(int fd, struct sockaddr *addr, socklen_t len);
|
||||
VALUE rsock_io_socket_addrinfo(VALUE io, struct sockaddr *addr, socklen_t len);
|
||||
@ -453,7 +453,6 @@ void free_fast_fallback_getaddrinfo_shared(struct fast_fallback_getaddrinfo_shar
|
||||
# endif
|
||||
#endif
|
||||
|
||||
unsigned int rsock_value_timeout_to_msec(VALUE);
|
||||
NORETURN(void rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port));
|
||||
|
||||
void rsock_init_basicsocket(void);
|
||||
|
||||
@ -965,7 +965,7 @@ sock_s_gethostbyname(VALUE obj, VALUE host)
|
||||
{
|
||||
rb_warn("Socket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
|
||||
struct rb_addrinfo *res =
|
||||
rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, 0);
|
||||
rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
|
||||
return rsock_make_hostent(host, res, sock_sockaddr);
|
||||
}
|
||||
|
||||
@ -1183,7 +1183,7 @@ sock_s_getaddrinfo(int argc, VALUE *argv, VALUE _)
|
||||
norevlookup = rsock_do_not_reverse_lookup;
|
||||
}
|
||||
|
||||
res = rsock_getaddrinfo(host, port, &hints, 0, 0);
|
||||
res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
|
||||
|
||||
ret = make_addrinfo(res, norevlookup);
|
||||
rb_freeaddrinfo(res);
|
||||
@ -1279,7 +1279,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
|
||||
hints.ai_socktype = (fl & NI_DGRAM) ? SOCK_DGRAM : SOCK_STREAM;
|
||||
/* af */
|
||||
hints.ai_family = NIL_P(af) ? PF_UNSPEC : rsock_family_arg(af);
|
||||
res = rsock_getaddrinfo(host, port, &hints, 0, 0);
|
||||
res = rsock_getaddrinfo(host, port, &hints, 0, Qnil);
|
||||
sap = res->ai->ai_addr;
|
||||
salen = res->ai->ai_addrlen;
|
||||
}
|
||||
@ -1335,7 +1335,7 @@ sock_s_getnameinfo(int argc, VALUE *argv, VALUE _)
|
||||
static VALUE
|
||||
sock_s_pack_sockaddr_in(VALUE self, VALUE port, VALUE host)
|
||||
{
|
||||
struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, 0);
|
||||
struct rb_addrinfo *res = rsock_addrinfo(host, port, AF_UNSPEC, 0, 0, Qnil);
|
||||
VALUE addr = rb_str_new((char*)res->ai->ai_addr, res->ai->ai_addrlen);
|
||||
|
||||
rb_freeaddrinfo(res);
|
||||
|
||||
@ -113,7 +113,7 @@ tcp_s_gethostbyname(VALUE obj, VALUE host)
|
||||
{
|
||||
rb_warn("TCPSocket.gethostbyname is deprecated; use Addrinfo.getaddrinfo instead.");
|
||||
struct rb_addrinfo *res =
|
||||
rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, 0);
|
||||
rsock_addrinfo(host, Qnil, AF_UNSPEC, SOCK_STREAM, AI_CANONNAME, Qnil);
|
||||
return rsock_make_hostent(host, res, tcp_sockaddr);
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ udp_connect(VALUE self, VALUE host, VALUE port)
|
||||
{
|
||||
struct udp_arg arg = {.io = self};
|
||||
|
||||
arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, 0);
|
||||
arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
|
||||
|
||||
int result = (int)rb_ensure(udp_connect_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
|
||||
if (!result) {
|
||||
@ -129,7 +129,7 @@ udp_bind(VALUE self, VALUE host, VALUE port)
|
||||
{
|
||||
struct udp_arg arg = {.io = self};
|
||||
|
||||
arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, 0);
|
||||
arg.res = rsock_addrinfo(host, port, rsock_fd_family(rb_io_descriptor(self)), SOCK_DGRAM, 0, Qnil);
|
||||
|
||||
VALUE result = rb_ensure(udp_bind_internal, (VALUE)&arg, rsock_freeaddrinfo, (VALUE)arg.res);
|
||||
if (!result) {
|
||||
@ -212,7 +212,7 @@ udp_send(int argc, VALUE *argv, VALUE sock)
|
||||
GetOpenFile(sock, arg.fptr);
|
||||
arg.sarg.fd = arg.fptr->fd;
|
||||
arg.sarg.flags = NUM2INT(flags);
|
||||
arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, 0);
|
||||
arg.res = rsock_addrinfo(host, port, rsock_fd_family(arg.fptr->fd), SOCK_DGRAM, 0, Qnil);
|
||||
ret = rb_ensure(udp_send_internal, (VALUE)&arg,
|
||||
rsock_freeaddrinfo, (VALUE)arg.res);
|
||||
if (!ret) rsock_sys_fail_host_port("sendto(2)", host, port);
|
||||
|
||||
@ -1011,7 +1011,7 @@ class TestSocket < Test::Unit::TestCase
|
||||
Addrinfo.define_singleton_method(:getaddrinfo) do |_, _, family, *_|
|
||||
case family
|
||||
when Socket::AF_INET6 then raise SocketError
|
||||
when Socket::AF_INET then sleep(0.001); raise SocketError, "Last hostname resolution error"
|
||||
when Socket::AF_INET then sleep(0.01); raise SocketError, "Last hostname resolution error"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user