[PATCH] rpc: Re-read the data if EAGAIN or EINTR were captured

yong.huang@smartx.com posted 1 patch 1 month ago
There is a newer version of this series
src/rpc/virnetclient.c | 9 +++++++++
1 file changed, 9 insertions(+)
[PATCH] rpc: Re-read the data if EAGAIN or EINTR were captured
Posted by yong.huang@smartx.com 1 month ago
From: Hyman Huang <yong.huang@smartx.com>

If EAGAIN or EINTR are returned from the gnutls_record_recv,
GNU TLS suggests calling the gnutls_record_recv once again to
get the data. Refer to the following link to see details:
https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html

To follow this guidance, add the re-read logic in the
virNetClientSetTLSSession function. This prevent the upper application,
when calling the virConnectOpenAuth API, from receiving the
follwoing error message:
Unable to read TLS confirmation: Resource temporarily unavailable
---
 src/rpc/virnetclient.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 92933220e2..69b8cac481 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -1003,7 +1003,16 @@ int virNetClientSetTLSSession(virNetClient *client,
     ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
 #endif /* !WIN32 */
 
+ reread:
     len = virNetTLSSessionRead(client->tls, buf, 1);
+    /*
+     * GNU TLS advises calling the function again to obtain the data if EAGAIN is returned.
+     * See reference: https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html
+     * */
+    if (len < 0 && (errno == EAGAIN || errno == EINTR)) {
+        VIR_WARN("Try reading data from the TLS session again");
+        goto reread;
+    }
     if (len < 0 && errno != ENOMSG) {
         virReportSystemError(errno, "%s",
                              _("Unable to read TLS confirmation"));
-- 
2.27.0
Re: [PATCH] rpc: Re-read the data if EAGAIN or EINTR were captured
Posted by Daniel P. Berrangé via Devel 3 weeks, 5 days ago
On Tue, Apr 08, 2025 at 12:55:04AM +0800, yong.huang@smartx.com wrote:
> From: Hyman Huang <yong.huang@smartx.com>
> 
> If EAGAIN or EINTR are returned from the gnutls_record_recv,
> GNU TLS suggests calling the gnutls_record_recv once again to
> get the data. Refer to the following link to see details:
> https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html
> 
> To follow this guidance, add the re-read logic in the
> virNetClientSetTLSSession function. This prevent the upper application,
> when calling the virConnectOpenAuth API, from receiving the
> follwoing error message:
> Unable to read TLS confirmation: Resource temporarily unavailable
> ---
>  src/rpc/virnetclient.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
> index 92933220e2..69b8cac481 100644
> --- a/src/rpc/virnetclient.c
> +++ b/src/rpc/virnetclient.c
> @@ -1003,7 +1003,16 @@ int virNetClientSetTLSSession(virNetClient *client,
>      ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
>  #endif /* !WIN32 */
>  
> + reread:
>      len = virNetTLSSessionRead(client->tls, buf, 1);
> +    /*
> +     * GNU TLS advises calling the function again to obtain the data if EAGAIN is returned.
> +     * See reference: https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html
> +     * */
> +    if (len < 0 && (errno == EAGAIN || errno == EINTR)) {
> +        VIR_WARN("Try reading data from the TLS session again");
> +        goto reread;
> +    }

This would surely be wrong for EAGAIN - if the socket is blocking we must
return to the main loop and wait for it to indicate that the socket has
new data. If we don't wait in the main loop, this code will busy-loop on
a non-blocking socket

>      if (len < 0 && errno != ENOMSG) {
>          virReportSystemError(errno, "%s",
>                               _("Unable to read TLS confirmation"));
> -- 
> 2.27.0
> 

With regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|
Re: [PATCH] rpc: Re-read the data if EAGAIN or EINTR were captured
Posted by Peter Krempa via Devel 1 month ago
On Tue, Apr 08, 2025 at 00:55:04 +0800, yong.huang@smartx.com wrote:
> From: Hyman Huang <yong.huang@smartx.com>
> 
> If EAGAIN or EINTR are returned from the gnutls_record_recv,
> GNU TLS suggests calling the gnutls_record_recv once again to

Since the guidance is about 'gnutls_record_recv' ...

> get the data. Refer to the following link to see details:
> https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html
> 
> To follow this guidance, add the re-read logic in the
> virNetClientSetTLSSession function. This prevent the upper application,
> when calling the virConnectOpenAuth API, from receiving the
> follwoing error message:
> Unable to read TLS confirmation: Resource temporarily unavailable
> ---
>  src/rpc/virnetclient.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
> index 92933220e2..69b8cac481 100644
> --- a/src/rpc/virnetclient.c
> +++ b/src/rpc/virnetclient.c
> @@ -1003,7 +1003,16 @@ int virNetClientSetTLSSession(virNetClient *client,
>      ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
>  #endif /* !WIN32 */
>  
> + reread:
>      len = virNetTLSSessionRead(client->tls, buf, 1);

why didn't you encapsulate the reread logic inside virNetTLSSessionRead
which has the call to gnutls_record_recv?

That way all users would automatically gain the retry per documentation.

> +    /*
> +     * GNU TLS advises calling the function again to obtain the data if EAGAIN is returned.
> +     * See reference: https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html
> +     * */
> +    if (len < 0 && (errno == EAGAIN || errno == EINTR)) {
> +        VIR_WARN("Try reading data from the TLS session again");

VIR_WARN gets logged to syslog in default settings; this is at best a
VIR_DEBUG.

> +        goto reread;
> +    }
>      if (len < 0 && errno != ENOMSG) {
>          virReportSystemError(errno, "%s",
>                               _("Unable to read TLS confirmation"));
> -- 
> 2.27.0
>