From 1b048a8a9743bbce961d1dfb4e10a82250c2a876 Mon Sep 17 00:00:00 2001 From: Andrey Volk Date: Wed, 27 Jan 2021 02:53:16 +0300 Subject: [PATCH] [Core, mod_hash] Add two APIs switch_core_hash_insert_alloc_destructor and switch_core_hash_insert_dup_destructor. Code cleanup in mod_hash. Add unit-tests. --- src/include/switch_core.h | 22 +++++++++++ src/mod/applications/mod_hash/mod_hash.c | 21 +++-------- src/switch_core_hash.c | 39 ++++++++++++++++++++ tests/unit/switch_core.c | 47 ++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 16 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 4f172a928e..9c9f6c490c 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -1457,6 +1457,28 @@ SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_auto_free(switch_hash_t SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ const void *data, hashtable_destructor_t destructor); #define switch_core_hash_insert(_h, _k, _d) switch_core_hash_insert_destructor(_h, _k, _d, NULL) +/*! + \brief Allocate memory and insert into a hash + \param hash the hash to add data to + \param key the name of the key to add the data to + \param size the size in bytes to allocate + \return pointer to the allocated memory + \note the string key must be a constant or a dynamic string +*/ +SWITCH_DECLARE(void *) switch_core_hash_insert_alloc_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ size_t size, hashtable_destructor_t destructor); +#define switch_core_hash_insert_alloc(_h, _k, _s) switch_core_hash_insert_alloc_destructor(_h, _k, _s, NULL) + +/*! + \brief Insert strdup(data) into a hash + \param hash the hash to add data to + \param key the name of the key to add the data to + \param data string to strdup and add + \return SWITCH_STATUS_SUCCESS if the data is added + \note the string key must be a constant or a dynamic string +*/ +SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_dup_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ const char *str, hashtable_destructor_t destructor); +#define switch_core_hash_insert_dup(_h, _k, _d) switch_core_hash_insert_dup_destructor(_h, _k, _d, NULL) + /*! \brief Insert data into a hash diff --git a/src/mod/applications/mod_hash/mod_hash.c b/src/mod/applications/mod_hash/mod_hash.c index 6899922ab6..70bffd18e1 100644 --- a/src/mod/applications/mod_hash/mod_hash.c +++ b/src/mod/applications/mod_hash/mod_hash.c @@ -144,10 +144,7 @@ SWITCH_LIMIT_INCR(limit_incr_hash) if (!(item = (limit_hash_item_t *) switch_core_hash_find(globals.limit_hash, hashkey))) { /* No, create an empty structure and add it, then continue like as if it existed */ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG10, "Creating new limit structure: key: %s\n", hashkey); - item = (limit_hash_item_t *) malloc(sizeof(limit_hash_item_t)); - switch_assert(item); - memset(item, 0, sizeof(limit_hash_item_t)); - switch_core_hash_insert(globals.limit_hash, hashkey, item); + item = (limit_hash_item_t *)switch_core_hash_insert_alloc(globals.limit_hash, hashkey, sizeof(limit_hash_item_t)); } if (!(pvt = switch_channel_get_private(channel, "limit_hash"))) { @@ -433,17 +430,13 @@ SWITCH_STANDARD_APP(hash_function) free(value); switch_core_hash_delete(globals.db_hash, hash_key); } - value = strdup(argv[3]); - switch_assert(value); - switch_core_hash_insert(globals.db_hash, hash_key, value); + switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]); } else if (!strcasecmp(argv[0], "insert_ifempty")) { if (argc < 4) { goto usage; } if (!(value = switch_core_hash_find(globals.db_hash, hash_key))) { - value = strdup(argv[3]); - switch_assert(value); - switch_core_hash_insert(globals.db_hash, hash_key, value); + switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]); } } else if (!strcasecmp(argv[0], "delete")) { @@ -506,9 +499,7 @@ SWITCH_STANDARD_API(hash_api_function) switch_safe_free(value); switch_core_hash_delete(globals.db_hash, hash_key); } - value = strdup(argv[3]); - switch_assert(value); - switch_core_hash_insert(globals.db_hash, hash_key, value); + switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]); stream->write_function(stream, "+OK\n"); switch_thread_rwlock_unlock(globals.db_hash_rwlock); } else if (!strcasecmp(argv[0], "insert_ifempty")) { @@ -519,9 +510,7 @@ SWITCH_STANDARD_API(hash_api_function) if ((value = switch_core_hash_find(globals.db_hash, hash_key))) { stream->write_function(stream, "-ERR key already exists\n"); } else { - value = strdup(argv[3]); - switch_assert(value); - switch_core_hash_insert(globals.db_hash, hash_key, value); + switch_core_hash_insert_dup(globals.db_hash, hash_key, argv[3]); stream->write_function(stream, "+OK\n"); } switch_thread_rwlock_unlock(globals.db_hash_rwlock); diff --git a/src/switch_core_hash.c b/src/switch_core_hash.c index 70102ce957..06d0475852 100644 --- a/src/switch_core_hash.c +++ b/src/switch_core_hash.c @@ -68,6 +68,45 @@ SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_auto_free(switch_hash_t return SWITCH_STATUS_FALSE; } +SWITCH_DECLARE(void *) switch_core_hash_insert_alloc_destructor(_In_ switch_hash_t *hash, _In_z_ const char *key, _In_opt_ size_t size, hashtable_destructor_t destructor) { + char *dkey; + void *data; + + if (!size) return NULL; + + dkey = strdup(key); + data = malloc(size); + + assert(data); + + if (switch_hashtable_insert_destructor(hash, dkey, data, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_DUP_CHECK, destructor)) { + memset(data, 0, size); + return data; + } + + free(data); + switch_safe_free(dkey); + + return NULL; +} + +SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_dup_destructor(switch_hash_t *hash, const char *key, const char *str, hashtable_destructor_t destructor) +{ + char *dkey = strdup(key); + char *dup = strdup(str); + + assert(dup); + + if (switch_hashtable_insert_destructor(hash, dkey, (void *)dup, HASHTABLE_FLAG_FREE_KEY | HASHTABLE_DUP_CHECK, destructor)) { + return SWITCH_STATUS_SUCCESS; + } + + switch_safe_free(dup); + switch_safe_free(dkey); + + return SWITCH_STATUS_FALSE; +} + SWITCH_DECLARE(switch_status_t) switch_core_hash_insert_destructor(switch_hash_t *hash, const char *key, const void *data, hashtable_destructor_t destructor) { char *dkey = strdup(key); diff --git a/tests/unit/switch_core.c b/tests/unit/switch_core.c index 0e914fa070..af52ab9495 100644 --- a/tests/unit/switch_core.c +++ b/tests/unit/switch_core.c @@ -267,6 +267,53 @@ FST_CORE_BEGIN("./conf") fst_check_int_equals(switch_safe_atoll(0, 3), 3); } FST_TEST_END() + + FST_TEST_BEGIN(test_switch_core_hash_insert_dup) + { + char *magicnumber = malloc(9); + switch_hash_index_t *hi; + switch_hash_t *hash = NULL; + void *hash_val; + switch_core_hash_init(&hash); + fst_requires(hash); + + snprintf(magicnumber, 9, "%s", "DEADBEEF"); + switch_core_hash_insert_dup(hash, "test", (const char *)magicnumber); + snprintf(magicnumber, 9, "%s", "BAADF00D"); + + hi = switch_core_hash_first(hash); + switch_core_hash_this(hi, NULL, NULL, &hash_val); + fst_check_string_equals(hash_val, "DEADBEEF"); + switch_safe_free(hash_val); + free(magicnumber); + free(hi); + switch_core_hash_destroy(&hash); + fst_requires(hash == NULL); + } + FST_TEST_END() + + FST_TEST_BEGIN(test_switch_core_hash_insert_alloc) + { + char *item; + switch_hash_index_t *hi; + switch_hash_t *hash = NULL; + void *hash_val; + switch_core_hash_init(&hash); + fst_requires(hash); + + item = switch_core_hash_insert_alloc(hash, "test", 10); + fst_requires(item); + snprintf(item, 9, "%s", "DEADBEEF"); + + hi = switch_core_hash_first(hash); + switch_core_hash_this(hi, NULL, NULL, &hash_val); + fst_check_string_equals(hash_val, "DEADBEEF"); + free(hi); + switch_core_hash_destroy(&hash); + fst_requires(hash == NULL); + free(item); + } + FST_TEST_END() } FST_SUITE_END() }