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)
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>
Tue, 25 Dec 2018 21:43:45 +0000 (22:43 +0100)
(cherry picked from commit 06faf21f3a84a3ac4aa4f7b1512087423d8c8541)

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

index 785d59bed05b40949ef1a62aeb53538e251a9ca7..ec7c8accdd61db0bab4f6e4917388120badd0b57 100644 (file)
@@ -5,6 +5,13 @@ affect Exim's operation, with an unchanged configuration file.  For new
 options, and new features, see the NewStuff file next to this ChangeLog.
 
 
 options, and new features, see the NewStuff file next to this ChangeLog.
 
 
+Exim version 4.93
+-----------------
+
+JH/01 GnuTLS: repeat lowlevel read and write operations while they return error
+      codes indicating retry.  Under TLS1.3 this becomes required.
+
+
 Exim version 4.92
 -----------------
 
 Exim version 4.92
 -----------------
 
index bceb5739563bf35a7699dca3d7bb943955cb9d31..c404dc29a0a3b1739b5702c313382a29f09b92a3 100644 (file)
@@ -2562,8 +2562,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);
 
 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_CLR(0);
 
 if (had_command_timeout)               /* set by signal handler */
 if (smtp_receive_timeout > 0) ALARM_CLR(0);
 
 if (had_command_timeout)               /* set by signal handler */
@@ -2618,7 +2622,7 @@ else if (inbytes == 0)
 
 else if (inbytes < 0)
   {
 
 else if (inbytes < 0)
   {
-debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+  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;
   record_io_error(state, (int) inbytes, US"recv", NULL);
   state->xfer_error = TRUE;
   return FALSE;
@@ -2740,17 +2744,20 @@ DEBUG(D_tls)
   debug_printf("Calling gnutls_record_recv(%p, %p, " SIZE_T_FMT ")\n",
       state->session, buff, len);
 
   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
 if (inbytes > 0) return inbytes;
 if (inbytes == 0)
   {
   DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
   }
 else
-{
-debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
-record_io_error(state, (int)inbytes, US"recv", NULL);
-}
+  {
+  DEBUG(D_tls) debug_printf("%s: err from gnutls_record_recv(\n", __FUNCTION__);
+  record_io_error(state, (int)inbytes, US"recv", NULL);
+  }
 
 return -1;
 }
 
 return -1;
 }
@@ -2792,7 +2799,10 @@ while (left > 0)
   {
   DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %p, " SIZE_T_FMT ")\n",
       buff, left);
   {
   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)
 
   DEBUG(D_tls) debug_printf("outbytes=" SSIZE_T_FMT "\n", outbytes);
   if (outbytes < 0)