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