This is an automated email from the ASF dual-hosted git repository.

bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 422d770f3f Test TLS async without ENGINE (#13264)
422d770f3f is described below

commit 422d770f3fe29f47f21695c2a1346835ea9a93a3
Author: Brian Neradt <[email protected]>
AuthorDate: Tue Jun 23 12:43:51 2026 -0500

    Test TLS async without ENGINE (#13264)
    
    Some OpenSSL builds expose the async APIs ATS needs while disabling
    the legacy ENGINE interface. The previous async handshake coverage
    depended on a test-only dynamic ENGINE just to make OpenSSL suspend
    during the TLS handshake, leaving those builds without the async-path
    AuTest coverage.
    
    This replaces the ENGINE plugin with a test plugin that pauses the
    current OpenSSL async job from a TLS certificate hook. This keeps the
    test focused on ATS's SSL_ERROR_WANT_ASYNC handling while avoiding the
    deprecated ENGINE API and dynamic ENGINE availability checks.
---
 ..._engine.test.py => tls_async_handshake.test.py} |  43 +--
 tests/tools/plugins/CMakeLists.txt                 |   6 +-
 tests/tools/plugins/async_engine.c                 | 326 ---------------------
 tests/tools/plugins/async_handshake.cc             | 182 ++++++++++++
 4 files changed, 194 insertions(+), 363 deletions(-)

diff --git a/tests/gold_tests/tls/tls_engine.test.py 
b/tests/gold_tests/tls/tls_async_handshake.test.py
similarity index 67%
rename from tests/gold_tests/tls/tls_engine.test.py
rename to tests/gold_tests/tls/tls_async_handshake.test.py
index eadc8e87c7..e652d0f6fc 100644
--- a/tests/gold_tests/tls/tls_engine.test.py
+++ b/tests/gold_tests/tls/tls_async_handshake.test.py
@@ -18,25 +18,23 @@
 
 import os
 
-# Someday should add client cert to origin to exercise the
-# engine interface on the other side
-
 Test.Summary = '''
-Test tls via the async interface with the sample async_engine
+Test TLS handshakes through OpenSSL's async job interface.
 '''
 
+async_handshake = os.path.join(Test.Variables.AtsTestPluginsDir, 
'async_handshake.so')
+
 Test.SkipUnless(
     Condition.HasOpenSSLVersion('1.1.1'),
     Condition.IsOpenSSL(),
+    Condition(lambda: os.path.isfile(async_handshake), async_handshake + " not 
found."),
 )
 
-# Define default ATS
 ts = Test.MakeATSProcess("ts", enable_tls=True)
 server = Test.MakeOriginServer("server")
 
-ts.Setup.Copy(os.path.join(Test.Variables.AtsTestPluginsDir, 
'async_engine.so'), Test.RunDirectory)
+Test.PrepareTestPlugin(async_handshake, ts)
 
-# Add info the origin server responses
 server.addResponse(
     "sessionlog.json", {
         "headers": "GET / HTTP/1.1\r\nuuid: basic\r\n\r\n",
@@ -44,12 +42,12 @@ server.addResponse(
         "body": ""
     }, {
         "headers":
-            "HTTP/1.1 200 OK\r\nServer: microserver\r\nConnection: 
close\r\nCache-Control: max-age=3600\r\nContent-Length: 2\r\n\r\n",
+            "HTTP/1.1 200 OK\r\nServer: microserver\r\nConnection: close\r\n"
+            "Cache-Control: max-age=3600\r\nContent-Length: 2\r\n\r\n",
         "timestamp": "1469733493.993",
         "body": "ok"
     })
 
-# add ssl materials like key, certificates for the server
 ts.addSSLfile("ssl/server.pem")
 ts.addSSLfile("ssl/server.key")
 
@@ -67,36 +65,11 @@ ts.Disk.records_config.update(
         'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir),
         'proxy.config.ssl.server.private_key.path': 
'{0}'.format(ts.Variables.SSLDir),
         'proxy.config.exec_thread.autoconfig.scale': 1.0,
-        'proxy.config.ssl.engine.conf_file': 
'{0}/ts/config/load_engine.cnf'.format(Test.RunDirectory),
         'proxy.config.ssl.async.handshake.enabled': 1,
         'proxy.config.diags.debug.enabled': 0,
         'proxy.config.diags.debug.tags': 'ssl|http'
     })
 
-ts.Disk.MakeConfigFile('load_engine.cnf').AddLines(
-    [
-        'openssl_conf = openssl_init',
-        '',
-        '[openssl_init]',
-        '',
-        'engines = engine_section',
-        '',
-        '[engine_section]',
-        '',
-        'async = async_section',
-        '',
-        '[async_section]',
-        '',
-        'dynamic_path = {0}/async_engine.so'.format(Test.RunDirectory),
-        '',
-        'engine_id = async-test',
-        '',
-        'default_algorithms = RSA',
-        '',
-        'init = 1',
-    ])
-
-# Make a basic request.  Hopefully it goes through
 tr = Test.AddTestRun("Run-Test")
 tr.MakeCurlCommand("-k -v -H uuid:basic -H host:example.com  
https://127.0.0.1:{0}/".format(ts.Variables.ssl_port), ts=ts)
 tr.ReturnCode = 0
@@ -105,4 +78,4 @@ tr.Processes.Default.StartBefore(Test.Processes.ts, 
ready=When.PortOpen(ts.Varia
 tr.Processes.Default.Streams.All = Testers.ContainsExpression(r"HTTP/(2|1\.1) 
200", "Request succeeds")
 tr.StillRunningAfter = server
 
-ts.Disk.traffic_out.Content += Testers.ContainsExpression("Send signal to ", 
"The Async engine triggers")
+ts.Disk.traffic_out.Content += Testers.ContainsExpression("resumed OpenSSL 
async job", "The OpenSSL async job resumes")
diff --git a/tests/tools/plugins/CMakeLists.txt 
b/tests/tools/plugins/CMakeLists.txt
index 05a4d3d6e1..bbdc5866cd 100644
--- a/tests/tools/plugins/CMakeLists.txt
+++ b/tests/tools/plugins/CMakeLists.txt
@@ -34,7 +34,6 @@ target_link_libraries(test_cppapi PRIVATE ts::tscppapi)
 add_autest_plugin(test_hooks test_hooks.cc)
 add_autest_plugin(test_log_interface test_log_interface.cc)
 add_autest_plugin(user_args user_args.cc)
-add_autest_plugin(async_engine async_engine.c)
 add_autest_plugin(hook_tunnel_plugin hook_tunnel_plugin.cc)
 add_autest_plugin(tunnel_transform tunnel_transform.cc)
 add_autest_plugin(http2_close_connection http2_close_connection.cc)
@@ -44,4 +43,7 @@ target_link_libraries(ssl_client_verify_test PRIVATE 
OpenSSL::SSL)
 target_link_libraries(ssl_hook_test PRIVATE OpenSSL::SSL)
 target_link_libraries(ssl_secret_load_test PRIVATE OpenSSL::SSL)
 target_link_libraries(ssl_verify_test PRIVATE OpenSSL::SSL)
-target_link_libraries(async_engine PRIVATE OpenSSL::SSL)
+if(TS_USE_TLS_ASYNC)
+  add_autest_plugin(async_handshake async_handshake.cc)
+  target_link_libraries(async_handshake PRIVATE OpenSSL::SSL)
+endif()
diff --git a/tests/tools/plugins/async_engine.c 
b/tests/tools/plugins/async_engine.c
deleted file mode 100644
index 4624f20dd1..0000000000
--- a/tests/tools/plugins/async_engine.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/** @file
-
-  Test crypto engine
-
-  @section license License
-
-  Licensed to the Apache Software Foundation (ASF) under one
-  or more contributor license agreements.  See the NOTICE file
-  distributed with this work for additional information
-  regarding copyright ownership.  The ASF licenses this file
-  to you under the Apache License, Version 2.0 (the
-  "License"); you may not use this file except in compliance
-  with the License.  You may obtain a copy of the License at
-
-      http://www.apache.org/licenses/LICENSE-2.0
-
-  Unless required by applicable law or agreed to in writing, software
-  distributed under the License is distributed on an "AS IS" BASIS,
-  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  See the License for the specific language governing permissions and
-  limitations under the License.
- */
-
-/*
- * Test engine to exercise the asynchronous job interface
- * It performs the standard RSA operations, but for private key
- * operations spawns a thread to sleep for 5 seconds before resuming
- * the asynchronous job
- */
-
-/* TLS_USE_TLS_ASYNC defined in ink_config.h */
-#include "tscore/ink_config.h"
-#include "tscore/ink_defs.h"
-#if TS_USE_TLS_ASYNC
-
-#include <stdio.h>
-#include <string.h>
-
-#include <openssl/engine.h>
-#include <openssl/rsa.h>
-#include <openssl/async.h>
-#include <openssl/crypto.h>
-#include <openssl/ssl.h>
-#include <openssl/modes.h>
-#include <pthread.h>
-#include <unistd.h>
-
-/* Engine Id and Name */
-static const char *engine_id   = "async-test";
-static const char *engine_name = "Asynchronous test engine";
-
-/* Engine Lifetime functions */
-static int async_destroy(ENGINE *e);
-static int engine_async_init(ENGINE *e);
-static int async_finish(ENGINE *e);
-void       engine_load_async_int(void);
-
-static void async_pause_job(void);
-
-/* RSA */
-
-static int async_pub_enc(int flen, const unsigned char *from, unsigned char 
*to, RSA *rsa, int padding);
-static int async_pub_dec(int flen, const unsigned char *from, unsigned char 
*to, RSA *rsa, int padding);
-static int async_rsa_priv_enc(int flen, const unsigned char *from, unsigned 
char *to, RSA *rsa, int padding);
-static int async_rsa_priv_dec(int flen, const unsigned char *from, unsigned 
char *to, RSA *rsa, int padding);
-static int async_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX 
*ctx);
-
-static int async_rsa_init(RSA *rsa);
-static int async_rsa_finish(RSA *rsa);
-
-static RSA_METHOD *async_rsa_method = NULL;
-
-EVP_PKEY *
-async_load_privkey(ENGINE *e ATS_UNUSED, const char *s_key_id, UI_METHOD 
*ui_method ATS_UNUSED, void *callback_data ATS_UNUSED)
-{
-  fprintf(stderr, "Loading key %s\n", s_key_id);
-  FILE *f = fopen(s_key_id, "r");
-  if (f) {
-    EVP_PKEY *key = PEM_read_PrivateKey(f, NULL, NULL, NULL);
-    fclose(f);
-    return key;
-  } else {
-    return NULL;
-  }
-}
-
-static int
-bind_async(ENGINE *e)
-{
-  /* Setup RSA_METHOD */
-  if ((async_rsa_method = RSA_meth_new("Async RSA method", 0)) == NULL ||
-      RSA_meth_set_pub_enc(async_rsa_method, async_pub_enc) == 0 || 
RSA_meth_set_pub_dec(async_rsa_method, async_pub_dec) == 0 ||
-      RSA_meth_set_priv_enc(async_rsa_method, async_rsa_priv_enc) == 0 ||
-      RSA_meth_set_priv_dec(async_rsa_method, async_rsa_priv_dec) == 0 ||
-      RSA_meth_set_mod_exp(async_rsa_method, async_rsa_mod_exp) == 0 ||
-      RSA_meth_set_bn_mod_exp(async_rsa_method, BN_mod_exp_mont) == 0 || 
RSA_meth_set_init(async_rsa_method, async_rsa_init) == 0 ||
-      RSA_meth_set_finish(async_rsa_method, async_rsa_finish) == 0) {
-    fprintf(stderr, "Failed to initialize rsa method\n");
-    return 0;
-  }
-
-  /* Ensure the dasync error handling is set up */
-  ERR_load_ASYNC_strings();
-
-  if (!ENGINE_set_id(e, engine_id) || !ENGINE_set_name(e, engine_name) || 
!ENGINE_set_RSA(e, async_rsa_method) ||
-      !ENGINE_set_destroy_function(e, async_destroy) || 
!ENGINE_set_init_function(e, engine_async_init) ||
-      !ENGINE_set_finish_function(e, async_finish) || 
!ENGINE_set_load_privkey_function(e, async_load_privkey)) {
-    fprintf(stderr, "Failed to initialize\n");
-    return 0;
-  }
-
-  return 1;
-}
-
-#ifndef OPENSSL_NO_DYNAMIC_ENGINE
-static int
-bind_helper(ENGINE *e, const char *id)
-{
-  if (id && (strcmp(id, engine_id) != 0))
-    return 0;
-  if (!bind_async(e))
-    return 0;
-  return 1;
-}
-
-IMPLEMENT_DYNAMIC_CHECK_FN()
-IMPLEMENT_DYNAMIC_BIND_FN(bind_helper)
-#endif
-
-static ENGINE *
-engine_async(void)
-{
-  ENGINE *ret = ENGINE_new();
-  if (!ret)
-    return NULL;
-  if (!bind_async(ret)) {
-    ENGINE_free(ret);
-    return NULL;
-  }
-  return ret;
-}
-
-void
-engine_load_async_int(void)
-{
-  ENGINE *toadd = engine_async();
-  if (!toadd)
-    return;
-  ENGINE_add(toadd);
-  ENGINE_free(toadd);
-  ERR_clear_error();
-}
-
-static int
-engine_async_init(ENGINE *e ATS_UNUSED)
-{
-  return 1;
-}
-
-static int
-async_finish(ENGINE *e ATS_UNUSED)
-{
-  return 1;
-}
-
-static int
-async_destroy(ENGINE *e ATS_UNUSED)
-{
-  RSA_meth_free(async_rsa_method);
-  return 1;
-}
-
-static void
-wait_cleanup(ASYNC_WAIT_CTX *ctx ATS_UNUSED, const void *key ATS_UNUSED, 
OSSL_ASYNC_FD readfd, void *pvwritefd)
-{
-  OSSL_ASYNC_FD *pwritefd  = (OSSL_ASYNC_FD *)pvwritefd;
-  OSSL_ASYNC_FD  writefd_v = *pwritefd;
-  close(readfd);
-  close(writefd_v);
-  OPENSSL_free(pwritefd);
-  fprintf(stderr, "Cleanup %d and %d\n", readfd, writefd_v);
-}
-
-#define DUMMY_CHAR 'X'
-
-static void
-async_pause_job(void)
-{
-  ASYNC_JOB      *job;
-  ASYNC_WAIT_CTX *waitctx;
-  OSSL_ASYNC_FD   pipefds[2] = {0, 0};
-  OSSL_ASYNC_FD  *writefd;
-  char            buf = DUMMY_CHAR;
-
-  if ((job = ASYNC_get_current_job()) == NULL) {
-    fprintf(stderr, "No job\n");
-    return;
-  }
-
-  waitctx = ASYNC_get_wait_ctx(job);
-
-  if (ASYNC_WAIT_CTX_get_fd(waitctx, engine_id, &pipefds[0], (void 
**)&writefd)) {
-    fprintf(stderr, "Existing wait ctx %d\n", *writefd);
-  } else {
-    writefd = (OSSL_ASYNC_FD *)OPENSSL_malloc(sizeof(*writefd));
-    if (writefd == NULL)
-      return;
-    if (pipe(pipefds) != 0) {
-      OPENSSL_free(writefd);
-      return;
-    }
-    *writefd = pipefds[1];
-
-    fprintf(stderr, "New wait ctx %d %d\n", pipefds[0], pipefds[1]);
-
-    if (!ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_id, pipefds[0], writefd, 
wait_cleanup)) {
-      fprintf(stderr, "set_wait_fd failed\n");
-      wait_cleanup(waitctx, engine_id, pipefds[0], writefd);
-      return;
-    }
-  }
-
-  /* Ignore errors - we carry on anyway */
-  ASYNC_pause_job();
-
-  /* Clear the wake signal */
-  if (read(pipefds[0], &buf, 1) < 0)
-    return;
-}
-
-void *
-delay_method(void *arg)
-{
-  int signal_fd = (intptr_t)arg;
-  sleep(2);
-  char buf = DUMMY_CHAR;
-  if (write(signal_fd, &buf, sizeof(buf)) < 0) {
-    fprintf(stderr, "Failed to send signal to %d, errno=%d\n", signal_fd, 
errno);
-  } else {
-    fprintf(stderr, "Send signal to %d\n", signal_fd);
-  }
-  return NULL;
-}
-
-void
-spawn_delay_thread()
-{
-  pthread_t  thread_id;
-  ASYNC_JOB *job;
-  if ((job = ASYNC_get_current_job()) == NULL) {
-    fprintf(stderr, "Spawn no job\n");
-    return;
-  }
-
-  ASYNC_WAIT_CTX *waitctx = ASYNC_get_wait_ctx(job);
-
-  size_t numfds;
-  if (ASYNC_WAIT_CTX_get_all_fds(waitctx, NULL, &numfds) && numfds > 0) {
-    fprintf(stderr, "Spawn, wait_ctx exists.  Go away, something else is using 
this job\n");
-  } else {
-    OSSL_ASYNC_FD  signal_fd;
-    OSSL_ASYNC_FD  pipefds[2] = {0, 0};
-    OSSL_ASYNC_FD *writefd    = OPENSSL_malloc(sizeof(*writefd));
-    if (pipe(pipefds) < 0) {
-      fprintf(stderr, "Spawn, failed to create pipe errno=%d\n", errno);
-      return;
-    }
-    signal_fd = *writefd = pipefds[1];
-    ASYNC_WAIT_CTX_set_wait_fd(waitctx, engine_id, pipefds[0], writefd, 
wait_cleanup);
-    fprintf(stderr, "Spawn, create wait_ctx %d %d\n", pipefds[0], pipefds[1]);
-    pthread_create(&thread_id, NULL, delay_method, (void 
*)((intptr_t)signal_fd));
-  }
-}
-
-/*
- * RSA implementation
- */
-
-static int
-async_pub_enc(int flen, const unsigned char *from, unsigned char *to, RSA 
*rsa, int padding)
-{
-  return RSA_meth_get_pub_enc(RSA_PKCS1_OpenSSL())(flen, from, to, rsa, 
padding);
-}
-
-static int
-async_pub_dec(int flen, const unsigned char *from, unsigned char *to, RSA 
*rsa, int padding)
-{
-  return RSA_meth_get_pub_dec(RSA_PKCS1_OpenSSL())(flen, from, to, rsa, 
padding);
-}
-
-static int
-async_rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA 
*rsa, int padding)
-{
-  fprintf(stderr, "async_priv_enc\n");
-  spawn_delay_thread();
-  async_pause_job();
-  fprintf(stderr, "async_priv_enc resume\n");
-  return RSA_meth_get_priv_enc(RSA_PKCS1_OpenSSL())(flen, from, to, rsa, 
padding);
-}
-
-static int
-async_rsa_priv_dec(int flen, const unsigned char *from, unsigned char *to, RSA 
*rsa, int padding)
-{
-  fprintf(stderr, "async_priv_dec\n");
-  spawn_delay_thread();
-  async_pause_job();
-  return RSA_meth_get_priv_dec(RSA_PKCS1_OpenSSL())(flen, from, to, rsa, 
padding);
-}
-
-static int
-async_rsa_mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx)
-{
-  return RSA_meth_get_mod_exp(RSA_PKCS1_OpenSSL())(r0, I, rsa, ctx);
-}
-
-static int
-async_rsa_init(RSA *rsa)
-{
-  return RSA_meth_get_init(RSA_PKCS1_OpenSSL())(rsa);
-}
-static int
-async_rsa_finish(RSA *rsa)
-{
-  return RSA_meth_get_finish(RSA_PKCS1_OpenSSL())(rsa);
-}
-#endif /* TS_USE_TLS_ASYNC */
diff --git a/tests/tools/plugins/async_handshake.cc 
b/tests/tools/plugins/async_handshake.cc
new file mode 100644
index 0000000000..3747ce17eb
--- /dev/null
+++ b/tests/tools/plugins/async_handshake.cc
@@ -0,0 +1,182 @@
+/** @file
+
+  Test TLS handshakes that pause inside an OpenSSL async job.
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+ */
+
+#include <ts/ts.h>
+
+#include <openssl/async.h>
+#include <openssl/crypto.h>
+
+#include <cerrno>
+#include <cstdint>
+#include <cstdio>
+#include <pthread.h>
+#include <unistd.h>
+
+#define PLUGIN_NAME "async_handshake"
+#define PCP         "[" PLUGIN_NAME "] "
+
+namespace
+{
+DbgCtl dbg_ctl{PLUGIN_NAME};
+char   async_hook_key;
+
+void
+wait_cleanup(ASYNC_WAIT_CTX * /* ctx ATS_UNUSED */, const void * /* key 
ATS_UNUSED */, OSSL_ASYNC_FD read_fd, void *write_fd_ptr)
+{
+  auto *write_fd = static_cast<OSSL_ASYNC_FD *>(write_fd_ptr);
+
+  close(read_fd);
+  close(*write_fd);
+  OPENSSL_free(write_fd);
+}
+
+void *
+wake_async_job(void *arg)
+{
+  auto signal_fd = static_cast<OSSL_ASYNC_FD>(reinterpret_cast<intptr_t>(arg));
+  char buf       = 'X';
+
+  usleep(100 * 1000);
+  if (write(signal_fd, &buf, sizeof(buf)) < 0) {
+    fprintf(stderr, PCP "failed to send async wake signal to %d, errno=%d\n", 
signal_fd, errno);
+  } else {
+    fprintf(stderr, PCP "sent async wake signal to %d\n", signal_fd);
+  }
+
+  return nullptr;
+}
+
+bool
+install_wait_fd(ASYNC_WAIT_CTX *wait_ctx, OSSL_ASYNC_FD &read_fd)
+{
+  OSSL_ASYNC_FD *write_fd = nullptr;
+  if (ASYNC_WAIT_CTX_get_fd(wait_ctx, &async_hook_key, &read_fd, 
reinterpret_cast<void **>(&write_fd))) {
+    return true;
+  }
+
+  OSSL_ASYNC_FD pipe_fds[2] = {-1, -1};
+  write_fd                  = static_cast<OSSL_ASYNC_FD 
*>(OPENSSL_malloc(sizeof(*write_fd)));
+  if (write_fd == nullptr) {
+    TSError(PCP "failed to allocate async wait fd storage");
+    return false;
+  }
+
+  if (pipe(pipe_fds) < 0) {
+    TSError(PCP "failed to create async wait pipe: errno=%d", errno);
+    OPENSSL_free(write_fd);
+    return false;
+  }
+  *write_fd = pipe_fds[1];
+
+  if (!ASYNC_WAIT_CTX_set_wait_fd(wait_ctx, &async_hook_key, pipe_fds[0], 
write_fd, wait_cleanup)) {
+    TSError(PCP "failed to install async wait fd");
+    close(pipe_fds[0]);
+    close(pipe_fds[1]);
+    OPENSSL_free(write_fd);
+    return false;
+  }
+
+  pthread_t thread_id;
+  if (pthread_create(&thread_id, nullptr, wake_async_job, 
reinterpret_cast<void *>(static_cast<intptr_t>(*write_fd))) == 0) {
+    pthread_detach(thread_id);
+  } else if (write(*write_fd, "X", 1) < 0) {
+    TSError(PCP "failed to start async wake thread and immediate wake failed: 
errno=%d", errno);
+    return false;
+  }
+
+  read_fd = pipe_fds[0];
+  return true;
+}
+
+void
+pause_current_async_job(TSVConn ssl_vc)
+{
+  ASYNC_JOB *job = ASYNC_get_current_job();
+  if (job == nullptr) {
+    TSError(PCP "SSL cert hook is not running in an OpenSSL async job");
+    TSVConnReenable(ssl_vc);
+    return;
+  }
+
+  ASYNC_WAIT_CTX *wait_ctx = ASYNC_get_wait_ctx(job);
+  if (wait_ctx == nullptr) {
+    TSError(PCP "OpenSSL async job has no wait context");
+    TSVConnReenable(ssl_vc);
+    return;
+  }
+
+  OSSL_ASYNC_FD read_fd = -1;
+  if (!install_wait_fd(wait_ctx, read_fd)) {
+    TSVConnReenable(ssl_vc);
+    return;
+  }
+
+  TSVConnReenable(ssl_vc);
+
+  fprintf(stderr, PCP "pausing OpenSSL async job\n");
+  if (!ASYNC_pause_job()) {
+    TSError(PCP "ASYNC_pause_job failed");
+    return;
+  }
+
+  fprintf(stderr, PCP "resumed OpenSSL async job\n");
+}
+
+int
+handle_ssl_cert(TSCont /* cont ATS_UNUSED */, TSEvent event, void *edata)
+{
+  TSVConn ssl_vc = static_cast<TSVConn>(edata);
+
+  if (event == TS_EVENT_SSL_CERT) {
+    pause_current_async_job(ssl_vc);
+  } else {
+    TSVConnReenable(ssl_vc);
+  }
+  return TS_SUCCESS;
+}
+
+} // namespace
+
+void
+TSPluginInit(int /* argc ATS_UNUSED */, const char ** /* argv ATS_UNUSED */)
+{
+  TSPluginRegistrationInfo info;
+
+  info.plugin_name   = PLUGIN_NAME;
+  info.vendor_name   = "Apache Software Foundation";
+  info.support_email = "[email protected]";
+
+  if (TS_SUCCESS != TSPluginRegister(&info)) {
+    TSError(PCP "registration failed");
+    return;
+  }
+
+  TSCont cb_cert = TSContCreate(handle_ssl_cert, TSMutexCreate());
+  if (cb_cert == nullptr) {
+    TSError(PCP "failed to create SSL cert hook");
+    return;
+  }
+
+  TSHttpHookAdd(TS_SSL_CERT_HOOK, cb_cert);
+  Dbg(dbg_ctl, "plugin online");
+}

Reply via email to