Add connect_timeout to TCPSocket
Add connect_timeout to TCPSocket.new in the same way as Socket.tcp. Closes [Feature #17187]
This commit is contained in:
parent
658b4ff609
commit
78f188524f
4
NEWS.md
4
NEWS.md
@ -348,6 +348,10 @@ Outstanding ones only.
|
|||||||
|
|
||||||
* Update to IRB 1.2.6
|
* Update to IRB 1.2.6
|
||||||
|
|
||||||
|
* Socket
|
||||||
|
|
||||||
|
* Add :connect_timeout to TCPSocket.new [[Feature #17187]]
|
||||||
|
|
||||||
* Net::HTTP
|
* Net::HTTP
|
||||||
|
|
||||||
* Net::HTTP#verify_hostname= and Net::HTTP#verify_hostname have been
|
* Net::HTTP#verify_hostname= and Net::HTTP#verify_hostname have been
|
||||||
|
@ -451,7 +451,7 @@ rsock_socket(int domain, int type, int proto)
|
|||||||
|
|
||||||
/* emulate blocking connect behavior on EINTR or non-blocking socket */
|
/* emulate blocking connect behavior on EINTR or non-blocking socket */
|
||||||
static int
|
static int
|
||||||
wait_connectable(int fd)
|
wait_connectable(int fd, struct timeval *timeout)
|
||||||
{
|
{
|
||||||
int sockerr, revents;
|
int sockerr, revents;
|
||||||
socklen_t sockerrlen;
|
socklen_t sockerrlen;
|
||||||
@ -488,7 +488,7 @@ wait_connectable(int fd)
|
|||||||
*
|
*
|
||||||
* Note: rb_wait_for_single_fd already retries on EINTR/ERESTART
|
* Note: rb_wait_for_single_fd already retries on EINTR/ERESTART
|
||||||
*/
|
*/
|
||||||
revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, NULL);
|
revents = rb_wait_for_single_fd(fd, RB_WAITFD_IN|RB_WAITFD_OUT, timeout);
|
||||||
|
|
||||||
if (revents < 0)
|
if (revents < 0)
|
||||||
return -1;
|
return -1;
|
||||||
@ -503,6 +503,12 @@ wait_connectable(int fd)
|
|||||||
* be defensive in case some platforms set SO_ERROR on the original,
|
* be defensive in case some platforms set SO_ERROR on the original,
|
||||||
* interrupted connect()
|
* interrupted connect()
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* when the connection timed out, no errno is set and revents is 0. */
|
||||||
|
if (timeout && revents == 0) {
|
||||||
|
errno = ETIMEDOUT;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
case EINTR:
|
case EINTR:
|
||||||
#ifdef ERESTART
|
#ifdef ERESTART
|
||||||
case ERESTART:
|
case ERESTART:
|
||||||
@ -550,7 +556,7 @@ socks_connect_blocking(void *data)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
int
|
int
|
||||||
rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
|
rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout)
|
||||||
{
|
{
|
||||||
int status;
|
int status;
|
||||||
rb_blocking_function_t *func = connect_blocking;
|
rb_blocking_function_t *func = connect_blocking;
|
||||||
@ -574,7 +580,7 @@ rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks)
|
|||||||
#ifdef EINPROGRESS
|
#ifdef EINPROGRESS
|
||||||
case EINPROGRESS:
|
case EINPROGRESS:
|
||||||
#endif
|
#endif
|
||||||
return wait_connectable(fd);
|
return wait_connectable(fd, timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
|
@ -20,6 +20,7 @@ struct inetsock_arg
|
|||||||
int type;
|
int type;
|
||||||
int fd;
|
int fd;
|
||||||
VALUE resolv_timeout;
|
VALUE resolv_timeout;
|
||||||
|
VALUE connect_timeout;
|
||||||
};
|
};
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
@ -50,6 +51,14 @@ init_inetsock_internal(VALUE v)
|
|||||||
int fd, status = 0, local = 0;
|
int fd, status = 0, local = 0;
|
||||||
int family = AF_UNSPEC;
|
int family = AF_UNSPEC;
|
||||||
const char *syscall = 0;
|
const char *syscall = 0;
|
||||||
|
VALUE connect_timeout = arg->connect_timeout;
|
||||||
|
struct timeval tv_storage;
|
||||||
|
struct timeval *tv = NULL;
|
||||||
|
|
||||||
|
if (!NIL_P(connect_timeout)) {
|
||||||
|
tv_storage = rb_time_interval(connect_timeout);
|
||||||
|
tv = &tv_storage;
|
||||||
|
}
|
||||||
|
|
||||||
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
|
arg->remote.res = rsock_addrinfo(arg->remote.host, arg->remote.serv,
|
||||||
family, SOCK_STREAM,
|
family, SOCK_STREAM,
|
||||||
@ -116,7 +125,7 @@ init_inetsock_internal(VALUE v)
|
|||||||
|
|
||||||
if (status >= 0) {
|
if (status >= 0) {
|
||||||
status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
|
status = rsock_connect(fd, res->ai_addr, res->ai_addrlen,
|
||||||
(type == INET_SOCKS));
|
(type == INET_SOCKS), tv);
|
||||||
syscall = "connect(2)";
|
syscall = "connect(2)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -161,7 +170,7 @@ init_inetsock_internal(VALUE v)
|
|||||||
VALUE
|
VALUE
|
||||||
rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
|
rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
|
||||||
VALUE local_host, VALUE local_serv, int type,
|
VALUE local_host, VALUE local_serv, int type,
|
||||||
VALUE resolv_timeout)
|
VALUE resolv_timeout, VALUE connect_timeout)
|
||||||
{
|
{
|
||||||
struct inetsock_arg arg;
|
struct inetsock_arg arg;
|
||||||
arg.sock = sock;
|
arg.sock = sock;
|
||||||
@ -174,6 +183,7 @@ rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv,
|
|||||||
arg.type = type;
|
arg.type = type;
|
||||||
arg.fd = -1;
|
arg.fd = -1;
|
||||||
arg.resolv_timeout = resolv_timeout;
|
arg.resolv_timeout = resolv_timeout;
|
||||||
|
arg.connect_timeout = connect_timeout;
|
||||||
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
|
return rb_ensure(init_inetsock_internal, (VALUE)&arg,
|
||||||
inetsock_cleanup, (VALUE)&arg);
|
inetsock_cleanup, (VALUE)&arg);
|
||||||
}
|
}
|
||||||
|
@ -346,7 +346,7 @@ int rsock_socket(int domain, int type, int proto);
|
|||||||
int rsock_detect_cloexec(int fd);
|
int rsock_detect_cloexec(int fd);
|
||||||
VALUE rsock_init_sock(VALUE sock, int fd);
|
VALUE rsock_init_sock(VALUE sock, int fd);
|
||||||
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
|
VALUE rsock_sock_s_socketpair(int argc, VALUE *argv, VALUE klass);
|
||||||
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout);
|
VALUE rsock_init_inetsock(VALUE sock, VALUE remote_host, VALUE remote_serv, VALUE local_host, VALUE local_serv, int type, VALUE resolv_timeout, VALUE connect_timeout);
|
||||||
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);
|
VALUE rsock_init_unixsock(VALUE sock, VALUE path, int server);
|
||||||
|
|
||||||
struct rsock_send_arg {
|
struct rsock_send_arg {
|
||||||
@ -371,7 +371,7 @@ VALUE rsock_s_recvfrom_nonblock(VALUE sock, VALUE len, VALUE flg, VALUE str,
|
|||||||
VALUE ex, enum sock_recv_type from);
|
VALUE ex, enum sock_recv_type from);
|
||||||
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
|
VALUE rsock_s_recvfrom(VALUE sock, int argc, VALUE *argv, enum sock_recv_type from);
|
||||||
|
|
||||||
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks);
|
int rsock_connect(int fd, const struct sockaddr *sockaddr, int len, int socks, struct timeval *timeout);
|
||||||
|
|
||||||
VALUE rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
|
VALUE rsock_s_accept(VALUE klass, int fd, struct sockaddr *sockaddr, socklen_t *len);
|
||||||
VALUE rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
|
VALUE rsock_s_accept_nonblock(VALUE klass, VALUE ex, rb_io_t *fptr,
|
||||||
|
@ -393,7 +393,7 @@ sock_connect(VALUE sock, VALUE addr)
|
|||||||
addr = rb_str_new4(addr);
|
addr = rb_str_new4(addr);
|
||||||
GetOpenFile(sock, fptr);
|
GetOpenFile(sock, fptr);
|
||||||
fd = fptr->fd;
|
fd = fptr->fd;
|
||||||
n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0);
|
n = rsock_connect(fd, (struct sockaddr*)RSTRING_PTR(addr), RSTRING_SOCKLEN(addr), 0, NULL);
|
||||||
if (n < 0) {
|
if (n < 0) {
|
||||||
rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
|
rsock_sys_fail_raddrinfo_or_sockaddr("connect(2)", addr, rai);
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ tcp_svr_init(int argc, VALUE *argv, VALUE sock)
|
|||||||
VALUE hostname, port;
|
VALUE hostname, port;
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "011", &hostname, &port);
|
rb_scan_args(argc, argv, "011", &hostname, &port);
|
||||||
return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil);
|
return rsock_init_inetsock(sock, hostname, port, Qnil, Qnil, INET_SERVER, Qnil, Qnil);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -12,13 +12,14 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil)
|
* TCPSocket.new(remote_host, remote_port, local_host=nil, local_port=nil, resolv_timeout: nil, connect_timeout: nil)
|
||||||
*
|
*
|
||||||
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
|
* Opens a TCP connection to +remote_host+ on +remote_port+. If +local_host+
|
||||||
* and +local_port+ are specified, then those parameters are used on the local
|
* and +local_port+ are specified, then those parameters are used on the local
|
||||||
* end to establish the connection.
|
* end to establish the connection.
|
||||||
*
|
*
|
||||||
* [:resolv_timeout] specify the name resolution timeout in seconds.
|
* [:resolv_timeout] specify the name resolution timeout in seconds.
|
||||||
|
* [:connect_timeout] specify the timeout in seconds.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
tcp_init(int argc, VALUE *argv, VALUE sock)
|
tcp_init(int argc, VALUE *argv, VALUE sock)
|
||||||
@ -26,27 +27,28 @@ tcp_init(int argc, VALUE *argv, VALUE sock)
|
|||||||
VALUE remote_host, remote_serv;
|
VALUE remote_host, remote_serv;
|
||||||
VALUE local_host, local_serv;
|
VALUE local_host, local_serv;
|
||||||
VALUE opt;
|
VALUE opt;
|
||||||
static ID keyword_ids[1];
|
static ID keyword_ids[2];
|
||||||
VALUE kwargs[1];
|
VALUE kwargs[2];
|
||||||
VALUE resolv_timeout = Qnil;
|
VALUE resolv_timeout = Qnil;
|
||||||
|
VALUE connect_timeout = Qnil;
|
||||||
|
|
||||||
if (!keyword_ids[0]) {
|
if (!keyword_ids[0]) {
|
||||||
CONST_ID(keyword_ids[0], "resolv_timeout");
|
CONST_ID(keyword_ids[0], "resolv_timeout");
|
||||||
|
CONST_ID(keyword_ids[1], "connect_timeout");
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_scan_args(argc, argv, "22:", &remote_host, &remote_serv,
|
rb_scan_args(argc, argv, "22:", &remote_host, &remote_serv,
|
||||||
&local_host, &local_serv, &opt);
|
&local_host, &local_serv, &opt);
|
||||||
|
|
||||||
if (!NIL_P(opt)) {
|
if (!NIL_P(opt)) {
|
||||||
rb_get_kwargs(opt, keyword_ids, 0, 1, kwargs);
|
rb_get_kwargs(opt, keyword_ids, 0, 2, kwargs);
|
||||||
if (kwargs[0] != Qundef) {
|
if (kwargs[0] != Qundef) { resolv_timeout = kwargs[0]; }
|
||||||
resolv_timeout = kwargs[0];
|
if (kwargs[1] != Qundef) { connect_timeout = kwargs[1]; }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rsock_init_inetsock(sock, remote_host, remote_serv,
|
return rsock_init_inetsock(sock, remote_host, remote_serv,
|
||||||
local_host, local_serv, INET_CLIENT,
|
local_host, local_serv, INET_CLIENT,
|
||||||
resolv_timeout);
|
resolv_timeout, connect_timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -60,7 +60,7 @@ udp_connect_internal(VALUE v)
|
|||||||
rb_io_check_closed(fptr = arg->fptr);
|
rb_io_check_closed(fptr = arg->fptr);
|
||||||
fd = fptr->fd;
|
fd = fptr->fd;
|
||||||
for (res = arg->res->ai; res; res = res->ai_next) {
|
for (res = arg->res->ai; res; res = res->ai_next) {
|
||||||
if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0) >= 0) {
|
if (rsock_connect(fd, res->ai_addr, res->ai_addrlen, 0, NULL) >= 0) {
|
||||||
return Qtrue;
|
return Qtrue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ unixsock_connect_internal(VALUE a)
|
|||||||
{
|
{
|
||||||
struct unixsock_arg *arg = (struct unixsock_arg *)a;
|
struct unixsock_arg *arg = (struct unixsock_arg *)a;
|
||||||
return (VALUE)rsock_connect(arg->fd, (struct sockaddr*)arg->sockaddr,
|
return (VALUE)rsock_connect(arg->fd, (struct sockaddr*)arg->sockaddr,
|
||||||
arg->sockaddrlen, 0);
|
arg->sockaddrlen, 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
|
@ -69,6 +69,12 @@ class TestSocket_TCPSocket < Test::Unit::TestCase
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_initialize_connect_timeout
|
||||||
|
assert_raise(Errno::ETIMEDOUT) do
|
||||||
|
TCPSocket.new("192.0.2.1", 80, connect_timeout: 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_recvfrom
|
def test_recvfrom
|
||||||
TCPServer.open("localhost", 0) {|svr|
|
TCPServer.open("localhost", 0) {|svr|
|
||||||
th = Thread.new {
|
th = Thread.new {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user