diff options
Diffstat (limited to 'ext/socket/ipsocket.c')
| -rw-r--r-- | ext/socket/ipsocket.c | 268 |
1 files changed, 200 insertions, 68 deletions
diff --git a/ext/socket/ipsocket.c b/ext/socket/ipsocket.c index 3e497a43be..931a1a629c 100644 --- a/ext/socket/ipsocket.c +++ b/ext/socket/ipsocket.c @@ -23,8 +23,25 @@ struct inetsock_arg int type; VALUE resolv_timeout; VALUE connect_timeout; + VALUE open_timeout; }; +void +rsock_raise_user_specified_timeout(struct addrinfo *ai, VALUE host, VALUE port) +{ + VALUE message; + + if (ai && ai->ai_addr) { + VALUE rai = rsock_addrinfo_new((struct sockaddr *)ai->ai_addr, (socklen_t)ai->ai_addrlen, PF_UNSPEC, 0, 0, Qnil, Qnil); + VALUE addr_str = rsock_addrinfo_inspect_sockaddr(rai); + message = rb_sprintf("user specified timeout for %" PRIsVALUE, addr_str); + } else { + message = rb_sprintf("user specified timeout for %" PRIsVALUE " port %" PRIsVALUE, host, port); + } + + rb_raise(rb_eIOTimeoutError, "%" PRIsVALUE, message); +} + static VALUE inetsock_cleanup(VALUE v) { @@ -45,6 +62,13 @@ inetsock_cleanup(VALUE v) } static VALUE +current_clocktime(void) +{ + VALUE clock_monotnic_const = rb_const_get(rb_mProcess, rb_intern("CLOCK_MONOTONIC")); + return rb_funcall(rb_mProcess, rb_intern("clock_gettime"), 1, clock_monotnic_const); +} + +static VALUE init_inetsock_internal(VALUE v) { struct inetsock_arg *arg = (void *)v; @@ -54,12 +78,18 @@ init_inetsock_internal(VALUE v) int status = 0, local = 0; int family = AF_UNSPEC; const char *syscall = 0; + VALUE resolv_timeout = arg->resolv_timeout; VALUE connect_timeout = arg->connect_timeout; + VALUE open_timeout = arg->open_timeout; + VALUE timeout; + VALUE starts_at; + + timeout = NIL_P(open_timeout) ? resolv_timeout : open_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); - + (type == INET_SERVER) ? AI_PASSIVE : 0, timeout); /* * Maybe also accept a local address @@ -67,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); + family, SOCK_STREAM, 0, timeout); } VALUE io = Qnil; @@ -122,8 +152,18 @@ init_inetsock_internal(VALUE v) syscall = "bind(2)"; } + if (NIL_P(open_timeout)) { + timeout = connect_timeout; + } else { + VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at); + timeout = rb_funcall(open_timeout, '-', 1, elapsed); + if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) { + rsock_raise_user_specified_timeout(res, arg->remote.host, arg->remote.serv); + } + } + if (status >= 0) { - status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), connect_timeout); + status = rsock_connect(io, res->ai_addr, res->ai_addrlen, (type == INET_SOCKS), timeout); syscall = "connect(2)"; } } @@ -172,8 +212,16 @@ init_inetsock_internal(VALUE v) #if FAST_FALLBACK_INIT_INETSOCK_IMPL == 0 VALUE -rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE _fast_fallback, VALUE _test_mode_settings) +rsock_init_inetsock( + VALUE self, VALUE remote_host, VALUE remote_serv, + VALUE local_host, VALUE local_serv, int type, + VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout, + VALUE _fast_fallback, VALUE _test_mode_settings) { + if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) { + rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout"); + } + struct inetsock_arg arg; arg.self = self; arg.io = Qnil; @@ -186,6 +234,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca arg.type = type; arg.resolv_timeout = resolv_timeout; arg.connect_timeout = connect_timeout; + arg.open_timeout = open_timeout; return rb_ensure(init_inetsock_internal, (VALUE)&arg, inetsock_cleanup, (VALUE)&arg); } @@ -209,6 +258,21 @@ is_specified_ip_address(const char *hostname) inet_pton(AF_INET, hostname, &ipv4addr) == 1); } +static int +is_local_port_fixed(const char *portp) +{ + if (!portp) return 0; + + char *endp; + errno = 0; + long port = strtol(portp, &endp, 10); + + if (endp == portp) return 0; + if (errno == ERANGE) return 0; + + return port > 0; +} + struct fast_fallback_inetsock_arg { VALUE self; @@ -221,6 +285,7 @@ struct fast_fallback_inetsock_arg int type; VALUE resolv_timeout; VALUE connect_timeout; + VALUE open_timeout; const char *hostp, *portp; int *families; @@ -295,7 +360,7 @@ struct hostname_resolution_store { struct hostname_resolution_result v6; struct hostname_resolution_result v4; - int is_all_finised; + int is_all_finished; }; static int @@ -380,12 +445,22 @@ select_expires_at( struct timeval *resolution_delay, struct timeval *connection_attempt_delay, struct timeval *user_specified_resolv_timeout_at, - struct timeval *user_specified_connect_timeout_at -) { + struct timeval *user_specified_connect_timeout_at, + struct timeval *user_specified_open_timeout_at) +{ if (any_addrinfos(resolution_store)) { - return resolution_delay ? resolution_delay : connection_attempt_delay; + struct timeval *delay; + delay = resolution_delay ? resolution_delay : connection_attempt_delay; + + if (user_specified_open_timeout_at && + timercmp(user_specified_open_timeout_at, delay, <)) { + return user_specified_open_timeout_at; + } + return delay; } + if (user_specified_open_timeout_at) return user_specified_open_timeout_at; + struct timeval *timeout = NULL; if (user_specified_resolv_timeout_at) { @@ -474,7 +549,8 @@ in_progress_fds(int fds_size) } static void -remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd) { +remove_connection_attempt_fd(int *fds, int *fds_size, int removing_fd) +{ int i, j; for (i = 0; i < *fds_size; i++) { @@ -503,6 +579,7 @@ init_fast_fallback_inetsock_internal(VALUE v) VALUE io = arg->io; VALUE resolv_timeout = arg->resolv_timeout; VALUE connect_timeout = arg->connect_timeout; + VALUE open_timeout = arg->open_timeout; VALUE test_mode_settings = arg->test_mode_settings; struct addrinfo *remote_ai = NULL, *local_ai = NULL; int connected_fd = -1, status = 0, local_status = 0; @@ -527,7 +604,7 @@ init_fast_fallback_inetsock_internal(VALUE v) struct timeval *delay_p = NULL; struct hostname_resolution_store resolution_store; - resolution_store.is_all_finised = false; + resolution_store.is_all_finished = false; resolution_store.v6.ai = NULL; resolution_store.v6.finished = false; resolution_store.v6.has_error = false; @@ -549,7 +626,16 @@ init_fast_fallback_inetsock_internal(VALUE v) struct timeval *user_specified_resolv_timeout_at = NULL; struct timeval user_specified_connect_timeout_storage; struct timeval *user_specified_connect_timeout_at = NULL; + struct timeval user_specified_open_timeout_storage; + struct timeval *user_specified_open_timeout_at = NULL; struct timespec now = current_clocktime_ts(); + VALUE starts_at = current_clocktime(); + + if (!NIL_P(open_timeout)) { + struct timeval open_timeout_tv = rb_time_interval(open_timeout); + user_specified_open_timeout_storage = add_ts_to_tv(open_timeout_tv, now); + user_specified_open_timeout_at = &user_specified_open_timeout_storage; + } /* start of hostname resolution */ if (arg->family_size == 1) { @@ -557,12 +643,15 @@ init_fast_fallback_inetsock_internal(VALUE v) arg->getaddrinfo_shared = NULL; int family = arg->families[0]; + VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout; + arg->remote.res = rsock_addrinfo( arg->remote.host, arg->remote.serv, family, SOCK_STREAM, - 0 + 0, + t ); if (family == AF_INET6) { @@ -574,7 +663,7 @@ init_fast_fallback_inetsock_internal(VALUE v) resolution_store.v4.finished = true; resolution_store.v6.finished = true; } - resolution_store.is_all_finised = true; + resolution_store.is_all_finished = true; } else { if (pipe(pipefd) != 0) rb_syserr_fail(errno, "pipe(2)"); hostname_resolution_waiter = pipefd[0]; @@ -593,7 +682,7 @@ init_fast_fallback_inetsock_internal(VALUE v) arg->getaddrinfo_shared->notify = hostname_resolution_notifier; arg->getaddrinfo_shared->node = arg->hostp ? ruby_strdup(arg->hostp) : NULL; - arg->getaddrinfo_shared->service = ruby_strdup(arg->portp); + arg->getaddrinfo_shared->service = arg->portp ? ruby_strdup(arg->portp) : NULL; arg->getaddrinfo_shared->refcount = arg->family_size + 1; for (int i = 0; i < arg->family_size; i++) { @@ -640,7 +729,6 @@ init_fast_fallback_inetsock_internal(VALUE v) if (raddrinfo_pthread_create(&threads[i], fork_safe_do_fast_fallback_getaddrinfo, arg->getaddrinfo_entries[i]) != 0) { rsock_raise_resolution_error("getaddrinfo(3)", EAI_AGAIN); } - pthread_detach(threads[i]); } if (NIL_P(resolv_timeout)) { @@ -664,7 +752,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (remote_ai->ai_family == AF_INET6) { if (any_addrinfos(&resolution_store)) continue; if (!in_progress_fds(arg->connection_attempt_fds_size)) break; - if (resolution_store.is_all_finised) break; + if (resolution_store.is_all_finished) break; if (local_status < 0) { host = arg->local.host; @@ -690,7 +778,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (!local_ai) { if (any_addrinfos(&resolution_store)) continue; if (in_progress_fds(arg->connection_attempt_fds_size)) break; - if (!resolution_store.is_all_finised) break; + if (!resolution_store.is_all_finished) break; /* Use a different family local address if no choice, this * will cause EAFNOSUPPORT. */ @@ -707,7 +795,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (any_addrinfos(&resolution_store)) continue; if (in_progress_fds(arg->connection_attempt_fds_size)) break; - if (!resolution_store.is_all_finised) break; + if (!resolution_store.is_all_finished) break; if (local_status < 0) { host = arg->local.host; @@ -743,7 +831,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (any_addrinfos(&resolution_store)) continue; if (in_progress_fds(arg->connection_attempt_fds_size)) break; - if (!resolution_store.is_all_finised) break; + if (!resolution_store.is_all_finished) break; if (local_status < 0) { host = arg->local.host; @@ -764,19 +852,31 @@ init_fast_fallback_inetsock_internal(VALUE v) if (any_addrinfos(&resolution_store) || in_progress_fds(arg->connection_attempt_fds_size) || - !resolution_store.is_all_finised) { + !resolution_store.is_all_finished) { socket_nonblock_set(fd); status = connect(fd, remote_ai->ai_addr, remote_ai->ai_addrlen); last_family = remote_ai->ai_family; } else { - if (!NIL_P(connect_timeout)) { - user_specified_connect_timeout_storage = rb_time_interval(connect_timeout); - user_specified_connect_timeout_at = &user_specified_connect_timeout_storage; + VALUE timeout = Qnil; + + if (!NIL_P(open_timeout)) { + VALUE elapsed = rb_funcall(current_clocktime(), '-', 1, starts_at); + timeout = rb_funcall(open_timeout, '-', 1, elapsed); + + if (rb_funcall(timeout, '<', 1, INT2FIX(0)) == Qtrue) { + rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv); + } + } + if (NIL_P(timeout)) { + if (!NIL_P(connect_timeout)) { + user_specified_connect_timeout_storage = rb_time_interval(connect_timeout); + user_specified_connect_timeout_at = &user_specified_connect_timeout_storage; + } + timeout = + (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ? + Qnil : tv_to_seconds(user_specified_connect_timeout_at); } - VALUE timeout = - (user_specified_connect_timeout_at && is_infinity(*user_specified_connect_timeout_at)) ? - Qnil : tv_to_seconds(user_specified_connect_timeout_at); io = arg->io = rsock_init_sock(arg->self, fd); status = rsock_connect(io, remote_ai->ai_addr, remote_ai->ai_addrlen, 0, timeout); } @@ -824,7 +924,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (any_addrinfos(&resolution_store)) continue; if (in_progress_fds(arg->connection_attempt_fds_size)) break; - if (!resolution_store.is_all_finised) break; + if (!resolution_store.is_all_finished) break; if (local_status < 0) { host = arg->local.host; @@ -848,7 +948,8 @@ init_fast_fallback_inetsock_internal(VALUE v) resolution_delay_expires_at, connection_attempt_delay_expires_at, user_specified_resolv_timeout_at, - user_specified_connect_timeout_at + user_specified_connect_timeout_at, + user_specified_open_timeout_at ); if (ends_at) { delay = tv_to_timeout(ends_at, now); @@ -892,7 +993,6 @@ init_fast_fallback_inetsock_internal(VALUE v) } status = rb_thread_fd_select(nfds, &arg->readfds, &arg->writefds, NULL, delay_p); - syscall = "select(2)"; now = current_clocktime_ts(); if (is_timeout_tv(resolution_delay_expires_at, now)) { @@ -923,7 +1023,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (any_addrinfos(&resolution_store)) continue; if (in_progress_fds(arg->connection_attempt_fds_size)) break; - if (!resolution_store.is_all_finised) break; + if (!resolution_store.is_all_finished) break; if (local_status < 0) { host = arg->local.host; @@ -962,7 +1062,7 @@ init_fast_fallback_inetsock_internal(VALUE v) if (connected_fd >= 0) break; if (!in_progress_fds(arg->connection_attempt_fds_size)) { - if (!any_addrinfos(&resolution_store) && resolution_store.is_all_finised) { + if (!any_addrinfos(&resolution_store) && resolution_store.is_all_finished) { if (local_status < 0) { host = arg->local.host; serv = arg->local.serv; @@ -982,7 +1082,7 @@ init_fast_fallback_inetsock_internal(VALUE v) } /* check for hostname resolution */ - if (!resolution_store.is_all_finised && rb_fd_isset(hostname_resolution_waiter, &arg->readfds)) { + if (!resolution_store.is_all_finished && rb_fd_isset(hostname_resolution_waiter, &arg->readfds)) { while (true) { resolved_type_size = read( hostname_resolution_waiter, @@ -998,15 +1098,17 @@ init_fast_fallback_inetsock_internal(VALUE v) if (arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err && arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err != EAI_ADDRFAMILY) { - last_error.type = RESOLUTION_ERROR; - last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err; - syscall = "getaddrinfo(3)"; + if (!resolution_store.v4.finished || resolution_store.v4.has_error) { + last_error.type = RESOLUTION_ERROR; + last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err; + syscall = "getaddrinfo(3)"; + } resolution_store.v6.has_error = true; } else { resolution_store.v6.ai = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->ai; } if (resolution_store.v4.finished) { - resolution_store.is_all_finised = true; + resolution_store.is_all_finished = true; resolution_delay_expires_at = NULL; user_specified_resolv_timeout_at = NULL; break; @@ -1015,16 +1117,18 @@ init_fast_fallback_inetsock_internal(VALUE v) resolution_store.v4.finished = true; if (arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err) { - last_error.type = RESOLUTION_ERROR; - last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err; - syscall = "getaddrinfo(3)"; + if (!resolution_store.v6.finished || resolution_store.v6.has_error) { + last_error.type = RESOLUTION_ERROR; + last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err; + syscall = "getaddrinfo(3)"; + } resolution_store.v4.has_error = true; } else { resolution_store.v4.ai = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->ai; } if (resolution_store.v6.finished) { - resolution_store.is_all_finised = true; + resolution_store.is_all_finished = true; resolution_delay_expires_at = NULL; user_specified_resolv_timeout_at = NULL; break; @@ -1052,21 +1156,23 @@ init_fast_fallback_inetsock_internal(VALUE v) } /* For cases where write(2) fails in child threads */ - if (!resolution_store.is_all_finised) { + if (!resolution_store.is_all_finished) { if (!resolution_store.v6.finished && arg->getaddrinfo_entries[IPV6_ENTRY_POS]->has_syserr) { resolution_store.v6.finished = true; if (arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err) { - last_error.type = RESOLUTION_ERROR; - last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err; - syscall = "getaddrinfo(3)"; + if (!resolution_store.v4.finished || resolution_store.v4.has_error) { + last_error.type = RESOLUTION_ERROR; + last_error.ecode = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->err; + syscall = "getaddrinfo(3)"; + } resolution_store.v6.has_error = true; } else { resolution_store.v6.ai = arg->getaddrinfo_entries[IPV6_ENTRY_POS]->ai; } if (resolution_store.v4.finished) { - resolution_store.is_all_finised = true; + resolution_store.is_all_finished = true; resolution_delay_expires_at = NULL; user_specified_resolv_timeout_at = NULL; } @@ -1075,16 +1181,18 @@ init_fast_fallback_inetsock_internal(VALUE v) resolution_store.v4.finished = true; if (arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err) { - last_error.type = RESOLUTION_ERROR; - last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err; - syscall = "getaddrinfo(3)"; + if (!resolution_store.v6.finished || resolution_store.v6.has_error) { + last_error.type = RESOLUTION_ERROR; + last_error.ecode = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->err; + syscall = "getaddrinfo(3)"; + } resolution_store.v4.has_error = true; } else { resolution_store.v4.ai = arg->getaddrinfo_entries[IPV4_ENTRY_POS]->ai; } if (resolution_store.v6.finished) { - resolution_store.is_all_finised = true; + resolution_store.is_all_finished = true; resolution_delay_expires_at = NULL; user_specified_resolv_timeout_at = NULL; } else { @@ -1094,9 +1202,13 @@ init_fast_fallback_inetsock_internal(VALUE v) } } + if (is_timeout_tv(user_specified_open_timeout_at, now)) { + rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv); + } + if (!any_addrinfos(&resolution_store)) { if (!in_progress_fds(arg->connection_attempt_fds_size) && - resolution_store.is_all_finised) { + resolution_store.is_all_finished) { if (local_status < 0) { host = arg->local.host; serv = arg->local.serv; @@ -1112,12 +1224,10 @@ init_fast_fallback_inetsock_internal(VALUE v) } if ((is_timeout_tv(user_specified_resolv_timeout_at, now) || - resolution_store.is_all_finised) && + resolution_store.is_all_finished) && (is_timeout_tv(user_specified_connect_timeout_at, now) || !in_progress_fds(arg->connection_attempt_fds_size))) { - VALUE errno_module = rb_const_get(rb_cObject, rb_intern("Errno")); - VALUE etimedout_error = rb_const_get(errno_module, rb_intern("ETIMEDOUT")); - rb_raise(etimedout_error, "user specified timeout"); + rsock_raise_user_specified_timeout(NULL, arg->remote.host, arg->remote.serv); } } } @@ -1152,13 +1262,19 @@ fast_fallback_inetsock_cleanup(VALUE v) getaddrinfo_shared->notify = -1; int shared_need_free = 0; - int need_free[2] = { 0, 0 }; + struct addrinfo *ais[arg->family_size]; + for (int i = 0; i < arg->family_size; i++) ais[i] = NULL; rb_nativethread_lock_lock(&getaddrinfo_shared->lock); { for (int i = 0; i < arg->family_size; i++) { - if (arg->getaddrinfo_entries[i] && --(arg->getaddrinfo_entries[i]->refcount) == 0) { - need_free[i] = 1; + struct fast_fallback_getaddrinfo_entry *getaddrinfo_entry = arg->getaddrinfo_entries[i]; + + if (!getaddrinfo_entry) continue; + + if (--(getaddrinfo_entry->refcount) == 0) { + ais[i] = getaddrinfo_entry->ai; + getaddrinfo_entry->ai = NULL; } } if (--(getaddrinfo_shared->refcount) == 0) { @@ -1168,9 +1284,11 @@ fast_fallback_inetsock_cleanup(VALUE v) rb_nativethread_lock_unlock(&getaddrinfo_shared->lock); for (int i = 0; i < arg->family_size; i++) { - if (need_free[i]) free_fast_fallback_getaddrinfo_entry(&arg->getaddrinfo_entries[i]); + if (ais[i]) freeaddrinfo(ais[i]); + } + if (getaddrinfo_shared && shared_need_free) { + free_fast_fallback_getaddrinfo_shared(&getaddrinfo_shared); } - if (shared_need_free) free_fast_fallback_getaddrinfo_shared(&getaddrinfo_shared); } int connection_attempt_fd; @@ -1199,17 +1317,27 @@ fast_fallback_inetsock_cleanup(VALUE v) } VALUE -rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout, VALUE fast_fallback, VALUE test_mode_settings) +rsock_init_inetsock( + VALUE self, VALUE remote_host, VALUE remote_serv, + VALUE local_host, VALUE local_serv, int type, + VALUE resolv_timeout, VALUE connect_timeout, VALUE open_timeout, + VALUE fast_fallback, VALUE test_mode_settings) { + if (!NIL_P(open_timeout) && (!NIL_P(resolv_timeout) || !NIL_P(connect_timeout))) { + rb_raise(rb_eArgError, "Cannot specify open_timeout along with connect_timeout or resolv_timeout"); + } + if (type == INET_CLIENT && FAST_FALLBACK_INIT_INETSOCK_IMPL == 1 && RTEST(fast_fallback)) { struct rb_addrinfo *local_res = NULL; - char *hostp, *portp; - char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; + char *hostp, *portp, *local_portp; + char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV], local_pbuf[NI_MAXSERV]; int additional_flags = 0; - hostp = host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags); - portp = port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags); + int local_flags = 0; + hostp = raddrinfo_host_str(remote_host, hbuf, sizeof(hbuf), &additional_flags); + portp = raddrinfo_port_str(remote_serv, pbuf, sizeof(pbuf), &additional_flags); + local_portp = raddrinfo_port_str(local_serv, local_pbuf, sizeof(local_pbuf), &local_flags); - if (!is_specified_ip_address(hostp)) { + if (!is_specified_ip_address(hostp) && !is_local_port_fixed(local_portp)) { int target_families[2] = { 0, 0 }; int resolving_family_size = 0; @@ -1217,16 +1345,18 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca * Maybe also accept a local address */ if (!NIL_P(local_host) || !NIL_P(local_serv)) { + VALUE t = NIL_P(open_timeout) ? resolv_timeout : open_timeout; local_res = rsock_addrinfo( local_host, local_serv, AF_UNSPEC, SOCK_STREAM, - 0 + 0, + t ); struct addrinfo *tmp_p = local_res->ai; - for (tmp_p; tmp_p != NULL; tmp_p = tmp_p->ai_next) { + for (; tmp_p != NULL; tmp_p = tmp_p->ai_next) { if (target_families[0] == 0 && tmp_p->ai_family == AF_INET6) { target_families[0] = AF_INET6; resolving_family_size++; @@ -1256,6 +1386,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca fast_fallback_arg.type = type; fast_fallback_arg.resolv_timeout = resolv_timeout; fast_fallback_arg.connect_timeout = connect_timeout; + fast_fallback_arg.open_timeout = open_timeout; fast_fallback_arg.hostp = hostp; fast_fallback_arg.portp = portp; fast_fallback_arg.additional_flags = additional_flags; @@ -1292,6 +1423,7 @@ rsock_init_inetsock(VALUE self, VALUE remote_host, VALUE remote_serv, VALUE loca arg.type = type; arg.resolv_timeout = resolv_timeout; arg.connect_timeout = connect_timeout; + arg.open_timeout = open_timeout; return rb_ensure(init_inetsock_internal, (VALUE)&arg, inetsock_cleanup, (VALUE)&arg); @@ -1477,7 +1609,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); + 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 */ |
