0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-27 07:31:03 +08:00

Merge pull request #2292 from bluca/osx_sigpipe

Problem: peer can close connection before SO_NOSIGPIPE is set
This commit is contained in:
Constantin Rack 2017-01-04 20:28:51 +01:00 committed by GitHub
commit ceb6be7751
5 changed files with 54 additions and 8 deletions

View File

@ -30,6 +30,7 @@
#include "precompiled.hpp"
#include "ip.hpp"
#include "err.hpp"
#include "macros.hpp"
#if !defined ZMQ_HAVE_WINDOWS
#include <fcntl.h>
@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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)

View File

@ -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);