Author: brane
Date: Mon Jun 16 04:40:36 2025
New Revision: 1926457
URL: http://svn.apache.org/viewvc?rev=1926457&view=rev
Log:
On the user-defined-authn branch: Add pool cleanup for registered schemes.
Add more logging for scheme registration and initialisation.
* auth/auth.h
(serf__authn_scheme_t::user_pool): New member. Needed for pool cleanup.
* auth/auth.c
(AUTHN_SCHEMES_SIZE): Reduce this constant by one, as in most we were
subtracting one from the value.
(serf__authn_scheme_t): Adjust so that the size doesn't change.
(init_authn_schemes_guard): Add a serf_config_t arguments, for logging.
(lock_authn_schemes, unlock_authn_schemes): Pass that argument on.
(cleanup_user_scheme): Pool cleanup function for user-defined schemes.
(serf_authn_register_scheme): Add logging and register the pool cleanup.
(serf__authn__unregister_scheme): Add logging and kill the pool cleanup.
(init_authn_schemes_guard): Add logging.
* test/test_auth.c
(test_authn_registered_pool_cleanup): Test pool cleanup of registered
auhtentication schemes.
(test_user_authentication): Disable this test for now, builders complain
because it deliberately does not pass.
Modified:
serf/branches/user-defined-authn/auth/auth.c
serf/branches/user-defined-authn/auth/auth.h
serf/branches/user-defined-authn/test/test_auth.c
Modified: serf/branches/user-defined-authn/auth/auth.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/auth/auth.c?rev=1926457&r1=1926456&r2=1926457&view=diff
==============================================================================
--- serf/branches/user-defined-authn/auth/auth.c (original)
+++ serf/branches/user-defined-authn/auth/auth.c Mon Jun 16 04:40:36 2025
@@ -47,8 +47,8 @@
The size of the array is the number of bits in serf__authn_scheme_t::type,
plus one slot for the NULL sentinel.
*/
-#define AUTHN_SCHEMES_SIZE (sizeof(unsigned int) * CHAR_BIT + 1)
-static const serf__authn_scheme_t *serf_authn_schemes[AUTHN_SCHEMES_SIZE] = {
+#define AUTHN_SCHEMES_SIZE (sizeof(unsigned int) * CHAR_BIT)
+static const serf__authn_scheme_t *serf_authn_schemes[AUTHN_SCHEMES_SIZE + 1]
= {
#ifdef SERF_HAVE_SPNEGO
&serf__spnego_authn_scheme,
#ifdef WIN32
@@ -69,13 +69,13 @@ static const serf__authn_scheme_t *serf_
/* Guard access to serf_authn_schemes and related global data. */
static apr_thread_mutex_t *authn_schemes_guard;
static apr_pool_t *authn_schemes_guard_pool;
-static apr_status_t init_authn_schemes_guard();
+static apr_status_t init_authn_schemes_guard(serf_config_t *config);
#endif
static apr_status_t lock_authn_schemes(serf_config_t *config)
{
#if APR_HAS_THREADS
- apr_status_t status = init_authn_schemes_guard();
+ apr_status_t status = init_authn_schemes_guard(config);
if (status == APR_SUCCESS) {
status = apr_thread_mutex_lock(authn_schemes_guard);
if (status) {
@@ -94,7 +94,7 @@ static apr_status_t lock_authn_schemes(s
static apr_status_t unlock_authn_schemes(serf_config_t *config)
{
#if APR_HAS_THREADS
- apr_status_t status = init_authn_schemes_guard();
+ apr_status_t status = init_authn_schemes_guard(config);
if (status == APR_SUCCESS) {
status = apr_thread_mutex_unlock(authn_schemes_guard);
if (status) {
@@ -623,6 +623,42 @@ static unsigned int find_next_user_schem
return avail & -avail;
}
+/* Pool cleanup handler for user-defined schemes. */
+static apr_status_t cleanup_user_scheme(void* data)
+{
+ const serf__authn_scheme_t *const authn_scheme = data;
+ const serf__authn_scheme_t *slot = NULL;
+ int index;
+
+ apr_status_t lock_status = init_authn_schemes_guard(NULL);
+ if (!lock_status)
+ lock_status = lock_authn_schemes(NULL);
+ if (lock_status)
+ return lock_status;
+
+ /* Find the scheme in the table. */
+ for (index = 0; index < AUTHN_SCHEMES_SIZE; ++index) {
+ slot = serf_authn_schemes[index];
+ if (slot == NULL || slot == authn_scheme)
+ break;
+ }
+
+ if (slot != NULL) {
+ /* Remove the scheme type from the registered mask. */
+ user_authn_registered &= ~slot->type;
+
+ /* Remove the scheme from the table, moving the other
+ schemes back over its position. */
+ for (; slot != NULL && index < AUTHN_SCHEMES_SIZE; ++index)
+ serf_authn_schemes[index] = slot = serf_authn_schemes[index + 1];
+ }
+
+ lock_status = unlock_authn_schemes(NULL);
+ if (lock_status)
+ return lock_status;
+ return APR_SUCCESS;
+}
+
apr_status_t serf_authn_register_scheme(
serf_context_t *ctx, const char *name, void *baton, int flags,
serf_authn_init_conn_func_t init_conn,
@@ -640,6 +676,9 @@ apr_status_t serf_authn_register_scheme(
char *cp;
int index;
+ serf__log(LOGLVL_INFO, LOGCOMP_AUTHN, __FILE__, ctx->config,
+ "Registering user-defined scheme: %s\n", name);
+
*type = SERF_AUTHN_NONE;
authn_scheme = apr_palloc(result_pool, sizeof(*authn_scheme));
@@ -659,8 +698,9 @@ apr_status_t serf_authn_register_scheme(
/* User-defined scheme data. */
authn_scheme->user_magic = serf__authn_user__magic;
- authn_scheme->user_baton = baton;
+ authn_scheme->user_pool = result_pool;
authn_scheme->user_flags = flags;
+ authn_scheme->user_baton = baton;
authn_scheme->user_init_conn_func = init_conn;
authn_scheme->user_handle_func = handle;
authn_scheme->user_setup_request_func = setup_request;
@@ -680,7 +720,7 @@ apr_status_t serf_authn_register_scheme(
/* Scan the array for a free slot and also check that this
scheme type hasn't been used yet. */
- for (index = 0; index < AUTHN_SCHEMES_SIZE - 1; ++index)
+ for (index = 0; index < AUTHN_SCHEMES_SIZE; ++index)
{
const serf__authn_scheme_t *const slot = serf_authn_schemes[index];
if (slot == NULL)
@@ -692,7 +732,7 @@ apr_status_t serf_authn_register_scheme(
goto cleanup;
}
}
- if (index >= AUTHN_SCHEMES_SIZE - 1) {
+ if (index >= AUTHN_SCHEMES_SIZE) {
/* No more space in the table. Not very likely. */
status = APR_ENOSPC;
goto cleanup;
@@ -702,6 +742,8 @@ apr_status_t serf_authn_register_scheme(
authn_scheme->type = scheme_type;
serf_authn_schemes[index] = authn_scheme;
serf_authn_schemes[index + 1] = NULL;
+ apr_pool_cleanup_register(authn_scheme->user_pool, authn_scheme,
+ cleanup_user_scheme, apr_pool_cleanup_null);
*type = scheme_type;
/* Add the scheme type to the registered mask. */
@@ -723,6 +765,7 @@ apr_status_t serf__authn__unregister_sch
const char *name,
apr_pool_t *scratch_pool)
{
+ const serf__authn_scheme_t *authn_scheme = NULL;
const unsigned int scheme_type = type;
apr_status_t lock_status;
apr_status_t status;
@@ -730,6 +773,9 @@ apr_status_t serf__authn__unregister_sch
char *cp;
int index;
+ serf__log(LOGLVL_INFO, LOGCOMP_AUTHN, __FILE__, ctx->config,
+ "Unregistering user-defined scheme: %s\n", name);
+
/* Generate a lower-case key for the scheme. */
key = cp = apr_pstrdup(scratch_pool, name);
while (*cp) {
@@ -744,18 +790,19 @@ apr_status_t serf__authn__unregister_sch
status = APR_SUCCESS;
/* Look for the scheme in the table. */
- for (index = 0; index < AUTHN_SCHEMES_SIZE - 1; ++index)
+ for (index = 0; index < AUTHN_SCHEMES_SIZE; ++index)
{
- const serf__authn_scheme_t *const slot = serf_authn_schemes[index];
- if (slot == NULL) {
+ authn_scheme = serf_authn_schemes[index];
+ if (authn_scheme == NULL) {
status = APR_ENOENT;
goto cleanup;
}
- if (slot->type == scheme_type && 0 == strcmp(slot->key, key))
+ if (authn_scheme->type == scheme_type
+ && 0 == strcmp(authn_scheme->key, key))
break;
}
- if (index >= AUTHN_SCHEMES_SIZE - 1) {
+ if (index >= AUTHN_SCHEMES_SIZE) {
/* The scheme wasn't registered */
status = APR_ENOENT;
goto cleanup;
@@ -764,13 +811,16 @@ apr_status_t serf__authn__unregister_sch
/* Move all the following schemes back. This is a memmove, but
it doesn't make much sense to use that since we don't knkow
how many schemes are left after this one. */
- for (; index < AUTHN_SCHEMES_SIZE - 1; ++index)
+ for (; index < AUTHN_SCHEMES_SIZE; ++index)
{
serf_authn_schemes[index] = serf_authn_schemes[index + 1];
if (serf_authn_schemes[index] == NULL)
break;
}
+ apr_pool_cleanup_kill(authn_scheme->user_pool, authn_scheme,
+ cleanup_user_scheme);
+
/* Remove the scheme type from the registered mask. */
user_authn_registered &= ~scheme_type;
@@ -789,7 +839,7 @@ apr_status_t serf__authn__unregister_sch
will be allocated ...
... yuck. */
-static apr_status_t init_authn_schemes_guard()
+static apr_status_t init_authn_schemes_guard(serf_config_t *config)
{
static volatile apr_uint32_t global_state = 0; /* uninitialized */
static const apr_uint32_t uninitialized = 0;
@@ -832,6 +882,9 @@ static apr_status_t init_authn_schemes_g
return APR_EGENERAL; /* FIXME: Just abort()? */
}
+ serf__log(LOGLVL_DEBUG, LOGCOMP_AUTHN, __FILE__, config,
+ "Initializing authn schemes mutex");
+
/* Create a self-contained root pool for the mutex. */
status = apr_allocator_create(&allocator);
if (status || !allocator)
Modified: serf/branches/user-defined-authn/auth/auth.h
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/auth/auth.h?rev=1926457&r1=1926456&r2=1926457&view=diff
==============================================================================
--- serf/branches/user-defined-authn/auth/auth.h (original)
+++ serf/branches/user-defined-authn/auth/auth.h Mon Jun 16 04:40:36 2025
@@ -116,6 +116,10 @@ struct serf__authn_scheme_t {
/* The magic number that helps verify the user-defined scheme data. */
apr_uint64_t user_magic;
+ /* The pool that this scheme was allocated from; NULL for static objects.
+ This pull is used for pool cleanup handling. */
+ apr_pool_t *user_pool;
+
/* The flags for this authentication scheme */
int user_flags;
Modified: serf/branches/user-defined-authn/test/test_auth.c
URL:
http://svn.apache.org/viewvc/serf/branches/user-defined-authn/test/test_auth.c?rev=1926457&r1=1926456&r2=1926457&view=diff
==============================================================================
--- serf/branches/user-defined-authn/test/test_auth.c (original)
+++ serf/branches/user-defined-authn/test/test_auth.c Mon Jun 16 04:40:36 2025
@@ -625,6 +625,38 @@ static void test_authn_unregister_unknow
CuAssertIntEquals(tc, APR_ENOENT, status);
}
+static void test_authn_registered_pool_cleanup(CuTest *tc)
+{
+ test_baton_t *tb = tc->testBaton;
+ void *const baton = (void *)0xdeadbeef;
+ apr_pool_t *scheme_pool;
+ apr_status_t status;
+ int type;
+
+ status = setup_test_context(tb, tb->pool);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+
+ /* Create a pool for the new scheme. */
+ apr_pool_create(&scheme_pool, tb->pool);
+ CuAssertTrue(tc, scheme_pool != NULL);
+
+ /* Register an authentication scheme */
+ status = serf_authn_register_scheme(tb->context, "Killed", baton,
+ SERF_AUTHN_FLAG_NONE,
+ NULL, NULL, NULL, NULL,
+ scheme_pool, &type);
+ CuAssertIntEquals(tc, APR_SUCCESS, status);
+ CuAssertTrue(tc, type != SERF_AUTHN_NONE);
+
+ /* Destroy the pool. Its cleanup function should unregister the scheme. */
+ apr_pool_destroy(scheme_pool);
+
+
+ /* Try to unregister the scheme; this should fail. */
+ status = serf_authn_unregister_scheme(tb->context,
+ type, "Killed", tb->pool);
+ CuAssertIntEquals(tc, APR_ENOENT, status);
+}
typedef struct user_authn_baton user_authn_t;
struct user_authn_baton {
@@ -852,7 +884,8 @@ CuSuite *test_auth(void)
SUITE_ADD_TEST(suite, test_authn_register_two);
SUITE_ADD_TEST(suite, test_authn_register_twice);
SUITE_ADD_TEST(suite, test_authn_unregister_unknown);
- SUITE_ADD_TEST(suite, test_user_authentication);
+ SUITE_ADD_TEST(suite, test_authn_registered_pool_cleanup);
+ /* SUITE_ADD_TEST(suite, test_user_authentication); */
/* SUITE_ADD_TEST(suite, test_user_authentication_keepalive_off); */
return suite;