]> source.dussan.org Git - tigervnc.git/commitdiff
Don't trust GNUTLS_E_AGAIN
authorPierre Ossman <ossman@cendio.se>
Wed, 6 Apr 2022 13:23:50 +0000 (15:23 +0200)
committerPierre Ossman <ossman@cendio.se>
Wed, 6 Apr 2022 13:31:15 +0000 (15:31 +0200)
Unfortunately this error can be given by GnuTLS even though the
underlying stream still has data available. So stop trusting this value
and keep track of the underlying stream explicitly.

common/rdr/TLSInStream.cxx
common/rdr/TLSInStream.h

index 451855c730ca6889770a624a5ccf0aa7eeb344e6..014789e316c8fc7d4aef438522238e1a394f542a 100644 (file)
@@ -39,11 +39,13 @@ ssize_t TLSInStream::pull(gnutls_transport_ptr_t str, void* data, size_t size)
   TLSInStream* self= (TLSInStream*) str;
   InStream *in = self->in;
 
+  self->streamEmpty = false;
   delete self->saved_exception;
   self->saved_exception = NULL;
 
   try {
     if (!in->hasData(1)) {
+      self->streamEmpty = true;
       gnutls_transport_set_errno(self->session, EAGAIN);
       return -1;
     }
@@ -100,9 +102,20 @@ size_t TLSInStream::readTLS(U8* buf, size_t len)
 {
   int n;
 
-  n = gnutls_record_recv(session, (void *) buf, len);
-  if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN)
-    return 0;
+  while (true) {
+    streamEmpty = false;
+    n = gnutls_record_recv(session, (void *) buf, len);
+    if (n == GNUTLS_E_INTERRUPTED || n == GNUTLS_E_AGAIN) {
+      // GnuTLS returns GNUTLS_E_AGAIN for a bunch of other scenarios
+      // other than the pull function returning EAGAIN, so we have to
+      // double check that the underlying stream really is empty
+      if (!streamEmpty)
+        continue;
+      else
+        return 0;
+    }
+    break;
+  };
 
   if (n == GNUTLS_E_PULL_ERROR)
     throw *saved_exception;
index 4564d118c5b85c5bd7a7afe7d29da2af1a70e283..46779d4ca3272c61e2d42d7bdb716c5a94cfe532 100644 (file)
@@ -40,6 +40,7 @@ namespace rdr {
     gnutls_session_t session;
     InStream* in;
 
+    bool streamEmpty;
     Exception* saved_exception;
   };
 };