about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <normalperson@yhbt.net>2011-03-21 10:57:30 -0700
committerEric Wong <normalperson@yhbt.net>2011-03-21 10:57:30 -0700
commit877433494e4a848d6c6a10d0e6521061e6a10118 (patch)
treec4a78ca79dab08a6f2de3f81a574be1d8bfef946
parenta5d552d90942fe3c3d1adfc809638fd78992da6e (diff)
downloadraindrops-877433494e4a848d6c6a10d0e6521061e6a10118.tar.gz
Very few programs can take advantage of inheriting FDs
across exec() boundaries, and inet_diag sockets have no
reason to be used in this way.
-rw-r--r--ext/raindrops/linux_inet_diag.c21
-rw-r--r--test/test_inet_diag_socket.rb3
2 files changed, 22 insertions, 2 deletions
diff --git a/ext/raindrops/linux_inet_diag.c b/ext/raindrops/linux_inet_diag.c
index 7fef77c..7f9caaa 100644
--- a/ext/raindrops/linux_inet_diag.c
+++ b/ext/raindrops/linux_inet_diag.c
@@ -43,6 +43,7 @@ rb_thread_blocking_region(
 #include <sys/types.h>
 #include <netdb.h>
 #include <unistd.h>
+#include <fcntl.h>
 #include <string.h>
 #include <asm/types.h>
 #include <netinet/in.h>
@@ -74,6 +75,21 @@ struct nogvl_args {
         int fd;
 };
 
+#ifdef SOCK_CLOEXEC
+#  define my_SOCK_RAW (SOCK_RAW|SOCK_CLOEXEC)
+#  define FORCE_CLOEXEC(v) (v)
+#else
+#  define my_SOCK_RAW SOCK_RAW
+static VALUE FORCE_CLOEXEC(VALUE io)
+{
+        int fd = my_fileno(io);
+        int flags = fcntl(fd, F_SETFD, FD_CLOEXEC);
+        if (flags == -1)
+                rb_sys_fail("fcntl(F_SETFD, FD_CLOEXEC)");
+        return io;
+}
+#endif
+
 /*
  * call-seq:
  *        Raindrops::InetDiagSocket.new        -> Socket
@@ -83,11 +99,12 @@ struct nogvl_args {
 static VALUE ids_s_new(VALUE klass)
 {
         VALUE argv[3];
+
         argv[0] = INT2NUM(AF_NETLINK);
-        argv[1] = INT2NUM(SOCK_RAW);
+        argv[1] = INT2NUM(my_SOCK_RAW);
         argv[2] = INT2NUM(NETLINK_INET_DIAG);
 
-        return rb_call_super(3, argv);
+        return FORCE_CLOEXEC(rb_call_super(3, argv));
 }
 
 /* creates a Ruby ListenStats Struct based on our internal listen_stats */
diff --git a/test/test_inet_diag_socket.rb b/test/test_inet_diag_socket.rb
index c40d50e..047dff3 100644
--- a/test/test_inet_diag_socket.rb
+++ b/test/test_inet_diag_socket.rb
@@ -1,6 +1,7 @@
 # -*- encoding: binary -*-
 require 'test/unit'
 require 'raindrops'
+require 'fcntl'
 $stderr.sync = $stdout.sync = true
 
 class TestInetDiagSocket < Test::Unit::TestCase
@@ -8,6 +9,8 @@ class TestInetDiagSocket < Test::Unit::TestCase
     sock = Raindrops::InetDiagSocket.new
     assert_kind_of Socket, sock
     assert_kind_of Fixnum, sock.fileno
+    flags = sock.fcntl(Fcntl::F_GETFD)
+    assert_equal Fcntl::FD_CLOEXEC, flags & Fcntl::FD_CLOEXEC
     assert_nil sock.close
   end
 end if RUBY_PLATFORM =~ /linux/