tls/openssl: handle SSL_shutdown() properly
Handle SSL_ERROR_WANT_READ/WRITE and return value 0.
This commit is contained in:
@@ -13,6 +13,7 @@
|
|||||||
* TLS implementation with OpenSSL.
|
* TLS implementation with OpenSSL.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h> /* EINTR */
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
@@ -36,6 +37,13 @@ struct _tls {
|
|||||||
int lasterror;
|
int lasterror;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
TLS_SHUTDOWN_MAX_RETRIES = 10,
|
||||||
|
TLS_TIMEOUT_SEC = 0,
|
||||||
|
TLS_TIMEOUT_USEC = 100000,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void _tls_sock_wait(tls_t *tls, int error);
|
||||||
static void _tls_set_error(tls_t *tls, int error);
|
static void _tls_set_error(tls_t *tls, int error);
|
||||||
static void _tls_log_error(xmpp_ctx_t *ctx);
|
static void _tls_log_error(xmpp_ctx_t *ctx);
|
||||||
|
|
||||||
@@ -108,8 +116,6 @@ int tls_set_credentials(tls_t *tls, const char *cafilename)
|
|||||||
|
|
||||||
int tls_start(tls_t *tls)
|
int tls_start(tls_t *tls)
|
||||||
{
|
{
|
||||||
fd_set fds;
|
|
||||||
struct timeval tv;
|
|
||||||
int error;
|
int error;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@@ -121,16 +127,7 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
if (ret == -1 && tls_is_recoverable(error)) {
|
if (ret == -1 && tls_is_recoverable(error)) {
|
||||||
/* wait for something to happen on the sock before looping back */
|
/* wait for something to happen on the sock before looping back */
|
||||||
tv.tv_sec = 0;
|
_tls_sock_wait(tls, error);
|
||||||
tv.tv_usec = 1000;
|
|
||||||
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(tls->sock, &fds);
|
|
||||||
|
|
||||||
if (error == SSL_ERROR_WANT_READ)
|
|
||||||
select(tls->sock + 1, &fds, NULL, NULL, &tv);
|
|
||||||
else
|
|
||||||
select(tls->sock + 1, NULL, &fds, NULL, &tv);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,10 +142,21 @@ int tls_start(tls_t *tls)
|
|||||||
|
|
||||||
int tls_stop(tls_t *tls)
|
int tls_stop(tls_t *tls)
|
||||||
{
|
{
|
||||||
|
int retries = 0;
|
||||||
|
int error;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = SSL_shutdown(tls->ssl);
|
while (1) {
|
||||||
_tls_set_error(tls, ret < 0 ? SSL_get_error(tls->ssl, ret) : 0);
|
++retries;
|
||||||
|
ret = SSL_shutdown(tls->ssl);
|
||||||
|
error = ret < 0 ? SSL_get_error(tls->ssl, ret) : 0;
|
||||||
|
if (ret == 1 || !tls_is_recoverable(error) ||
|
||||||
|
retries >= TLS_SHUTDOWN_MAX_RETRIES) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_tls_sock_wait(tls, error);
|
||||||
|
}
|
||||||
|
_tls_set_error(tls, error);
|
||||||
|
|
||||||
return ret <= 0 ? 0 : 1;
|
return ret <= 0 ? 0 : 1;
|
||||||
}
|
}
|
||||||
@@ -191,6 +199,29 @@ int tls_clear_pending_write(tls_t *tls)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _tls_sock_wait(tls_t *tls, int error)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
fd_set rfds;
|
||||||
|
fd_set wfds;
|
||||||
|
int nfds;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_ZERO(&wfds);
|
||||||
|
if (error == SSL_ERROR_WANT_READ)
|
||||||
|
FD_SET(tls->sock, &rfds);
|
||||||
|
if (error == SSL_ERROR_WANT_WRITE)
|
||||||
|
FD_SET(tls->sock, &wfds);
|
||||||
|
nfds = (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) ?
|
||||||
|
tls->sock + 1 : 0;
|
||||||
|
do {
|
||||||
|
tv.tv_sec = TLS_TIMEOUT_SEC;
|
||||||
|
tv.tv_usec = TLS_TIMEOUT_USEC;
|
||||||
|
ret = select(nfds, &rfds, &wfds, NULL, &tv);
|
||||||
|
} while (ret == -1 && errno == EINTR);
|
||||||
|
}
|
||||||
|
|
||||||
static void _tls_set_error(tls_t *tls, int error)
|
static void _tls_set_error(tls_t *tls, int error)
|
||||||
{
|
{
|
||||||
if (error != 0 && !tls_is_recoverable(error)) {
|
if (error != 0 && !tls_is_recoverable(error)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user