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
Add the retry parameter for virNetTLSSession{Read,Write}
functions in accordance with this guideline.
This prevents the upper application from encountering the
following error message when it calls the virConnectOpenAuth API:
Unable to read TLS confirmation: Resource temporarily unavailable
Signed-off-by: Hyman Huang <yong.huang(a)smartx.com>
---
src/rpc/virnetclient.c | 2 +-
src/rpc/virnetsocket.c | 4 ++--
src/rpc/virnettlscontext.c | 28 ++++++++++++++++++++++++++--
src/rpc/virnettlscontext.h | 6 ++++--
4 files changed, 33 insertions(+), 7 deletions(-)
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 92933220e2..5340db4211 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -1003,7 +1003,7 @@ int virNetClientSetTLSSession(virNetClient *client,
ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
#endif /* !WIN32 */
- len = virNetTLSSessionRead(client->tls, buf, 1);
+ len = virNetTLSSessionRead(client->tls, buf, 1, true);
if (len < 0 && errno != ENOMSG) {
virReportSystemError(errno, "%s",
_("Unable to read TLS confirmation"));
diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c
index e8fc2d5f7d..6774dd4a4b 100644
--- a/src/rpc/virnetsocket.c
+++ b/src/rpc/virnetsocket.c
@@ -1739,7 +1739,7 @@ static ssize_t virNetSocketReadWire(virNetSocket *sock, char *buf,
size_t len)
if (sock->tlsSession &&
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
VIR_NET_TLS_HANDSHAKE_COMPLETE) {
- ret = virNetTLSSessionRead(sock->tlsSession, buf, len);
+ ret = virNetTLSSessionRead(sock->tlsSession, buf, len, false);
} else {
ret = read(sock->fd, buf, len);
}
@@ -1807,7 +1807,7 @@ static ssize_t virNetSocketWriteWire(virNetSocket *sock, const char
*buf, size_t
if (sock->tlsSession &&
virNetTLSSessionGetHandshakeStatus(sock->tlsSession) ==
VIR_NET_TLS_HANDSHAKE_COMPLETE) {
- ret = virNetTLSSessionWrite(sock->tlsSession, buf, len);
+ ret = virNetTLSSessionWrite(sock->tlsSession, buf, len, false);
} else {
ret = write(sock->fd, buf, len); /* sc_avoid_write */
}
diff --git a/src/rpc/virnettlscontext.c b/src/rpc/virnettlscontext.c
index e8023133b4..92d909c0b7 100644
--- a/src/rpc/virnettlscontext.c
+++ b/src/rpc/virnettlscontext.c
@@ -679,16 +679,28 @@ void virNetTLSSessionSetIOCallbacks(virNetTLSSession *sess,
ssize_t virNetTLSSessionWrite(virNetTLSSession *sess,
- const char *buf, size_t len)
+ const char *buf, size_t len,
+ bool retry)
{
ssize_t ret;
+ rewrite:
virObjectLock(sess);
ret = gnutls_record_send(sess->session, buf, len);
if (ret >= 0)
goto cleanup;
+ if (retry && (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)) {
+ /*
+ * 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
+ * */
+ VIR_DEBUG("Try writing data from the TLS session again");
+ virObjectUnlock(sess);
+ goto rewrite;
+ }
+
switch (ret) {
case GNUTLS_E_AGAIN:
errno = EAGAIN;
@@ -712,16 +724,28 @@ ssize_t virNetTLSSessionWrite(virNetTLSSession *sess,
}
ssize_t virNetTLSSessionRead(virNetTLSSession *sess,
- char *buf, size_t len)
+ char *buf, size_t len,
+ bool retry)
{
ssize_t ret;
+ reread:
virObjectLock(sess);
ret = gnutls_record_recv(sess->session, buf, len);
if (ret >= 0)
goto cleanup;
+ if (retry && (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)) {
+ /*
+ * 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
+ * */
+ VIR_DEBUG("Try reading data from the TLS session again");
+ virObjectUnlock(sess);
+ goto reread;
+ }
+
switch (ret) {
case GNUTLS_E_AGAIN:
errno = EAGAIN;
diff --git a/src/rpc/virnettlscontext.h b/src/rpc/virnettlscontext.h
index 11c954ce4b..da26d7836b 100644
--- a/src/rpc/virnettlscontext.h
+++ b/src/rpc/virnettlscontext.h
@@ -81,9 +81,11 @@ void virNetTLSSessionSetIOCallbacks(virNetTLSSession *sess,
void *opaque);
ssize_t virNetTLSSessionWrite(virNetTLSSession *sess,
- const char *buf, size_t len);
+ const char *buf, size_t len,
+ bool retry);
ssize_t virNetTLSSessionRead(virNetTLSSession *sess,
- char *buf, size_t len);
+ char *buf, size_t len,
+ bool retry);
int virNetTLSSessionHandshake(virNetTLSSession *sess);
--
2.27.0