Implement Async SSL_shutdown
authorMatt Caswell <matt@openssl.org>
Mon, 25 Jan 2016 15:00:10 +0000 (15:00 +0000)
committerMatt Caswell <matt@openssl.org>
Fri, 29 Jan 2016 11:36:44 +0000 (11:36 +0000)
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 <viktor@openssl.org>
apps/s_client.c
ssl/ssl_lib.c

index 717d7c1..fe402ae 100644 (file)
@@ -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) {
index d29da6d..a43ec52 100644 (file)
@@ -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);
 }