add an additional async notification communication method based on callback
authorPing Yu <ping.yu@intel.com>
Mon, 5 Nov 2018 20:41:01 +0000 (15:41 -0500)
committerMatt Caswell <matt@openssl.org>
Sun, 27 Jan 2019 12:27:17 +0000 (12:27 +0000)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Paul Yang <yang.yang@baishancloud.com>
Signed-off-by: Ping Yu <ping.yu@intel.com>
Signed-off-by: Steven Linsell <stevenx.linsell@intel.com>
(Merged from https://github.com/openssl/openssl/pull/7573)

14 files changed:
crypto/async/async_locl.h
crypto/async/async_wait.c
doc/man3/ASYNC_WAIT_CTX_new.pod
doc/man3/ASYNC_start_job.pod
doc/man3/SSL_set_async_callback.pod [new file with mode: 0644]
engines/e_dasync.c
include/openssl/async.h
include/openssl/ssl.h
ssl/ssl_lib.c
ssl/ssl_locl.h
test/asynctest.c
util/libcrypto.num
util/libssl.num
util/private.num

index 2325ce95ba686fe6a337d3e65bf6ef9c3475d71b..85dfcfa6327a9d9c67a897e2cc733a6c7fc795b6 100644 (file)
@@ -59,6 +59,9 @@ struct async_wait_ctx_st {
     struct fd_lookup_st *fds;
     size_t numadd;
     size_t numdel;
     struct fd_lookup_st *fds;
     size_t numadd;
     size_t numdel;
+    ASYNC_callback_fn callback;
+    void *callback_arg;
+    int status;
 };
 
 DEFINE_STACK_OF(ASYNC_JOB)
 };
 
 DEFINE_STACK_OF(ASYNC_JOB)
index 2553298e8e18705589c4ab7d38e54e73519b2444..642b781f7e79106251ea3cbae7081e4cd9798662 100644 (file)
@@ -182,6 +182,41 @@ int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key)
     return 0;
 }
 
     return 0;
 }
 
+int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn callback,
+                                void *callback_arg)
+{
+      if (ctx == NULL)
+          return 0;
+
+      ctx->callback = callback;
+      ctx->callback_arg = callback_arg;
+      return 1;
+}
+
+int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn *callback,
+                                void **callback_arg)
+{
+      if (ctx->callback == NULL)
+          return 0;
+
+      *callback = ctx->callback;
+      *callback_arg = ctx->callback_arg;
+      return 1;
+}
+
+int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status)
+{
+      ctx->status = status;
+      return 1;
+}
+
+int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx)
+{
+      return ctx->status;
+}
+
 void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx)
 {
     struct fd_lookup_st *curr, *prev = NULL;
 void async_wait_ctx_reset_counts(ASYNC_WAIT_CTX *ctx)
 {
     struct fd_lookup_st *curr, *prev = NULL;
index eeb2777a8b3f07b9677ea8c7b5ba675a59317e5e..9076be817171228b035c789fc5ace85d53d1a737 100644 (file)
@@ -4,13 +4,22 @@
 
 ASYNC_WAIT_CTX_new, ASYNC_WAIT_CTX_free, ASYNC_WAIT_CTX_set_wait_fd,
 ASYNC_WAIT_CTX_get_fd, ASYNC_WAIT_CTX_get_all_fds,
 
 ASYNC_WAIT_CTX_new, ASYNC_WAIT_CTX_free, ASYNC_WAIT_CTX_set_wait_fd,
 ASYNC_WAIT_CTX_get_fd, ASYNC_WAIT_CTX_get_all_fds,
-ASYNC_WAIT_CTX_get_changed_fds, ASYNC_WAIT_CTX_clear_fd - functions to manage
-waiting for asynchronous jobs to complete
+ASYNC_WAIT_CTX_get_changed_fds, ASYNC_WAIT_CTX_clear_fd,
+ASYNC_WAIT_CTX_set_callback, ASYNC_WAIT_CTX_get_callback,
+ASYNC_WAIT_CTX_set_status, ASYNC_WAIT_CTX_get_status, ASYNC_callback_fn,
+ASYNC_STATUS_UNSUPPORTED, ASYNC_STATUS_ERR, ASYNC_STATUS_OK,
+ASYNC_STATUS_EAGAIN
+- functions to manage waiting for asynchronous jobs to complete
 
 =head1 SYNOPSIS
 
  #include <openssl/async.h>
 
 
 =head1 SYNOPSIS
 
  #include <openssl/async.h>
 
+ #define ASYNC_STATUS_UNSUPPORTED    0
+ #define ASYNC_STATUS_ERR            1
+ #define ASYNC_STATUS_OK             2
+ #define ASYNC_STATUS_EAGAIN         3
+ typedef int (*ASYNC_callback_fn)(void *arg);
  ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void);
  void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx);
  int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
  ASYNC_WAIT_CTX *ASYNC_WAIT_CTX_new(void);
  void ASYNC_WAIT_CTX_free(ASYNC_WAIT_CTX *ctx);
  int ASYNC_WAIT_CTX_set_wait_fd(ASYNC_WAIT_CTX *ctx, const void *key,
@@ -26,6 +35,14 @@ waiting for asynchronous jobs to complete
                                     size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                     size_t *numdelfds);
  int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key);
                                     size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                     size_t *numdelfds);
  int ASYNC_WAIT_CTX_clear_fd(ASYNC_WAIT_CTX *ctx, const void *key);
