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");
+}