1 /*
2 * Copyright (C) 2007 iptelorg GmbH
3 *
4 * This file is part of Kamailio, a free SIP server.
5 *
6 * Kamailio is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version
10 *
11 * Kamailio is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 */
21
22 #include <string.h>
23
24 #include "../mem/mem.h"
25 #include "../mem/shm_mem.h"
26 #include "../ut.h"
27 #include "../locking.h"
28 #include "../bit_scan.h"
29 #include "cfg_ctx.h"
30 #include "cfg_script.h"
31 #include "cfg_select.h"
32 #include "cfg_struct.h"
33
34 cfg_group_t *cfg_group = NULL; /* linked list of registered cfg groups */
35 cfg_block_t **cfg_global = NULL; /* pointer to the active cfg block */
36 cfg_block_t *cfg_local = NULL; /* per-process pointer to the active cfg block.
37 * Updated only when the child process
38 * finishes working on the SIP message */
39 int cfg_block_size = 0; /* size of the cfg block including the meta-data (constant) */
40 gen_lock_t *cfg_global_lock = 0; /* protects *cfg_global */
41 gen_lock_t *cfg_writer_lock = 0; /* This lock makes sure that two processes do not
42 * try to clone *cfg_global at the same time.
43 * Never try to get cfg_writer_lock when
44 * cfg_global_lock is held */
45 int cfg_shmized = 0; /* indicates whether the cfg block has been
46 * already shmized */
47
48 cfg_child_cb_t **cfg_child_cb_first = NULL; /* first item of the per-child process
49 * callback list */
50 cfg_child_cb_t **cfg_child_cb_last = NULL; /* last item of the above list */
51 cfg_child_cb_t *cfg_child_cb = NULL; /* pointer to the previously executed cb */
52 int cfg_ginst_count = 0; /* number of group instances set within the child process */
53
54
55 /* forward declarations */
56 static void del_add_var_list(cfg_group_t *group);
57 static int apply_add_var_list(cfg_block_t *block, cfg_group_t *group);
58
59 /* creates a new cfg group, and adds it to the linked list */
cfg_new_group(char * name,int name_len,int num,cfg_mapping_t * mapping,char * vars,int size,void ** handle)60 cfg_group_t *cfg_new_group(char *name, int name_len,
61 int num, cfg_mapping_t *mapping,
62 char *vars, int size, void **handle)
63 {
64 cfg_group_t *group;
65
66 if (cfg_shmized) {
67 LM_ERR("too late config declaration\n");
68 return NULL;
69 }
70
71 if (num > CFG_MAX_VAR_NUM) {
72 LM_ERR("too many variables (%d) within a single group,"
73 " the limit is %d. Increase CFG_MAX_VAR_NUM, or split the group"
74 " into multiple definitions.\n",
75 num, CFG_MAX_VAR_NUM);
76 return NULL;
77 }
78
79 group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+name_len-1);
80 if (!group) {
81 PKG_MEM_ERROR;
82 return NULL;
83 }
84 memset(group, 0, sizeof(cfg_group_t)+name_len-1);
85
86 group->num = num;
87 group->mapping = mapping;
88 group->vars = vars;
89 group->size = size;
90 group->handle = handle;
91 if (handle)
92 group->orig_handle = *handle;
93 group->name_len = name_len;
94 memcpy(&group->name, name, name_len);
95
96 /* add the new group to the beginning of the list */
97 group->next = cfg_group;
98 cfg_group = group;
99
100 return group;
101 }
102
103 /* Set the values of an existing cfg group. */
cfg_set_group(cfg_group_t * group,int num,cfg_mapping_t * mapping,char * vars,int size,void ** handle)104 void cfg_set_group(cfg_group_t *group,
105 int num, cfg_mapping_t *mapping,
106 char *vars, int size, void **handle)
107 {
108 group->num = num;
109 group->mapping = mapping;
110 group->vars = vars;
111 group->size = size;
112 group->handle = handle;
113 if (handle)
114 group->orig_handle = *handle;
115 }
116
117 /* clones a string to shared memory
118 * (src and dst can be the same)
119 */
cfg_clone_str(str * src,str * dst)120 int cfg_clone_str(str *src, str *dst)
121 {
122 char *c;
123
124 if (!src->s) {
125 dst->s = NULL;
126 dst->len = 0;
127 return 0;
128 }
129
130 c = (char *)shm_malloc(sizeof(char)*(src->len+1));
131 if (!c) {
132 SHM_MEM_ERROR;
133 return -1;
134 }
135 memcpy(c, src->s, src->len);
136 c[src->len] = '\0';
137
138 dst->s = c;
139 dst->len = src->len;
140
141 return 0;
142 }
143
144 /* copies the strings to shared memory */
cfg_shmize_strings(cfg_group_t * group)145 static int cfg_shmize_strings(cfg_group_t *group)
146 {
147 cfg_mapping_t *mapping;
148 int i;
149 str s;
150
151 /* We do not know in advance whether the variable will be changed or not,
152 * and it can happen that we try to free the shm memory area when
153 * the variable is changed, hence, it must be already in shm mem */
154 mapping = group->mapping;
155 for (i=0; i<group->num; i++) {
156 /* the cfg driver module may have already shmized the variable */
157 if (mapping[i].flag & cfg_var_shmized) continue;
158
159 if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) {
160 s.s = *(char **)(group->vars + mapping[i].offset);
161 if (!s.s) continue;
162 s.len = strlen(s.s);
163
164 } else if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR) {
165 memcpy(&s, group->vars + mapping[i].offset, sizeof(str));
166 if (!s.s) continue;
167
168 } else {
169 continue;
170 }
171 if (cfg_clone_str(&s, &s)) return -1;
172 *(char **)(group->vars + mapping[i].offset) = s.s;
173 mapping[i].flag |= cfg_var_shmized;
174 }
175
176 return 0;
177 }
178
179 /* copy the variables to shm mem */
cfg_shmize(void)180 int cfg_shmize(void)
181 {
182 cfg_group_t *group;
183 cfg_block_t *block = NULL;
184 int size;
185
186 if (!cfg_group) return 0;
187
188 /* Let us allocate one memory block that
189 * will contain all the variables + meta-data
190 * in the following form:
191 * |-----------|
192 * | meta-data | <- group A: meta_offset
193 * | variables | <- group A: var_offset
194 * |-----------|
195 * | meta-data | <- group B: meta_offset
196 * | variables | <- group B: var_offset
197 * |-----------|
198 * | ... |
199 * |-----------|
200 *
201 * The additional array for the multiple values
202 * of the same variable is linked to the meta-data.
203 */
204 for (size=0, group = cfg_group;
205 group;
206 group=group->next
207 ) {
208 size = ROUND_POINTER(size);
209 group->meta_offset = size;
210 size += sizeof(cfg_group_meta_t);
211
212 size = ROUND_POINTER(size);
213 group->var_offset = size;
214 size += group->size;
215 }
216
217 block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1);
218 if (!block) {
219 SHM_MEM_ERROR;
220 goto error;
221 }
222 memset(block, 0, sizeof(cfg_block_t)+size-1);
223 cfg_block_size = size;
224
225 /* copy the memory fragments to the single block */
226 for ( group = cfg_group;
227 group;
228 group=group->next
229 ) {
230 if (group->dynamic == CFG_GROUP_STATIC) {
231 /* clone the strings to shm mem */
232 if (cfg_shmize_strings(group)) goto error;
233
234 /* copy the values to the new block */
235 memcpy(CFG_GROUP_DATA(block, group), group->vars, group->size);
236 } else if (group->dynamic == CFG_GROUP_DYNAMIC) {
237 /* The group was declared with NULL values,
238 * we have to fix it up.
239 * The fixup function takes care about the values,
240 * it fills up the block */
241 if (cfg_script_fixup(group, CFG_GROUP_DATA(block, group))) goto error;
242
243 /* Notify the drivers about the new config definition.
244 * Temporary set the group handle so that the drivers have a chance to
245 * overwrite the default values. The handle must be reset after this
246 * because the main process does not have a local configuration. */
247 *(group->handle) = CFG_GROUP_DATA(block, group);
248 cfg_notify_drivers(group->name, group->name_len,
249 group->mapping->def);
250 *(group->handle) = NULL;
251 } else {
252 LM_ERR("configuration group is declared without any variable: %.*s\n",
253 group->name_len, group->name);
254 goto error;
255 }
256
257 /* Create the additional group instances with applying
258 * the temporary list. */
259 if (apply_add_var_list(block, group))
260 goto error;
261 }
262
263 /* try to fixup the selects that failed to be fixed-up previously */
264 if (cfg_fixup_selects()) goto error;
265
266 /* install the new config */
267 cfg_install_global(block, NULL, NULL, NULL);
268 cfg_shmized = 1;
269
270 return 0;
271
272 error:
273 if (block) shm_free(block);
274 return -1;
275 }
276
277 /* deallocate the list of groups, and the shmized strings */
cfg_destory_groups(unsigned char * block)278 static void cfg_destory_groups(unsigned char *block)
279 {
280 cfg_group_t *group, *group2;
281 cfg_mapping_t *mapping;
282 cfg_def_t *def;
283 void *old_string;
284 int i;
285
286 group = cfg_group;
287 while(group) {
288 mapping = group->mapping;
289 def = mapping ? mapping->def : NULL;
290
291 /* destory the shmized strings in the block */
292 if (block && def)
293 for (i=0; i<group->num; i++)
294 if (((CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) ||
295 (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR)) &&
296 mapping[i].flag & cfg_var_shmized) {
297
298 old_string = *(char **)(block + group->var_offset + mapping[i].offset);
299 if (old_string) shm_free(old_string);
300 }
301
302 if (group->dynamic == CFG_GROUP_DYNAMIC) {
303 /* the group was dynamically allocated */
304 cfg_script_destroy(group);
305 } else {
306 /* only the mapping was allocated, all the other
307 * pointers are just set to static variables */
308 if (mapping) pkg_free(mapping);
309 }
310 /* Delete the additional variable list */
311 del_add_var_list(group);
312
313 group2 = group->next;
314 pkg_free(group);
315 group = group2;
316 }
317 }
318
319 /* initiate the cfg framework */
sr_cfg_init(void)320 int sr_cfg_init(void)
321 {
322 /* lock_alloc() is a define for shm_malloc */
323 cfg_global_lock = lock_alloc();
324 if (!cfg_global_lock) {
325 SHM_MEM_ERROR;
326 goto error;
327 }
328 if (lock_init(cfg_global_lock) == 0) {
329 LM_ERR("failed to init lock\n");
330 lock_dealloc(cfg_global_lock);
331 cfg_global_lock = 0;
332 goto error;
333 }
334
335 cfg_writer_lock = lock_alloc();
336 if (!cfg_writer_lock) {
337 SHM_MEM_ERROR;
338 goto error;
339 }
340 if (lock_init(cfg_writer_lock) == 0) {
341 LM_ERR("failed to init lock\n");
342 lock_dealloc(cfg_writer_lock);
343 cfg_writer_lock = 0;
344 goto error;
345 }
346
347 cfg_global = (cfg_block_t **)shm_malloc(sizeof(cfg_block_t *));
348 if (!cfg_global) {
349 SHM_MEM_ERROR;
350 goto error;
351 }
352 *cfg_global = NULL;
353
354 cfg_child_cb_first = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
355 if (!cfg_child_cb_first) {
356 SHM_MEM_ERROR;
357 goto error;
358 }
359 *cfg_child_cb_first = NULL;
360
361 cfg_child_cb_last = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
362 if (!cfg_child_cb_last) {
363 SHM_MEM_ERROR;
364 goto error;
365 }
366 *cfg_child_cb_last = NULL;
367
368 /* A new cfg_child_cb struct must be created with a NULL callback function.
369 * This stucture will be the entry point for the child processes, and
370 * will be freed later, when none of the processes refers to it */
371 *cfg_child_cb_first = *cfg_child_cb_last =
372 cfg_child_cb_new(NULL, NULL, NULL, 0);
373
374 if (!*cfg_child_cb_first) goto error;
375
376 return 0;
377
378 error:
379 cfg_destroy();
380
381 return -1;
382 }
383
384 /* destroy the memory allocated for the cfg framework */
cfg_destroy(void)385 void cfg_destroy(void)
386 {
387 /* free the contexts */
388 cfg_ctx_destroy();
389
390 /* free the list of groups */
391 cfg_destory_groups((cfg_global && (*cfg_global)) ? (*cfg_global)->vars : NULL);
392
393 /* free the select list */
394 cfg_free_selects();
395
396 if (cfg_child_cb_first) {
397 if (*cfg_child_cb_first) cfg_child_cb_free_list(*cfg_child_cb_first);
398 shm_free(cfg_child_cb_first);
399 cfg_child_cb_first = NULL;
400 }
401
402 if (cfg_child_cb_last) {
403 shm_free(cfg_child_cb_last);
404 cfg_child_cb_last = NULL;
405 }
406
407 if (cfg_global) {
408 if (*cfg_global) cfg_block_free(*cfg_global);
409 shm_free(cfg_global);
410 cfg_global = NULL;
411 }
412 if (cfg_global_lock) {
413 lock_destroy(cfg_global_lock);
414 lock_dealloc(cfg_global_lock);
415 cfg_global_lock = 0;
416 }
417 if (cfg_writer_lock) {
418 lock_destroy(cfg_writer_lock);
419 lock_dealloc(cfg_writer_lock);
420 cfg_writer_lock = 0;
421 }
422 }
423
424 /* Register num number of child processes that will
425 * keep updating their local configuration.
426 * This function needs to be called from mod_init
427 * before any child process is forked.
428 */
cfg_register_child(int num)429 void cfg_register_child(int num)
430 {
431 /* Increase the reference counter of the first list item
432 * with the number of child processes.
433 * If the counter was increased after forking then it
434 * could happen that a child process is forked and updates
435 * its local config very fast before the other processes have
436 * a chance to refer to the list item. The result is that the
437 * item is freed by the "fast" child process and the other
438 * processes do not see the beginning of the list and miss
439 * some config changes.
440 */
441 atomic_add(&((*cfg_child_cb_first)->refcnt), num);
442 }
443
444 /* per-child process init function.
445 * It needs to be called from the forked process.
446 * cfg_register_child() must be called before this function!
447 */
cfg_child_init(void)448 int cfg_child_init(void)
449 {
450 /* set the callback list pointer to the beginning of the list */
451 cfg_child_cb = *cfg_child_cb_first;
452
453 return 0;
454 }
455
456 /* Child process init function that can be called
457 * without cfg_register_child().
458 * Note that the child process may miss some configuration changes.
459 */
cfg_late_child_init(void)460 int cfg_late_child_init(void)
461 {
462 /* set the callback list pointer to the beginning of the list */
463 CFG_LOCK();
464 atomic_inc(&((*cfg_child_cb_first)->refcnt));
465 cfg_child_cb = *cfg_child_cb_first;
466 CFG_UNLOCK();
467
468 return 0;
469 }
470
471
472 /* per-child init function for non-cb executing processes.
473 * Mark this process as not wanting to execute any per-child config
474 * callback (it will have only limited config functionality, but is useful
475 * when a process needs only to watch some non-callback cfg. values,
476 * e.g. the main attendant process, debug and memlog).
477 * It needs to be called from the forked process.
478 * cfg_register_child must _not_ be called.
479 */
cfg_child_no_cb_init(void)480 int cfg_child_no_cb_init(void)
481 {
482 /* set the callback list pointer to the beginning of the list */
483 cfg_child_cb = CFG_NO_CHILD_CBS;
484 return 0;
485 }
486
487 /* per-child process destroy function
488 * Should be called only when the child process exits,
489 * but SER continues running
490 *
491 * WARNING: this function call must be the very last action
492 * before the child process exits, because the local config
493 * is not available afterwards.
494 */
cfg_child_destroy(void)495 void cfg_child_destroy(void)
496 {
497 cfg_child_cb_t *prev_cb;
498
499 /* unref the local config */
500 if (cfg_local) {
501 CFG_UNREF(cfg_local);
502 cfg_local = NULL;
503 }
504
505 if (!cfg_child_cb || cfg_child_cb==CFG_NO_CHILD_CBS) return;
506
507 /* The lock must be held to make sure that the global config
508 * is not replaced meantime, and the other child processes do not
509 * leave the old value of *cfg_child_cb_last. Otherwise it could happen,
510 * that all the other processes move their own cfg_child_cb pointer before
511 * this process reaches *cfg_child_cb_last, though, it is very unlikely. */
512 CFG_LOCK();
513
514 /* go through the list and check whether there is any item that
515 * has to be freed (similar to cfg_update_local(), but without executing
516 * the callback functions) */
517 while (cfg_child_cb != *cfg_child_cb_last) {
518 prev_cb = cfg_child_cb;
519 cfg_child_cb = cfg_child_cb->next;
520 atomic_inc(&cfg_child_cb->refcnt);
521 if (atomic_dec_and_test(&prev_cb->refcnt)) {
522 /* No more pocess refers to this callback.
523 * Did this process block the deletion,
524 * or is there any other process that has not
525 * reached prev_cb yet? */
526 if (*cfg_child_cb_first == prev_cb) {
527 /* yes, this process was blocking the deletion */
528 *cfg_child_cb_first = cfg_child_cb;
529 cfg_child_cb_free_item(prev_cb);
530 }
531 } else {
532 /* no need to continue, because there is at least
533 * one process that stays exactly at the same point
534 * in the list, so it will free the items later */
535 break;
536 }
537 }
538 atomic_dec(&cfg_child_cb->refcnt);
539
540 CFG_UNLOCK();
541 cfg_child_cb = NULL;
542 }
543
544 /* searches a group by name */
cfg_lookup_group(char * name,int len)545 cfg_group_t *cfg_lookup_group(char *name, int len)
546 {
547 cfg_group_t *g;
548
549 for ( g = cfg_group;
550 g;
551 g = g->next
552 )
553 if ((g->name_len == len)
554 && (memcmp(g->name, name, len)==0))
555 return g;
556
557 return NULL;
558 }
559
560 /* searches a variable definition by group and variable name */
cfg_lookup_var(str * gname,str * vname,cfg_group_t ** group,cfg_mapping_t ** var)561 int cfg_lookup_var(str *gname, str *vname,
562 cfg_group_t **group, cfg_mapping_t **var)
563 {
564 cfg_group_t *g;
565 int i;
566
567 for (g = cfg_group;
568 g;
569 g = g->next
570 )
571 if ((g->name_len == gname->len)
572 && (memcmp(g->name, gname->s, gname->len)==0)) {
573
574 if (!g->mapping) return -1; /* dynamic group is not ready */
575
576 for ( i = 0;
577 i < g->num;
578 i++
579 ) {
580 if ((g->mapping[i].name_len == vname->len)
581 && (memcmp(g->mapping[i].def->name, vname->s, vname->len)==0)) {
582 if (group) *group = g;
583 if (var) *var = &(g->mapping[i]);
584 return 0;
585 }
586 }
587 break;
588 }
589
590 LM_DBG("variable not found: %.*s.%.*s\n",
591 gname->len, gname->s,
592 vname->len, vname->s);
593 return -1;
594 }
595
596 /* searches a variable definition within a group by its name */
cfg_lookup_var2(cfg_group_t * group,char * name,int len)597 cfg_mapping_t *cfg_lookup_var2(cfg_group_t *group, char *name, int len)
598 {
599 int i;
600
601 if (!group->mapping) return NULL; /* dynamic group is not ready */
602
603 for ( i = 0;
604 i < group->num;
605 i++
606 ) {
607 if ((group->mapping[i].name_len == len)
608 && (memcmp(group->mapping[i].def->name, name, len)==0)) {
609 return &(group->mapping[i]);
610 }
611 }
612
613 LM_DBG("variable not found: %.*s.%.*s\n",
614 group->name_len, group->name,
615 len, name);
616 return NULL;
617 }
618
619 /* clones the global config block
620 * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
621 */
cfg_clone_global(void)622 cfg_block_t *cfg_clone_global(void)
623 {
624 cfg_block_t *block;
625
626 block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+cfg_block_size-1);
627 if (!block) {
628 SHM_MEM_ERROR;
629 return NULL;
630 }
631 memcpy(block, *cfg_global, sizeof(cfg_block_t)+cfg_block_size-1);
632
633 /* reset the reference counter */
634 atomic_set(&block->refcnt, 0);
635
636 return block;
637 }
638
639 /* Clone an array of configuration group instances. */
cfg_clone_array(cfg_group_meta_t * meta,cfg_group_t * group)640 cfg_group_inst_t *cfg_clone_array(cfg_group_meta_t *meta, cfg_group_t *group)
641 {
642 cfg_group_inst_t *new_array;
643 int size;
644
645 if (!meta->array || !meta->num)
646 return NULL;
647
648 size = (sizeof(cfg_group_inst_t) + group->size - 1) * meta->num;
649 new_array = (cfg_group_inst_t *)shm_malloc(size);
650 if (!new_array) {
651 SHM_MEM_ERROR;
652 return NULL;
653 }
654 memcpy(new_array, meta->array, size);
655
656 return new_array;
657 }
658
659 /* Extend the array of configuration group instances with one more instance.
660 * Only the ID of the new group is set, nothing else. */
cfg_extend_array(cfg_group_meta_t * meta,cfg_group_t * group,unsigned int group_id,cfg_group_inst_t ** new_group)661 cfg_group_inst_t *cfg_extend_array(cfg_group_meta_t *meta, cfg_group_t *group,
662 unsigned int group_id,
663 cfg_group_inst_t **new_group)
664 {
665 int i;
666 cfg_group_inst_t *new_array, *old_array;
667 int inst_size;
668
669 inst_size = sizeof(cfg_group_inst_t) + group->size - 1;
670 new_array = (cfg_group_inst_t *)shm_malloc(inst_size * (meta->num + 1));
671 if (!new_array) {
672 SHM_MEM_ERROR;
673 return NULL;
674 }
675 /* Find the position of the new group in the array. The array is ordered
676 * by the group IDs. */
677 old_array = meta->array;
678 for ( i = 0;
679 (i < meta->num)
680 && (((cfg_group_inst_t *)((char *)old_array + inst_size * i))->id < group_id);
681 i++
682 );
683 if (i > 0)
684 memcpy( new_array,
685 old_array,
686 (size_t) inst_size * i);
687
688 memset((char*)new_array + inst_size * i, 0, inst_size);
689 *new_group = (cfg_group_inst_t *)((char*)new_array + inst_size * i);
690 (*new_group)->id = group_id;
691
692 if (i < meta->num)
693 memcpy( (char*)new_array + inst_size * (i + 1),
694 (char*)old_array + inst_size * i,
695 (size_t) inst_size * (meta->num - i));
696
697 return new_array;
698 }
699
700 /* Remove an instance from a group array.
701 * inst must point to an instance within meta->array.
702 * *_new_array is set to the newly allocated array. */
cfg_collapse_array(cfg_group_meta_t * meta,cfg_group_t * group,cfg_group_inst_t * inst,cfg_group_inst_t ** _new_array)703 int cfg_collapse_array(cfg_group_meta_t *meta, cfg_group_t *group,
704 cfg_group_inst_t *inst,
705 cfg_group_inst_t **_new_array)
706 {
707 cfg_group_inst_t *new_array, *old_array;
708 int inst_size, offset;
709
710 if (!meta->num)
711 return -1;
712
713 if (meta->num == 1) {
714 *_new_array = NULL;
715 return 0;
716 }
717
718 inst_size = sizeof(cfg_group_inst_t) + group->size - 1;
719 new_array = (cfg_group_inst_t *)shm_malloc(inst_size * (meta->num - 1));
720 if (!new_array) {
721 SHM_MEM_ERROR;
722 return -1;
723 }
724
725 old_array = meta->array;
726 offset = (char *)inst - (char *)old_array;
727 if (offset)
728 memcpy( new_array,
729 old_array,
730 offset);
731
732 if (meta->num * inst_size > offset + inst_size)
733 memcpy( (char *)new_array + offset,
734 (char *)old_array + offset + inst_size,
735 (meta->num - 1) * inst_size - offset);
736
737 *_new_array = new_array;
738 return 0;
739 }
740
741 /* Find the group instance within the meta-data based on the group_id */
cfg_find_group(cfg_group_meta_t * meta,int group_size,unsigned int group_id)742 cfg_group_inst_t *cfg_find_group(cfg_group_meta_t *meta, int group_size, unsigned int group_id)
743 {
744 int i;
745 cfg_group_inst_t *ginst;
746
747 if (!meta)
748 return NULL;
749
750 /* For now, search lineray. TODO: improve */
751 for (i = 0; i < meta->num; i++) {
752 ginst = (cfg_group_inst_t *)((char *)meta->array
753 + (sizeof(cfg_group_inst_t) + group_size - 1) * i);
754 if (ginst->id == group_id)
755 return ginst;
756 else if (ginst->id > group_id)
757 break; /* needless to continue, the array is ordered */
758 }
759 return NULL;
760 }
761
762 /* append new callbacks to the end of the child callback list
763 *
764 * WARNING: the function is unsafe, either hold CFG_LOCK(),
765 * or call the function before forking
766 */
cfg_install_child_cb(cfg_child_cb_t * cb_first,cfg_child_cb_t * cb_last)767 void cfg_install_child_cb(cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
768 {
769 /* add the new callbacks to the end of the linked-list */
770 (*cfg_child_cb_last)->next = cb_first;
771 *cfg_child_cb_last = cb_last;
772 }
773
774 /* installs a new global config
775 *
776 * replaced is an array of strings that must be freed together
777 * with the previous global config.
778 * cb_first and cb_last define a linked list of per-child process
779 * callbacks. This list is added to the global linked list.
780 */
cfg_install_global(cfg_block_t * block,void ** replaced,cfg_child_cb_t * cb_first,cfg_child_cb_t * cb_last)781 void cfg_install_global(cfg_block_t *block, void **replaced,
782 cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
783 {
784 cfg_block_t* old_cfg;
785
786 CFG_REF(block);
787
788 if (replaced) {
789 /* The replaced array is specified, it has to be linked to the child cb structure.
790 * The last child process processing this structure will free the old strings and the array. */
791 if (cb_first) {
792 cb_first->replaced = replaced;
793 } else {
794 /* At least one child cb structure is needed. */
795 cb_first = cfg_child_cb_new(NULL, NULL, NULL, 0 /* gname, name, cb, type */);
796 if (cb_first) {
797 cb_last = cb_first;
798 cb_first->replaced = replaced;
799 } else {
800 SHM_MEM_ERROR;
801 /* Nothing more can be done here, the replaced strings are still needed,
802 * they cannot be freed at this moment.
803 */
804 }
805 }
806 }
807
808 CFG_LOCK();
809
810 old_cfg = *cfg_global;
811 *cfg_global = block;
812
813 if (cb_first)
814 cfg_install_child_cb(cb_first, cb_last);
815
816 CFG_UNLOCK();
817
818 if (old_cfg)
819 CFG_UNREF(old_cfg);
820 }
821
822 /* creates a structure for a per-child process callback */
cfg_child_cb_new(str * gname,str * name,cfg_on_set_child cb,unsigned int type)823 cfg_child_cb_t *cfg_child_cb_new(str *gname, str *name,
824 cfg_on_set_child cb,
825 unsigned int type)
826 {
827 cfg_child_cb_t *cb_struct;
828
829 cb_struct = (cfg_child_cb_t *)shm_malloc(sizeof(cfg_child_cb_t));
830 if (!cb_struct) {
831 SHM_MEM_ERROR;
832 return NULL;
833 }
834 memset(cb_struct, 0, sizeof(cfg_child_cb_t));
835 if (gname) {
836 cb_struct->gname.s = gname->s;
837 cb_struct->gname.len = gname->len;
838 }
839 if (name) {
840 cb_struct->name.s = name->s;
841 cb_struct->name.len = name->len;
842 }
843 cb_struct->cb = cb;
844 atomic_set(&cb_struct->refcnt, 0);
845
846 if (type & CFG_CB_ONLY_ONCE) {
847 /* The callback needs to be executed only once.
848 * Set the cb_count value to 1, so the first child
849 * process that executes the callback will decrement
850 * it to 0, and no other children will execute the
851 * callback again.
852 */
853 atomic_set(&cb_struct->cb_count, 1);
854 } else {
855 /* Set the cb_count to a high value, i.e. max signed integer,
856 * so all the child processes will execute the callback,
857 * the counter will never reach 0.
858 */
859 atomic_set(&cb_struct->cb_count, (1U<<(sizeof(int)*8-1))-1);
860 }
861
862 return cb_struct;
863 }
864
865 /* free the memory allocated for a child cb list */
cfg_child_cb_free_list(cfg_child_cb_t * child_cb_first)866 void cfg_child_cb_free_list(cfg_child_cb_t *child_cb_first)
867 {
868 cfg_child_cb_t *cb, *cb_next;
869
870 for(cb = child_cb_first;
871 cb;
872 cb = cb_next
873 ) {
874 cb_next = cb->next;
875 cfg_child_cb_free_item(cb);
876 }
877 }
878
879 /* Allocate memory for a new additional variable
880 * and link it to a configuration group.
881 * type==0 results in creating a new group instance with the default values.
882 * The group is created with CFG_GROUP_UNKNOWN type if it does not exist.
883 * Note: this function is usable only before the configuration is shmized.
884 */
new_add_var(str * group_name,unsigned int group_id,str * var_name,void * val,unsigned int type)885 int new_add_var(str *group_name, unsigned int group_id, str *var_name,
886 void *val, unsigned int type)
887 {
888 cfg_group_t *group;
889 cfg_add_var_t *add_var = NULL, **add_var_p;
890 int len;
891
892 if (type && !var_name) {
893 LM_ERR("Missing variable specification\n");
894 goto error;
895 }
896 if (type)
897 LM_DBG("declaring a new variable instance %.*s[%u].%.*s\n",
898 group_name->len, group_name->s,
899 group_id,
900 var_name->len, var_name->s);
901 else
902 LM_DBG("declaring a new group instance %.*s[%u]\n",
903 group_name->len, group_name->s,
904 group_id);
905
906 if (cfg_shmized) {
907 LM_ERR("too late, the configuration has already been shmized\n");
908 goto error;
909 }
910
911 group = cfg_lookup_group(group_name->s, group_name->len);
912 if (!group) {
913 /* create a new group with NULL values, it will be filled in later */
914 group = cfg_new_group(group_name->s, group_name->len,
915 0 /* num */, NULL /* mapping */,
916 NULL /* vars */, 0 /* size */, NULL /* handle */);
917
918 if (!group)
919 goto error;
920 /* It is not yet known whether the group will be static or dynamic */
921 group->dynamic = CFG_GROUP_UNKNOWN;
922 }
923
924 add_var = (cfg_add_var_t *)pkg_malloc(sizeof(cfg_add_var_t) +
925 (type ? (var_name->len - 1) : 0));
926 if (!add_var) {
927 PKG_MEM_ERROR;
928 goto error;
929 }
930 memset(add_var, 0, sizeof(cfg_add_var_t) +
931 (type ? (var_name->len - 1) : 0));
932
933 add_var->group_id = group_id;
934 if (type) {
935 add_var->name_len = var_name->len;
936 memcpy(add_var->name, var_name->s, var_name->len);
937
938 switch (type) {
939 case CFG_VAR_INT:
940 add_var->val.i = (int)(long)val;
941 break;
942
943 case CFG_VAR_STR:
944 len = ((str *)val)->len;
945 if (len) {
946 add_var->val.s.s = (char *)pkg_malloc(sizeof(char) * len);
947 if (!add_var->val.s.s) {
948 PKG_MEM_ERROR;
949 goto error;
950 }
951 memcpy(add_var->val.s.s, ((str *)val)->s, len);
952 } else {
953 add_var->val.s.s = NULL;
954 }
955 add_var->val.s.len = len;
956 break;
957
958 case CFG_VAR_STRING:
959 if (val) {
960 len = strlen((char *)val);
961 add_var->val.ch = (char *)pkg_malloc(sizeof(char) * (len + 1));
962 if (!add_var->val.ch) {
963 PKG_MEM_ERROR;
964 goto error;
965 }
966 memcpy(add_var->val.ch, (char *)val, len);
967 add_var->val.ch[len] = '\0';
968 } else {
969 add_var->val.ch = NULL;
970 }
971 break;
972
973 default:
974 LM_ERR("unsupported value type: %u\n", type);
975 goto error;
976 }
977 add_var->type = type;
978 }
979
980 /* order the list by group_id, it will be easier
981 * to count the group instances */
982 for( add_var_p = &group->add_var;
983 *add_var_p && ((*add_var_p)->group_id <= group_id);
984 add_var_p = &((*add_var_p)->next));
985
986 add_var->next = *add_var_p;
987 *add_var_p = add_var;
988
989 return 0;
990
991 error:
992 if (!type)
993 LM_ERR("failed to add the additional group instance: %.*s[%u]\n",
994 group_name->len, group_name->s, group_id);
995 else
996 LM_ERR("failed to add the additional variable instance: %.*s[%u].%.*s\n",
997 group_name->len, group_name->s, group_id,
998 (var_name)?var_name->len:0,
999 (var_name&&var_name->s)?var_name->s:"");
1000
1001 if (add_var)
1002 pkg_free(add_var);
1003 return -1;
1004 }
1005
1006 /* delete the additional variable list */
del_add_var_list(cfg_group_t * group)1007 static void del_add_var_list(cfg_group_t *group)
1008 {
1009 cfg_add_var_t *add_var, *add_var2;
1010
1011 add_var = group->add_var;
1012 while (add_var) {
1013 add_var2 = add_var->next;
1014 if ((add_var->type == CFG_VAR_STR) && add_var->val.s.s)
1015 pkg_free(add_var->val.s.s);
1016 else if ((add_var->type == CFG_VAR_STRING) && add_var->val.ch)
1017 pkg_free(add_var->val.ch);
1018 pkg_free(add_var);
1019 add_var = add_var2;
1020 }
1021 group->add_var = NULL;
1022 }
1023
1024 /* create the array of additional group instances from the linked list */
apply_add_var_list(cfg_block_t * block,cfg_group_t * group)1025 static int apply_add_var_list(cfg_block_t *block, cfg_group_t *group)
1026 {
1027 int i, num, size;
1028 unsigned int group_id;
1029 cfg_add_var_t *add_var;
1030 cfg_group_inst_t *new_array, *ginst;
1031 cfg_group_meta_t *gm;
1032
1033 /* count the number of group instances */
1034 for ( add_var = group->add_var, num = 0, group_id = 0;
1035 add_var;
1036 add_var = add_var->next
1037 ) {
1038 if (!num || (group_id != add_var->group_id)) {
1039 num++;
1040 group_id = add_var->group_id;
1041 }
1042 }
1043
1044 if (!num) /* nothing to do */
1045 return 0;
1046
1047 LM_DBG("creating the group instance array "
1048 "for '%.*s' with %d slots\n",
1049 group->name_len, group->name, num);
1050 size = (sizeof(cfg_group_inst_t) + group->size - 1) * num;
1051 new_array = (cfg_group_inst_t *)shm_malloc(size);
1052 if (!new_array) {
1053 SHM_MEM_ERROR;
1054 return -1;
1055 }
1056 memset(new_array, 0, size);
1057
1058 for (i = 0; i < num; i++) {
1059 /* Go though each group instance, set the default values,
1060 * and apply the changes */
1061
1062 if (!group->add_var) {
1063 LM_ERR("BUG: no more additional variable left\n");
1064 goto error;
1065 }
1066 ginst = (cfg_group_inst_t *)((char*)new_array
1067 + (sizeof(cfg_group_inst_t) + group->size - 1) * i);
1068 ginst->id = group->add_var->group_id;
1069 /* fill in the new group instance with the default data */
1070 memcpy( ginst->vars,
1071 CFG_GROUP_DATA(block, group),
1072 group->size);
1073 /* cfg_apply_list() moves the group->add_var pointer to
1074 * the beginning of the new group instance. */
1075 if (cfg_apply_list(ginst, group, ginst->id, &group->add_var))
1076 goto error;
1077 }
1078
1079 #ifdef EXTRA_DEBUG
1080 if (group->add_var) {
1081 LM_ERR("not all the additional variables have been consumed\n");
1082 goto error;
1083 }
1084 #endif
1085
1086 gm = CFG_GROUP_META(block, group);
1087 gm->num = num;
1088 gm->array = new_array;
1089 return 0;
1090
1091 error:
1092 LM_ERR("failed to apply the additional variable list\n");
1093 shm_free(new_array);
1094 return -1;
1095 }
1096
1097 /* Move the group handle to the specified group instance pointed by dst_ginst.
1098 * src_ginst shall point to the active group instance.
1099 * Both parameters can be NULL meaning that the src/dst config is the default,
1100 * not an additional group instance.
1101 * The function executes all the per-child process callbacks which are different
1102 * in the two instaces.
1103 */
cfg_move_handle(cfg_group_t * group,cfg_group_inst_t * src_ginst,cfg_group_inst_t * dst_ginst)1104 void cfg_move_handle(cfg_group_t *group, cfg_group_inst_t *src_ginst, cfg_group_inst_t *dst_ginst)
1105 {
1106 cfg_mapping_t *var;
1107 unsigned int bitmap;
1108 int i, pos;
1109 str gname, vname;
1110
1111 if (src_ginst == dst_ginst)
1112 return; /* nothing to do */
1113
1114 /* move the handle to the variables of the dst group instance,
1115 * or to the local config if no dst group instance is specified */
1116 *(group->handle) = dst_ginst ?
1117 dst_ginst->vars
1118 : CFG_GROUP_DATA(cfg_local, group);
1119
1120 if (cfg_child_cb != CFG_NO_CHILD_CBS) {
1121 /* call the per child process callback of those variables
1122 * that have different value in the two group instances */
1123 /* TODO: performance optimization: this entire loop can be
1124 * skipped if the group does not have any variable with
1125 * per-child process callback. Use some flag in the group
1126 * structure for this purpose. */
1127 gname.s = group->name;
1128 gname.len = group->name_len;
1129 for (i = 0; i < CFG_MAX_VAR_NUM/(sizeof(int)*8); i++) {
1130 bitmap = ((src_ginst) ? src_ginst->set[i] : 0U)
1131 | ((dst_ginst) ? dst_ginst->set[i] : 0U);
1132 while (bitmap) {
1133 pos = bit_scan_forward32(bitmap);
1134 var = &group->mapping[pos + i*sizeof(int)*8];
1135 if (var->def->on_set_child_cb) {
1136 vname.s = var->def->name;
1137 vname.len = var->name_len;
1138 var->def->on_set_child_cb(&gname, &vname);
1139 }
1140 bitmap -= (1U << pos);
1141 }
1142 }
1143 }
1144 /* keep track of how many group instences are set in the child process */
1145 if (!src_ginst && dst_ginst)
1146 cfg_ginst_count++;
1147 else if (!dst_ginst)
1148 cfg_ginst_count--;
1149 #ifdef EXTRA_DEBUG
1150 if (cfg_ginst_count < 0)
1151 LM_ERR("BUG: cfg_ginst_count is negative: %d. group=%.*s\n",
1152 cfg_ginst_count, group->name_len, group->name);
1153 #endif
1154 return;
1155 }
1156
1157 /* Move the group handle to the specified group instance. */
cfg_select(cfg_group_t * group,unsigned int id)1158 int cfg_select(cfg_group_t *group, unsigned int id)
1159 {
1160 cfg_group_inst_t *ginst;
1161
1162 if (!cfg_local) {
1163 LM_ERR("The child process has no local configuration\n");
1164 return -1;
1165 }
1166
1167 if (!(ginst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
1168 group->size,
1169 id))
1170 ) {
1171 LM_ERR("group instance '%.*s[%u]' does not exist\n",
1172 group->name_len, group->name, id);
1173 return -1;
1174 }
1175
1176 cfg_move_handle(group,
1177 CFG_HANDLE_TO_GINST(*(group->handle)), /* the active group instance */
1178 ginst);
1179
1180 LM_DBG("group instance '%.*s[%u]' has been selected\n",
1181 group->name_len, group->name, id);
1182 return 0;
1183 }
1184
1185 /* Reset the group handle to the default, local configuration */
cfg_reset(cfg_group_t * group)1186 int cfg_reset(cfg_group_t *group)
1187 {
1188 if (!cfg_local) {
1189 LM_ERR("The child process has no local configuration\n");
1190 return -1;
1191 }
1192
1193 cfg_move_handle(group,
1194 CFG_HANDLE_TO_GINST(*(group->handle)), /* the active group instance */
1195 NULL);
1196
1197 LM_DBG("default group '%.*s' has been selected\n",
1198 group->name_len, group->name);
1199 return 0;
1200 }
1201
1202 /* Move the group handle to the first group instance.
1203 * This function together with cfg_select_next() can be used
1204 * to iterate though the list of instances.
1205 *
1206 * Return value:
1207 * -1: no group instance found
1208 * 0: first group instance is successfully selected.
1209 */
cfg_select_first(cfg_group_t * group)1210 int cfg_select_first(cfg_group_t *group)
1211 {
1212 cfg_group_meta_t *meta;
1213 cfg_group_inst_t *ginst;
1214
1215 if (!cfg_local) {
1216 LM_ERR("The child process has no local configuration\n");
1217 return -1;
1218 }
1219
1220 meta = CFG_GROUP_META(cfg_local, group);
1221 if (!meta || (meta->num == 0))
1222 return -1;
1223
1224 ginst = (cfg_group_inst_t *)meta->array;
1225 cfg_move_handle(group,
1226 CFG_HANDLE_TO_GINST(*(group->handle)), /* the active group instance */
1227 ginst);
1228
1229 LM_DBG("group instance '%.*s[%u]' has been selected\n",
1230 group->name_len, group->name, ginst->id);
1231 return 0;
1232 }
1233
1234 /* Move the group handle to the next group instance.
1235 * This function together with cfg_select_first() can be used
1236 * to iterate though the list of instances.
1237 *
1238 * Return value:
1239 * -1: no more group instance found. Note, that the active group
1240 * instance is not changed in this case.
1241 * 0: the next group instance is successfully selected.
1242 */
cfg_select_next(cfg_group_t * group)1243 int cfg_select_next(cfg_group_t *group)
1244 {
1245 cfg_group_meta_t *meta;
1246 cfg_group_inst_t *old_ginst, *new_ginst;
1247 int size;
1248
1249 if (!cfg_local) {
1250 LM_ERR("The child process has no local configuration\n");
1251 return -1;
1252 }
1253
1254 meta = CFG_GROUP_META(cfg_local, group);
1255
1256 if (!(old_ginst = CFG_HANDLE_TO_GINST(*(group->handle))
1257 /* the active group instance */)) {
1258 LM_ERR("No group instance is set currently."
1259 "Forgot to call cfg_select_first()?\n");
1260 return -1;
1261 }
1262
1263 size = sizeof(cfg_group_inst_t) + group->size - 1;
1264 if (((char *)old_ginst - (char *)meta->array)/size + 1 >= meta->num)
1265 return -1; /* this is the last group instance */
1266
1267 new_ginst = (cfg_group_inst_t *)((char *)old_ginst + size);
1268 cfg_move_handle(group,
1269 old_ginst, /* the active group instance */
1270 new_ginst);
1271
1272 LM_DBG("group instance '%.*s[%u]' has been selected\n",
1273 group->name_len, group->name, new_ginst->id);
1274 return 0;
1275 }
1276
1277 /* Temporary set the local configuration in the main process before forking.
1278 * This makes the group instances usable in the main process after
1279 * the configuration is shmized, but before the children are forked.
1280 */
cfg_main_set_local(void)1281 void cfg_main_set_local(void)
1282 {
1283 /* Disable the execution of child-process callbacks,
1284 * they can cause trouble because the children inherit all the
1285 * values later */
1286 cfg_child_cb = CFG_NO_CHILD_CBS;
1287 cfg_update_no_cbs();
1288 }
1289
1290 /* Reset the local configuration of the main process back to its original state
1291 * to make sure that the forked processes are not affected.
1292 */
cfg_main_reset_local(void)1293 void cfg_main_reset_local(void)
1294 {
1295 cfg_group_t *group;
1296
1297 /* Unref the local config, and set it back to NULL.
1298 * Each child will set its own local configuration. */
1299 if (cfg_local) {
1300 CFG_UNREF(cfg_local);
1301 cfg_local = NULL;
1302
1303 /* restore the original value of the module handles */
1304 for ( group = cfg_group;
1305 group;
1306 group = group->next
1307 )
1308 *(group->handle) = group->orig_handle;
1309 /* The handle might have pointed to a group instance,
1310 * reset the instance counter. */
1311 cfg_ginst_count = 0;
1312 }
1313 cfg_child_cb = NULL;
1314 }
1315