+ int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+                                 ASYNC_callback_fn callback,
+                                 void *callback_arg);
+ int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+                                 ASYNC_callback_fn *callback,
+                                 void **callback_arg);
+ int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
+ int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
 
 
 =head1 DESCRIPTION
 
 
 =head1 DESCRIPTION
@@ -103,14 +120,58 @@ code that the job should be resumed by making the wait file descriptor
 "readable". Once resumed the engine should clear the wake signal on the wait
 file descriptor.
 
 "readable". Once resumed the engine should clear the wake signal on the wait
 file descriptor.
 
+As well as a file descriptor, user code may also be notified via a callback. The
+callback and data pointers are stored within the ASYNC_WAIT_CTX along with an
+additional status field that can be used for the notification of retries from an
+engine. This additional method can be used when the user thinks that a file
+descriptor is too costly in terms of CPU cycles or in some context where a file
+descriptor is not appropriate.
+
+ASYNC_WAIT_CTX_set_callback() sets the callback and the callback argument. The
+callback will be called to notify user code when an engine completes a
+cryptography operation. It is a requirement that the callback function is small
+and non-blocking as it will be run in the context of a polling mechanism or an
+interrupt.
+
+ASYNC_WAIT_CTX_get_callback() returns the callback set in the ASYNC_WAIT_CTX
+structure.
+
+ASYNC_WAIT_CTX_set_status() allows an engine to set the current engine status.
+The possible status values are the following:
+ASYNC_STATUS_UNSUPPORTED: The engine does not support the callback mechanism.
+This is the default value. The engine must call ASYNC_WAIT_CTX_set_status() to
+set the status to some value other than ASYNC_STATUS_UNSUPPORTED if it intends
+to enable the callback mechanism.
+ASYNC_STATUS_ERR: The engine has a fatal problem with this request. The user
+code should clean up this session.
+ASYNC_STATUS_OK: The request has been successfully submitted.
+ASYNC_STATUS_EAGAIN: The engine has some problem which will be recovered soon,
+such as a buffer is full, so user code should resume the job.
+
+ASYNC_WAIT_CTX_get_status() allows user code to obtain the current status value.
+If the status is any value other than ASYNC_STATUS_OK then the user code should
+not expect to receive a callback from the engine even if one has been set.
+
+An example of the usage of the callback method might be the following. User
+code would initiate cryptographic operations, and the engine code would dispatch
+this operation to hardware, and if the dispatch is successful, then the engine
+code would call ASYNC_pause_job() to return control to the user code. After
+that, user code can perform other tasks. When the hardware completes the
+operation, normally it is detected by a polling function or an interrupt, as the
+user code set a callback by calling ASYNC_WAIT_CTX_set_callback() previously,
+then the registered callback will be called.
+
 =head1 RETURN VALUES
 
 ASYNC_WAIT_CTX_new() returns a pointer to the newly allocated ASYNC_WAIT_CTX or
 NULL on error.
 
 ASYNC_WAIT_CTX_set_wait_fd, ASYNC_WAIT_CTX_get_fd, ASYNC_WAIT_CTX_get_all_fds,
 =head1 RETURN VALUES
 
 ASYNC_WAIT_CTX_new() returns a pointer to the newly allocated ASYNC_WAIT_CTX or
 NULL on error.
 
 ASYNC_WAIT_CTX_set_wait_fd, ASYNC_WAIT_CTX_get_fd, ASYNC_WAIT_CTX_get_all_fds,
