- Fix to wait for blocked write on UDP sockets, with a timeout if it

takes too long the packet is dropped.
This commit is contained in:
W.C.A. Wijngaards 2022-08-31 11:54:11 +02:00
parent 10a5a5880a
commit ec5812a748
5 changed files with 98 additions and 8 deletions

View File

@ -457,6 +457,12 @@
/* Define to 1 if you have the `OSSL_PARAM_BLD_new' function. */
#undef HAVE_OSSL_PARAM_BLD_NEW
/* Define to 1 if you have the `poll' function. */
#undef HAVE_POLL
/* Define to 1 if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD

4
configure vendored
View File

@ -14772,7 +14772,7 @@ fi
fi
# Checks for header files.
for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h
for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
@ -20591,7 +20591,7 @@ if test "$ac_res" != no; then :
fi
for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex
for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"

View File

@ -397,7 +397,7 @@ PKG_PROG_PKG_CONFIG
fi
# Checks for header files.
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
# net/if.h portability for Darwin see:
# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
AC_CHECK_HEADERS([net/if.h],,, [
@ -1644,7 +1644,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
AC_MSG_RESULT(no))
AC_SEARCH_LIBS([setusercontext], [util])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll])
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])

View File

@ -4,6 +4,8 @@
- Patch from Vadim Fedorenko that adds MSG_DONTWAIT to receive
operations, so that instruction reordering does not cause mistakenly
blocking socket operations.
- Fix to wait for blocked write on UDP sockets, with a timeout if it
takes too long the packet is dropped.
22 August 2022: Wouter
- Fix #741: systemd socket activation fails on IPv6.

View File

@ -60,6 +60,9 @@
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
#ifdef HAVE_OPENSSL_SSL_H
#include <openssl/ssl.h>
@ -107,6 +110,9 @@
#define NUM_UDP_PER_SELECT 1
#endif
/** timeout in millisec to wait for write to unblock, packets dropped after.*/
#define SEND_BLOCKED_WAIT_TIMEOUT 200
/**
* The internal event structure for keeping ub_event info for the event.
* Possibly other structures (list, tree) this is part of.
@ -369,13 +375,14 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
* we want to send the answer, and we will wait for
* the ethernet interface buffer to have space. */
#ifndef USE_WINSOCK
if(errno == EAGAIN ||
if(errno == EAGAIN || errno == EINTR ||
# ifdef EWOULDBLOCK
errno == EWOULDBLOCK ||
# endif
errno == ENOBUFS) {
#else
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAENOBUFS ||
WSAGetLastError() == WSAEWOULDBLOCK) {
#endif
@ -383,17 +390,54 @@ comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
* have a blocking fd that they operate on */
while(
#ifndef USE_WINSOCK
errno == EAGAIN ||
errno == EAGAIN || errno == EINTR ||
# ifdef EWOULDBLOCK
errno == EWOULDBLOCK ||
# endif
errno == ENOBUFS
#else
WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAENOBUFS ||
WSAGetLastError() == WSAEWOULDBLOCK
#endif
) {
#if defined(HAVE_POLL) || defined(USE_WINSOCK)
struct pollfd p;
int pret;
memset(&p, 0, sizeof(p));
p.fd = c->fd;
p.events = POLLOUT | POLLERR | POLLHUP;
# ifndef USE_WINSOCK
pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
# else
pret = WSAPoll(&p, 1,
SEND_BLOCKED_WAIT_TIMEOUT);
# endif
if(pret == 0) {
/* timer expired */
verbose(VERB_OPS, "send udp blocked "
"for long, dropping packet.");
return 0;
} else if(pret < 0 &&
#ifndef USE_WINSOCK
errno != EAGAIN && errno != EINTR &&
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
WSAGetLastError() != WSAENOBUFS &&
WSAGetLastError() != WSAEWOULDBLOCK
#endif
) {
log_err("poll udp out failed: %s",
sock_strerror(errno));
return 0;
}
#endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
if (!is_connected) {
sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
sldns_buffer_remaining(packet), 0,
@ -569,29 +613,67 @@ comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
* we want to send the answer, and we will wait for
* the ethernet interface buffer to have space. */
#ifndef USE_WINSOCK
if(errno == EAGAIN ||
if(errno == EAGAIN || errno == EINTR ||
# ifdef EWOULDBLOCK
errno == EWOULDBLOCK ||
# endif
errno == ENOBUFS) {
#else
if(WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAENOBUFS ||
WSAGetLastError() == WSAEWOULDBLOCK) {
#endif
while(
#ifndef USE_WINSOCK
errno == EAGAIN ||
errno == EAGAIN || errno == EINTR ||
# ifdef EWOULDBLOCK
errno == EWOULDBLOCK ||
# endif
errno == ENOBUFS
#else
WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAENOBUFS ||
WSAGetLastError() == WSAEWOULDBLOCK
#endif
) {
#if defined(HAVE_POLL) || defined(USE_WINSOCK)
struct pollfd p;
int pret;
memset(&p, 0, sizeof(p));
p.fd = c->fd;
p.events = POLLOUT | POLLERR | POLLHUP;
# ifndef USE_WINSOCK
pret = poll(&p, 1, SEND_BLOCKED_WAIT_TIMEOUT);
# else
pret = WSAPoll(&p, 1,
SEND_BLOCKED_WAIT_TIMEOUT);
# endif
if(pret == 0) {
/* timer expired */
verbose(VERB_OPS, "send udp blocked "
"for long, dropping packet.");
return 0;
} else if(pret < 0 &&
#ifndef USE_WINSOCK
errno != EAGAIN && errno != EINTR &&
# ifdef EWOULDBLOCK
errno != EWOULDBLOCK &&
# endif
errno != ENOBUFS
#else
WSAGetLastError() != WSAEINPROGRESS &&
WSAGetLastError() != WSAEINTR &&
WSAGetLastError() != WSAENOBUFS &&
WSAGetLastError() != WSAEWOULDBLOCK
#endif
) {
log_err("poll udp out failed: %s",
sock_strerror(errno));
return 0;
}
#endif /* defined(HAVE_POLL) || defined(USE_WINSOCK) */
sent = sendmsg(c->fd, &msg, 0);
}
}