Module: sip-router Branch: tirpi/cfg_framework_multivalue Commit: 8e1d174cc6ddcbdb573e2f6435ed2086d5b1c5ac URL: http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=8e1d174c...
Author: Miklos Tirpak miklos@iptel.org Committer: Miklos Tirpak miklos@iptel.org Date: Thu Sep 9 16:21:41 2010 +0200
cfg framework: group instances can be deleted + bugfix
- cfg_del_group_inst() is added which can be used to delete the group instances apart from the default one. - cfg_find_group_inst() used a wrong offset for shifting. - The copies of the default variable needs to be updated even if the variable is atomic.
---
cfg/cfg_ctx.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++---- cfg/cfg_ctx.h | 3 + cfg/cfg_struct.c | 43 +++++++++++++++++++++- cfg/cfg_struct.h | 7 +++ 4 files changed, 151 insertions(+), 10 deletions(-)
diff --git a/cfg/cfg_ctx.c b/cfg/cfg_ctx.c index b0fa851..3ecc69e 100644 --- a/cfg/cfg_ctx.c +++ b/cfg/cfg_ctx.c @@ -274,10 +274,11 @@ static int cfg_update_defaults(cfg_group_meta_t *meta, int i, clone_done=0; cfg_group_inst_t *array, *ginst;
- array = meta->array; + if (!(array = meta->array)) + return 0; for (i = 0; i < meta->num; i++) { ginst = (cfg_group_inst_t *)((char *)array - + (sizeof(cfg_group_meta_t) + group->size - 1) * i); + + (sizeof(cfg_group_inst_t) + group->size - 1) * i);
if (!CFG_VAR_TEST(ginst, var)) { /* The variable uses the default value, it needs to be rewritten. */ @@ -514,15 +515,15 @@ int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *va it cannot be freed */
if (cfg_shmized) { - if (!group_inst && block && CFG_GROUP_META(block, group)->array) { - if (cfg_update_defaults(CFG_GROUP_META(block, group), + if (!group_inst) { + /* the default value is changed, the copies of this value + need to be also updated */ + if (cfg_update_defaults(CFG_GROUP_META(block ? block : *cfg_global, group), group, var, p, - ((var->def->type & CFG_ATOMIC) == 0)) /* clone if needed */ - ) { - LOG(L_ERR, "ERROR: cfg_set_now(): not enough shm memory\n"); + block ? 1 : 0) /* clone if needed */ + ) goto error; - } - if (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array) + if (block && (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array)) new_array = CFG_GROUP_META(block, group)->array; }
@@ -1338,3 +1339,92 @@ error:
return -1; } + +/* Delete an instance of a group */ +int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id) +{ + cfg_group_t *group; + cfg_block_t *block = NULL; + void **replaced = NULL; + cfg_group_inst_t *new_array = NULL, *group_inst; + + /* verify the context even if we do not need it now + to make sure that a cfg driver has called the function + (very very weak security) */ + if (!ctx) { + LOG(L_ERR, "ERROR: cfg_del_group_inst(): context is undefined\n"); + return -1; + } + + if (!cfg_shmized) { + /* It makes no sense to delete a group instance that has not + been created yet */ + return -1; + } + + if (!(group = cfg_lookup_group(group_name->s, group_name->len))) { + LOG(L_ERR, "ERROR: cfg_del_group_inst(): group not found\n"); + return -1; + } + + /* make sure that nobody else replaces the global config + while the new one is prepared */ + CFG_WRITER_LOCK(); + if (!(group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group), + group->size, + group_id)) + ) { + LOG(L_DBG, "DEBUG: cfg_del_group_inst(): the group instance does not exist\n"); + goto error; + } + + /* clone the global memory block because the additional array can be + replaced only together with the block. */ + if (!(block = cfg_clone_global())) + goto error; + + /* Remove the group instance from the array. */ + if (cfg_collapse_array(CFG_GROUP_META(*cfg_global, group), group, + group_inst, + &new_array) + ) + goto error; + + CFG_GROUP_META(block, group)->array = new_array; + CFG_GROUP_META(block, group)->num--; + + if (CFG_GROUP_META(*cfg_global, group)->array) { + /* prepare the array of the replaced strings, + and replaced group instances, + they will be freed when the old block is freed */ + replaced = (void **)shm_malloc(sizeof(void *) * 2); + if (!replaced) { + LOG(L_ERR, "ERROR: cfg_del_group_inst(): not enough shm memory\n"); + goto error; + } + replaced[0] = CFG_GROUP_META(*cfg_global, group)->array; + replaced[1] = NULL; + } + /* replace the global config with the new one */ + cfg_install_global(block, replaced, NULL, NULL); + CFG_WRITER_UNLOCK(); + + LOG(L_INFO, "INFO: cfg_del_group_inst(): " + "group instance is deleted: %.*s[%u]\n", + group_name->len, group_name->s, + group_id); + + return 0; +error: + CFG_WRITER_UNLOCK(); + if (block) cfg_block_free(block); + if (new_array) shm_free(new_array); + if (replaced) shm_free(replaced); + + LOG(L_ERR, "ERROR: cfg_add_group_inst(): " + "Failed to delete the group instance: %.*s[%u]\n", + group_name->len, group_name->s, + group_id); + + return -1; +} diff --git a/cfg/cfg_ctx.h b/cfg/cfg_ctx.h index 255911e..964e7f5 100644 --- a/cfg/cfg_ctx.h +++ b/cfg/cfg_ctx.h @@ -180,4 +180,7 @@ void cfg_diff_release(cfg_ctx_t *ctx); /* Add a new instance to an existing group */ int cfg_add_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id);
+/* Delete an instance of a group */ +int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id); + #endif /* _CFG_CTX_H */ diff --git a/cfg/cfg_struct.c b/cfg/cfg_struct.c index 77d7cf5..9d5f008 100644 --- a/cfg/cfg_struct.c +++ b/cfg/cfg_struct.c @@ -645,6 +645,47 @@ cfg_group_inst_t *cfg_extend_array(cfg_group_meta_t *meta, cfg_group_t *group, return new_array; }
+/* Remove an instance from a group array. + * inst must point to an instance within meta->array. + * *_new_array is set to the newly allocated array. */ +int cfg_collapse_array(cfg_group_meta_t *meta, cfg_group_t *group, + cfg_group_inst_t *inst, + cfg_group_inst_t **_new_array) +{ + cfg_group_inst_t *new_array, *old_array; + int inst_size, offset; + + if (!meta->num) + return -1; + + if (meta->num == 1) { + *_new_array = NULL; + return 0; + } + + inst_size = sizeof(cfg_group_inst_t) + group->size - 1; + new_array = (cfg_group_inst_t *)shm_malloc(inst_size * (meta->num - 1)); + if (!new_array) { + LOG(L_ERR, "ERROR: cfg_collapse_array(): not enough shm memory\n"); + return -1; + } + + old_array = meta->array; + offset = (char *)inst - (char *)old_array; + if (offset) + memcpy( new_array, + old_array, + offset); + + if (meta->num * inst_size > offset + inst_size) + memcpy( (char *)new_array + offset, + (char *)old_array + offset + inst_size, + (meta->num - 1) * inst_size - offset); + + *_new_array = new_array; + return 0; +} + /* Find the group instance within the meta-data based on the group_id */ cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigned int group_id) { @@ -658,7 +699,7 @@ cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigne TODO: improve */ for (i = 0; i < meta->num; i++) { ginst = (cfg_group_inst_t *)((char *)meta->array - + (sizeof(cfg_group_meta_t) + group_size - 1) * i); + + (sizeof(cfg_group_inst_t) + group_size - 1) * i); if (ginst->id == group_id) return ginst; else if (ginst->id > group_id) diff --git a/cfg/cfg_struct.h b/cfg/cfg_struct.h index 65519e2..5f1fa0a 100644 --- a/cfg/cfg_struct.h +++ b/cfg/cfg_struct.h @@ -381,6 +381,13 @@ cfg_group_inst_t *cfg_extend_array(cfg_group_meta_t *meta, cfg_group_t *group, unsigned int group_id, cfg_group_inst_t **new_group);
+/* Remove an instance from a group array. + * inst must point to an instance within meta->array. + * *_new_array is set to the newly allocated array. */ +int cfg_collapse_array(cfg_group_meta_t *meta, cfg_group_t *group, + cfg_group_inst_t *inst, + cfg_group_inst_t **_new_array); + /* clones a string to shared memory */ int cfg_clone_str(str *src, str *dst);