4 * Copyright (C) 2007 iptelorg GmbH
6 * This file is part of ser, a free SIP server.
8 * ser is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version
13 * For a license to use the ser software under conditions
14 * other than those described here, or to purchase support for this
15 * software, please contact iptel.org by e-mail at the following addresses:
18 * ser is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 * 2007-12-03 Initial version (Miklos)
34 #include "../mem/mem.h"
35 #include "../mem/shm_mem.h"
37 #include "../locking.h"
39 #include "cfg_struct.h"
41 cfg_group_t *cfg_group = NULL; /* linked list of registered cfg groups */
42 cfg_block_t **cfg_global = NULL; /* pointer to the active cfg block */
43 cfg_block_t *cfg_local = NULL; /* per-process pointer to the active cfg block.
44 Updated only when the child process
45 finishes working on the SIP message */
46 static int cfg_block_size = 0; /* size of the cfg block (constant) */
47 gen_lock_t *cfg_global_lock = 0; /* protects *cfg_global */
48 gen_lock_t *cfg_writer_lock = 0; /* This lock makes sure that two processes do not
49 try to clone *cfg_global at the same time.
50 Never try to get cfg_writer_lock when
51 cfg_global_lock is held */
52 int cfg_shmized = 0; /* indicates whether the cfg block has been
55 cfg_child_cb_t **cfg_child_cb_first = NULL; /* first item of the per-child process
57 cfg_child_cb_t **cfg_child_cb_last = NULL; /* last item of the above list */
58 cfg_child_cb_t *cfg_child_cb = NULL; /* pointer to the previously executed cb */
60 /* creates a new cfg group, and adds it to the linked list */
61 int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
62 char *vars, int size, void **handle)
68 LOG(L_ERR, "ERROR: cfg_new_group(): too late config declaration\n");
73 group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+len-1);
75 LOG(L_ERR, "ERROR: cfg_new_group(): not enough memory\n");
78 memset(group, 0, sizeof(cfg_group_t)+len-1);
81 group->mapping = mapping;
84 group->handle = handle;
85 group->name_len = len;
86 memcpy(&group->name, name, len);
88 /* add the new group to the beginning of the list */
89 group->next = cfg_group;
95 /* clones a string to shared memory */
96 char *cfg_clone_str(str s)
100 c = (char *)shm_malloc(sizeof(char)*(s.len+1));
102 LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
105 memcpy(c, s.s, s.len);
111 /* copies the strings to shared memory */
112 static int cfg_shmize_strings(cfg_group_t *group)
114 cfg_mapping_t *mapping;
118 /* We do not know in advance whether the variable will be changed or not,
119 and it can happen that we try to free the shm memory area when the variable
120 is changed, hence, it must be already in shm mem */
121 mapping = group->mapping;
122 for (i=0; i<group->num; i++) {
123 /* the cfg driver module may have already shmized the variable */
124 if (mapping[i].flag & cfg_var_shmized) continue;
126 if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) {
127 memcpy(&s.s, group->vars + mapping[i].offset, sizeof(char *));
130 } else if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR) {
131 memcpy(&s, group->vars + mapping[i].offset, sizeof(str));
136 if (!(s.s = cfg_clone_str(s))) return -1;
137 memcpy(group->vars + mapping[i].offset, &s.s, sizeof(char *));
138 mapping[i].flag |= cfg_var_shmized;
144 /* copy the variables to shm mem */
148 cfg_block_t *block = NULL;
151 if (!cfg_group) return 0;
153 /* Let us allocate one memory block that
154 will contain all the variables */
155 for ( size=0, group = cfg_group;
159 size = ROUND_POINTER(size);
160 group->offset = size;
164 block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1);
166 LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
169 memset(block, 0, sizeof(cfg_block_t)+size-1);
170 cfg_block_size = size;
172 /* copy the memory fragments to the single block */
173 for ( group = cfg_group;
177 /* clone the strings to shm mem */
178 if (cfg_shmize_strings(group)) goto error;
180 /* copy the values to the new block,
181 and update the module's handle */
182 memcpy(block->vars+group->offset, group->vars, group->size);
183 *(group->handle) = block->vars+group->offset;
186 /* install the new config */
187 cfg_install_global(block, NULL, NULL, NULL);
193 if (block) shm_free(block);
197 /* initiate the cfg framework */
200 cfg_global_lock = lock_alloc();
201 if (!cfg_global_lock) {
202 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
205 if (lock_init(cfg_global_lock) == 0) {
206 LOG(L_ERR, "ERROR: cfg_init(): failed to init lock\n");
207 lock_dealloc(cfg_global_lock);
212 cfg_writer_lock = lock_alloc();
213 if (!cfg_writer_lock) {
214 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
217 if (lock_init(cfg_writer_lock) == 0) {
218 LOG(L_ERR, "ERROR: cfg_init(): failed to init lock\n");
219 lock_dealloc(cfg_writer_lock);
224 cfg_global = (cfg_block_t **)shm_malloc(sizeof(cfg_block_t *));
226 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
231 cfg_child_cb_first = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
232 if (!cfg_child_cb_first) {
233 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
236 *cfg_child_cb_first = NULL;
238 cfg_child_cb_last = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
239 if (!cfg_child_cb_last) {
240 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
243 *cfg_child_cb_last = NULL;
245 /* A new cfg_child_cb struct must be created with a NULL callback function.
246 This stucture will be the entry point for the child processes, and
247 will be freed later, when none of the processes refers to it */
248 *cfg_child_cb_first = *cfg_child_cb_last =
249 cfg_child_cb_new(NULL, NULL);
251 if (!*cfg_child_cb_first) goto error;
261 /* destroy the memory allocated for the cfg framework */
262 void cfg_destroy(void)
264 /* free the contexts */
267 if (cfg_child_cb_first) {
268 if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
269 shm_free(cfg_child_cb_first);
270 cfg_child_cb_first = NULL;
273 if (cfg_child_cb_last) {
274 shm_free(cfg_child_cb_last);
275 cfg_child_cb_last = NULL;
279 if (*cfg_global) cfg_block_free(*cfg_global);
280 shm_free(cfg_global);
283 if (cfg_global_lock) {
284 lock_destroy(cfg_global_lock);
285 lock_dealloc(cfg_global_lock);
288 if (cfg_writer_lock) {
289 lock_destroy(cfg_writer_lock);
290 lock_dealloc(cfg_writer_lock);
295 /* per-child process init function */
296 int cfg_child_init(void)
298 /* set the callback list pointer to the beginning of the list */
299 cfg_child_cb = *cfg_child_cb_first;
300 atomic_inc(&cfg_child_cb->refcnt);
305 /* searches a variable definition by group and variable name */
306 int cfg_lookup_var(str *gname, str *vname,
307 cfg_group_t **group, cfg_mapping_t **var)
316 if ((g->name_len == gname->len)
317 && (memcmp(g->name, gname->s, gname->len)==0)) {
323 if ((g->mapping[i].name_len == vname->len)
324 && (memcmp(g->mapping[i].def->name, vname->s, vname->len)==0)) {
325 if (group) *group = g;
326 if (var) *var = &(g->mapping[i]);
333 LOG(L_ERR, "ERROR: cfg_lookup_var(): variable not found: %.*s.%.*s\n",
334 gname->len, gname->s,
335 vname->len, vname->s);
339 /* clones the global config block
340 * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
342 cfg_block_t *cfg_clone_global(void)
346 block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+cfg_block_size-1);
348 LOG(L_ERR, "ERROR: cfg_clone_global(): not enough shm memory\n");
351 memcpy(block, *cfg_global, sizeof(cfg_block_t)+cfg_block_size-1);
353 /* reset the reference counter */
354 atomic_set(&block->refcnt, 0);
359 /* installs a new global config
361 * replaced is an array of strings that must be freed together
362 * with the previous global config.
363 * cb_first and cb_last define a linked list of per-child process
364 * callbacks. This list is added to the global linked list.
366 void cfg_install_global(cfg_block_t *block, char **replaced,
367 cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
372 if (replaced) (*cfg_global)->replaced = replaced;
373 CFG_UNREF(*cfg_global);
379 /* add the new callbacks to the end of the linked-list */
380 (*cfg_child_cb_last)->next = cb_first;
381 *cfg_child_cb_last = cb_last;
388 /* creates a structure for a per-child process callback */
389 cfg_child_cb_t *cfg_child_cb_new(str *name, cfg_on_set_child cb)
391 cfg_child_cb_t *cb_struct;
393 cb_struct = (cfg_child_cb_t *)shm_malloc(sizeof(cfg_child_cb_t));
395 LOG(L_ERR, "ERROR: cfg_child_cb_new(): not enough shm memory\n");
398 memset(cb_struct, 0, sizeof(cfg_child_cb_t));
400 cb_struct->name.s = name->s;
401 cb_struct->name.len = name->len;
404 atomic_set(&cb_struct->refcnt, 0);
409 /* free the memory allocated for a child cb list */
410 void cfg_child_cb_free(cfg_child_cb_t *child_cb_first)
412 cfg_child_cb_t *cb, *cb_next;
414 for( cb = child_cb_first;