diff options
-rw-r--r-- | ext/kgio/connect.c | 37 | ||||
-rw-r--r-- | ext/kgio/extconf.rb | 2 | ||||
-rw-r--r-- | ext/kgio/tryopen.c | 6 | ||||
-rw-r--r-- | test/test_tcp_connect.rb | 11 | ||||
-rw-r--r-- | test/test_tryopen.rb | 4 | ||||
-rw-r--r-- | test/test_unix_connect.rb | 8 |
6 files changed, 59 insertions, 9 deletions
diff --git a/ext/kgio/connect.c b/ext/kgio/connect.c index dd2f409..ff5e639 100644 --- a/ext/kgio/connect.c +++ b/ext/kgio/connect.c @@ -9,16 +9,30 @@ static void close_fail(int fd, const char *msg) rb_sys_fail(msg); } -#ifdef SOCK_NONBLOCK -# define MY_SOCK_STREAM (SOCK_STREAM|SOCK_NONBLOCK) +static int MY_SOCK_STREAM = +#if defined(SOCK_NONBLOCK) && defined(SOCK_CLOEXEC) +# ifdef HAVE_RB_FD_FIX_CLOEXEC + (SOCK_STREAM|SOCK_NONBLOCK|SOCK_CLOEXEC) +# else + (SOCK_STREAM|SOCK_NONBLOCK) +# endif #else -# define MY_SOCK_STREAM SOCK_STREAM + SOCK_STREAM #endif /* ! SOCK_NONBLOCK */ +; + +/* do not set close-on-exec by default on Ruby <2.0.0 */ +#ifndef HAVE_RB_FD_FIX_CLOEXEC +# define rb_fd_fix_cloexec(fd) for (;0;) +#endif /* HAVE_RB_FD_FIX_CLOEXEC */ static VALUE my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen) { - int fd = socket(domain, MY_SOCK_STREAM, 0); + int fd; + +retry: + fd = socket(domain, MY_SOCK_STREAM, 0); if (fd == -1) { switch (errno) { @@ -30,15 +44,22 @@ my_connect(VALUE klass, int io_wait, int domain, void *addr, socklen_t addrlen) errno = 0; rb_gc(); fd = socket(domain, MY_SOCK_STREAM, 0); + break; + case EINVAL: + if (MY_SOCK_STREAM != SOCK_STREAM) { + MY_SOCK_STREAM = SOCK_STREAM; + goto retry; + } } if (fd == -1) rb_sys_fail("socket"); } -#ifndef SOCK_NONBLOCK - if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK) == -1) - close_fail(fd, "fcntl(F_SETFL, O_RDWR | O_NONBLOCK)"); -#endif /* SOCK_NONBLOCK */ + if (MY_SOCK_STREAM == SOCK_STREAM) { + if (fcntl(fd, F_SETFL, O_RDWR | O_NONBLOCK) == -1) + close_fail(fd, "fcntl(F_SETFL, O_RDWR | O_NONBLOCK)"); + rb_fd_fix_cloexec(fd); + } if (connect(fd, addr, addrlen) == -1) { if (errno == EINPROGRESS) { diff --git a/ext/kgio/extconf.rb b/ext/kgio/extconf.rb index a76454d..fb680f7 100644 --- a/ext/kgio/extconf.rb +++ b/ext/kgio/extconf.rb @@ -42,6 +42,8 @@ have_type("struct RObject") and check_sizeof("struct RObject") check_sizeof("int") have_func('rb_io_ascii8bit_binmode') have_func('rb_update_max_fd') +have_func('rb_fd_fix_cloexec') +have_func('rb_cloexec_open') have_func('rb_thread_blocking_region') have_func('rb_thread_io_blocking_region') have_func('rb_str_set_len') diff --git a/ext/kgio/tryopen.c b/ext/kgio/tryopen.c index 16f47fb..85bbbc2 100644 --- a/ext/kgio/tryopen.c +++ b/ext/kgio/tryopen.c @@ -25,11 +25,15 @@ struct open_args { mode_t mode; }; +#ifndef HAVE_RB_CLOEXEC_OPEN +# define rb_cloexec_open(p,f,m) open((p),(f),(m)) +#endif + static VALUE nogvl_open(void *ptr) { struct open_args *o = ptr; - return (VALUE)open(o->pathname, o->flags, o->mode); + return (VALUE)rb_cloexec_open(o->pathname, o->flags, o->mode); } #ifndef HAVE_RB_THREAD_BLOCKING_REGION diff --git a/test/test_tcp_connect.rb b/test/test_tcp_connect.rb index 9756407..2dbe541 100644 --- a/test/test_tcp_connect.rb +++ b/test/test_tcp_connect.rb @@ -31,10 +31,17 @@ class TestKgioTcpConnect < Test::Unit::TestCase ready = IO.select(nil, [ sock ]) assert_equal sock, ready[1][0] assert_equal nil, sock.kgio_write("HELLO") + + sock.respond_to?(:close_on_exec?) and + assert_equal(RUBY_VERSION.to_f >= 2.0, sock.close_on_exec?) end def test_start sock = Kgio::Socket.start(@addr) + + sock.respond_to?(:close_on_exec?) and + assert_equal(RUBY_VERSION.to_f >= 2.0, sock.close_on_exec?) + assert_kind_of Kgio::Socket, sock ready = IO.select(nil, [ sock ]) assert_equal sock, ready[1][0] @@ -50,6 +57,10 @@ class TestKgioTcpConnect < Test::Unit::TestCase def test_tcp_socket_new sock = Kgio::TCPSocket.new(@host, @port) + + sock.respond_to?(:close_on_exec?) and + assert_equal(RUBY_VERSION.to_f >= 2.0, sock.close_on_exec?) + assert_instance_of Kgio::TCPSocket, sock ready = IO.select(nil, [ sock ]) assert_equal sock, ready[1][0] diff --git a/test/test_tryopen.rb b/test/test_tryopen.rb index 380026d..5a8efb2 100644 --- a/test/test_tryopen.rb +++ b/test/test_tryopen.rb @@ -7,6 +7,10 @@ class TestTryopen < Test::Unit::TestCase def test_tryopen_success tmp = Kgio::File.tryopen(__FILE__) + + tmp.respond_to?(:close_on_exec?) and + assert_equal(RUBY_VERSION.to_f >= 2.0, tmp.close_on_exec?) + assert_kind_of File, tmp assert_equal File.read(__FILE__), tmp.read assert_equal __FILE__, tmp.path diff --git a/test/test_unix_connect.rb b/test/test_unix_connect.rb index f99a877..b85f1f6 100644 --- a/test/test_unix_connect.rb +++ b/test/test_unix_connect.rb @@ -34,6 +34,10 @@ class TestKgioUnixConnect < Test::Unit::TestCase def test_unix_socket_new sock = Kgio::UNIXSocket.new(@path) + + sock.respond_to?(:close_on_exec?) and + assert_equal(RUBY_VERSION.to_f >= 2.0, sock.close_on_exec?) + assert_instance_of Kgio::UNIXSocket, sock ready = IO.select(nil, [ sock ]) assert_equal sock, ready[1][0] @@ -42,6 +46,10 @@ class TestKgioUnixConnect < Test::Unit::TestCase def test_new sock = Kgio::Socket.new(@addr) + + sock.respond_to?(:close_on_exec?) and + assert_equal(RUBY_VERSION.to_f >= 2.0, sock.close_on_exec?) + assert_instance_of Kgio::Socket, sock ready = IO.select(nil, [ sock ]) assert_equal sock, ready[1][0] |