Commit f48c86d0 authored by Andrei Tomashpolskiy's avatar Andrei Tomashpolskiy Committed by Luca Boccassi

UDP engine aborts on networking-related errors from socket syscalls #2862 (#3638)

* UDP engine aborts on networking-related errors from socket syscalls #2862

* Add relicense statement
parent e492dea8
# Permission to Relicense under MPLv2 or any other OSI approved license chosen by the current ZeroMQ BDFL
This is a statement by Andrei Tomashpolskiy
that grants permission to relicense its copyrights in the libzmq C++
library (ZeroMQ) under the Mozilla Public License v2 (MPLv2) or any other
Open Source Initiative approved license chosen by the current ZeroMQ
BDFL (Benevolent Dictator for Life).
A portion of the commits made by the Github handle "atomashpolskiy", with
commit author "Andrei Tomashpolskiy <nordmann89@gmail.com>", are copyright of Andrei Tomashpolskiy .
This document hereby grants the libzmq project team to relicense libzmq,
including all past, present and future contributions of the author listed above.
Andrei Tomashpolskiy
2019/08/22
......@@ -681,3 +681,47 @@ void zmq::make_socket_noninheritable (fd_t sock_)
LIBZMQ_UNUSED (sock_);
#endif
}
void zmq::assert_socket_tuning_error (zmq::fd_t s_, int rc_)
{
if (rc_ == 0)
return;
// Check whether an error occurred
int err = 0;
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS
int len = sizeof err;
#else
socklen_t len = sizeof err;
#endif
int rc = getsockopt (s_, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *> (&err), &len);
// Assert if the error was caused by 0MQ bug.
// Networking problems are OK. No need to assert.
#ifdef ZMQ_HAVE_WINDOWS
zmq_assert (rc == 0);
if (err != 0) {
wsa_assert (err == WSAECONNREFUSED || err == WSAECONNRESET
|| err == WSAECONNABORTED || err == WSAEINTR
|| err == WSAETIMEDOUT || err == WSAEHOSTUNREACH
|| err == WSAENETUNREACH || err == WSAENETDOWN
|| err == WSAENETRESET || err == WSAEACCES
|| err == WSAEINVAL || err == WSAEADDRINUSE);
}
#else
// Following code should handle both Berkeley-derived socket
// implementations and Solaris.
if (rc == -1)
err = errno;
if (err != 0) {
errno = err;
errno_assert (errno == ECONNREFUSED || errno == ECONNRESET
|| errno == ECONNABORTED || errno == EINTR
|| errno == ETIMEDOUT || errno == EHOSTUNREACH
|| errno == ENETUNREACH || errno == ENETDOWN
|| errno == ENETRESET || errno == EINVAL);
}
#endif
}
......@@ -71,6 +71,10 @@ int make_fdpair (fd_t *r_, fd_t *w_);
// Makes a socket non-inheritable to child processes.
// Asserts on any failure.
void make_socket_noninheritable (fd_t sock_);
// Asserts that an internal error did not occur. Does not assert
// on network errors such as reset or aborted connections.
void assert_socket_tuning_error (fd_t s_, int rc_);
}
#endif
......@@ -62,7 +62,7 @@ int zmq::tune_tcp_socket (fd_t s_)
int nodelay = 1;
int rc = setsockopt (s_, IPPROTO_TCP, TCP_NODELAY,
reinterpret_cast<char *> (&nodelay), sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc != 0)
return rc;
......@@ -71,7 +71,7 @@ int zmq::tune_tcp_socket (fd_t s_)
int nodelack = 1;
rc = setsockopt (s_, IPPROTO_TCP, TCP_NODELACK, (char *) &nodelack,
sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
#endif
return rc;
}
......@@ -81,7 +81,7 @@ int zmq::set_tcp_send_buffer (fd_t sockfd_, int bufsize_)
const int rc =
setsockopt (sockfd_, SOL_SOCKET, SO_SNDBUF,
reinterpret_cast<char *> (&bufsize_), sizeof bufsize_);
tcp_assert_tuning_error (sockfd_, rc);
assert_socket_tuning_error (sockfd_, rc);
return rc;
}
......@@ -90,7 +90,7 @@ int zmq::set_tcp_receive_buffer (fd_t sockfd_, int bufsize_)
const int rc =
setsockopt (sockfd_, SOL_SOCKET, SO_RCVBUF,
reinterpret_cast<char *> (&bufsize_), sizeof bufsize_);
tcp_assert_tuning_error (sockfd_, rc);
assert_socket_tuning_error (sockfd_, rc);
return rc;
}
......@@ -123,7 +123,7 @@ int zmq::tune_tcp_keepalives (fd_t s_,
int rc = WSAIoctl (s_, SIO_KEEPALIVE_VALS, &keepalive_opts,
sizeof (keepalive_opts), NULL, 0,
&num_bytes_returned, NULL, NULL);
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc == SOCKET_ERROR)
return rc;
}
......@@ -133,7 +133,7 @@ int zmq::tune_tcp_keepalives (fd_t s_,
int rc =
setsockopt (s_, SOL_SOCKET, SO_KEEPALIVE,
reinterpret_cast<char *> (&keepalive_), sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc != 0)
return rc;
......@@ -141,7 +141,7 @@ int zmq::tune_tcp_keepalives (fd_t s_,
if (keepalive_cnt_ != -1) {
int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPCNT, &keepalive_cnt_,
sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc != 0)
return rc;
}
......@@ -151,7 +151,7 @@ int zmq::tune_tcp_keepalives (fd_t s_,
if (keepalive_idle_ != -1) {
int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPIDLE,
&keepalive_idle_, sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc != 0)
return rc;
}
......@@ -160,7 +160,7 @@ int zmq::tune_tcp_keepalives (fd_t s_,
if (keepalive_idle_ != -1) {
int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPALIVE,
&keepalive_idle_, sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc != 0)
return rc;
}
......@@ -171,7 +171,7 @@ int zmq::tune_tcp_keepalives (fd_t s_,
if (keepalive_intvl_ != -1) {
int rc = setsockopt (s_, IPPROTO_TCP, TCP_KEEPINTVL,
&keepalive_intvl_, sizeof (int));
tcp_assert_tuning_error (s_, rc);
assert_socket_tuning_error (s_, rc);
if (rc != 0)
return rc;
}
......@@ -196,13 +196,13 @@ int zmq::tune_tcp_maxrt (fd_t sockfd_, int timeout_)
int rc =
setsockopt (sockfd_, IPPROTO_TCP, TCP_MAXRT,
reinterpret_cast<char *> (&timeout_), sizeof (timeout_));
tcp_assert_tuning_error (sockfd_, rc);
assert_socket_tuning_error (sockfd_, rc);
return rc;
// FIXME: should be ZMQ_HAVE_TCP_USER_TIMEOUT
#elif defined(TCP_USER_TIMEOUT)
int rc = setsockopt (sockfd_, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout_,
sizeof (timeout_));
tcp_assert_tuning_error (sockfd_, rc);
assert_socket_tuning_error (sockfd_, rc);
return rc;
#else
return 0;
......@@ -316,50 +316,6 @@ int zmq::tcp_read (fd_t s_, void *data_, size_t size_)
#endif
}
void zmq::tcp_assert_tuning_error (zmq::fd_t s_, int rc_)
{
if (rc_ == 0)
return;
// Check whether an error occurred
int err = 0;
#if defined ZMQ_HAVE_HPUX || defined ZMQ_HAVE_VXWORKS
int len = sizeof err;
#else
socklen_t len = sizeof err;
#endif
int rc = getsockopt (s_, SOL_SOCKET, SO_ERROR,
reinterpret_cast<char *> (&err), &len);
// Assert if the error was caused by 0MQ bug.
// Networking problems are OK. No need to assert.
#ifdef ZMQ_HAVE_WINDOWS
zmq_assert (rc == 0);
if (err != 0) {
wsa_assert (err == WSAECONNREFUSED || err == WSAECONNRESET
|| err == WSAECONNABORTED || err == WSAEINTR
|| err == WSAETIMEDOUT || err == WSAEHOSTUNREACH
|| err == WSAENETUNREACH || err == WSAENETDOWN
|| err == WSAENETRESET || err == WSAEACCES
|| err == WSAEINVAL || err == WSAEADDRINUSE);
}
#else
// Following code should handle both Berkeley-derived socket
// implementations and Solaris.
if (rc == -1)
err = errno;
if (err != 0) {
errno = err;
errno_assert (errno == ECONNREFUSED || errno == ECONNRESET
|| errno == ECONNABORTED || errno == EINTR
|| errno == ETIMEDOUT || errno == EHOSTUNREACH
|| errno == ENETUNREACH || errno == ENETDOWN
|| errno == ENETRESET || errno == EINVAL);
}
#endif
}
void zmq::tcp_tune_loopback_fast_path (const fd_t socket_)
{
#if defined ZMQ_HAVE_WINDOWS && defined SIO_LOOPBACK_FAST_PATH
......
......@@ -66,10 +66,6 @@ int tcp_write (fd_t s_, const void *data_, size_t size_);
// Zero indicates the peer has closed the connection.
int tcp_read (fd_t s_, void *data_, size_t size_);
// Asserts that an internal error did not occur. Does not assert
// on network errors such as reset or aborted connections.
void tcp_assert_tuning_error (fd_t s_, int rc_);
void tcp_tune_loopback_fast_path (const fd_t socket_);
// Resolves the given address_ string, opens a socket and sets socket options
......
This diff is collapsed.
......@@ -49,6 +49,22 @@ class udp_engine_t : public io_object_t, public i_engine
int resolve_raw_address (char *addr_, size_t length_);
void sockaddr_to_msg (zmq::msg_t *msg_, sockaddr_in *addr_);
int set_udp_reuse_address (fd_t s_, bool on_);
int set_udp_reuse_port (fd_t s_, bool on_);
// Indicate, if the multicast data being sent should be looped back
int set_udp_multicast_loop (fd_t s_, bool is_ipv6_, bool loop_);
// Set multicast TTL
int set_udp_multicast_ttl (fd_t s_, bool is_ipv6_, int hops_);
// Set multicast address/interface
int set_udp_multicast_iface (fd_t s_,
bool is_ipv6_,
const udp_address_t *addr_);
// Join a multicast group
int add_membership (fd_t s_, const udp_address_t *addr_);
// Function to handle network issues.
void error (error_reason_t reason_);
const endpoint_uri_pair_t _empty_endpoint;
bool _plugged;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment