From c2f86a20f8095d8b459c509cbd3b936c917fa4aa Mon Sep 17 00:00:00 2001 From: Kevin McCarthy Date: Mon, 21 Jan 2019 11:56:04 -0800 Subject: [PATCH] Fix gnutls tls_socket_write() to properly retry Retry on GNUTLS_E_AGAIN and GNUTLS_E_INTERRUPTED. This prevents an aborted send due to a SIGWINCH, for instance. Change tls_socket_read() to follow the same flow. Don't bother checking gnutls_error_is_fatal() because return codes besides AGAIN and INTERRUPTED end up closing the connection regardless. (We don't handle handshakes and negotations during send/receive). Co-authored-by: Richard Russon --- conn/ssl_gnutls.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/conn/ssl_gnutls.c b/conn/ssl_gnutls.c index eaea3e204..fe3f5e5f4 100644 --- a/conn/ssl_gnutls.c +++ b/conn/ssl_gnutls.c @@ -1151,12 +1151,13 @@ static int tls_socket_read(struct Connection *conn, char *buf, size_t count) do { rc = gnutls_record_recv(data->state, buf, count); - if ((rc < 0 && gnutls_error_is_fatal(rc) == 1) || rc == GNUTLS_E_INTERRUPTED) - { - mutt_error("tls_socket_read (%s)", gnutls_strerror(rc)); - return -1; - } - } while (rc == GNUTLS_E_AGAIN); + } while ((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)); + + if (rc < 0) + { + mutt_error("tls_socket_read (%s)", gnutls_strerror(rc)); + return -1; + } return rc; } @@ -1177,16 +1178,18 @@ static int tls_socket_write(struct Connection *conn, const char *buf, size_t cou do { - const int ret = gnutls_record_send(data->state, buf + sent, count - sent); + int ret; + do + { + ret = gnutls_record_send(data->state, buf + sent, count - sent); + } while ((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)); + if (ret < 0) { - if (gnutls_error_is_fatal(ret) == 1 || ret == GNUTLS_E_INTERRUPTED) - { - mutt_error("tls_socket_write (%s)", gnutls_strerror(ret)); - return -1; - } - return ret; + mutt_error("tls_socket_write (%s)", gnutls_strerror(ret)); + return -1; } + sent += ret; } while (sent < count); -- 2.40.0