Module: sip-router
Branch: tirpi/cfg_framework_multivalue
Commit: 28d46c65eaecd623a5e472522fc53564730fe2c8
URL:
http://git.sip-router.org/cgi-bin/gitweb.cgi/sip-router/?a=commit;h=28d46c6…
Author: Miklos Tirpak <miklos(a)iptel.org>
Committer: Miklos Tirpak <miklos(a)iptel.org>
Date: Wed Sep 8 15:26:59 2010 +0200
cfg framework: cfg_add_group_inst() added
The function can add a new group instance to an existing group.
The values of the new instance are identical to the default values
of the group. After the new group instance is added, the values can be
changed by cfg_set_now().
---
cfg/cfg_ctx.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
cfg/cfg_struct.c | 49 +++++++++++++++++++++++++--
cfg/cfg_struct.h | 6 +++
3 files changed, 146 insertions(+), 4 deletions(-)
diff --git a/cfg/cfg_ctx.c b/cfg/cfg_ctx.c
index cc64a0d..1ca2ec9 100644
--- a/cfg/cfg_ctx.c
+++ b/cfg/cfg_ctx.c
@@ -593,6 +593,7 @@ error:
if (block) cfg_block_free(block);
if (new_array) shm_free(new_array);
if (child_cb) cfg_child_cb_free(child_cb);
+ if (replaced) shm_free(replaced);
error0:
LOG(L_ERR, "ERROR: cfg_set_now(): failed to set the variable: %.*s.%.*s\n",
@@ -1219,3 +1220,97 @@ void cfg_diff_release(cfg_ctx_t *ctx)
CFG_CTX_UNLOCK(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)
+{
+ cfg_group_t *group;
+ cfg_block_t *block = NULL;
+ void **replaced = NULL;
+ cfg_group_inst_t *new_array = NULL, *new_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_add_group_inst(): context is undefined\n");
+ return -1;
+ }
+
+ if (!cfg_shmized) {
+ /* TODO: Add a new fake variable belonging to
+ the additional group instance to the linked list. */
+ return -1;
+ }
+
+ if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
+ LOG(L_ERR, "ERROR: cfg_add_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 (cfg_find_group(CFG_GROUP_META(*cfg_global, group),
+ group->size,
+ group_id)
+ ) {
+ LOG(L_DBG, "DEBUG: cfg_add_group_inst(): the group instance already
exists\n");
+ CFG_WRITER_UNLOCK();
+ return 0; /* not an 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;
+
+ /* Extend the array with a new group instance */
+ if (!(new_array = cfg_extend_array(CFG_GROUP_META(*cfg_global, group), group,
+ group_id,
+ &new_inst))
+ )
+ goto error;
+
+ /* fill in the new group instance with the default data */
+ memcpy( new_inst->vars,
+ CFG_GROUP_DATA(*cfg_global, group),
+ sizeof(cfg_group_inst_t) + group->size - 1);
+
+ CFG_GROUP_META(block, group)->array = new_array;
+
+ 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_add_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_add_group_inst(): "
+ "group instance is added: %.*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 add the group instance: %.*s[%u]\n",
+ group_name->len, group_name->s,
+ group_id);
+
+ return -1;
+}
diff --git a/cfg/cfg_struct.c b/cfg/cfg_struct.c
index 3e92080..77d7cf5 100644
--- a/cfg/cfg_struct.c
+++ b/cfg/cfg_struct.c
@@ -584,9 +584,7 @@ cfg_block_t *cfg_clone_global(void)
return block;
}
-/* Clone an array of configuration group instances.
- * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
- */
+/* Clone an array of configuration group instances. */
cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t *group)
{
cfg_group_inst_t *new_array;
@@ -606,6 +604,47 @@ cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t
*group)
return new_array;
}
+/* Extend the array of configuration group instances with one more instance.
+ * Only the ID of the new group is set, nothing else. */
+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)
+{
+ int i;
+ cfg_group_inst_t *new_array, *old_array;
+ int inst_size;
+
+ 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_extend_array(): not enough shm memory\n");
+ return NULL;
+ }
+ /* Find the position of the new group in the array. The array is ordered
+ by the group IDs. */
+ old_array = meta->array;
+ for ( i = 0;
+ (i < meta->num)
+ && (((cfg_group_inst_t *)((char *)old_array + inst_size * i))->id <
group_id);
+ i++
+ );
+ if (i > 0)
+ memcpy( new_array,
+ old_array,
+ inst_size * i);
+
+ memset((char*)new_array + inst_size * i, 0, inst_size);
+ *new_group = (cfg_group_inst_t *)((char*)new_array + inst_size * i);
+ (*new_group)->id = group_id;
+
+ if (i < meta->num)
+ memcpy( (char*)new_array + inst_size * (i + 1),
+ (char*)old_array + inst_size * i,
+ inst_size * (meta->num - i));
+
+ return new_array;
+}
+
/* 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)
{
@@ -615,13 +654,15 @@ cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int
group_size, unsigne
if (!meta)
return NULL;
- /* For now, search lineray till the end of the array.
+ /* For now, search lineray.
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);
if (ginst->id == group_id)
return ginst;
+ else if (ginst->id > group_id)
+ break; /* needless to continue, the array is ordered */
}
return NULL;
}
diff --git a/cfg/cfg_struct.h b/cfg/cfg_struct.h
index 58cd810..65519e2 100644
--- a/cfg/cfg_struct.h
+++ b/cfg/cfg_struct.h
@@ -375,6 +375,12 @@ cfg_block_t *cfg_clone_global(void);
/* Clone an array of configuration group instances. */
cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t *group);
+/* Extend the array of configuration group instances with one more instance.
+ * Only the ID of the new group is set, nothing else. */
+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);
+
/* clones a string to shared memory */
int cfg_clone_str(str *src, str *dst);