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