@@ -713,15 +713,6 @@ static int client_exists(client_id_t key, const request_rec *r)
713713 return found ;
714714}
715715
716- /* Note that a client entry was created to replace one which had been
717- * garbage collected. */
718- static void client_note_renewed (void )
719- {
720- apr_global_mutex_lock (client_lock );
721- client_list -> num_renewed ++ ;
722- apr_global_mutex_unlock (client_lock );
723- }
724-
725716/* Identifies the authenticated user of r, within the protection space the
726717 * configuration defines - the origin server and realm, narrowed by any
727718 * AuthDigestDomain - for binding a client entry to. A keyed hash, so that
@@ -847,12 +838,17 @@ static enum nonce_state client_update_nonce(request_rec *r,
847838}
848839
849840/* A simple garbage-collecter to remove unused clients. It removes the
850- * last entry in each bucket and updates the counters. Returns the
851- * number of removed entries.
841+ * last entry in each bucket and updates the counters, returning the
842+ * number of removed entries in *num_removed. The result is the first
843+ * failure to free an entry, if any, for the caller to log once the lock
844+ * is released.
852845 */
853- static unsigned long gc (server_rec * s )
846+ static apr_status_t gc (unsigned long * num_removed )
854847{
855- unsigned long num_removed = 0 , idx ;
848+ apr_status_t rv = APR_SUCCESS ;
849+ unsigned long idx ;
850+
851+ * num_removed = 0 ;
856852
857853 /* garbage collect one entry from each bucket */
858854
@@ -882,73 +878,91 @@ static unsigned long gc(server_rec *s)
882878
883879 * victim = entry -> next ;
884880 err = rmm_free (client_rmm , entry );
885- num_removed ++ ;
881+ ( * num_removed ) ++ ;
886882
887- if (err ) {
888- /* Nothing we can really do but log... */
889- ap_log_error (APLOG_MARK , APLOG_ERR , err , s , APLOGNO (10007 )
890- "Failed to free auth_digest client allocation" );
883+ if (err && rv == APR_SUCCESS ) {
884+ rv = err ;
891885 }
892886 }
893887 }
894888
895- /* update counters and log */
889+ /* update counters */
896890
897- client_list -> num_entries -= num_removed ;
898- client_list -> num_removed += num_removed ;
891+ client_list -> num_entries -= * num_removed ;
892+ client_list -> num_removed += * num_removed ;
899893
900- return num_removed ;
894+ return rv ;
901895}
902896
903897/*
904- * Add a new client to the list, under a newly issued id. Returns the id if
905- * successful, zero otherwise. This triggers the garbage collection if
906- * memory is low. (The new entry is not returned: see find_client().)
898+ * Add a new client to the list, under a newly issued id; renewed is set
899+ * when it replaces an entry which had been garbage collected. Returns the
900+ * id if successful, zero otherwise. This triggers the garbage collection
901+ * if memory is low. (The new entry is not returned: see find_client().)
907902 */
908- static client_id_t client_generate (request_rec * r )
903+ static client_id_t client_generate (request_rec * r , int renewed )
909904{
910905 server_rec * s = r -> server ;
911906 int bucket ;
912907 client_entry * entry ;
913- client_id_t key ;
908+ client_id_t key = 0 ;
909+ int ran_gc = 0 ;
910+ unsigned long gc_removed = 0 , created , removed , renewals ;
911+ apr_status_t gc_rv = APR_SUCCESS ;
914912
915913 apr_global_mutex_lock (client_lock );
916914
917915 /* try to allocate a new entry */
918916
919917 entry = rmm_malloc (client_rmm , sizeof (client_entry ));
920918 if (!entry ) {
921- unsigned long num_removed = gc (s );
922- ap_log_error (APLOG_MARK , APLOG_INFO , 0 , s , APLOGNO (01766 )
923- "gc'd %lu client entries. Total new clients: "
924- "%lu; Total removed clients: %lu; Total renewed clients: "
925- "%lu" , num_removed ,
926- client_list -> num_created - client_list -> num_renewed ,
927- client_list -> num_removed , client_list -> num_renewed );
919+ gc_rv = gc (& gc_removed );
920+ ran_gc = 1 ;
928921 entry = rmm_malloc (client_rmm , sizeof (client_entry ));
929- if (!entry ) {
930- apr_global_mutex_unlock (client_lock );
931- ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01769 )
932- "unable to allocate a client entry - failing the "
933- "request, since this configuration needs one" );
934- return 0 ;
935- }
936922 }
937923
938- /* now issue the id, in 1..CLIENT_ID_MAX, and add the entry */
924+ if (entry ) {
925+ /* now issue the id, in 1..CLIENT_ID_MAX, and add the entry */
939926
940- key = client_list -> next_id = client_list -> next_id % CLIENT_ID_MAX + 1 ;
941- bucket = key % client_list -> tbl_len ;
927+ key = client_list -> next_id = client_list -> next_id % CLIENT_ID_MAX + 1 ;
928+ bucket = key % client_list -> tbl_len ;
942929
943- memset (entry , 0 , sizeof (client_entry ));
944- entry -> key = key ;
945- entry -> next = client_list -> table [bucket ];
946- client_list -> table [bucket ] = entry ;
947- client_list -> num_created ++ ;
948- client_list -> num_entries ++ ;
930+ memset (entry , 0 , sizeof (client_entry ));
931+ entry -> key = key ;
932+ entry -> next = client_list -> table [bucket ];
933+ client_list -> table [bucket ] = entry ;
934+ client_list -> num_created ++ ;
935+ client_list -> num_entries ++ ;
936+ client_list -> num_renewed += !!renewed ;
937+ }
938+
939+ /* for logging after the lock is released */
940+ created = client_list -> num_created ;
941+ removed = client_list -> num_removed ;
942+ renewals = client_list -> num_renewed ;
949943
950944 apr_global_mutex_unlock (client_lock );
951945
946+ if (gc_rv ) {
947+ /* Nothing we can really do but log... */
948+ ap_log_error (APLOG_MARK , APLOG_ERR , gc_rv , s , APLOGNO (10007 )
949+ "Failed to free auth_digest client allocation" );
950+ }
951+ if (ran_gc ) {
952+ ap_log_error (APLOG_MARK , APLOG_INFO , 0 , s , APLOGNO (01766 )
953+ "gc'd %lu client entries. Total new clients: "
954+ "%lu; Total removed clients: %lu; Total renewed clients: "
955+ "%lu" , gc_removed , created - renewals , removed ,
956+ renewals );
957+ }
958+
959+ if (!key ) {
960+ ap_log_rerror (APLOG_MARK , APLOG_ERR , 0 , r , APLOGNO (01769 )
961+ "unable to allocate a client entry - failing the "
962+ "request, since this configuration needs one" );
963+ return 0 ;
964+ }
965+
952966 ap_log_error (APLOG_MARK , APLOG_DEBUG , 0 , s , APLOGNO (01768 )
953967 "allocated new client %" APR_UINT64_T_FMT , key );
954968
@@ -1266,7 +1280,7 @@ static int note_digest_auth_failure(request_rec *r,
12661280 if (resp -> opaque == NULL ) {
12671281 /* new client */
12681282 if (conf -> check_nc || conf -> nonce_lifetime == 0 ) {
1269- if ((client_key = client_generate (r )) == 0 ) {
1283+ if ((client_key = client_generate (r , 0 )) == 0 ) {
12701284 return HTTP_SERVICE_UNAVAILABLE ;
12711285 }
12721286 opaque = client_id_to_opaque (r -> pool , client_key );
@@ -1281,11 +1295,10 @@ static int note_digest_auth_failure(request_rec *r,
12811295 * a new entry; whether the challenge is stale is the caller's
12821296 * call, since credentials which failed are no less wrong for the
12831297 * opaque being unknown. */
1284- if ((client_key = client_generate (r )) == 0 ) {
1298+ if ((client_key = client_generate (r , 1 )) == 0 ) {
12851299 return HTTP_SERVICE_UNAVAILABLE ;
12861300 }
12871301 opaque = client_id_to_opaque (r -> pool , client_key );
1288- client_note_renewed ();
12891302 }
12901303 else {
12911304 /* Note that the nonce-count tracked for this client is left alone
0 commit comments