-ASYNC_WAIT_CTX_get_changed_fds and ASYNC_WAIT_CTX_clear_fd all return 1 on
-success or 0 on error.
+ASYNC_WAIT_CTX_get_changed_fds, ASYNC_WAIT_CTX_clear_fd,
+ASYNC_WAIT_CTX_set_callback, ASYNC_WAIT_CTX_get_callback and
+ASYNC_WAIT_CTX_set_status all return 1 on success or 0 on error.
+ASYNC_WAIT_CTX_get_status() returs the engine status.
+
 
 =head1 NOTES
 
 
 =head1 NOTES
 
@@ -132,6 +193,10 @@ ASYNC_WAIT_CTX_get_fd(), ASYNC_WAIT_CTX_get_all_fds(),
 ASYNC_WAIT_CTX_get_changed_fds() and ASYNC_WAIT_CTX_clear_fd()
 were added in OpenSSL 1.1.0.
 
 ASYNC_WAIT_CTX_get_changed_fds() and ASYNC_WAIT_CTX_clear_fd()
 were added in OpenSSL 1.1.0.
 
+ASYNC_WAIT_CTX_set_callback(), ASYNC_WAIT_CTX_get_callback(),
+ASYNC_WAIT_CTX_set_status(), and ASYNC_WAIT_CTX_get_status()
+were added in OpenSSL 3.0.0.
+
 =head1 COPYRIGHT
 
 Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
 =head1 COPYRIGHT
 
 Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
index 95694b636a4c367417e14f1f269ba86c87496df1..5ac368d3ff01c36a6ba922c612b01589f6fc005d 100644 (file)
@@ -107,22 +107,26 @@ ASYNC_pause_job() is called whilst not within the context of a job then no
 action is taken and ASYNC_pause_job() returns immediately.
 
 ASYNC_get_wait_ctx() can be used to get a pointer to the ASYNC_WAIT_CTX
 action is taken and ASYNC_pause_job() returns immediately.
 
 ASYNC_get_wait_ctx() can be used to get a pointer to the ASYNC_WAIT_CTX
-for the B<job>. ASYNC_WAIT_CTXs can have a "wait" file descriptor associated
-with them. Applications can wait for the file descriptor to be ready for "read"
-using a system function call such as select or poll (being ready for "read"
-indicates that the job should be resumed). If no file descriptor is made
-available then an application will have to periodically "poll" the job by
-attempting to restart it to see if it is ready to continue.
-
-An example of typical usage might be an async capable engine. User code would
-initiate cryptographic operations. The engine would initiate those operations
-asynchronously and then call L<ASYNC_WAIT_CTX_set_wait_fd(3)> followed by
-ASYNC_pause_job() to return control to the user code. The user code can then
-perform other tasks or wait for the job to be ready by calling "select" or other
-similar function on the wait file descriptor. The engine can signal to the user
-code that the job should be resumed by making the wait file descriptor
-"readable". Once resumed the engine should clear the wake signal on the wait
-file descriptor.
+for the B<job>. ASYNC_WAIT_CTXs contain two different ways to notify
+applications that a job is ready to be resumed. One is a "wait" file
+descriptor, and the other is a "callback" mechanism.
+
+The "wait" file descriptor associated with ASYNC_WAIT_CTX is used for
+applications to wait for the file descriptor to be ready for "read" using a
+system function call such as select or poll (being ready for "read" indicates
+that the job should be resumed). If no file descriptor is made available then
+an application will have to periodically "poll" the job by attempting to restart
+it to see if it is ready to continue.
+
+ASYNC_WAIT_CTXs also have a "callback" mechanism to notify applications. The
+callback is set by an application, and it will be automatically called when an
+engine completes a cryptography operation, so that the application can resume
+the paused work flow without polling. An engine could be written to look whether
+the callback has been set. If it has then it would use the callback mechanism
+in preference to the file descriptor notifications. If a callback is not set
+then the engine may use file descriptor based notifications. Please note that
+not all engines may support the callback mechanism, so the callback may not be
+used even if it has been set. See ASYNC_WAIT_CTX_new() for more details.
 
 The ASYNC_block_pause() function will prevent the currently active job from
 pausing. The block will remain in place until a subsequent call to
 
 The ASYNC_block_pause() function will prevent the currently active job from
 pausing. The block will remain in place until a subsequent call to
