GnuTLS: repeat lowlevel read and write operations while they request retry
authorAndreas Metzler <ametzler@bebt.de>
Mon, 24 Dec 2018 16:11:41 +0000 (16:11 +0000)
committerJeremy Harris <jgh146exb@wizmail.org>
Wed, 23 Jan 2019 10:54:48 +0000 (10:54 +0000)
(cherry picked from commit 06faf21f3a84a3ac4aa4f7b1512087423d8c8541)

doc/doc-txt/ChangeLog
src/src/tls-gnu.c

index 2fa08c0a4a6fdd75355e140e039d009354a1e57e..05ad0c213305e993b1c662ca6a3560ef2bc55a87 100644 (file)
@@ -75,6 +75,9 @@ JH/36 Harder the handling of string-lists.  When a list consisted of a sole
       "<" character, which should be a list-separator specification, we walked
       off past the nul-terimation.
 
+AM/01 GnuTLS: repeat lowlevel read and write operations while they return error
+      codes indicating retry.  Under TLS1.3 this becomes required.
+
 
 Exim version 4.91
 -----------------
index 5274cfc54d7cf4a5b56dda2fb091962c5d6fc9ba..c9061f5c38dc95068b419b6b92cc33b75d5f0c33 100644 (file)
@@ -2523,8 +2523,12 @@ DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%p, %p, %u)\n",
 
 sigalrm_seen = FALSE;
 if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
-  MIN(ssl_xfer_buffer_size, lim));
+
+do
+  inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
+    MIN(ssl_xfer_buffer_size, lim));
+while (inbytes == GNUTLS_E_AGAIN);
+
 if (smtp_receive_timeout > 0) alarm(0);
 
 if (had_command_timeout)               /* set by signal handler */
@@ -2578,6 +2582,7 @@ else if (inbytes == 0)
 
 else if (inbytes < 0)
   {
+  DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
   record_io_error(state, (int) inbytes, US"recv", NULL);
   state->xfer_error = TRUE;
   return FALSE;
@@ -2698,13 +2703,20 @@ DEBUG(D_tls)
   debug_printf("Calling gnutls_record_recv(%p, %p, " SIZE_T_FMT ")\n",
       state->session, buff, len);
 
-inbytes = gnutls_record_recv(state->session, buff, len);
+do
+  inbytes = gnutls_record_recv(state->session, buff, len);
+while (inbytes == GNUTLS_E_AGAIN);
+
 if (inbytes > 0) return inbytes;
 if (inbytes == 0)
   {
   DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
   }
-else record_io_error(state, (int)inbytes, US"recv", NULL);
+else
+  {
+  DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+  record_io_error(state, (int)inbytes, US"recv", NULL);
+  }
 
 return -1;
 }
@@ -2746,7 +2758,10 @@ while (left > 0)
   {
   DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %p, " SIZE_T_FMT ")\n",
       buff, left);
-  outbytes = gnutls_record_send(state->session, buff, left);
+
+  do
+    outbytes = gnutls_record_send(state->session, buff, left);
+  while (outbytes == GNUTLS_E_AGAIN);
 
   DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes);
   if (outbytes < 0)