diff --git a/src/ip.cpp b/src/ip.cpp index f84e13c0..22cf3317 100644 --- a/src/ip.cpp +++ b/src/ip.cpp @@ -30,6 +30,7 @@ #include "precompiled.hpp" #include "ip.hpp" #include "err.hpp" +#include "macros.hpp" #if !defined ZMQ_HAVE_WINDOWS #include @@ -46,6 +47,8 @@ zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_) { + int rc; + // 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 ZMQ_HAVE_SOCK_CLOEXEC @@ -65,7 +68,7 @@ zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_) // race condition can cause socket not to be closed (if fork happens // between socket creation and this point). #if !defined ZMQ_HAVE_SOCK_CLOEXEC && defined FD_CLOEXEC - int rc = fcntl (s, F_SETFD, FD_CLOEXEC); + rc = fcntl (s, F_SETFD, FD_CLOEXEC); errno_assert (rc != -1); #endif @@ -75,6 +78,10 @@ zmq::fd_t zmq::open_socket (int domain_, int type_, int protocol_) win_assert (brc); #endif + // Socket is not yet connected so EINVAL is not a valid networking error + rc = zmq::set_nosigpipe (s); + errno_assert (rc == 0); + return s; } @@ -190,3 +197,23 @@ void zmq::set_ip_type_of_service (fd_t s_, int iptos) } #endif } + +int zmq::set_nosigpipe (fd_t s_) +{ +#ifdef SO_NOSIGPIPE + // Make sure that SIGPIPE signal is not generated when writing to a + // connection that was already closed by the peer. + // As per POSIX spec, EINVAL will be returned if the socket was valid but + // the connection has been reset by the peer. Return an error so that the + // socket can be closed and the connection retried if necessary. + int set = 1; + int rc = setsockopt (s_, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof (int)); + if (rc != 0 && errno == EINVAL) + return -1; + errno_assert (rc == 0); +#else + LIBZMQ_UNUSED (s_); +#endif + + return 0; +} diff --git a/src/ip.hpp b/src/ip.hpp index 0758c301..26cea3e2 100644 --- a/src/ip.hpp +++ b/src/ip.hpp @@ -52,6 +52,10 @@ namespace zmq // Sets the IP Type-Of-Service for the underlying socket void set_ip_type_of_service (fd_t s_, int iptos); + // Sets the SO_NOSIGPIPE option for the underlying socket. + // Return 0 on success, -1 if the connection has been closed by the peer + int set_nosigpipe (fd_t s_); + } #endif diff --git a/src/ipc_listener.cpp b/src/ipc_listener.cpp index 62b75c66..016d98c5 100644 --- a/src/ipc_listener.cpp +++ b/src/ipc_listener.cpp @@ -418,6 +418,17 @@ zmq::fd_t zmq::ipc_listener_t::accept () } #endif + if (zmq::set_nosigpipe (sock)) { +#ifdef ZMQ_HAVE_WINDOWS + int rc = closesocket (sock); + wsa_assert (rc != SOCKET_ERROR); +#else + int rc = ::close (sock); + errno_assert (rc == 0); +#endif + return retired_fd; + } + return sock; } diff --git a/src/stream_engine.cpp b/src/stream_engine.cpp index 878160b7..4eacdc90 100644 --- a/src/stream_engine.cpp +++ b/src/stream_engine.cpp @@ -132,13 +132,6 @@ zmq::stream_engine_t::stream_engine_t (fd_t fd_, const options_t &options_, } #endif -#ifdef SO_NOSIGPIPE - // Make sure that SIGPIPE signal is not generated when writing to a - // connection that was already closed by the peer. - int set = 1; - rc = setsockopt (s, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof (int)); - errno_assert (rc == 0); -#endif if(options.heartbeat_interval > 0) { heartbeat_timeout = options.heartbeat_timeout; if(heartbeat_timeout == -1) diff --git a/src/tcp_listener.cpp b/src/tcp_listener.cpp index 0863916b..6228bd2a 100644 --- a/src/tcp_listener.cpp +++ b/src/tcp_listener.cpp @@ -330,6 +330,17 @@ zmq::fd_t zmq::tcp_listener_t::accept () } } + if (zmq::set_nosigpipe (sock)) { +#ifdef ZMQ_HAVE_WINDOWS + int rc = closesocket (sock); + wsa_assert (rc != SOCKET_ERROR); +#else + int rc = ::close (sock); + errno_assert (rc == 0); +#endif + return retired_fd; + } + // Set the IP Type-Of-Service priority for this client socket if (options.tos != 0) set_ip_type_of_service (sock, options.tos);