- Call the per-child process callback functions even if the
[sip-router] / cfg / cfg_struct.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2007 iptelorg GmbH
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History
28  * -------
29  *  2007-12-03  Initial version (Miklos)
30  *  2008-01-24  dynamic groups are introduced in order to make
31  *              variable declaration possible in the script (Miklos)
32  */
33
34 #include <string.h>
35
36 #include "../mem/mem.h"
37 #include "../mem/shm_mem.h"
38 #include "../ut.h"
39 #include "../locking.h"
40 #include "cfg_ctx.h"
41 #include "cfg_script.h"
42 #include "cfg_struct.h"
43
44 cfg_group_t     *cfg_group = NULL;      /* linked list of registered cfg groups */
45 cfg_block_t     **cfg_global = NULL;    /* pointer to the active cfg block */
46 cfg_block_t     *cfg_local = NULL;      /* per-process pointer to the active cfg block.
47                                         Updated only when the child process
48                                         finishes working on the SIP message */
49 static int      cfg_block_size = 0;     /* size of the cfg block (constant) */
50 gen_lock_t      *cfg_global_lock = 0;   /* protects *cfg_global */
51 gen_lock_t      *cfg_writer_lock = 0;   /* This lock makes sure that two processes do not
52                                         try to clone *cfg_global at the same time.
53                                         Never try to get cfg_writer_lock when
54                                         cfg_global_lock is held */
55 int             cfg_shmized = 0;        /* indicates whether the cfg block has been
56                                         already shmized */
57
58 cfg_child_cb_t  **cfg_child_cb_first = NULL;    /* first item of the per-child process
59                                                 callback list */
60 cfg_child_cb_t  **cfg_child_cb_last = NULL;     /* last item of the above list */
61 cfg_child_cb_t  *cfg_child_cb = NULL;   /* pointer to the previously executed cb */     
62
63 /* creates a new cfg group, and adds it to the linked list */
64 cfg_group_t *cfg_new_group(char *name, int name_len,
65                 int num, cfg_mapping_t *mapping,
66                 char *vars, int size, void **handle)
67 {
68         cfg_group_t     *group;
69
70         if (cfg_shmized) {
71                 LOG(L_ERR, "ERROR: cfg_new_group(): too late config declaration\n");
72                 return NULL;
73         }
74
75         group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+name_len-1);
76         if (!group) {
77                 LOG(L_ERR, "ERROR: cfg_new_group(): not enough memory\n");
78                 return NULL;
79         }
80         memset(group, 0, sizeof(cfg_group_t)+name_len-1);
81
82         group->num = num;
83         group->mapping = mapping;
84         group->vars = vars;
85         group->size = size;
86         group->handle = handle;
87         group->name_len = name_len;
88         memcpy(&group->name, name, name_len);
89
90         /* add the new group to the beginning of the list */
91         group->next = cfg_group;
92         cfg_group = group;
93
94         return group;
95 }
96
97 /* clones a string to shared memory
98  * (src and dst can be the same)
99  */
100 int cfg_clone_str(str *src, str *dst)
101 {
102         char    *c;
103
104         if (!src->s) {
105                 dst->s = NULL;
106                 dst->len = 0;
107                 return 0;
108         }
109
110         c = (char *)shm_malloc(sizeof(char)*(src->len+1));
111         if (!c) {
112                 LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
113                 return -1;
114         }
115         memcpy(c, src->s, src->len);
116         c[src->len] = '\0';
117
118         dst->s = c;
119         dst->len = src->len;
120
121         return 0;
122 }
123
124 /* copies the strings to shared memory */
125 static int cfg_shmize_strings(cfg_group_t *group)
126 {
127         cfg_mapping_t   *mapping;
128         int     i;
129         str     s;
130
131         /* We do not know in advance whether the variable will be changed or not,
132         and it can happen that we try to free the shm memory area when the variable
133         is changed, hence, it must be already in shm mem */
134         mapping = group->mapping;
135         for (i=0; i<group->num; i++) {
136                 /* the cfg driver module may have already shmized the variable */
137                 if (mapping[i].flag & cfg_var_shmized) continue;
138
139                 if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) {
140                         memcpy(&s.s, group->vars + mapping[i].offset, sizeof(char *));
141                         if (!s.s) continue;
142                         s.len = strlen(s.s);
143
144                 } else if (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR) {
145                         memcpy(&s, group->vars + mapping[i].offset, sizeof(str));
146                         if (!s.s) continue;
147
148                 } else {
149                         continue;
150                 }
151                 if (cfg_clone_str(&s, &s)) return -1;
152                 memcpy(group->vars + mapping[i].offset, &s.s, sizeof(char *));
153                 mapping[i].flag |= cfg_var_shmized;
154         }
155
156         return 0;
157 }
158
159 /* copy the variables to shm mem */
160 int cfg_shmize(void)
161 {
162         cfg_group_t     *group;
163         cfg_block_t     *block = NULL;
164         int     size;
165
166         if (!cfg_group) return 0;
167
168         /* Let us allocate one memory block that
169         will contain all the variables */
170         for (   size=0, group = cfg_group;
171                 group;
172                 group=group->next
173         ) {
174                 size = ROUND_POINTER(size);
175                 group->offset = size;
176                 size += group->size;
177         }
178
179         block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+size-1);
180         if (!block) {
181                 LOG(L_ERR, "ERROR: cfg_clone_str(): not enough shm memory\n");
182                 goto error;
183         }
184         memset(block, 0, sizeof(cfg_block_t)+size-1);
185         cfg_block_size = size;
186
187         /* copy the memory fragments to the single block */
188         for (   group = cfg_group;
189                 group;
190                 group=group->next
191         ) {
192                 if (group->dynamic == 0) {
193                         /* clone the strings to shm mem */
194                         if (cfg_shmize_strings(group)) goto error;
195
196                         /* copy the values to the new block,
197                         and update the module's handle */
198                         memcpy(block->vars+group->offset, group->vars, group->size);
199                         *(group->handle) = block->vars+group->offset;
200                 } else {
201                         /* The group was declared with NULL values,
202                          * we have to fix it up.
203                          * The fixup function takes care about the values,
204                          * it fills up the block */
205                         if (cfg_script_fixup(group, block->vars+group->offset)) goto error;
206                         *(group->handle) = block->vars+group->offset;
207
208                         /* notify the drivers about the new config definition */
209                         cfg_notify_drivers(group->name, group->name_len,
210                                         group->mapping->def);
211                 }
212         }
213
214         /* install the new config */
215         cfg_install_global(block, NULL, NULL, NULL);
216         cfg_shmized = 1;
217
218         return 0;
219
220 error:
221         if (block) shm_free(block);
222         return -1;
223 }
224
225 /* deallocate the list of groups, and the shmized strings */
226 static void cfg_destory_groups(unsigned char *block)
227 {
228         cfg_group_t     *group, *group2;
229         cfg_mapping_t   *mapping;
230         cfg_def_t       *def;
231         void            *old_string;
232         int             i;
233
234         group = cfg_group;
235         while(group) {
236                 mapping = group->mapping;
237                 def = mapping ? mapping->def : NULL;
238
239                 /* destory the shmized strings in the block */
240                 if (block && def)
241                         for (i=0; i<group->num; i++)
242                                 if (((CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) ||
243                                 (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR)) &&
244                                         mapping[i].flag & cfg_var_shmized) {
245
246                                                 memcpy( &old_string,
247                                                         block + group->offset + mapping[i].offset,
248                                                         sizeof(char *));
249                                                 if (old_string) shm_free(old_string);
250                                 }
251
252                 if (group->dynamic) {
253                         /* the group was dynamically allocated */
254                         cfg_script_destroy(group);
255                 } else {
256                         /* only the mapping was allocated, all the other
257                         pointers are just set to static variables */
258                         if (mapping) pkg_free(mapping);
259                 }
260
261                 group2 = group->next;
262                 pkg_free(group);
263                 group = group2;
264         }
265 }
266
267 /* initiate the cfg framework */
268 int cfg_init(void)
269 {
270         cfg_global_lock = lock_alloc();
271         if (!cfg_global_lock) {
272                 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
273                 goto error;
274         }
275         if (lock_init(cfg_global_lock) == 0) {
276                 LOG(L_ERR, "ERROR: cfg_init(): failed to init lock\n");
277                 lock_dealloc(cfg_global_lock);
278                 cfg_global_lock = 0;
279                 goto error;
280         }
281
282         cfg_writer_lock = lock_alloc();
283         if (!cfg_writer_lock) {
284                 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
285                 goto error;
286         }
287         if (lock_init(cfg_writer_lock) == 0) {
288                 LOG(L_ERR, "ERROR: cfg_init(): failed to init lock\n");
289                 lock_dealloc(cfg_writer_lock);
290                 cfg_writer_lock = 0;
291                 goto error;
292         }
293
294         cfg_global = (cfg_block_t **)shm_malloc(sizeof(cfg_block_t *));
295         if (!cfg_global) {
296                 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
297                 goto error;
298         }
299         *cfg_global = NULL;
300
301         cfg_child_cb_first = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
302         if (!cfg_child_cb_first) {
303                 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
304                 goto error;
305         }
306         *cfg_child_cb_first = NULL;
307
308         cfg_child_cb_last = (cfg_child_cb_t **)shm_malloc(sizeof(cfg_child_cb_t *));
309         if (!cfg_child_cb_last) {
310                 LOG(L_ERR, "ERROR: cfg_init(): not enough shm memory\n");
311                 goto error;
312         }
313         *cfg_child_cb_last = NULL;
314
315         /* A new cfg_child_cb struct must be created with a NULL callback function.
316         This stucture will be the entry point for the child processes, and
317         will be freed later, when none of the processes refers to it */
318         *cfg_child_cb_first = *cfg_child_cb_last =
319                 cfg_child_cb_new(NULL, NULL);
320
321         if (!*cfg_child_cb_first) goto error;
322
323         return 0;
324
325 error:
326         cfg_destroy();
327
328         return -1;
329 }
330
331 /* destroy the memory allocated for the cfg framework */
332 void cfg_destroy(void)
333 {
334         /* free the contexts */
335         cfg_ctx_destroy();
336
337         /* free the list of groups */
338         cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
339
340         if (cfg_child_cb_first) {
341                 if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
342                 shm_free(cfg_child_cb_first);
343                 cfg_child_cb_first = NULL;
344         }
345
346         if (cfg_child_cb_last) {
347                 shm_free(cfg_child_cb_last);
348                 cfg_child_cb_last = NULL;
349         }
350
351         if (cfg_global) {
352                 if (*cfg_global) cfg_block_free(*cfg_global);
353                 shm_free(cfg_global);
354                 cfg_global = NULL;
355         }
356         if (cfg_global_lock) {
357                 lock_destroy(cfg_global_lock);
358                 lock_dealloc(cfg_global_lock);
359                 cfg_global_lock = 0;
360         }
361         if (cfg_writer_lock) {
362                 lock_destroy(cfg_writer_lock);
363                 lock_dealloc(cfg_writer_lock);
364                 cfg_writer_lock = 0;
365         }
366 }
367
368 /* per-child process init function */
369 int cfg_child_init(void)
370 {
371         /* set the callback list pointer to the beginning of the list */
372         cfg_child_cb = *cfg_child_cb_first;
373         atomic_inc(&cfg_child_cb->refcnt);
374
375         return 0;
376 }
377
378 /* per-child process destroy function
379  * Should be called only when the child process exits,
380  * but SER continues running
381  *
382  * WARNING: this function call must be the very last action
383  * before the child process exits, because the local config
384  * is not available afterwards.
385  */
386 void cfg_child_destroy(void)
387 {
388         cfg_child_cb_t  *prev_cb;
389
390         /* unref the local config */
391         if (cfg_local) {
392                 CFG_UNREF(cfg_local);
393                 cfg_local = NULL;
394         }
395
396         if (!cfg_child_cb) return;
397
398         /* The lock must be held to make sure that the global config
399         is not replaced meantime, and the other child processes do not
400         leave the old value of *cfg_child_cb_last. Otherwise it could happen,
401         that all the other processes move their own cfg_child_cb pointer before
402         this process reaches *cfg_child_cb_last, though, it is very unlikely. */
403         CFG_LOCK();
404
405         /* go through the list and check whether there is any item that
406         has to be freed (similar to cfg_update_local(), but without executing
407         the callback functions) */
408         while (cfg_child_cb != *cfg_child_cb_last) {
409                 prev_cb = cfg_child_cb;
410                 cfg_child_cb = cfg_child_cb->next;
411                 atomic_inc(&cfg_child_cb->refcnt);
412                 if (atomic_dec_and_test(&prev_cb->refcnt)) {
413                         /* No more pocess refers to this callback.
414                         Did this process block the deletion,
415                         or is there any other process that has not
416                         reached prev_cb yet? */
417                         if (*cfg_child_cb_first == prev_cb) {
418                                 /* yes, this process was blocking the deletion */
419                                 *cfg_child_cb_first = cfg_child_cb;
420                                 shm_free(prev_cb);
421                         }
422                 } else {
423                         /* no need to continue, because there is at least
424                         one process that stays exactly at the same point
425                         in the list, so it will free the items later */
426                         break;
427                 }
428         }
429         atomic_dec(&cfg_child_cb->refcnt);
430
431         CFG_UNLOCK();
432         cfg_child_cb = NULL;
433 }
434
435 /* searches a group by name */
436 cfg_group_t *cfg_lookup_group(char *name, int len)
437 {
438         cfg_group_t     *g;
439
440         for (   g = cfg_group;
441                 g;
442                 g = g->next
443         )
444                 if ((g->name_len == len)
445                 && (memcmp(g->name, name, len)==0))
446                         return g;
447
448         return NULL;
449 }
450
451 /* searches a variable definition by group and variable name */
452 int cfg_lookup_var(str *gname, str *vname,
453                         cfg_group_t **group, cfg_mapping_t **var)
454 {
455         cfg_group_t     *g;
456         int             i;
457
458         for (   g = cfg_group;
459                 g;
460                 g = g->next
461         )
462                 if ((g->name_len == gname->len)
463                 && (memcmp(g->name, gname->s, gname->len)==0)) {
464
465                         for (   i = 0;
466                                 i < g->num;
467                                 i++
468                         ) {
469                                 if ((g->mapping[i].name_len == vname->len)
470                                 && (memcmp(g->mapping[i].def->name, vname->s, vname->len)==0)) {
471                                         if (group) *group = g;
472                                         if (var) *var = &(g->mapping[i]);
473                                         return 0;
474                                 }
475                         }
476                         break;
477                 }
478
479         LOG(L_ERR, "ERROR: cfg_lookup_var(): variable not found: %.*s.%.*s\n",
480                         gname->len, gname->s,
481                         vname->len, vname->s);
482         return -1;
483 }
484
485 /* clones the global config block
486  * WARNING: unsafe, cfg_writer_lock or cfg_global_lock must be held!
487  */
488 cfg_block_t *cfg_clone_global(void)
489 {
490         cfg_block_t     *block;
491
492         block = (cfg_block_t*)shm_malloc(sizeof(cfg_block_t)+cfg_block_size-1);
493         if (!block) {
494                 LOG(L_ERR, "ERROR: cfg_clone_global(): not enough shm memory\n");
495                 return NULL;
496         }
497         memcpy(block, *cfg_global, sizeof(cfg_block_t)+cfg_block_size-1);
498
499         /* reset the reference counter */
500         atomic_set(&block->refcnt, 0);
501
502         return block;
503 }
504
505 /* append new callbacks to the end of the child callback list
506  *
507  * WARNING: the function is unsafe, either hold CFG_LOCK(),
508  * or call the function before forking
509  */
510 void cfg_install_child_cb(cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
511 {
512         /* add the new callbacks to the end of the linked-list */
513         (*cfg_child_cb_last)->next = cb_first;
514         *cfg_child_cb_last = cb_last;
515 }
516
517 /* installs a new global config
518  *
519  * replaced is an array of strings that must be freed together
520  * with the previous global config.
521  * cb_first and cb_last define a linked list of per-child process
522  * callbacks. This list is added to the global linked list.
523  */
524 void cfg_install_global(cfg_block_t *block, char **replaced,
525                         cfg_child_cb_t *cb_first, cfg_child_cb_t *cb_last)
526 {
527         CFG_LOCK();
528
529         if (*cfg_global) {
530                 if (replaced) (*cfg_global)->replaced = replaced;
531                 CFG_UNREF(*cfg_global);
532         }
533         CFG_REF(block);
534         *cfg_global = block;
535
536         if (cb_first)
537                 cfg_install_child_cb(cb_first, cb_last);
538
539         CFG_UNLOCK();
540
541 }
542
543 /* creates a structure for a per-child process callback */
544 cfg_child_cb_t *cfg_child_cb_new(str *name, cfg_on_set_child cb)
545 {
546         cfg_child_cb_t  *cb_struct;
547
548         cb_struct = (cfg_child_cb_t *)shm_malloc(sizeof(cfg_child_cb_t));
549         if (!cb_struct) {
550                 LOG(L_ERR, "ERROR: cfg_child_cb_new(): not enough shm memory\n");
551                 return NULL;
552         }
553         memset(cb_struct, 0, sizeof(cfg_child_cb_t));
554         if (name) {
555                 cb_struct->name.s = name->s;
556                 cb_struct->name.len = name->len;
557         }
558         cb_struct->cb = cb;
559         atomic_set(&cb_struct->refcnt, 0);
560
561         return cb_struct;
562 }
563
564 /* free the memory allocated for a child cb list */
565 void cfg_child_cb_free(cfg_child_cb_t *child_cb_first)
566 {
567         cfg_child_cb_t  *cb, *cb_next;
568
569         for(    cb = child_cb_first;
570                 cb;
571                 cb = cb_next
572         ) {
573                 cb_next = cb->next;
574                 shm_free(cb);
575         }
576 }