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