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;


Reply via email to