From 052972082acd6218ab167fd749dfeb9be17df284 Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 31 Jan 2025 08:48:19 -0400 Subject: [PATCH] MT#62053 generalise config loading Switch from specialised handling of config sections (used to load signalling templates) to a more general approach using a callback mechanism. This allows us to add more information to the config file while keeping the details of the underlying GKeyFile hidden. Use a typed hash table for type safety. Change-Id: I71ddfda0202b47df363bcc5acf1725078774f8f1 --- daemon/call_interfaces.c | 14 +++++++------- daemon/main.c | 18 ++++++++++++++---- include/call_interfaces.h | 2 +- lib/auxlib.c | 35 +++++++++++++++++++++++++---------- lib/auxlib.h | 32 +++++++++++++++++++++++++++++--- t/test-stats.c | 2 +- 6 files changed, 77 insertions(+), 26 deletions(-) diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index 455c06c39..d7a181df9 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -4188,14 +4188,14 @@ void call_interfaces_free(void) { t_hash_table_destroy(rtpe_signalling_templates); } -static void parse_templates(GHashTable *templates) { - if (!templates) +static void parse_templates(charp_ht templates) { + if (!t_hash_table_is_set(templates)) return; - GHashTableIter iter; - g_hash_table_iter_init(&iter, templates); - void *keyp, *valuep; - while (g_hash_table_iter_next(&iter, &keyp, &valuep)) { + charp_ht_iter iter; + t_hash_table_iter_init(&iter, templates); + char *keyp, *valuep; + while (t_hash_table_iter_next(&iter, &keyp, &valuep)) { char *key = keyp; char *value = valuep; t_hash_table_insert(rtpe_signalling_templates, str_dup(STR_PTR(key)), str_dup(STR_PTR(value))); @@ -4215,7 +4215,7 @@ static void parse_templates(GHashTable *templates) { rtpe_default_signalling_templates[OP_OTHER] = *tmpl; } -int call_interfaces_init(GHashTable *templates) { +int call_interfaces_init(charp_ht templates) { int errcode; PCRE2_SIZE erroff; diff --git a/daemon/main.c b/daemon/main.c index 21881aae6..ca55440ef 100644 --- a/daemon/main.c +++ b/daemon/main.c @@ -492,7 +492,7 @@ static void release_listeners(GQueue *q) { } -static void options(int *argc, char ***argv, GHashTable *templates) { +static void options(int *argc, char ***argv, charp_ht templates) { g_autoptr(char_p) if_a = NULL; g_autoptr(char_p) ks_a = NULL; long int_keyspace_db; @@ -730,7 +730,17 @@ static void options(int *argc, char ***argv, GHashTable *templates) { config_load_ext(argc, argv, e, " - next-generation media proxy", "/etc/rtpengine/rtpengine.conf", "rtpengine", &rtpe_config.common, - &templates_section, templates); + (struct rtpenging_config_callback []) { + { + .type = RCC_SECTION_KEYS, + .arg.ht = templates, + .section_keys = { + .name = &templates_section, + .callback = add_c_str_to_ht, + }, + }, + { 0 }, + }); // default values, if not configured if (rtpe_config.rec_method == NULL) @@ -1319,7 +1329,7 @@ fallback: } -static void init_everything(GHashTable *templates) { +static void init_everything(charp_ht templates) { bufferpool_init(); gettimeofday(&rtpe_now, NULL); log_init(rtpe_common_config_ptr->log_name); @@ -1585,7 +1595,7 @@ static void uring_poller_loop(void *ptr) { int main(int argc, char **argv) { early_init(); { - g_autoptr(GHashTable) templates = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + g_auto(charp_ht) templates = charp_ht_new(); options(&argc, &argv, templates); init_everything(templates); } diff --git a/include/call_interfaces.h b/include/call_interfaces.h index 2e019a2fa..e2870a613 100644 --- a/include/call_interfaces.h +++ b/include/call_interfaces.h @@ -323,7 +323,7 @@ void call_unlock_release(call_t *c); G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(sdp_ng_flags, call_ng_free_flags) G_DEFINE_AUTOPTR_CLEANUP_FUNC(call_t, call_unlock_release) -int call_interfaces_init(GHashTable *); +int call_interfaces_init(charp_ht); void call_interfaces_free(void); void call_interfaces_timer(void); diff --git a/lib/auxlib.c b/lib/auxlib.c index 59781f887..2f3c3d184 100644 --- a/lib/auxlib.c +++ b/lib/auxlib.c @@ -155,20 +155,26 @@ void config_load_free(struct rtpengine_common_config *cconfig) { g_free(cconfig->pidfile); } -static void load_templates(GKeyFile *kf, const char *template_section, GHashTable *templates) { - size_t length; +static void section_keys_callback(GKeyFile *kf, + const char *section_name, + void (*callback)(const char *key, char *value, union rtpenging_config_callback_arg), + union rtpenging_config_callback_arg arg) +{ + if (!section_name) + return; + g_autoptr(GError) err = NULL; - g_autoptr(char_p) keys = g_key_file_get_keys(kf, template_section, &length, &err); + g_autoptr(char_p) keys = g_key_file_get_keys(kf, section_name, NULL, &err); if (err) - die("Failed to load templates from given config file section '%s': %s", template_section, err->message); + die("Failed to load keys from given config file section '%s': %s", section_name, err->message); if (!keys) return; // empty config section for (char **key = keys; *key; key++) { - char *val = g_key_file_get_string(kf, template_section, *key, &err); + char *val = g_key_file_get_string(kf, section_name, *key, &err); if (err) - die("Failed to read template value '%s' from config file: %s", *key, err->message); - g_hash_table_insert(templates, g_strdup(*key), val); // hash table takes ownership of both + die("Failed to read config value '%s' (section '%s') from config file: %s", *key, section_name, err->message); + callback(*key, val, arg); } } @@ -179,7 +185,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(char_p_shallow, g_free) void config_load_ext(int *argc, char ***argv, GOptionEntry *app_entries, const char *description, char *default_config, char *default_section, struct rtpengine_common_config *cconfig, - char * const *template_section, GHashTable *templates) + const struct rtpenging_config_callback *callbacks) { g_autoptr(GOptionContext) c = NULL; g_autoptr(GError) er = NULL; @@ -380,8 +386,17 @@ void config_load_ext(int *argc, char ***argv, GOptionEntry *app_entries, const c } } - if (template_section && *template_section && templates) - load_templates(kf, *template_section, templates); + for (const struct rtpenging_config_callback *cb = callbacks; cb; cb++) { + switch (cb->type) { + case RCC_END: + break; + + case RCC_SECTION_KEYS: + section_keys_callback(kf, *cb->section_keys.name, cb->section_keys.callback, cb->arg); + continue; + } + break; + } out: // default common values, if not configured diff --git a/lib/auxlib.h b/lib/auxlib.h index 8416f5398..31afe709a 100644 --- a/lib/auxlib.h +++ b/lib/auxlib.h @@ -49,6 +49,30 @@ struct rtpengine_common_config { extern struct rtpengine_common_config *rtpe_common_config_ptr; +INLINE unsigned int c_str_hash(const char *s); +INLINE gboolean c_str_equal(const char *a, const char *b); + +TYPED_GHASHTABLE(charp_ht, char, char, c_str_hash, c_str_equal, g_free, g_free) + +union rtpenging_config_callback_arg { + charp_ht ht; +} __attribute__((__transparent_union__)); + +struct rtpenging_config_callback { + enum { + RCC_END = 0, + RCC_SECTION_KEYS, + } type; + union rtpenging_config_callback_arg arg; + union { + struct { + char * const *name; + void (*callback)(const char *key, char *value, + union rtpenging_config_callback_arg); + } section_keys; + }; +}; + /*** GLOBALS ***/ @@ -69,12 +93,12 @@ void config_load_free(struct rtpengine_common_config *); void config_load_ext(int *argc, char ***argv, GOptionEntry *entries, const char *description, char *default_config, char *default_section, struct rtpengine_common_config *, - char * const *template_section, GHashTable *templates); + const struct rtpenging_config_callback *); INLINE void config_load(int *argc, char ***argv, GOptionEntry *entries, const char *description, char *default_config, char *default_section, struct rtpengine_common_config *cc) { - config_load_ext(argc, argv, entries, description, default_config, default_section, cc, NULL, NULL); + config_load_ext(argc, argv, entries, description, default_config, default_section, cc, NULL); } char *get_thread_buf(void); @@ -113,7 +137,9 @@ INLINE unsigned int c_str_hash(const char *s) { INLINE gboolean c_str_equal(const char *a, const char *b) { return g_str_equal(a, b); } - +INLINE void add_c_str_to_ht(const char *key, char *value, charp_ht ht) { + t_hash_table_insert(ht, g_strdup(key), value); // hash table takes ownership of both +} /*** MUTEX ABSTRACTION ***/ diff --git a/t/test-stats.c b/t/test-stats.c index c0bdd26bf..3537ae9d8 100644 --- a/t/test-stats.c +++ b/t/test-stats.c @@ -74,7 +74,7 @@ int main(void) { rtpe_ssl_init(); call_init(); statistics_init(); - call_interfaces_init(NULL); + call_interfaces_init(charp_ht_null()); ice_init(); control_ng_init(); dtls_init();