diff --git a/doc/man3/SSL_set_async_callback.pod b/doc/man3/SSL_set_async_callback.pod
new file mode 100644 (file)
index 0000000..5e7f61e
--- /dev/null
@@ -0,0 +1,96 @@
+=pod
+
+=head1 NAME
+
+SSL_CTX_set_async_callback,
+SSL_CTX_set_async_callback_arg,
+SSL_set_async_callback,
+SSL_set_async_callback_arg,
+SSL_get_async_status,
+SSL_async_callback_fn
+- manage asynchronous operations
+
+=head1 SYNOPSIS
+
+=for comment multiple includes
+
+ #include <openssl/ssl.h>
+
+ typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
+ int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback);
+ int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg);
+ int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback);
+ int SSL_set_async_callback_arg(SSL *s, void *arg);
+ int SSL_get_async_status(SSL *s, int *status);
+
+=head1 DESCRIPTION
+
+SSL_CTX_set_async_callback() sets an asynchronous callback function. All SSL
+objects generated based on this SSL_CTX will get this callback. If an engine
+supports the callback mechanism, it will be automatically called if
+SSL_MODE_ASYNC has been set and an asynchronous capable engine completes a
+cryptography operation to notify the application to resume the paused work flow.
+
+SSL_CTX_set_async_callback_arg() sets the callback argument.
+
+SSL_set_async_callback() allows an application to set a callback in an
+asynchronous SSL object, so that when an engine completes a cryptography
+operation, the callback will be called to notify the application to resume the
+paused work flow.
+
+SSL_set_async_callback_arg() sets an argument for the SSL object when the above
+callback is called.
+
+SSL_get_async_status() returns the engine status. This function facilitates the
+communication from the engine to the application. During an SSL session,
+cryptographic operations are dispatched to an engine. The engine status is very
+useful for an application to know if the operation has been successfully
+dispatched. If the engine does not support this additional callback method,
+"ASYNC_STATUS_UNSUPPORTED" will be returned. See ASYNC_WAIT_CTX_set_status() for
+a description of all of the status values.
+
+An example of the above functions would be the following.
+1. Application sets the async callback and callback data on an SSL connection
+by calling SSL_set_async_callback().
+2. Application sets SSL_MODE_ASYNC and makes an asynchronous SSL call
+3. OpenSSL submits the asynchronous request to the engine. If a retry occurs at
+this point then the status within the ASYNC_WAIT_CTX would be set and the async
+callback function would be called (goto Step 7).
+4. The OpenSSL engine pauses the current job and returns, so that the
+application can continue processing other connections.
+5. At a future point in time (probably via a polling mechanism or via an
+interrupt) the engine will become aware that the asynchronous request has
+finished processing.
+6. The engine will call the application's callback passing the callback data as
+a parameter.
+7. The callback function should then run. Note: it is a requirement that the
+callback function is small and non-blocking as it will be run in the context of
+a polling mechanism or an interrupt.
+8. It is the application's responsibility via the callback function to schedule
+recalling the OpenSSL asynchronous function and to continue processing.
+9. The callback function has the option to check the status returned via
+SSL_get_async_status() to determine whether a retry happened instead of the
+request being submitted, allowing different processing if required.
+
+=head1 RETURN VALUES
+
+SSL_CTX_set_async_callback(), SSL_set_async_callback(),
+SSL_CTX_set_async_callback_arg(), SSL_CTX_set_async_callback_arg() and
+SSL_get_async_status() return 1 on success or 0 on error.
+
+=head1 HISTORY
+
+SSL_CTX_set_async_callback(), SSL_CTX_set_async_callback_arg(),
+SSL_set_async_callback(), SSL_set_async_callback_arg() and
+SSL_get_async_status() were first added to OpenSSL 3.0.0.
+
+=head1 COPYRIGHT
+
+Copyright 2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the OpenSSL license (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index 2e124114f9a6e67ce8b81f202c3d52c389768d75..3d80610b67ec5e2bc8276da40dc911fb164f9622 100644 (file)
@@ -403,6 +403,8 @@ static void wait_cleanup(ASYNC_WAIT_CTX *ctx, const void *key,
 static void dummy_pause_job(void) {
     ASYNC_JOB *job;
     ASYNC_WAIT_CTX *waitctx;
 static void dummy_pause_job(void) {
     ASYNC_JOB *job;
     ASYNC_WAIT_CTX *waitctx;
+    ASYNC_callback_fn callback;
+    void * callback_arg;
     OSSL_ASYNC_FD pipefds[2] = {0, 0};
     OSSL_ASYNC_FD *writefd;
 #if defined(ASYNC_WIN)
     OSSL_ASYNC_FD pipefds[2] = {0, 0};
     OSSL_ASYNC_FD *writefd;
 #if defined(ASYNC_WIN)
@@ -417,6 +419,18 @@ static void dummy_pause_job(void) {
 
     waitctx = ASYNC_get_wait_ctx(job);
 
 
     waitctx = ASYNC_get_wait_ctx(job);
 
+    if (ASYNC_WAIT_CTX_get_callback(waitctx, &callback, &callback_arg) && callback != NULL) {
+        /*
+         * In the Dummy async engine we are cheating. We call the callback that the job
+         * is complete before the call to ASYNC_pause_job(). A real
+         * async engine would only call the callback when the job was actually complete
+         */
+        (*callback)(callback_arg);
+        ASYNC_pause_job();
+        return;
+    }
+
+
     if (ASYNC_WAIT_CTX_get_fd(waitctx, engine_dasync_id, &pipefds[0],
                               (void **)&writefd)) {
         pipefds[1] = *writefd;
     if (ASYNC_WAIT_CTX_get_fd(waitctx, engine_dasync_id, &pipefds[0],
                               (void **)&writefd)) {
         pipefds[1] = *writefd;
index 71aef3bf9889223ea416f9422633e76bdf46088f..910c144c6b8281790385a0b86c30230900bc1ae0 100644 (file)
@@ -31,12 +31,18 @@ extern "C" {
 
 typedef struct async_job_st ASYNC_JOB;
 typedef struct async_wait_ctx_st ASYNC_WAIT_CTX;
 
 typedef struct async_job_st ASYNC_JOB;
 typedef struct async_wait_ctx_st ASYNC_WAIT_CTX;
+typedef int (*ASYNC_callback_fn)(void *arg);
 
 #define ASYNC_ERR      0
 #define ASYNC_NO_JOBS  1
 #define ASYNC_PAUSE    2
 #define ASYNC_FINISH   3
 
 
 #define ASYNC_ERR      0
 #define ASYNC_NO_JOBS  1
 #define ASYNC_PAUSE    2
 #define ASYNC_FINISH   3
 
+#define ASYNC_STATUS_UNSUPPORTED    0
+#define ASYNC_STATUS_ERR            1
+#define ASYNC_STATUS_OK             2
+#define ASYNC_STATUS_EAGAIN         3
+
 int ASYNC_init_thread(size_t max_size, size_t init_size);
 void ASYNC_cleanup_thread(void);
 
 int ASYNC_init_thread(size_t max_size, size_t init_size);
 void ASYNC_cleanup_thread(void);
 
@@ -52,6 +58,14 @@ int ASYNC_WAIT_CTX_get_fd(ASYNC_WAIT_CTX *ctx, const void *key,
                         OSSL_ASYNC_FD *fd, void **custom_data);
 int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
                                size_t *numfds);
                         OSSL_ASYNC_FD *fd, void **custom_data);
 int ASYNC_WAIT_CTX_get_all_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *fd,
                                size_t *numfds);
+int ASYNC_WAIT_CTX_get_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn *callback,
+                                void **callback_arg);
+int ASYNC_WAIT_CTX_set_callback(ASYNC_WAIT_CTX *ctx,
+                                ASYNC_callback_fn callback,
+                                void *callback_arg);
+int ASYNC_WAIT_CTX_set_status(ASYNC_WAIT_CTX *ctx, int status);
+int ASYNC_WAIT_CTX_get_status(ASYNC_WAIT_CTX *ctx);
 int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
                                    size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                    size_t *numdelfds);
 int ASYNC_WAIT_CTX_get_changed_fds(ASYNC_WAIT_CTX *ctx, OSSL_ASYNC_FD *addfd,
                                    size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                    size_t *numdelfds);
index ea41dd089eabf699575e746ceda98f7750f3838a..c7a830445b6861c2cd4f53bfc705a0d2e9d608d2 100644 (file)
@@ -293,6 +293,9 @@ typedef int (*SSL_custom_ext_parse_cb_ex)(SSL *s, unsigned int ext_type,
 /* Typedef for verification callback */
 typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
 
 /* Typedef for verification callback */
 typedef int (*SSL_verify_cb)(int preverify_ok, X509_STORE_CTX *x509_ctx);
 
+/* Typedef for SSL async callback */
+typedef int (*SSL_async_callback_fn)(SSL *s, void *arg);
+
 /*
  * Some values are reserved until OpenSSL 1.2.0 because they were previously
  * included in SSL_OP_ALL in a 1.1.x release.
 /*
  * Some values are reserved until OpenSSL 1.2.0 because they were previously
  * included in SSL_OP_ALL in a 1.1.x release.
@@ -1815,6 +1818,12 @@ __owur int SSL_get_all_async_fds(SSL *s, OSSL_ASYNC_FD *fds, size_t *numfds);
 __owur int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd,
                                      size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                      size_t *numdelfds);
 __owur int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd,
                                      size_t *numaddfds, OSSL_ASYNC_FD *delfd,
                                      size_t *numdelfds);
+__owur int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback);
+__owur int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg);
+__owur int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback);
+__owur int SSL_set_async_callback_arg(SSL *s, void *arg);
+__owur int SSL_get_async_status(SSL *s, int *status);
+
 # endif
 __owur int SSL_accept(SSL *ssl);
 __owur int SSL_stateless(SSL *s);
 # endif
 __owur int SSL_accept(SSL *ssl);
 __owur int SSL_stateless(SSL *s);
index ba606e35ed486616ac64702aa03a1078cb9e7ed6..6d6060a2121fdde2a918a5119df593562d545ab5 100644 (file)
@@ -831,6 +831,9 @@ SSL *SSL_new(SSL_CTX *ctx)
     s->psk_find_session_cb = ctx->psk_find_session_cb;
     s->psk_use_session_cb = ctx->psk_use_session_cb;
 
     s->psk_find_session_cb = ctx->psk_find_session_cb;
     s->psk_use_session_cb = ctx->psk_use_session_cb;
 
+    s->async_cb = ctx->async_cb;
+    s->async_cb_arg = ctx->async_cb_arg;
+
     s->job = NULL;
 
 #ifndef OPENSSL_NO_CT
     s->job = NULL;
 
 #ifndef OPENSSL_NO_CT
@@ -1652,6 +1655,40 @@ int SSL_get_changed_async_fds(SSL *s, OSSL_ASYNC_FD *addfd, size_t *numaddfds,
                                           numdelfds);
 }
 
                                           numdelfds);
 }
 
+int SSL_CTX_set_async_callback(SSL_CTX *ctx, SSL_async_callback_fn callback)
+{
+    ctx->async_cb = callback;
+    return 1;
+}
+
+int SSL_CTX_set_async_callback_arg(SSL_CTX *ctx, void *arg)
+{
+    ctx->async_cb_arg = arg;
+    return 1;
+}
+
+int SSL_set_async_callback(SSL *s, SSL_async_callback_fn callback)
+{
+    s->async_cb = callback;
+    return 1;
+}
+
+int SSL_set_async_callback_arg(SSL *s, void *arg)
+{
+    s->async_cb_arg = arg;
+    return 1;
+}
+
+int SSL_get_async_status(SSL *s, int *status)
+{
+    ASYNC_WAIT_CTX *ctx = s->waitctx;
+
+    if (ctx == NULL)
+        return 0;
+    *status = ASYNC_WAIT_CTX_get_status(ctx);
+    return 1;
+}
+
 int SSL_accept(SSL *s)
 {
     if (s->handshake_func == NULL) {
 int SSL_accept(SSL *s)
 {
     if (s->handshake_func == NULL) {
@@ -1677,6 +1714,13 @@ long SSL_get_default_timeout(const SSL *s)
     return s->method->get_timeout();
 }
 
     return s->method->get_timeout();
 }
 
+static int ssl_async_wait_ctx_cb(void *arg)
+{
+    SSL *s = (SSL *)arg;
+
+    return s->async_cb(s, s->async_cb_arg);
+}
+
 static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
                                int (*func) (void *))
 {
 static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
                                int (*func) (void *))
 {
@@ -1685,6 +1729,10 @@ static int ssl_start_async_job(SSL *s, struct ssl_async_args *args,
         s->waitctx = ASYNC_WAIT_CTX_new();
         if (s->waitctx == NULL)
             return -1;
         s->waitctx = ASYNC_WAIT_CTX_new();
         if (s->waitctx == NULL)
             return -1;
+        if (s->async_cb != NULL
+            && !ASYNC_WAIT_CTX_set_callback
+                 (s->waitctx, ssl_async_wait_ctx_cb, s))
+            return -1;
     }
     switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
                             sizeof(struct ssl_async_args))) {
     }
     switch (ASYNC_start_job(&s->job, s->waitctx, &ret, func, args,
                             sizeof(struct ssl_async_args))) {
index 2d68691a0fb5a5230f79529b247fa7ba6f737bdc..bd0d4210f4790461b9e3d4efc43a2b5ccdbf908d 100644 (file)
@@ -1076,6 +1076,10 @@ struct ssl_ctx_st {
 
     /* Do we advertise Post-handshake auth support? */
     int pha_enabled;
 
     /* Do we advertise Post-handshake auth support? */
     int pha_enabled;
+
+    /* Callback for SSL async handling */
+    SSL_async_callback_fn async_cb;
+    void *async_cb_arg;
 };
 
 struct ssl_st {
 };
 
 struct ssl_st {
@@ -1471,6 +1475,10 @@ struct ssl_st {
     /* Callback to determine if early_data is acceptable or not */
     SSL_allow_early_data_cb_fn allow_early_data_cb;
     void *allow_early_data_cb_data;
     /* Callback to determine if early_data is acceptable or not */
     SSL_allow_early_data_cb_fn allow_early_data_cb;
     void *allow_early_data_cb_data;
+
+    /* Callback for SSL async handling */
+    SSL_async_callback_fn async_cb;
+    void *async_cb_arg;
 };
 
 /*
 };
 
 /*
index 3c08974146ddf5efa6653c89836985c303bf43a2..3ce190fb1b4b3bc36d694f7b2f766d123f4d3906 100644 (file)
@@ -123,6 +123,43 @@ static int test_ASYNC_init_thread(void)
     return 1;
 }
 
     return 1;
 }
 
+static int test_callback(void *arg)
+{
+    printf("callback test pass\n");
+    return 1;
+}
+
+static int test_ASYNC_callback_status(void)
+{
+    ASYNC_WAIT_CTX *waitctx = NULL;
+    int set_arg = 100;
+    ASYNC_callback_fn get_callback;
+    void *get_arg;
+    int set_status = 1;
+
+    if (       !ASYNC_init_thread(1, 0)
+            || (waitctx = ASYNC_WAIT_CTX_new()) == NULL
+            || ASYNC_WAIT_CTX_set_callback(waitctx, test_callback, (void*)&set_arg)
+               != 1
+            || ASYNC_WAIT_CTX_get_callback(waitctx, &get_callback, &get_arg)
+               != 1
+            || test_callback != get_callback
+            || get_arg != (void*)&set_arg
+            || (*get_callback)(get_arg) != 1
+            || ASYNC_WAIT_CTX_set_status(waitctx, set_status) != 1
+            || set_status != ASYNC_WAIT_CTX_get_status(waitctx)) {
+        fprintf(stderr, "test_ASYNC_callback_status() failed\n");
+        ASYNC_WAIT_CTX_free(waitctx);
+        ASYNC_cleanup_thread();
+        return 0;
+    }
+
+    ASYNC_WAIT_CTX_free(waitctx);
+    ASYNC_cleanup_thread();
+    return 1;
+
+}
+
 static int test_ASYNC_start_job(void)
 {
     ASYNC_JOB *job = NULL;
 static int test_ASYNC_start_job(void)
 {
     ASYNC_JOB *job = NULL;
@@ -279,6 +316,7 @@ int main(int argc, char **argv)
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
 
         if (       !test_ASYNC_init_thread()
         CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON);
 
         if (       !test_ASYNC_init_thread()
+                || !test_ASYNC_callback_status()
                 || !test_ASYNC_start_job()
                 || !test_ASYNC_get_current_job()
                 || !test_ASYNC_WAIT_CTX_get_all_fds()
                 || !test_ASYNC_start_job()
                 || !test_ASYNC_get_current_job()
                 || !test_ASYNC_WAIT_CTX_get_all_fds()
index b8b19801b2e0651e28955eec51af5e7cd22b29bb..e7d2ed7625855555e781ff2057fff560823b4901 100644 (file)
@@ -4622,3 +4622,7 @@ CRYPTO_siv128_cleanup                   4577      3_0_0   EXIST::FUNCTION:SIV
 CRYPTO_siv128_speed                     4578   3_0_0   EXIST::FUNCTION:SIV
 OPENSSL_INIT_set_config_filename        4579   3_0_0   EXIST::FUNCTION:STDIO
 OPENSSL_INIT_set_config_file_flags      4580   3_0_0   EXIST::FUNCTION:STDIO
 CRYPTO_siv128_speed                     4578   3_0_0   EXIST::FUNCTION:SIV
 OPENSSL_INIT_set_config_filename        4579   3_0_0   EXIST::FUNCTION:STDIO
 OPENSSL_INIT_set_config_file_flags      4580   3_0_0   EXIST::FUNCTION:STDIO
+ASYNC_WAIT_CTX_get_callback             4581   3_0_0   EXIST::FUNCTION:
+ASYNC_WAIT_CTX_set_callback             4582   3_0_0   EXIST::FUNCTION:
+ASYNC_WAIT_CTX_set_status               4583   3_0_0   EXIST::FUNCTION:
+ASYNC_WAIT_CTX_get_status               4584   3_0_0   EXIST::FUNCTION:
index 6bc668833a47b42631765f0d8f4afd72ba86cd16..d59ccf9974db4abe385d9e794d777ff9f434086d 100644 (file)
@@ -498,3 +498,8 @@ SSL_CTX_get_recv_max_early_data         498 3_0_0   EXIST::FUNCTION:
 SSL_CTX_set_recv_max_early_data         499    3_0_0   EXIST::FUNCTION:
 SSL_CTX_set_post_handshake_auth         500    3_0_0   EXIST::FUNCTION:
 SSL_get_signature_type_nid              501    3_0_0   EXIST::FUNCTION:
 SSL_CTX_set_recv_max_early_data         499    3_0_0   EXIST::FUNCTION:
 SSL_CTX_set_post_handshake_auth         500    3_0_0   EXIST::FUNCTION:
 SSL_get_signature_type_nid              501    3_0_0   EXIST::FUNCTION:
+SSL_CTX_set_async_callback              502    3_0_0   EXIST::FUNCTION:
+SSL_CTX_set_async_callback_arg          503    3_0_0   EXIST::FUNCTION:
+SSL_set_async_callback                  504    3_0_0   EXIST::FUNCTION:
+SSL_set_async_callback_arg              505    3_0_0   EXIST::FUNCTION:
+SSL_get_async_status                    506    3_0_0   EXIST::FUNCTION:
index 09ab417f6902ce568bc5e362b8f10f5e5b3f4ae5..7a7c73f0da0eca6dcc2ef1addb04627976214436 100644 (file)
@@ -90,6 +90,8 @@ custom_ext_free_cb                      datatype
 custom_ext_parse_cb                     datatype
 pem_password_cb                         datatype
 ssl_ct_validation_cb                    datatype
 custom_ext_parse_cb                     datatype
 pem_password_cb                         datatype
 ssl_ct_validation_cb                    datatype
+ASYNC_callback_fn                       datatype
+SSL_async_callback_fn                   datatype
 #
 BIO_append_filename                     define
 BIO_destroy_bio_pair                    define
 #
 BIO_append_filename                     define
 BIO_destroy_bio_pair                    define
@@ -475,3 +477,7 @@ X509_STORE_set_verify_func              define
 EVP_PKEY_CTX_set1_id                    define
 EVP_PKEY_CTX_get1_id                    define
 EVP_PKEY_CTX_get1_id_len                define
 EVP_PKEY_CTX_set1_id                    define
 EVP_PKEY_CTX_get1_id                    define
 EVP_PKEY_CTX_get1_id_len                define
+ASYNC_STATUS_EAGAIN                     define
+ASYNC_STATUS_OK                         define
+ASYNC_STATUS_ERR                        define
+ASYNC_STATUS_UNSUPPORTED                define