From acef5e27b0b89076308286208999cd31161cf741 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Mon, 25 Apr 2022 20:32:15 +0200 Subject: [PATCH] MINOR: tree-wide: always consider EWOULDBLOCK in addition to EAGAIN Some older systems may routinely return EWOULDBLOCK for some syscalls while we tend to check only for EAGAIN nowadays. Modern systems define EWOULDBLOCK as EAGAIN so that solves it, but on a few older ones (AIX, VMS etc) both are different, and for portability we'd need to test for both or we never know if we risk to confuse some status codes with plain errors. There were few entries, the most annoying ones are the switch/case because they require to only add the entry when it differs, but the other ones are really trivial. --- src/check.c | 2 +- src/connection.c | 6 +++--- src/dns.c | 6 +++--- src/fd.c | 2 +- src/log.c | 4 ++-- src/mworker.c | 2 +- src/proto_quic.c | 4 ++-- src/proto_sockpair.c | 3 +++ src/proto_tcp.c | 4 ++-- src/proto_uxst.c | 4 ++-- src/quic_sock.c | 4 ++-- src/raw_sock.c | 8 ++++---- src/sock.c | 5 ++++- src/ssl_sock.c | 2 +- 14 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/check.c b/src/check.c index c39561a50..fdc82f526 100644 --- a/src/check.c +++ b/src/check.c @@ -369,7 +369,7 @@ static const struct analyze_status analyze_statuses[HANA_STATUS_SIZE] = { /* 0: */ static inline int unclean_errno(int err) { - if (err == EAGAIN || err == EINPROGRESS || + if (err == EAGAIN || err == EWOULDBLOCK || err == EINPROGRESS || err == EISCONN || err == EALREADY) return 0; return err; diff --git a/src/connection.c b/src/connection.c index bc47ac886..d37ad76d9 100644 --- a/src/connection.c +++ b/src/connection.c @@ -811,7 +811,7 @@ int conn_recv_proxy(struct connection *conn, int flag) if (ret < 0) { if (errno == EINTR) continue; - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_recv(conn->handle.fd); goto not_ready; } @@ -1287,7 +1287,7 @@ int conn_recv_netscaler_cip(struct connection *conn, int flag) if (ret < 0) { if (errno == EINTR) continue; - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_recv(conn->handle.fd); goto not_ready; } @@ -1581,7 +1581,7 @@ int conn_recv_socks4_proxy_response(struct connection *conn) if (errno == EINTR) { continue; } - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_recv(conn->handle.fd); goto not_ready; } diff --git a/src/dns.c b/src/dns.c index 9785c6e19..4a776a1ef 100644 --- a/src/dns.c +++ b/src/dns.c @@ -101,7 +101,7 @@ int dns_send_nameserver(struct dns_nameserver *ns, void *buf, size_t len) ret = send(fd, buf, len, 0); if (ret < 0) { - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { struct ist myist; myist = ist2(buf, len); @@ -155,7 +155,7 @@ ssize_t dns_recv_nameserver(struct dns_nameserver *ns, void *data, size_t size) return -1; if ((ret = recv(fd, data, size, 0)) < 0) { - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_recv(fd); return 0; } @@ -333,7 +333,7 @@ static void dns_resolve_send(struct dgram_conn *dgram) ret = send(fd, dns_msg_trash, len, 0); if (ret < 0) { - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_send(fd); goto out; } diff --git a/src/fd.c b/src/fd.c index c2dfcf1d6..c983b8c9a 100644 --- a/src/fd.c +++ b/src/fd.c @@ -666,7 +666,7 @@ void my_closefrom(int start) ret = poll(poll_events, fd - start, 0); if (ret >= 0) break; - } while (errno == EAGAIN || errno == EINTR || errno == ENOMEM); + } while (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR || errno == ENOMEM); if (ret) ret = fd - start; diff --git a/src/log.c b/src/log.c index 36d6d36ca..de9561d84 100644 --- a/src/log.c +++ b/src/log.c @@ -1725,7 +1725,7 @@ static inline void __do_send_log(struct logsrv *logsrv, int nblogger, int level, if (sent < 0) { static char once; - if (errno == EAGAIN) + if (errno == EAGAIN || errno == EWOULDBLOCK) _HA_ATOMIC_INC(&dropped_logs); else if (!once) { once = 1; /* note: no need for atomic ops here */ @@ -3533,7 +3533,7 @@ void syslog_fd_handler(int fd) if (ret < 0) { if (errno == EINTR) continue; - if (errno == EAGAIN) + if (errno == EAGAIN || errno == EWOULDBLOCK) fd_cant_recv(fd); goto out; } diff --git a/src/mworker.c b/src/mworker.c index 2bc3b776f..ccfcb5c6b 100644 --- a/src/mworker.c +++ b/src/mworker.c @@ -384,7 +384,7 @@ void mworker_accept_wrapper(int fd) if (ret == -1) { if (errno == EINTR) continue; - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_recv(fd); return; } diff --git a/src/proto_quic.c b/src/proto_quic.c index b7d50df36..eb3a316df 100644 --- a/src/proto_quic.c +++ b/src/proto_quic.c @@ -467,9 +467,9 @@ int quic_connect_server(struct connection *conn, int flags) /* should normally not happen but if so, indicates that it's OK */ conn->flags &= ~CO_FL_WAIT_L4_CONN; } - else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { + else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { char *msg; - if (errno == EAGAIN || errno == EADDRNOTAVAIL) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EADDRNOTAVAIL) { msg = "no free ports"; conn->err_code = CO_ER_FREE_PORTS; } diff --git a/src/proto_sockpair.c b/src/proto_sockpair.c index c63f02ae1..b244dd1b3 100644 --- a/src/proto_sockpair.c +++ b/src/proto_sockpair.c @@ -489,6 +489,9 @@ struct connection *sockpair_accept_conn(struct listener *l, int *status) } switch (errno) { +#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif case EAGAIN: ret = CO_AC_DONE; /* nothing more to accept */ if (fdtab[l->rx.fd].state & (FD_POLL_HUP|FD_POLL_ERR)) { diff --git a/src/proto_tcp.c b/src/proto_tcp.c index 4aaac9d82..738d2d113 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -514,9 +514,9 @@ int tcp_connect_server(struct connection *conn, int flags) /* should normally not happen but if so, indicates that it's OK */ conn->flags &= ~CO_FL_WAIT_L4_CONN; } - else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { + else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { char *msg; - if (errno == EAGAIN || errno == EADDRNOTAVAIL) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EADDRNOTAVAIL) { msg = "no free ports"; conn->err_code = CO_ER_FREE_PORTS; } diff --git a/src/proto_uxst.c b/src/proto_uxst.c index 663369db4..2db4fa20b 100644 --- a/src/proto_uxst.c +++ b/src/proto_uxst.c @@ -298,9 +298,9 @@ static int uxst_connect_server(struct connection *conn, int flags) else if (errno == EISCONN) { conn->flags &= ~CO_FL_WAIT_L4_CONN; } - else if (errno == EAGAIN || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { + else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EADDRINUSE || errno == EADDRNOTAVAIL) { char *msg; - if (errno == EAGAIN || errno == EADDRNOTAVAIL) { + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EADDRNOTAVAIL) { msg = "can't connect to destination unix socket, check backlog size on the server"; conn->err_code = CO_ER_FREE_PORTS; } diff --git a/src/quic_sock.c b/src/quic_sock.c index 3baf3fd13..b6d2d18dc 100644 --- a/src/quic_sock.c +++ b/src/quic_sock.c @@ -289,7 +289,7 @@ void quic_sock_fd_iocb(int fd) do { ret = recvfrom(fd, dgram_buf, max_sz, 0, (struct sockaddr *)&saddr, &saddrlen); - if (ret < 0 && errno == EAGAIN) { + if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { fd_cant_recv(fd); goto out; } @@ -339,7 +339,7 @@ size_t qc_snd_buf(struct quic_conn *qc, const struct buffer *buf, size_t count, if (ret < try) break; } - else if (ret == 0 || errno == EAGAIN || errno == ENOTCONN || errno == EINPROGRESS) { + else if (ret == 0 || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN || errno == EINPROGRESS) { /* TODO must be handle properly. It is justified for UDP ? */ ABORT_NOW(); } diff --git a/src/raw_sock.c b/src/raw_sock.c index cc72e6023..b161f90f2 100644 --- a/src/raw_sock.c +++ b/src/raw_sock.c @@ -94,7 +94,7 @@ int raw_sock_to_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pipe, if (ret == 0) goto out_read0; - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { /* there are two reasons for EAGAIN : * - nothing in the socket buffer (standard) * - pipe is full @@ -191,7 +191,7 @@ int raw_sock_from_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pip SPLICE_F_MOVE|SPLICE_F_NONBLOCK); if (ret <= 0) { - if (ret == 0 || errno == EAGAIN) { + if (ret == 0 || errno == EAGAIN || errno == EWOULDBLOCK) { fd_cant_send(conn->handle.fd); break; } @@ -301,7 +301,7 @@ static size_t raw_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu else if (ret == 0) { goto read0; } - else if (errno == EAGAIN || errno == ENOTCONN) { + else if (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN) { /* socket buffer exhausted */ fd_cant_recv(conn->handle.fd); break; @@ -395,7 +395,7 @@ static size_t raw_sock_from_buf(struct connection *conn, void *xprt_ctx, const s if (!count) fd_stop_send(conn->handle.fd); } - else if (ret == 0 || errno == EAGAIN || errno == ENOTCONN || errno == EINPROGRESS) { + else if (ret == 0 || errno == EAGAIN || errno == EWOULDBLOCK || errno == ENOTCONN || errno == EINPROGRESS) { /* nothing written, we need to poll for write first */ fd_cant_send(conn->handle.fd); break; diff --git a/src/sock.c b/src/sock.c index 7ccdbd3ba..f4d8ba4d0 100644 --- a/src/sock.c +++ b/src/sock.c @@ -126,6 +126,9 @@ struct connection *sock_accept_conn(struct listener *l, int *status) sockaddr_free(&addr); switch (errno) { +#if defined(EWOULDBLOCK) && defined(EAGAIN) && EWOULDBLOCK != EAGAIN + case EWOULDBLOCK: +#endif case EAGAIN: ret = CO_AC_DONE; /* nothing more to accept */ if (fdtab[l->rx.fd].state & (FD_POLL_HUP|FD_POLL_ERR)) { @@ -925,7 +928,7 @@ int sock_drain(struct connection *conn) goto shut; if (len < 0) { - if (errno == EAGAIN) { + if (errno == EAGAIN || errno == EWOULDBLOCK) { /* connection not closed yet */ fd_cant_recv(fd); break; diff --git a/src/ssl_sock.c b/src/ssl_sock.c index fd2aff92a..92121860e 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -6503,7 +6503,7 @@ static size_t ssl_sock_to_buf(struct connection *conn, void *xprt_ctx, struct bu /* For SSL_ERROR_SYSCALL, make sure to clear the error * stack before shutting down the connection for * reading. */ - if (ret == SSL_ERROR_SYSCALL && (!errno || errno == EAGAIN)) + if (ret == SSL_ERROR_SYSCALL && (!errno || errno == EAGAIN || errno == EWOULDBLOCK)) goto clear_ssl_error; /* otherwise it's a real error */ goto out_error;