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=8e1d174…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)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);