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)
30 * 2008-01-24 dynamic groups are introduced in order to make
31 * variable declaration possible in the script (Miklos)
36 #include "../mem/mem.h"
37 #include "../mem/shm_mem.h"
39 #include "../locking.h"
41 #include "cfg_script.h"
42 #include "cfg_select.h"
43 #include "cfg_struct.h"
45 cfg_group_t *cfg_group = NULL; /* linked list of registered cfg groups */
46 cfg_block_t **cfg_global = NULL; /* pointer to the active cfg block */
47 cfg_block_t *cfg_local = NULL; /* per-process pointer to the active cfg block.
48 Updated only when the child process
49 finishes working on the SIP message */
50 static int cfg_block_size = 0; /* size of the cfg block (constant) */
51 gen_lock_t *cfg_global_lock = 0; /* protects *cfg_global */
52 gen_lock_t *cfg_writer_lock = 0; /* This lock makes sure that two processes do not
53 try to clone *cfg_global at the same time.
54 Never try to get cfg_writer_lock when
55 cfg_global_lock is held */
56 int cfg_shmized = 0; /* indicates whether the cfg block has been
59 cfg_child_cb_t **cfg_child_cb_first = NULL; /* first item of the per-child process
61 cfg_child_cb_t **cfg_child_cb_last = NULL; /* last item of the above list */
62 cfg_child_cb_t *cfg_child_cb = NULL; /* pointer to the previously executed cb */
64 /* creates a new cfg group, and adds it to the linked list */
65 cfg_group_t *cfg_new_group(char *name, int name_len,
66 int num, cfg_mapping_t *mapping,
67 char *vars, int size, void **handle)
72 LOG(L_ERR, "ERROR: cfg_new_group(): too late config declaration\n");
76 group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+name_len-1);
78 LOG(L_ERR, "ERROR: cfg_new_group(): not enough memory\n");
81 memset(group, 0, sizeof(cfg_group_t)+name_len-1);
84 group->mapping = mapping;
87 group->handle = handle;
88 group->name_len = name_len;
89 memcpy(&group->name, name, name_len);
91 /* add the new group to the beginning of the list */
92 group->next = cfg_group;
98 /* clones a string to shared memory
99 * (src and dst can be the same)
101 int cfg_clone_str(str *src, str *dst)
111 c = (char *)shm_malloc(sizeof(char)*(src->len+1));
113 LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
116 memcpy(c, src->s, src->len);
125 /* copies the strings to shared memory */
126 static int cfg_shmize_strings(cfg_group_t *group)
128 cfg_mapping_t *mapping;
132 /* We do not know in advance whether the variable will be changed or not,
133 and it can happen that we try to free the shm memory area when the variable
134 is changed, hence, it must be already in shm mem */
135 mapping = group->mapping;
136 for (i=0; i<group->num; i++) {
137 /* the cfg driver module may have already shmized the variable */
138 if (mapping[i].flag & cfg_var_shmized) continue;
140 if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) {
141 s.s = *(char **)(group->vars + mapping[i].offset);
145 } else if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR) {
146 memcpy(&s, group->vars + mapping[i].offset, sizeof(str));
152 if (cfg_clone_str(&s, &s)) return -1;
153 *(char **)(group->vars + mapping[i].offset) = s.s;
154 mapping[i].flag |= cfg_var_shmized;
160 /* copy the variables to shm mem */
164 cfg_block_t *block = NULL;
167 if (!cfg_group) return 0;
169 /* Let us allocate one memory block that
170 will contain all the variables */
171 for ( size=0, group = cfg_group;
175 size = ROUND_POINTER(size);
176 group->offset = size;
180 block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1);
182 LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
185 memset(block, 0, sizeof(cfg_block_t)+size-1);
186 cfg_block_size = size;
188 /* copy the memory fragments to the single block */
189 for ( group = cfg_group;
193 if (group->dynamic == 0) {
194 /* clone the strings to shm mem */
195 if (cfg_shmize_strings(group)) goto error;
197 /* copy the values to the new block,
198 and update the module's handle */
199 memcpy(block->vars+group->offset, group->vars, group->size);
200 *(group->handle) = block->vars+group->offset;
202 /* The group was declared with NULL values,
203 * we have to fix it up.
204 * The fixup function takes care about the values,
205 * it fills up the block */
206 if (cfg_script_fixup(group, block->vars+group->offset)) goto error;
207 *(group->handle) = block->vars+group->offset;
209 /* notify the drivers about the new config definition */
210 cfg_notify_drivers(group->name, group->name_len,
211 group->mapping->def);
214 /* try to fixup the selects that failed to be fixed-up previously */
215 if (cfg_fixup_selects()) goto error;
217 /* install the new config */
218 cfg_install_global(block, NULL, NULL, NULL);
224 if (block) shm_free(block);
228 /* deallocate the list of groups, and the shmized strings */
229 static void cfg_destory_groups(unsigned char *block)
231 cfg_group_t *group, *group2;
232 cfg_mapping_t *mapping;
239 mapping = group->mapping;
240 def = mapping ? mapping->def : NULL;
242 /* destory the shmized strings in the block */
244 for (i=0; i<group->num; i++)
245 if (((CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) ||
246 (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR)) &&
247 mapping[i].flag & cfg_var_shmized) {
249 old_string = *(char **)(block + group->offset + mapping[i].offset);
250 if (old_string) shm_free(old_string);
253 if (group->dynamic) {
254 /* the group was dynamically allocated */
255 cfg_script_destroy(group);
257 /* only the mapping was allocated, all the other
258 pointers are just set to static variables */
259 if (mapping) pkg_free(mapping);
262 group2 = group->next;
268 /* initiate the cfg framework */
271 cfg_global_lock = lock_alloc();
272 if (!cfg_global_lock) {
273 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
276 if (lock_init(cfg_global_lock) == 0) {
277 LOG(L_ERR, "ERROR: cfg_init(): failed to init lock\n");
278 lock_dealloc(cfg_global_lock);
283 cfg_writer_lock = lock_alloc();
284 if (!cfg_writer_lock) {
285 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
288 if (lock_init(cfg_writer_lock) == 0) {
289 LOG(L_ERR, "ERROR: cfg_init(): failed to init lock\n");
290 lock_dealloc(cfg_writer_lock);
295 cfg_global = (cfg_block_t **)shm_malloc(sizeof(cfg_block_t *));
297 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
302 cfg_child_cb_first = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
303 if (!cfg_child_cb_first) {
304 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
307 *cfg_child_cb_first = NULL;
309 cfg_child_cb_last = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
310 if (!cfg_child_cb_last) {
311 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
314 *cfg_child_cb_last = NULL;
316 /* A new cfg_child_cb struct must be created with a NULL callback function.
317 This stucture will be the entry point for the child processes, and
318 will be freed later, when none of the processes refers to it */
319 *cfg_child_cb_first = *cfg_child_cb_last =
320 cfg_child_cb_new(NULL, NULL);
322 if (!*cfg_child_cb_first) goto error;
332 /* destroy the memory allocated for the cfg framework */
333 void cfg_destroy(void)
335 /* free the contexts */
338 /* free the list of groups */
339 cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
341 /* free the select list */
344 if (cfg_child_cb_first) {
345 if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
346 shm_free(cfg_child_cb_first);
347 cfg_child_cb_first = NULL;
350 if (cfg_child_cb_last) {
351 shm_free(cfg_child_cb_last);
352 cfg_child_cb_last = NULL;
356 if (*cfg_global) cfg_block_free(*cfg_global);
357 shm_free(cfg_global);
360 if (cfg_global_lock) {
361 lock_destroy(cfg_global_lock);
362 lock_dealloc(cfg_global_lock);
365 if (cfg_writer_lock) {
366 lock_destroy(cfg_writer_lock);
367 lock_dealloc(cfg_writer_lock);
372 /* per-child process init function */
373 int cfg_child_init(void)
375 /* set the callback list pointer to the beginning of the list */
376 cfg_child_cb = *cfg_child_cb_first;
377 atomic_inc(&cfg_child_cb->refcnt);
382 /* per-child process destroy function
383 * Should be called only when the child process exits,
384 * but SER continues running
386 * WARNING: this function call must be the very last action
387 * before the child process exits, because the local config
388 * is not available afterwards.
390 void cfg_child_destroy(void)
392 cfg_child_cb_t *prev_cb;
394 /* unref the local config */
396 CFG_UNREF(cfg_local);
400 if (!cfg_child_cb) return;
402 /* The lock must be held to make sure that the global config
403 is not replaced meantime, and the other child processes do not
404 leave the old value of *cfg_child_cb_last. Otherwise it could happen,
405 that all the other processes move their own cfg_child_cb pointer before
406 this process reaches *cfg_child_cb_last, though, it is very unlikely. */
409 /* go through the list and check whether there is any item that
410 has to be freed (similar to cfg_update_local(), but without executing
411 the callback functions) */
412 while (cfg_child_cb != *cfg_child_cb_last) {
413 prev_cb = cfg_child_cb;
414 cfg_child_cb = cfg_child_cb->next;
415 atomic_inc(&cfg_child_cb->refcnt);
416 if (atomic_dec_and_test(&prev_cb->refcnt)) {
417 /* No more pocess refers to this callback.
418 Did this process block the deletion,
419 or is there any other process that has not
420 reached prev_cb yet? */
421 if (*cfg_child_cb_first == prev_cb) {
422 /* yes, this process was blocking the deletion */
423 *cfg_child_cb_first = cfg_child_cb;
427 /* no need to continue, because there is at least
428 one process that stays exactly at the same point
429 in the list, so it will free the items later */
433 atomic_dec(&cfg_child_cb->refcnt);
439 /* searches a group by name */
440 cfg_group_t *cfg_lookup_group(char *name, int len)
448 if ((g->name_len == len)
449 && (memcmp(g->name, name, len)==0))
455 /* searches a variable definition by group and variable name */
456 int cfg_lookup_var(str *gname, str *vname,
457 cfg_group_t **group, cfg_mapping_t **var)
466 if ((g->name_len == gname->len)
467 && (memcmp(g->name, gname->s, gname->len)==0)) {
469 if (!g->mapping) return -1; /* dynamic group is not ready */
475 if ((g->mapping[i].name_len == vname->len)
476 && (memcmp(g->mapping[i].def->name, vname->s, vname->len)==0)) {
477 if (group) *group = g;
478 if (var) *var = &(g->mapping[i]);
485 LOG(L_ERR, "ERROR: cfg_lookup_var(): variable not found: %.*s.%.*s\n",
486 gname->len, gname->s,
487 vname->len, vname->s);
491 /* clones the global config block
492 * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
494 cfg_block_t *cfg_clone_global(void)
498 block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+cfg_block_size-1);
500 LOG(L_ERR, "ERROR: cfg_clone_global(): not enough shm memory\n");
503 memcpy(block, *cfg_global, sizeof(cfg_block_t)+cfg_block_size-1);
505 /* reset the reference counter */
506 atomic_set(&block->refcnt, 0);
511 /* append new callbacks to the end of the child callback list
513 * WARNING: the function is unsafe, either hold CFG_LOCK(),
514 * or call the function before forking
516 void cfg_install_child_cb(cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
518 /* add the new callbacks to the end of the linked-list */
519 (*cfg_child_cb_last)->next = cb_first;
520 *cfg_child_cb_last = cb_last;
523 /* installs a new global config
525 * replaced is an array of strings that must be freed together
526 * with the previous global config.
527 * cb_first and cb_last define a linked list of per-child process
528 * callbacks. This list is added to the global linked list.
530 void cfg_install_global(cfg_block_t *block, char **replaced,
531 cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
533 cfg_block_t* old_cfg;
539 old_cfg = *cfg_global;
543 cfg_install_child_cb(cb_first, cb_last);
548 if (replaced) (old_cfg)->replaced = replaced;
554 /* creates a structure for a per-child process callback */
555 cfg_child_cb_t *cfg_child_cb_new(str *name, cfg_on_set_child cb)
557 cfg_child_cb_t *cb_struct;
559 cb_struct = (cfg_child_cb_t *)shm_malloc(sizeof(cfg_child_cb_t));
561 LOG(L_ERR, "ERROR: cfg_child_cb_new(): not enough shm memory\n");
564 memset(cb_struct, 0, sizeof(cfg_child_cb_t));
566 cb_struct->name.s = name->s;
567 cb_struct->name.len = name->len;
570 atomic_set(&cb_struct->refcnt, 0);
575 /* free the memory allocated for a child cb list */
576 void cfg_child_cb_free(cfg_child_cb_t *child_cb_first)
578 cfg_child_cb_t *cb, *cb_next;
580 for( cb = child_cb_first;