From ec4479249d9c0b0a9e2ba6a8c59a0ed62530e954 Mon Sep 17 00:00:00 2001 From: Matt Caswell Date: Mon, 25 Jan 2016 15:00:10 +0000 Subject: [PATCH] Implement Async SSL_shutdown This extends the existing async functionality to SSL_shutdown(), i.e. SSL_shutdown() can now casuse an SSL_ERROR_WANT_ASYNC error to be returned from SSL_get_error() if async mode has been enabled. Reviewed-by: Viktor Dukhovni --- apps/s_client.c | 25 +++++++++++++++++++++++-- ssl/ssl_lib.c | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 15 deletions(-) diff --git a/apps/s_client.c b/apps/s_client.c index 717d7c146..fe402ae3a 100644 --- a/apps/s_client.c +++ b/apps/s_client.c @@ -218,6 +218,27 @@ static int restore_errno(void) return ret; } +static void do_ssl_shutdown(SSL *ssl) +{ + int ret; + + do { + /* We only do unidirectional shutdown */ + ret = SSL_shutdown(ssl); + if (ret < 0) { + switch (SSL_get_error(ssl, ret)) { + case SSL_ERROR_WANT_READ: + case SSL_ERROR_WANT_WRITE: + case SSL_ERROR_WANT_ASYNC: + /* We just do busy waiting. Nothing clever */ + continue; + } + ret = 0; + } + } while (ret < 0); +} + + #ifndef OPENSSL_NO_PSK /* Default PSK identity and key */ static char *psk_identity = "Client_identity"; @@ -2002,7 +2023,7 @@ int s_client_main(int argc, char **argv) reconnect--; BIO_printf(bio_c_out, "drop connection and then reconnect\n"); - SSL_shutdown(con); + do_ssl_shutdown(con); SSL_set_connect_state(con); SHUTDOWN(SSL_get_fd(con)); goto re_start; @@ -2320,7 +2341,7 @@ int s_client_main(int argc, char **argv) shut: if (in_init) print_stuff(bio_c_out, con, full_log); - SSL_shutdown(con); + do_ssl_shutdown(con); SHUTDOWN(SSL_get_fd(con)); end: if (con != NULL) { diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index d29da6dfb..a43ec5273 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -190,10 +190,11 @@ struct ssl_async_args { SSL *s; void *buf; int num; - int type; + enum { READFUNC, WRITEFUNC, OTHERFUNC} type; union { - int (*func1)(SSL *, void *, int); - int (*func2)(SSL *, const void *, int); + int (*func_read)(SSL *, void *, int); + int (*func_write)(SSL *, const void *, int); + int (*func_other)(SSL *); } f; }; @@ -1469,10 +1470,15 @@ static int ssl_io_intern(void *vargs) s = args->s; buf = args->buf; num = args->num; - if (args->type == 1) - return args->f.func1(s, buf, num); - else - return args->f.func2(s, buf, num); + switch (args->type) { + case READFUNC: + return args->f.func_read(s, buf, num); + case WRITEFUNC: + return args->f.func_write(s, buf, num); + case OTHERFUNC: + return args->f.func_other(s); + } + return -1; } int SSL_read(SSL *s, void *buf, int num) @@ -1493,8 +1499,8 @@ int SSL_read(SSL *s, void *buf, int num) args.s = s; args.buf = buf; args.num = num; - args.type = 1; - args.f.func1 = s->method->ssl_read; + args.type = READFUNC; + args.f.func_read = s->method->ssl_read; return ssl_start_async_job(s, &args, ssl_io_intern); } else { @@ -1518,8 +1524,8 @@ int SSL_peek(SSL *s, void *buf, int num) args.s = s; args.buf = buf; args.num = num; - args.type = 1; - args.f.func1 = s->method->ssl_peek; + args.type = READFUNC; + args.f.func_read = s->method->ssl_peek; return ssl_start_async_job(s, &args, ssl_io_intern); } else { @@ -1546,8 +1552,8 @@ int SSL_write(SSL *s, const void *buf, int num) args.s = s; args.buf = (void *)buf; args.num = num; - args.type = 2; - args.f.func2 = s->method->ssl_write; + args.type = WRITEFUNC; + args.f.func_write = s->method->ssl_write; return ssl_start_async_job(s, &args, ssl_io_intern); } else { @@ -1569,6 +1575,18 @@ int SSL_shutdown(SSL *s) return -1; } + if((s->mode & SSL_MODE_ASYNC) && ASYNC_get_current_job() == NULL) { + struct ssl_async_args args; + + args.s = s; + args.type = OTHERFUNC; + args.f.func_other = s->method->ssl_shutdown; + + return ssl_start_async_job(s, &args, ssl_io_intern); + } else { + return s->method->ssl_shutdown(s); + } + return s->method->ssl_shutdown(s); }