]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
guile: Writes to record ports handle EAGAIN/EINTR transparently.
authorLudovic Courtès <ludo@gnu.org>
Sat, 24 Apr 2021 20:02:14 +0000 (22:02 +0200)
committerLudovic Courtès <ludo@gnu.org>
Wed, 16 Jun 2021 09:24:02 +0000 (11:24 +0200)
Reported at <https://issues.guix.gnu.org/47867>
by Florian Pelz <pelzflorian@pelzflorian.de>.

This is a followup to a229bb36c9592b151f6feb277238c41ab39f40a9.

* guile/src/core.c (write_to_session_record_port) [USING_GUILE_BEFORE_2_2]:
Keep looping upon GNUTLS_E_AGAIN and GNUTLS_E_INTERRUPTED.
(write_to_session_record_port) [!USING_GUILE_BEFORE_2_2]: Loop on
GNUTLS_E_INTERRUPTED and return -1 on GNUTLS_E_AGAIN if C_SESSION is
backed by a file descriptor.
* NEWS: Update.

Signed-off-by: Ludovic Courtès <ludo@gnu.org>
NEWS
guile/src/core.c

diff --git a/NEWS b/NEWS
index f5b726e7cf35f7562b196df93a47df730dfe9a54..b13c97b35ad36bde6cacc61ae890ff33f53be1db 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -37,6 +37,9 @@ See the end for copying conditions.
 gnutls_early_cipher_get: Added
 gnutls_early_prf_hash_get: Added
 
+** guile: Writes to a session record port no longer throw an exception upon
+   GNUTLS_E_AGAIN or GNUTLS_E_INTERRUPTED.
+
 * Version 3.7.1 (released 2021-03-10)
 
 ** libgnutls: Fixed potential use-after-free in sending "key_share"
index a13670fc7b25720af180f5258aadb168b972431f..0926dc8a97571cb1dfd7985e3ac689c412151b15 100644 (file)
@@ -985,7 +985,10 @@ write_to_session_record_port (SCM port, const void *data, size_t size)
       c_result = gnutls_record_send (c_session, (char *) data + c_sent,
                                      size - c_sent);
       if (EXPECT_FALSE (c_result < 0))
-        scm_gnutls_error (c_result, FUNC_NAME);
+       {
+         if (c_result != GNUTLS_E_AGAIN && c_result != GNUTLS_E_INTERRUPTED)
+           scm_gnutls_error (c_result, FUNC_NAME);
+       }
       else
         c_sent += c_result;
     }
@@ -1069,7 +1072,8 @@ read_from_session_record_port (SCM port, SCM dst, size_t start, size_t count)
 #undef FUNC_NAME
 
 /* Return the file descriptor that backs PORT.  This function is called upon a
-   blocking read--i.e., 'read_from_session_record_port' returned -1.  */
+   blocking read--i.e., 'read_from_session_record_port' or
+   'write_to_session_record_port' returned -1.  */
 static int
 session_record_port_fd (SCM port)
 {
@@ -1097,7 +1101,16 @@ write_to_session_record_port (SCM port, SCM src, size_t start, size_t count)
   c_session = scm_to_gnutls_session (session, 1, FUNC_NAME);
   data = (char *) SCM_BYTEVECTOR_CONTENTS (src) + start;
 
-  result = gnutls_record_send (c_session, data, count);
+  do
+    result = gnutls_record_send (c_session, data, count);
+  while (result == GNUTLS_E_INTERRUPTED
+        || (result == GNUTLS_E_AGAIN
+            && !SCM_GNUTLS_SESSION_TRANSPORT_IS_FD (c_session)));
+
+  if (result == GNUTLS_E_AGAIN
+      && SCM_GNUTLS_SESSION_TRANSPORT_IS_FD (c_session))
+    /* Tell Guile that reading would block.  */
+    return (size_t) -1;
 
   if (EXPECT_FALSE (result < 0))
     scm_gnutls_error (result, FUNC_NAME);