From: Hyman Huang <yong.huang(a)smartx.com>
As advised by the GNU TLS, the caller should attempt again
if the gnutls_record_{recv,send} return EAGAIN or EINTR;
check the following link to view the details:
https://www.gnutls.org/manual/html_node/Data-transfer-and-termination.html
virNetClientSetTLSSession failed to handle EINTR/EGAIN,
though EGAIN seems like it ought to be unlikely given that
the caller waited for G_IO_IN.
Add the {repoll, retry} logic to handle EINTR/EGAIN that
may happen theoretically. This may reduce the likelihood
that the upper application receives the following error
message utmostly when it calls the virConnectOpenAuth API:
Unable to read TLS confirmation: Resource temporarily unavailable
Note that in order to fully avoid the mentioned problem, the
upper application should retry virConnectOpenAuth.
Signed-off-by: Hyman Huang <yong.huang(a)smartx.com>
---
src/rpc/virnetclient.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 92933220e2..ee729d5e62 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -987,6 +987,7 @@ int virNetClientSetTLSSession(virNetClient *client,
* etc. If we make the grade, it will send us a '\1' byte.
*/
+ repoll:
source = virEventGLibAddSocketWatch(virNetSocketGetFD(client->sock),
G_IO_IN,
client->eventCtx,
@@ -1003,7 +1004,14 @@ int virNetClientSetTLSSession(virNetClient *client,
ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
#endif /* !WIN32 */
+ retry:
len = virNetTLSSessionRead(client->tls, buf, 1);
+ if (len < 0 && errno == EINTR) {
+ goto retry;
+ }
+ if (len < 0 && errno == EAGAIN) {
+ goto repoll;
+ }
if (len < 0 && errno != ENOMSG) {
virReportSystemError(errno, "%s",
_("Unable to read TLS confirmation"));
--
2.27.0