diff --git a/src/event.c b/src/event.c index b51b2e1..1eaa643 100644 --- a/src/event.c +++ b/src/event.c @@ -85,6 +85,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) char buf[4096]; uint64_t next; long usec; + int tls_read_bytes = 0; if (ctx->loop_status == XMPP_LOOP_QUIT) return; ctx->loop_status = XMPP_LOOP_RUNNING; @@ -215,6 +216,11 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) break; } + /* Check if there is something in the SSL buffer. */ + if (conn->tls) { + tls_read_bytes += tls_pending(conn->tls); + } + if (conn->sock > max) max = conn->sock; connitem = connitem->next; @@ -232,8 +238,8 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) } /* no events happened */ - if (ret == 0) return; - + if (ret == 0 && tls_read_bytes == 0) return; + /* process events */ connitem = ctx->connlist; while (connitem) { @@ -262,7 +268,7 @@ void xmpp_run_once(xmpp_ctx_t *ctx, const unsigned long timeout) break; case XMPP_STATE_CONNECTED: - if (FD_ISSET(conn->sock, &rfds)) { + if (FD_ISSET(conn->sock, &rfds) || (conn->tls && tls_pending(conn->tls))) { if (conn->tls) { ret = tls_read(conn->tls, buf, 4096); } else { diff --git a/src/tls.h b/src/tls.h index d89fe3e..fa670b9 100644 --- a/src/tls.h +++ b/src/tls.h @@ -37,6 +37,7 @@ int tls_stop(tls_t *tls); int tls_error(tls_t *tls); +int tls_pending(tls_t *tls); int tls_read(tls_t *tls, void * const buff, const size_t len); int tls_write(tls_t *tls, const void * const buff, const size_t len); diff --git a/src/tls_dummy.c b/src/tls_dummy.c index c7d5214..00505fe 100644 --- a/src/tls_dummy.c +++ b/src/tls_dummy.c @@ -68,6 +68,11 @@ int tls_error(tls_t *tls) return 0; } +int tls_pending(tls_t *tls) +{ + return 0; +} + int tls_read(tls_t *tls, void * const buff, const size_t len) { return -1; diff --git a/src/tls_gnutls.c b/src/tls_gnutls.c index a751ec5..7841331 100644 --- a/src/tls_gnutls.c +++ b/src/tls_gnutls.c @@ -107,6 +107,11 @@ int tls_error(tls_t *tls) return 0; } +int tls_pending(tls_t *tls) +{ + return gnutls_record_check_pending (tls->session); +} + int tls_read(tls_t *tls, void * const buff, const size_t len) { int ret; diff --git a/src/tls_openssl.c b/src/tls_openssl.c index a8a76d3..7e59f8e 100644 --- a/src/tls_openssl.c +++ b/src/tls_openssl.c @@ -152,6 +152,11 @@ int tls_is_recoverable(int error) || error == SSL_ERROR_WANT_ACCEPT); } +int tls_pending(tls_t *tls) +{ + return SSL_pending(tls->ssl); +} + int tls_read(tls_t *tls, void * const buff, const size_t len) { int ret = SSL_read(tls->ssl, buff, len); diff --git a/src/tls_schannel.c b/src/tls_schannel.c index 1723b2a..c1db394 100644 --- a/src/tls_schannel.c +++ b/src/tls_schannel.c @@ -398,6 +398,22 @@ int tls_is_recoverable(int error) || error == WSAEINPROGRESS); } +int tls_pending(tls_t *tls) { + // There are 3 cases: + // - there is data in ready buffer, so it is by default pending + // - there is data in recv buffer. If it is not decrypted yet, means it + // was incomplete. This should be processed again only if there is data + // on the physical connection + // - there is data on the physical connection. This case is treated + // outside the tls (in event.c) + + if (tls->readybufferpos < tls->readybufferlen) { + return tls->readybufferlen - tls->readybufferpos; + } + + return 0; +} + int tls_read(tls_t *tls, void * const buff, const size_t len) { int bytes;