From 8b7ac4c2a9c3ede95d6f5f9717a1939a23788964 Mon Sep 17 00:00:00 2001 From: Martin Sustrik Date: Fri, 2 Sep 2011 15:34:12 +0200 Subject: Close file descriptors on exec (issue 218) When exec is executed to start a different process image old 0MQ file descriptors could stay open, thus blocking TCP ports and alike. This patch should solve the problem. Signed-off-by: Martin Sustrik --- src/ip.cpp | 23 +++++++++++++++++++++++ src/ip.hpp | 3 +++ src/ipc_connecter.cpp | 2 +- src/ipc_listener.cpp | 3 ++- src/signaler.cpp | 6 +++--- src/tcp_address.cpp | 5 +++-- src/tcp_connecter.cpp | 2 +- src/tcp_listener.cpp | 2 +- 8 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/ip.cpp b/src/ip.cpp index e1f0e6b..b11a244 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -36,6 +36,29 @@ #include #endif +zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_) +{ + // Setting this option result in sane behaviour when exec() functions + // are used. Old sockets are closed and don't block TCP ports etc. +#if defined SOCK_CLOEXEC + type_ |= SOCK_CLOEXEC; +#endif + + fd_t s = socket (domain_, type_, protocol_); + if (s == retired_fd) + return retired_fd; + + // If there's no SOCK_CLOEXEC, let's try the second best option. Note that + // race condition can cause socket not to be closed (if fork happens + // between socket creation and this point). +#if !defined SOCK_CLOEXEC && defined FD_CLOEXEC + int rc = fcntl (s, F_SETFD, FD_CLOEXEC); + errno_assert (rc != -1); +#endif + + return s; +} + void zmq::tune_tcp_socket (fd_t s_) { // Disable Nagle's algorithm. We are doing data batching on 0MQ level, diff --git a/src/ip.hpp b/src/ip.hpp index f1a1668..d8553de 100644 --- a/src/ip.hpp +++ b/src/ip.hpp @@ -26,6 +26,9 @@ namespace zmq { + // Same as socket(2), but allows for transparent tweaking the options. + fd_t open_socket (int domain_, int type_, int protocol_); + // Tunes the supplied TCP socket for the best latency. void tune_tcp_socket (fd_t s_); diff --git a/src/ipc_connecter.cpp b/src/ipc_connecter.cpp index 54def6e..9b8520d 100644 --- a/src/ipc_connecter.cpp +++ b/src/ipc_connecter.cpp @@ -174,7 +174,7 @@ int zmq::ipc_connecter_t::open () zmq_assert (s == retired_fd); // Create the socket. - s = socket (AF_UNIX, SOCK_STREAM, 0); + s = open_socket (AF_UNIX, SOCK_STREAM, 0); if (s == -1) return -1; diff --git a/src/ipc_listener.cpp b/src/ipc_listener.cpp index 1457349..cad58ba 100644 --- a/src/ipc_listener.cpp +++ b/src/ipc_listener.cpp @@ -32,6 +32,7 @@ #include "session.hpp" #include "config.hpp" #include "err.hpp" +#include "ip.hpp" #include #include @@ -108,7 +109,7 @@ int zmq::ipc_listener_t::set_address (const char *addr_) return -1; // Create a listening socket. - s = ::socket (AF_UNIX, SOCK_STREAM, 0); + s = open_socket (AF_UNIX, SOCK_STREAM, 0); if (s == -1) return -1; diff --git a/src/signaler.cpp b/src/signaler.cpp index 1c1c5b6..aac3e7c 100644 --- a/src/signaler.cpp +++ b/src/signaler.cpp @@ -240,7 +240,7 @@ int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_) // Create listening socket. SOCKET listener; - listener = socket (AF_INET, SOCK_STREAM, 0); + listener = open_socket (AF_INET, SOCK_STREAM, 0); wsa_assert (listener != INVALID_SOCKET); // Set SO_REUSEADDR and TCP_NODELAY on listening socket. @@ -308,7 +308,7 @@ int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_) lcladdr.sin_addr.s_addr = htonl (INADDR_LOOPBACK); lcladdr.sin_port = 0; - int listener = socket (AF_INET, SOCK_STREAM, 0); + int listener = open_socket (AF_INET, SOCK_STREAM, 0); errno_assert (listener != -1); int on = 1; @@ -329,7 +329,7 @@ int zmq::signaler_t::make_fdpair (fd_t *r_, fd_t *w_) rc = listen (listener, 1); errno_assert (rc != -1); - *w_ = socket (AF_INET, SOCK_STREAM, 0); + *w_ = open_socket (AF_INET, SOCK_STREAM, 0); errno_assert (*w_ != -1); rc = setsockopt (*w_, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)); diff --git a/src/tcp_address.cpp b/src/tcp_address.cpp index 999c015..b6370fa 100644 --- a/src/tcp_address.cpp +++ b/src/tcp_address.cpp @@ -25,6 +25,7 @@ #include "platform.hpp" #include "stdint.hpp" #include "err.hpp" +#include "ip.hpp" #ifdef ZMQ_HAVE_WINDOWS #include "windows.hpp" @@ -56,7 +57,7 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) (void) ipv4only_; // Create a socket. - int fd = socket (AF_INET, SOCK_DGRAM, 0); + int fd = open_socket (AF_INET, SOCK_DGRAM, 0); zmq_assert (fd != -1); // Retrieve number of interfaces. @@ -121,7 +122,7 @@ int zmq::tcp_address_t::resolve_nic_name (const char *nic_, bool ipv4only_) (void) ipv4only_; // Create a socket. - int sd = socket (AF_INET, SOCK_DGRAM, 0); + int sd = open_socket (AF_INET, SOCK_DGRAM, 0); zmq_assert (sd != -1); struct ifreq ifr; diff --git a/src/tcp_connecter.cpp b/src/tcp_connecter.cpp index ac27181..00eb5f6 100644 --- a/src/tcp_connecter.cpp +++ b/src/tcp_connecter.cpp @@ -184,7 +184,7 @@ int zmq::tcp_connecter_t::open () zmq_assert (s == retired_fd); // Create the socket. - s = socket (address.family (), SOCK_STREAM, IPPROTO_TCP); + s = open_socket (address.family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) { wsa_error_to_errno (); diff --git a/src/tcp_listener.cpp b/src/tcp_listener.cpp index e78a4a3..da476a4 100644 --- a/src/tcp_listener.cpp +++ b/src/tcp_listener.cpp @@ -126,7 +126,7 @@ int zmq::tcp_listener_t::set_address (const char *addr_) return -1; // Create a listening socket. - s = ::socket (address.family (), SOCK_STREAM, IPPROTO_TCP); + s = open_socket (address.family (), SOCK_STREAM, IPPROTO_TCP); #ifdef ZMQ_HAVE_WINDOWS if (s == INVALID_SOCKET) wsa_error_to_errno (); -- cgit v1.2.3