core: cfg ctx - checks for valid variable offset
[kamailio] / src / core / cfg / cfg_ctx.c
1 /*
2  * Copyright (C) 2007 iptelorg GmbH
3  *
4  * This file is part of Kamailio, a free SIP server.
5  *
6  * Kamailio is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version
10  *
11  * Kamailio is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  *
20  */
21
22 #include <string.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #include "../ut.h"
27 #include "cfg_struct.h"
28 #include "cfg_script.h"
29 #include "cfg_ctx.h"
30
31
32 /* linked list of all the registered cfg contexts */
33 static cfg_ctx_t        *cfg_ctx_list = NULL;
34
35 /* creates a new config context that is an interface to the
36  * cfg variables with write permission
37  */
38 int cfg_register_ctx(cfg_ctx_t **handle, cfg_on_declare on_declare_cb)
39 {
40         cfg_ctx_t       *ctx;
41         cfg_group_t     *group;
42         str             gname;
43
44         /* allocate memory for the new context
45          * Better to use shm mem, because 'changed' and 'lock'
46          * must be in shm mem anyway */
47         ctx = (cfg_ctx_t *)shm_malloc(sizeof(cfg_ctx_t));
48         if (!ctx) {
49                 SHM_MEM_ERROR;
50                 return -1;
51         }
52         memset(ctx, 0, sizeof(cfg_ctx_t));
53         if (lock_init(&ctx->lock) == 0) {
54                 LM_ERR("failed to init lock\n");
55                 shm_free(ctx);
56                 return -1;
57         }
58
59         /* add the new ctx to the beginning of the list */
60         ctx->next = cfg_ctx_list;
61         cfg_ctx_list = ctx;
62
63         /* let the driver know about the already registered groups
64          * The handle of the context must be set before calling the
65          * on_declare callbacks. */
66         *handle = ctx;
67         if (on_declare_cb) {
68                 ctx->on_declare_cb = on_declare_cb;
69
70                 for (group = cfg_group;
71                                 group;
72                                 group = group->next
73                                 ) {
74                         /* dynamic groups are not ready, the callback
75                          * will be called later when the group is fixed-up */
76                         if (group->dynamic != CFG_GROUP_STATIC) continue;
77
78                         gname.s = group->name;
79                         gname.len = group->name_len;
80                         on_declare_cb(&gname, group->mapping->def);
81                 }
82         }
83
84         return 0;
85 }
86
87 /* free the memory allocated for the contexts */
88 void cfg_ctx_destroy(void)
89 {
90         cfg_ctx_t       *ctx, *ctx2;
91
92         for (ctx = cfg_ctx_list;
93                         ctx;
94                         ctx = ctx2
95                         ) {
96                 ctx2 = ctx->next;
97                 shm_free(ctx);
98         }
99         cfg_ctx_list = NULL;
100 }
101
102 /* notify the drivers about the new config definition */
103 void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
104 {
105         cfg_ctx_t       *ctx;
106         str             gname;
107
108         gname.s = group_name;
109         gname.len = group_name_len;
110
111         for (ctx = cfg_ctx_list;
112                         ctx;
113                         ctx = ctx->next
114                         )
115                 if (ctx->on_declare_cb)
116                         ctx->on_declare_cb(&gname, def);
117 }
118
119 /* placeholder for a temporary string */
120 static char     *temp_string = NULL;
121
122 /* convert the value to the requested type */
123 int convert_val(unsigned int val_type, void *val,
124                 unsigned int var_type, void **new_val)
125 {
126         static str      s;
127         char            *end;
128         int             i;
129         static char     buf[INT2STR_MAX_LEN];
130
131         /* we have to convert from val_type to var_type */
132         switch (CFG_INPUT_MASK(var_type)) {
133                 case CFG_INPUT_INT:
134                         if (val_type == CFG_VAR_INT) {
135                                 *new_val = val;
136                                 break;
137
138                         } else if (val_type == CFG_VAR_STRING) {
139                                 if (!val || (((char *)val)[0] == '\0')) {
140                                         LM_ERR("cannot convert NULL string value to integer\n");
141                                         return -1;
142                                 }
143                                 *new_val = (void *)(long)strtol((char *)val, &end, 10);
144                                 if (*end != '\0') {
145                                         LM_ERR("cannot convert string to integer '%s'\n",
146                                                         (char *)val);
147                                         return -1;
148                                 }
149                                 break;
150
151                         } else if (val_type == CFG_VAR_STR) {
152                                 if (!((str *)val)->len || !((str *)val)->s) {
153                                         LM_ERR("cannot convert NULL str value to integer\n");
154                                         return -1;
155                                 }
156                                 if (str2sint((str *)val, &i)) {
157                                         LM_ERR("cannot convert string to integer '%.*s'\n",
158                                                         ((str *)val)->len, ((str *)val)->s);
159                                         return -1;
160                                 }
161                                 *new_val = (void *)(long)i;
162                                 break;
163                         }
164                         goto error;
165
166                 case CFG_INPUT_STRING:
167                         if (val_type == CFG_VAR_INT) {
168                                 buf[snprintf(buf, sizeof(buf)-1, "%ld", (long)val)] = '\0';
169                                 *new_val = buf;
170                                 break;
171
172                         } else if (val_type == CFG_VAR_STRING) {
173                                 *new_val = val;
174                                 break;
175
176                         } else if (val_type == CFG_VAR_STR) {
177                                 if (!((str *)val)->s) {
178                                         *new_val = NULL;
179                                         break;
180                                 }
181                                 /* the value may not be zero-terminated, thus,
182                                  * a new variable has to be allocated with larger memory space */
183                                 if (temp_string) pkg_free(temp_string);
184                                 temp_string = (char *)pkg_malloc(sizeof(char) * (((str *)val)->len + 1));
185                                 if (!temp_string) {
186                                         PKG_MEM_ERROR;
187                                         return -1;
188                                 }
189                                 memcpy(temp_string, ((str *)val)->s, ((str *)val)->len);
190                                 temp_string[((str *)val)->len] = '\0';
191                                 *new_val = (void *)temp_string;
192                                 break;
193
194                         }
195                         goto error;
196
197                 case CFG_INPUT_STR:
198                         if (val_type == CFG_VAR_INT) {
199                                 s.len = snprintf(buf, sizeof(buf)-1, "%ld", (long)val);
200                                 buf[s.len] = '\0';
201                                 s.s = buf;
202                                 *new_val = (void *)&s;
203                                 break;
204
205                         } else if (val_type == CFG_VAR_STRING) {
206                                 s.s = (char *)val;
207                                 s.len = (s.s) ? strlen(s.s) : 0;
208                                 *new_val = (void *)&s;
209                                 break;
210
211                         } else if (val_type == CFG_VAR_STR) {
212                                 *new_val = val;
213                                 break;
214                         }
215                         goto error;
216         }
217
218         return 0;
219
220 error:
221         LM_ERR("got a value with type %u, but expected %u\n",
222                         val_type, CFG_INPUT_MASK(var_type));
223         return -1;
224 }
225
226 void convert_val_cleanup(void)
227 {
228         if (temp_string) {
229                 pkg_free(temp_string);
230                 temp_string = NULL;
231         }
232 }
233
234 /* returns the size of the variable */
235 static int cfg_var_size(cfg_mapping_t *var)
236 {
237         switch (CFG_VAR_TYPE(var)) {
238
239                 case CFG_VAR_INT:
240                         return sizeof(int);
241
242                 case CFG_VAR_STRING:
243                         return sizeof(char *);
244
245                 case CFG_VAR_STR:
246                         return sizeof(str);
247
248                 case CFG_VAR_POINTER:
249                         return sizeof(void *);
250
251                 default:
252                         LM_CRIT("unknown type: %u\n", CFG_VAR_TYPE(var));
253                         return 0;
254         }
255 }
256
257 /* Update the varibales of the array within the meta structure
258  * with the new default value.
259  * The array is cloned before a change if clone is set to 1.
260  */
261 static int cfg_update_defaults(cfg_group_meta_t *meta,
262                 cfg_group_t *group, cfg_mapping_t *var, char *new_val,
263                 int clone)
264 {
265         int     i, clone_done=0;
266         cfg_group_inst_t *array, *ginst;
267
268         if (!(array = meta->array))
269                 return 0;
270         for (i = 0; i < meta->num; i++) {
271                 ginst = (cfg_group_inst_t *)((char *)array
272                                 + (sizeof(cfg_group_inst_t) + group->size - 1) * i);
273
274                 if (!CFG_VAR_TEST(ginst, var)) {
275                         /* The variable uses the default value, it needs to be rewritten. */
276                         if (clone && !clone_done) {
277                                 /* The array needs to be cloned before the modification */
278                                 if (!(array = cfg_clone_array(meta, group)))
279                                         return -1;
280                                 ginst = (cfg_group_inst_t *)translate_pointer((char *)array,
281                                                 (char *)meta->array,
282                                                 (char *)ginst);
283                                 /* re-link the array to the meta-data */
284                                 meta->array = array;
285                                 clone_done = 1;
286                         }
287                         if(ginst->vars + var->offset) {
288                                 memcpy(ginst->vars + var->offset, new_val, cfg_var_size(var));
289                         } else {
290                                 LM_ERR("invalid variable offset\n");
291                         }
292                 }
293         }
294         return 0;
295 }
296
297 /* sets the value of a variable without the need of commit
298  *
299  * return value:
300  *   0: success
301  *  -1: error
302  *   1: variable has not been found
303  */
304 int cfg_set_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id, str *var_name,
305                 void *val, unsigned int val_type)
306 {
307         int             i;
308         cfg_group_t     *group;
309         cfg_mapping_t   *var;
310         void            *p, *v;
311         cfg_block_t     *block = NULL;
312         str             s, s2;
313         char            *old_string = NULL;
314         void            **replaced = NULL;
315         cfg_child_cb_t  *child_cb = NULL;
316         cfg_group_inst_t        *group_inst = NULL, *new_array = NULL;
317         unsigned char           *var_block;
318
319         /* verify the context even if we do not need it now
320          * to make sure that a cfg driver has called the function
321          * (very very weak security) */
322         if (!ctx) {
323                 LM_ERR("context is undefined\n");
324                 return -1;
325         }
326
327         if ((val_type == CFG_VAR_UNSET) && !group_id) {
328                 LM_ERR("Only group instance values can be deleted\n");
329                 return -1;
330         }
331
332         if (group_id && !cfg_shmized) {
333                 /* The config group has not been shmized yet, but
334                  * an additional instance of a variable needs to be added to the group.
335                  * Add this instance to the linked list of variables, they
336                  * will be fixed later. */
337                 return new_add_var(group_name, *group_id, var_name,
338                                 val, val_type);
339         }
340
341         /* look-up the group and the variable */
342         if (cfg_lookup_var(group_name, var_name, &group, &var)) {
343                 if (!cfg_shmized) {
344                         /* The group may be dynamic which is not yet ready
345                          * before forking */
346                         if ((group = cfg_lookup_group(group_name->s, group_name->len))
347                                         && (group->dynamic == CFG_GROUP_DYNAMIC))
348                                 return cfg_set_script_var(group, var_name, val, val_type);
349                 }
350                 return 1;
351         }
352
353         /* check whether the variable is read-only */
354         if (var->def->type & CFG_READONLY) {
355                 LM_ERR("variable is read-only\n");
356                 goto error0;
357         }
358
359         /* The additional variable instances having per-child process callback
360          * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
361          * The reason is that such variables typically set global parameters
362          * as opposed to per-process variables. Hence, it is not possible to set
363          * the group handle temporary to another block, and then reset it back later. */
364         if (group_id
365                         && var->def->on_set_child_cb
366                         && var->def->type & CFG_CB_ONLY_ONCE ) {
367                 LM_ERR("This variable does not support muliple values.\n");
368                 goto error0;
369         }
370
371         /* check whether we have to convert the type */
372         if ((val_type != CFG_VAR_UNSET)
373                         && convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
374                 goto error0;
375
376         if ((val_type != CFG_VAR_UNSET)
377                         && (CFG_INPUT_TYPE(var) == CFG_INPUT_INT)
378                         && (var->def->min || var->def->max)) {
379                 /* perform a simple min-max check for integers */
380                 if (((int)(long)v < var->def->min)
381                                 || ((int)(long)v > var->def->max)) {
382                         LM_ERR("integer value is out of range\n");
383                         goto error0;
384                 }
385         }
386
387         if ((val_type != CFG_VAR_UNSET)
388                         && var->def->on_change_cb) {
389                 /* Call the fixup function.
390                  * There is no need to set a temporary cfg handle,
391                  * becaue a single variable is changed */
392                 if (!group_id) {
393                         var_block = *(group->handle);
394                 } else {
395                         if (!cfg_local) {
396                                 LM_ERR("Local configuration is missing\n");
397                                 goto error0;
398                         }
399                         group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
400                                         group->size,
401                                         *group_id);
402                         if (!group_inst) {
403                                 LM_ERR("local group instance %.*s[%u] is not found\n",
404                                                 group_name->len, group_name->s, *group_id);
405                                 goto error0;
406                         }
407                         var_block = group_inst->vars;
408                 }
409
410                 if (var->def->on_change_cb(var_block,
411                                         group_name,
412                                         var_name,
413                                         &v) < 0) {
414                         LM_ERR("fixup failed\n");
415                         goto error0;
416                 }
417
418         }
419
420         /* Set the per-child process callback only if the default value is changed.
421          * The callback of other instances will be called when the config is
422          * switched to that instance. */
423         if (!group_id && var->def->on_set_child_cb) {
424                 /* get the name of the variable from the internal struct,
425                  * because var_name may be freed before the callback needs it */
426                 s.s = group->name;
427                 s.len = group->name_len;
428                 s2.s = var->def->name;
429                 s2.len = var->name_len;
430                 child_cb = cfg_child_cb_new(&s, &s2,
431                                 var->def->on_set_child_cb,
432                                 var->def->type);
433                 if (!child_cb) {
434                         SHM_MEM_ERROR;
435                         goto error0;
436                 }
437         }
438
439         if (cfg_shmized) {
440                 /* make sure that nobody else replaces the global config
441                  * while the new one is prepared */
442                 CFG_WRITER_LOCK();
443
444                 if (group_id) {
445                         group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
446                                         group->size,
447                                         *group_id);
448                         if (!group_inst) {
449                                 LM_ERR("global group instance %.*s[%u] is not found\n",
450                                                 group_name->len, group_name->s, *group_id);
451                                 goto error;
452                         }
453                         if ((val_type == CFG_VAR_UNSET) && !CFG_VAR_TEST(group_inst, var)) {
454                                 /* nothing to do, the variable is not set in the group instance */
455                                 CFG_WRITER_UNLOCK();
456                                 LM_DBG("The variable is not set\n");
457                                 return 0;
458                         }
459                         var_block = group_inst->vars;
460                 } else {
461                         group_inst = NULL;
462                         var_block = CFG_GROUP_DATA(*cfg_global, group);
463                 }
464
465                 if (var->def->type & CFG_ATOMIC) {
466                         /* atomic change is allowed, we can rewrite the value
467                          * directly in the global config */
468                         p = var_block + var->offset;
469
470                 } else {
471                         /* clone the memory block, and prepare the modification */
472                         if (!(block = cfg_clone_global())) goto error;
473
474                         if (group_inst) {
475                                 /* The additional array of the group needs to be also cloned.
476                                  * When any of the variables within this array is changed, then
477                                  * the complete config block and this array is replaced. */
478                                 if (!(new_array = cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group)))
479                                         goto error;
480                                 group_inst = (cfg_group_inst_t *)translate_pointer((char *)new_array,
481                                                 (char *)CFG_GROUP_META(*cfg_global, group)->array,
482                                                 (char *)group_inst);
483                                 var_block = group_inst->vars;
484                                 CFG_GROUP_META(block, group)->array = new_array;
485                         } else {
486                                 /* The additional array may need to be replaced depending
487                                  * on whether or not there is any variable in the array set
488                                  * to the default value which is changed now. If this is the case,
489                                  * then the array will be replaced later when the variables are
490                                  * updated.
491                                  */
492                                 var_block = CFG_GROUP_DATA(block, group);
493                         }
494                         p = var_block + var->offset;
495                 }
496         } else {
497                 /* we are allowed to rewrite the value on-the-fly
498                  * The handle either points to group->vars, or to the
499                  * shared memory block (dynamic group) */
500                 p = *(group->handle) + var->offset;
501         }
502
503         if (val_type != CFG_VAR_UNSET) {
504                 /* set the new value */
505                 switch (CFG_VAR_TYPE(var)) {
506                         case CFG_VAR_INT:
507                                 *(int *)p = (int)(long)v;
508                                 break;
509
510                         case CFG_VAR_STRING:
511                                 /* clone the string to shm mem */
512                                 s.s = v;
513                                 s.len = (s.s) ? strlen(s.s) : 0;
514                                 if (cfg_clone_str(&s, &s)) goto error;
515                                 old_string = *(char **)p;
516                                 *(char **)p = s.s;
517                                 break;
518
519                         case CFG_VAR_STR:
520                                 /* clone the string to shm mem */
521                                 s = *(str *)v;
522                                 if (cfg_clone_str(&s, &s)) goto error;
523                                 old_string = *(char **)p;
524                                 memcpy(p, &s, sizeof(str));
525                                 break;
526
527                         case CFG_VAR_POINTER:
528                                 *(void **)p = v;
529                                 break;
530
531                 }
532                 if (group_inst && !CFG_VAR_TEST_AND_SET(group_inst, var))
533                         old_string = NULL; /* the string is the same as the default one,
534                                                                 * it cannot be freed */
535         } else {
536                 /* copy the default value to the group instance */
537                 if ((CFG_VAR_TYPE(var) == CFG_VAR_STRING)
538                                 || (CFG_VAR_TYPE(var) == CFG_VAR_STR))
539                         old_string = *(char **)p;
540                 memcpy(p, CFG_GROUP_DATA(*cfg_global, group) + var->offset, cfg_var_size(var));
541
542                 CFG_VAR_TEST_AND_RESET(group_inst, var);
543         }
544
545         if (cfg_shmized) {
546                 if (!group_inst) {
547                         /* the default value is changed, the copies of this value
548                          * need to be also updated */
549                         if (cfg_update_defaults(CFG_GROUP_META(block ? block : *cfg_global, group),
550                                                 group, var, p,
551                                                 block ? 1 : 0) /* clone if needed */
552                                         )
553                                 goto error;
554                         if (block && (CFG_GROUP_META(block, group)->array != CFG_GROUP_META(*cfg_global, group)->array))
555                                 new_array = CFG_GROUP_META(block, group)->array;
556                 }
557
558                 if (old_string || new_array) {
559                         /* prepare the array of the replaced strings,
560                          * and replaced group instances,
561                          * they will be freed when the old block is freed */
562                         replaced = (void **)shm_malloc(sizeof(void *)
563                                         * ((old_string?1:0) + (new_array?1:0) + 1));
564                         if (!replaced) {
565                                 SHM_MEM_ERROR;
566                                 goto error;
567                         }
568                         i = 0;
569                         if (old_string) {
570                                 replaced[i] = old_string;
571                                 i++;
572                         }
573                         if (new_array) {
574                                 replaced[i] = CFG_GROUP_META(*cfg_global, group)->array;
575                                 i++;
576                         }
577                         replaced[i] = NULL;
578                 }
579                 /* replace the global config with the new one */
580                 if (block) cfg_install_global(block, replaced, child_cb, child_cb);
581                 CFG_WRITER_UNLOCK();
582         } else {
583                 /* cfg_set() may be called more than once before forking */
584                 if (old_string && (var->flag & cfg_var_shmized))
585                         shm_free(old_string);
586
587                 /* flag the variable because there is no need
588                  * to shmize it again */
589                 var->flag |= cfg_var_shmized;
590
591                 /* the global config does not have to be replaced,
592                  * but the child callback has to be installed, otherwise the
593                  * child processes will miss the change */
594                 if (child_cb)
595                         cfg_install_child_cb(child_cb, child_cb);
596         }
597
598         if (val_type == CFG_VAR_INT)
599                 LM_INFO("%.*s.%.*s has been changed to %d\n",
600                                 group_name->len, group_name->s,
601                                 var_name->len, var_name->s,
602                                 (int)(long)val);
603
604         else if (val_type == CFG_VAR_STRING)
605                 LM_INFO("%.*s.%.*s has been changed to \"%s\"\n",
606                                 group_name->len, group_name->s,
607                                 var_name->len, var_name->s,
608                                 (char *)val);
609
610         else if (val_type == CFG_VAR_STR)
611                 LM_INFO("%.*s.%.*s has been changed to \"%.*s\"\n",
612                                 group_name->len, group_name->s,
613                                 var_name->len, var_name->s,
614                                 ((str *)val)->len, ((str *)val)->s);
615
616         else if (val_type == CFG_VAR_UNSET)
617                 LM_INFO("%.*s.%.*s has been deleted\n",
618                                 group_name->len, group_name->s,
619                                 var_name->len, var_name->s);
620
621         else
622                 LM_INFO("%.*s.%.*s has been changed\n",
623                                 group_name->len, group_name->s,
624                                 var_name->len, var_name->s);
625
626         if (group_id)
627                 LM_INFO("group id = %u\n", *group_id);
628
629         convert_val_cleanup();
630         return 0;
631
632 error:
633         if (cfg_shmized) CFG_WRITER_UNLOCK();
634         if (block) cfg_block_free(block);
635         if (new_array) shm_free(new_array);
636         if (child_cb) cfg_child_cb_free_list(child_cb);
637         if (replaced) shm_free(replaced);
638
639 error0:
640         LM_ERR("failed to set the variable: %.*s.%.*s\n",
641                         group_name->len, group_name->s,
642                         var_name->len, var_name->s);
643
644
645         convert_val_cleanup();
646         return -1;
647 }
648
649 /* wrapper function for cfg_set_now */
650 int cfg_set_now_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
651                 str *var_name, int val)
652 {
653         return cfg_set_now(ctx, group_name, group_id, var_name,
654                         (void *)(long)val, CFG_VAR_INT);
655 }
656
657 /* wrapper function for cfg_set_now */
658 int cfg_set_now_string(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
659                 str *var_name, char *val)
660 {
661         return cfg_set_now(ctx, group_name, group_id, var_name,
662                         (void *)val, CFG_VAR_STRING);
663 }
664
665 /* wrapper function for cfg_set_now */
666 int cfg_set_now_str(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
667                 str *var_name, str *val)
668 {
669         return cfg_set_now(ctx, group_name, group_id, var_name,
670                         (void *)val, CFG_VAR_STR);
671 }
672
673 /* Delete a variable from the group instance.
674  * wrapper function for cfg_set_now */
675 int cfg_del_now(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
676                 str *var_name)
677 {
678         return cfg_set_now(ctx, group_name, group_id, var_name,
679                         NULL, CFG_VAR_UNSET);
680 }
681
682 /* sets the value of a variable but does not commit the change
683  *
684  * return value:
685  *   0: success
686  *  -1: error
687  *   1: variable has not been found
688  */
689 int cfg_set_delayed(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
690                 str *var_name, void *val, unsigned int val_type)
691 {
692         cfg_group_t     *group;
693         cfg_mapping_t   *var;
694         void            *v;
695         unsigned char   *temp_handle;
696         int             temp_handle_created;
697         cfg_changed_var_t       *changed = NULL, **changed_p;
698         int             size;
699         str             s;
700         cfg_group_inst_t        *group_inst = NULL;
701         unsigned char           *var_block;
702
703         if (!cfg_shmized)
704                 /* the cfg has not been shmized yet, there is no
705                  * point in registering the change and committing it later */
706                 return cfg_set_now(ctx, group_name, group_id, var_name,
707                                 val, val_type);
708
709         if (!ctx) {
710                 LM_ERR("context is undefined\n");
711                 return -1;
712         }
713
714         if ((val_type == CFG_VAR_UNSET) && !group_id) {
715                 LM_ERR("Only group instance values can be deleted\n");
716                 return -1;
717         }
718
719         /* look-up the group and the variable */
720         if (cfg_lookup_var(group_name, var_name, &group, &var))
721                 return 1;
722
723         /* check whether the variable is read-only */
724         if (var->def->type & CFG_READONLY) {
725                 LM_ERR("variable is read-only\n");
726                 goto error0;
727         }
728
729         /* The additional variable instances having per-child process callback
730          * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
731          * The reason is that such variables typically set global parameters
732          * as opposed to per-process variables. Hence, it is not possible to set
733          * the group handle temporary to another block, and then reset it back later. */
734         if (group_id
735                         && var->def->on_set_child_cb
736                         && var->def->type & CFG_CB_ONLY_ONCE) {
737                 LM_ERR("This variable does not support muliple values.\n");
738                 goto error0;
739         }
740
741         /* check whether we have to convert the type */
742         if ((val_type != CFG_VAR_UNSET)
743                         && convert_val(val_type, val, CFG_INPUT_TYPE(var), &v))
744                 goto error0;
745
746         if ((val_type != CFG_VAR_UNSET)
747                         && (CFG_INPUT_TYPE(var) == CFG_INPUT_INT)
748                         && (var->def->min || var->def->max)) {
749                 /* perform a simple min-max check for integers */
750                 if (((int)(long)v < var->def->min)
751                                 || ((int)(long)v > var->def->max)) {
752                         LM_ERR("integer value is out of range\n");
753                         goto error0;
754                 }
755         }
756
757         /* the ctx must be locked while reading and writing
758          * the list of changed variables */
759         CFG_CTX_LOCK(ctx);
760
761         if ((val_type != CFG_VAR_UNSET) && var->def->on_change_cb) {
762                 /* The fixup function must see also the
763                  * not yet committed values, so a temporary handle
764                  * must be prepared that points to the new config.
765                  * Only the values within the group are applied,
766                  * other modifications are not visible to the callback.
767                  * The local config is the base. */
768                 if (!group_id) {
769                         var_block = *(group->handle);
770                 } else {
771                         if (!cfg_local) {
772                                 LM_ERR("Local configuration is missing\n");
773                                 goto error;
774                         }
775                         group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
776                                         group->size,
777                                         *group_id);
778                         if (!group_inst) {
779                                 LM_ERR("local group instance %.*s[%u] is not found\n",
780                                                 group_name->len, group_name->s, *group_id);
781                                 goto error;
782                         }
783                         var_block = group_inst->vars;
784                 }
785
786                 if (ctx->changed_first) {
787                         temp_handle = (unsigned char *)pkg_malloc(group->size);
788                         if (!temp_handle) {
789                                 PKG_MEM_ERROR;
790                                 goto error;
791                         }
792                         temp_handle_created = 1;
793                         memcpy(temp_handle, var_block, group->size);
794
795                         /* apply the changes */
796                         for (   changed = ctx->changed_first;
797                                         changed;
798                                         changed = changed->next
799                                 ) {
800                                 if (changed->group != group)
801                                         continue;
802                                 if ((!group_id && !changed->group_id_set) /* default values */
803                                                 || (group_id && !changed->group_id_set
804                                                         && !CFG_VAR_TEST(group_inst, changed->var))
805                                                 /* default value is changed which affects the group_instance */
806                                                 || (group_id && changed->group_id_set
807                                                         && (*group_id == changed->group_id))
808                                                 /* change within the group instance */
809                                                 )
810                                         memcpy( temp_handle + changed->var->offset,
811                                                         changed->new_val.vraw,
812                                                         cfg_var_size(changed->var));
813                         }
814                 } else {
815                         /* there is not any change */
816                         temp_handle = var_block;
817                         temp_handle_created = 0;
818                 }
819
820                 if (var->def->on_change_cb(temp_handle,
821                                         group_name,
822                                         var_name,
823                                         &v) < 0) {
824                         LM_ERR("fixup failed\n");
825                         if (temp_handle_created) pkg_free(temp_handle);
826                         goto error;
827                 }
828                 if (temp_handle_created) pkg_free(temp_handle);
829
830         }
831
832         /* everything went ok, we can add the new value to the list */
833         size = sizeof(cfg_changed_var_t)
834                 - sizeof(((cfg_changed_var_t*)0)->new_val)
835                 + ((val_type != CFG_VAR_UNSET) ? cfg_var_size(var) : 0);
836         changed = (cfg_changed_var_t *)shm_malloc(size);
837         if (!changed) {
838                 SHM_MEM_ERROR;
839                 goto error;
840         }
841         memset(changed, 0, size);
842         changed->group = group;
843         changed->var = var;
844         if (group_id) {
845                 changed->group_id = *group_id;
846                 changed->group_id_set = 1;
847         }
848
849         if (val_type != CFG_VAR_UNSET) {
850                 switch (CFG_VAR_TYPE(var)) {
851
852                         case CFG_VAR_INT:
853                                 changed->new_val.vint = (int)(long)v;
854                                 break;
855
856                         case CFG_VAR_STRING:
857                                 /* clone the string to shm mem */
858                                 s.s = v;
859                                 s.len = (s.s) ? strlen(s.s) : 0;
860                                 if (cfg_clone_str(&s, &s)) goto error;
861                                 changed->new_val.vp = s.s;
862                                 break;
863
864                         case CFG_VAR_STR:
865                                 /* clone the string to shm mem */
866                                 s = *(str *)v;
867                                 if (cfg_clone_str(&s, &s)) goto error;
868                                 changed->new_val.vstr=s;
869                                 break;
870
871                         case CFG_VAR_POINTER:
872                                 changed->new_val.vp=v;
873                                 break;
874
875                 }
876         } else {
877                 changed->del_value = 1;
878         }
879
880         /* Order the changes by group + group_id + original order.
881          * Hence, the list is still kept in order within the group.
882          * The changes can be committed faster this way, the group instances
883          * do not have to be looked-up for each and every variable. */
884         /* Check whether there is any variable in the list which
885          * belongs to the same group */
886         for (   changed_p = &ctx->changed_first;
887                         *changed_p && ((*changed_p)->group != changed->group);
888                         changed_p = &(*changed_p)->next);
889         /* try to find the group instance, and move changed_p to the end of
890          * the instance. */
891         for (   ;
892                         *changed_p
893                         && ((*changed_p)->group == changed->group)
894                         && (!(*changed_p)->group_id_set
895                                 || ((*changed_p)->group_id_set && changed->group_id_set
896                                         && ((*changed_p)->group_id <= changed->group_id)));
897                         changed_p = &(*changed_p)->next);
898         /* Add the new variable before *changed_p */
899         changed->next = *changed_p;
900         *changed_p = changed;
901
902         CFG_CTX_UNLOCK(ctx);
903
904         if (val_type == CFG_VAR_INT)
905                 LM_INFO("%.*s.%.*s is going to be changed to %d "
906                                 "[context=%p]\n",
907                                 group_name->len, group_name->s,
908                                 var_name->len, var_name->s,
909                                 (int)(long)val,
910                                 ctx);
911
912         else if (val_type == CFG_VAR_STRING)
913                 LM_INFO("%.*s.%.*s is going to be changed to \"%s\" "
914                                 "[context=%p]\n",
915                                 group_name->len, group_name->s,
916                                 var_name->len, var_name->s,
917                                 (char *)val,
918                                 ctx);
919
920         else if (val_type == CFG_VAR_STR)
921                 LM_INFO("%.*s.%.*s is going to be changed to \"%.*s\" "
922                                 "[context=%p]\n",
923                                 group_name->len, group_name->s,
924                                 var_name->len, var_name->s,
925                                 ((str *)val)->len, ((str *)val)->s,
926                                 ctx);
927
928         else if (val_type == CFG_VAR_UNSET)
929                 LM_INFO("%.*s.%.*s is going to be deleted "
930                                 "[context=%p]\n",
931                                 group_name->len, group_name->s,
932                                 var_name->len, var_name->s,
933                                 ctx);
934
935         else
936                 LM_INFO("%.*s.%.*s is going to be changed "
937                                 "[context=%p]\n",
938                                 group_name->len, group_name->s,
939                                 var_name->len, var_name->s,
940                                 ctx);
941
942         if (group_id)
943                 LM_INFO("group id = %u [context=%p]\n",
944                                 *group_id,
945                                 ctx);
946
947         convert_val_cleanup();
948         return 0;
949
950 error:
951         CFG_CTX_UNLOCK(ctx);
952         if (changed) shm_free(changed);
953 error0:
954         LM_ERR("failed to set the variable: %.*s.%.*s\n",
955                         group_name->len, group_name->s,
956                         var_name->len, var_name->s);
957
958         convert_val_cleanup();
959         return -1;
960 }
961
962 /* wrapper function for cfg_set_delayed */
963 int cfg_set_delayed_int(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
964                 str *var_name, int val)
965 {
966         return cfg_set_delayed(ctx, group_name, group_id, var_name,
967                         (void *)(long)val, CFG_VAR_INT);
968 }
969
970 /* wrapper function for cfg_set_delayed */
971 int cfg_set_delayed_string(cfg_ctx_t *ctx, str *group_name,
972                 unsigned int *group_id, str *var_name, char *val)
973 {
974         return cfg_set_delayed(ctx, group_name, group_id, var_name,
975                         (void *)val, CFG_VAR_STRING);
976 }
977
978 /* wrapper function for cfg_set_delayed */
979 int cfg_set_delayed_str(cfg_ctx_t *ctx, str *group_name,
980                 unsigned int *group_id, str *var_name, str *val)
981 {
982         return cfg_set_delayed(ctx, group_name, group_id, var_name,
983                         (void *)val, CFG_VAR_STR);
984 }
985
986 /* Delete a variable from the group instance.
987  * wrapper function for cfg_set_delayed */
988 int cfg_del_delayed(cfg_ctx_t *ctx, str *group_name,
989                 unsigned int *group_id, str *var_name)
990 {
991         return cfg_set_delayed(ctx, group_name, group_id, var_name,
992                         NULL, CFG_VAR_UNSET);
993 }
994
995 /* commits the previously prepared changes within the context */
996 int cfg_commit(cfg_ctx_t *ctx)
997 {
998         int     replaced_num = 0;
999         cfg_changed_var_t       *changed, *changed2;
1000         cfg_block_t     *block = NULL;
1001         void    **replaced = NULL;
1002         cfg_child_cb_t  *child_cb;
1003         cfg_child_cb_t  *child_cb_first = NULL;
1004         cfg_child_cb_t  *child_cb_last = NULL;
1005         int     size;
1006         void    *p;
1007         str     s, s2;
1008         cfg_group_t     *group;
1009         cfg_group_inst_t        *group_inst = NULL;
1010
1011         if (!ctx) {
1012                 LM_ERR("context is undefined\n");
1013                 return -1;
1014         }
1015
1016         if (!cfg_shmized) return 0; /* nothing to do */
1017
1018         /* the ctx must be locked while reading and writing
1019          * the list of changed variables */
1020         CFG_CTX_LOCK(ctx);
1021
1022         /* is there any change? */
1023         if (!ctx->changed_first) goto done;
1024
1025         /* Count the number of replaced strings,
1026          * and replaced group arrays.
1027          * Prepare the linked list of per-child process
1028          * callbacks, that will be added to the global list. */
1029         for(changed = ctx->changed_first, group = NULL; changed;
1030                         changed = changed->next) {
1031                 /* Each string/str potentially causes an old string to be freed
1032                  * unless the variable of an additional group instance is set
1033                  * which uses the default value. This case cannot be determined
1034                  * without locking *cfg_global, hence, it is better to count these
1035                  * strings as well even though the slot might not be used later. */
1036                 if((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1037                                 || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1038                         replaced_num++;
1039
1040                 /* See the above comments for strings */
1041                 if (group != changed->group) {
1042                         replaced_num++;
1043                         group = changed->group;
1044                 }
1045
1046                 if (changed->group && !changed->group_id_set
1047                                 && changed->var->def->on_set_child_cb) {
1048                         s.s = changed->group->name;
1049                         s.len = changed->group->name_len;
1050                         s2.s = changed->var->def->name;
1051                         s2.len = changed->var->name_len;
1052                         child_cb = cfg_child_cb_new(&s, &s2,
1053                                         changed->var->def->on_set_child_cb,
1054                                         changed->var->def->type);
1055                         if (!child_cb) goto error0;
1056
1057                         if (child_cb_last)
1058                                 child_cb_last->next = child_cb;
1059                         else
1060                                 child_cb_first = child_cb;
1061                         child_cb_last = child_cb;
1062                 }
1063         }
1064
1065         if (replaced_num) {
1066                 /* allocate memory for the replaced string array */
1067                 size = sizeof(void *)*(replaced_num + 1);
1068                 replaced = (void **)shm_malloc(size);
1069                 if (!replaced) {
1070                         SHM_MEM_ERROR;
1071                         goto error0;
1072                 }
1073                 memset(replaced, 0 , size);
1074         } else {
1075                 /* no replacement */
1076                 LM_INFO("commit operation executed without having changes\n");
1077                 return 0;
1078         }
1079
1080         /* make sure that nobody else replaces the global config
1081          * while the new one is prepared */
1082         CFG_WRITER_LOCK();
1083
1084         /* clone the memory block, and prepare the modification */
1085         if (!(block = cfg_clone_global()))
1086                 goto error;
1087
1088         /* Apply the modifications to the buffer.
1089          * Note that the cycle relies on the order of the groups and group
1090          * instances, i.e. the order is group + group_id + order of commits. */
1091         replaced_num = 0;
1092         for(changed = ctx->changed_first, group = NULL; /* group points to the
1093                                                                                                          * last group array that
1094                                                                                                          * has been cloned */
1095                         changed; changed = changed->next) {
1096                 if (!changed->group_id_set) {
1097                         p = CFG_GROUP_DATA(block, changed->group)
1098                                 + changed->var->offset;
1099                         group_inst = NULL; /* force the look-up of the next group_inst */
1100                 } else {
1101                         if (group != changed->group) {
1102                                 /* The group array has not been cloned yet. */
1103                                 group = changed->group;
1104                                 if (!(CFG_GROUP_META(block, group)->array =
1105                                                         cfg_clone_array(CFG_GROUP_META(*cfg_global, group), group))
1106                                                 ) {
1107                                         LM_ERR("group array cannot be cloned for %.*s[%u]\n",
1108                                                         group->name_len, group->name, changed->group_id);
1109                                         goto error;
1110                                 }
1111
1112                                 replaced[replaced_num] = CFG_GROUP_META(*cfg_global, group)->array;
1113                                 replaced_num++;
1114
1115                                 group_inst = NULL; /* fore the look-up of group_inst */
1116                         }
1117                         if (group && (!group_inst || (group_inst->id != changed->group_id))) {
1118                                 group_inst = cfg_find_group(CFG_GROUP_META(block, group),
1119                                                 group->size,
1120                                                 changed->group_id);
1121                         }
1122                         if (group && !group_inst) {
1123                                 LM_ERR("global group instance %.*s[%u] is not found\n",
1124                                                 group->name_len, group->name, changed->group_id);
1125                                 goto error;
1126                         }
1127                         p = group_inst->vars + changed->var->offset;
1128                 }
1129                 if(p==NULL) {
1130                         LM_ERR("failed to resolve valid variable offset\n");
1131                         goto error;
1132                 }
1133
1134                 if (((changed->group_id_set && !changed->del_value
1135                                                 && CFG_VAR_TEST_AND_SET(group_inst, changed->var))
1136                                         || (changed->group_id_set && changed->del_value
1137                                                 && CFG_VAR_TEST_AND_RESET(group_inst, changed->var))
1138                                         || !changed->group_id_set)
1139                                 && ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1140                                         || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1141                                 ) {
1142                         replaced[replaced_num] = *(char **)p;
1143                         if (replaced[replaced_num])
1144                                 replaced_num++;
1145                         /* else do not increase replaced_num, because
1146                          * the cfg_block_free() will stop at the first
1147                          * NULL value */
1148                 }
1149
1150                 if (!changed->del_value)
1151                         memcpy( p,
1152                                         changed->new_val.vraw,
1153                                         cfg_var_size(changed->var));
1154                 else
1155                         memcpy( p,
1156                                         CFG_GROUP_DATA(block, changed->group) + changed->var->offset,
1157                                         cfg_var_size(changed->var));
1158
1159
1160                 if (!changed->group_id_set) {
1161                         /* the default value is changed, the copies of this value
1162                          * need to be also updated */
1163                         if (cfg_update_defaults(CFG_GROUP_META(block, changed->group),
1164                                                 changed->group, changed->var, p,
1165                                                 (group != changed->group)) /* clone if the array
1166                                                                                                         * has not been cloned yet */
1167                                         )
1168                                 goto error;
1169                         if ((group != changed->group)
1170                                         && (CFG_GROUP_META(block, changed->group)->array
1171                                                 != CFG_GROUP_META(*cfg_global, changed->group)->array)
1172                                         ) {
1173                                 /* The array has been cloned */
1174                                 group = changed->group;
1175
1176                                 replaced[replaced_num] = CFG_GROUP_META(*cfg_global, group)->array;
1177                                 replaced_num++;
1178                         }
1179                 }
1180         }
1181
1182         /* replace the global config with the new one */
1183         cfg_install_global(block, replaced, child_cb_first, child_cb_last);
1184         CFG_WRITER_UNLOCK();
1185
1186         /* free the changed list */
1187         for (   changed = ctx->changed_first;
1188                         changed;
1189                         changed = changed2
1190                 ) {
1191                 changed2 = changed->next;
1192                 shm_free(changed);
1193         }
1194         ctx->changed_first = NULL;
1195
1196 done:
1197         LM_INFO("config changes have been applied [context=%p]\n",
1198                         ctx);
1199
1200         CFG_CTX_UNLOCK(ctx);
1201         return 0;
1202
1203 error:
1204         if (block) {
1205                 /* clean the new block from the cloned arrays */
1206                 for (group = cfg_group;
1207                                 group;
1208                                 group = group->next
1209                                 )
1210                         if (CFG_GROUP_META(block, group)->array
1211                                         && (CFG_GROUP_META(block, group)->array
1212                                                 != CFG_GROUP_META(*cfg_global, group)->array)
1213                                         )
1214                                 shm_free(CFG_GROUP_META(block, group)->array);
1215                 /* the block can be freed outside of the writer lock */
1216         }
1217         CFG_WRITER_UNLOCK();
1218         if (block)
1219                 shm_free(block);
1220
1221 error0:
1222         CFG_CTX_UNLOCK(ctx);
1223
1224         if (child_cb_first) cfg_child_cb_free_list(child_cb_first);
1225         if (replaced) shm_free(replaced);
1226
1227         return -1;
1228 }
1229
1230 /* drops the not yet committed changes within the context */
1231 int cfg_rollback(cfg_ctx_t *ctx)
1232 {
1233         cfg_changed_var_t       *changed, *changed2;
1234
1235         if (!ctx) {
1236                 LM_ERR("context is undefined\n");
1237                 return -1;
1238         }
1239
1240         if (!cfg_shmized) return 0; /* nothing to do */
1241
1242         LM_INFO("deleting the config changes [context=%p]\n",
1243                         ctx);
1244
1245         /* the ctx must be locked while reading and writing
1246          * the list of changed variables */
1247         CFG_CTX_LOCK(ctx);
1248
1249         for (changed = ctx->changed_first;
1250                         changed;
1251                         changed = changed2
1252                         ) {
1253                 changed2 = changed->next;
1254
1255                 if (!changed->del_value
1256                                 && ((CFG_VAR_TYPE(changed->var) == CFG_VAR_STRING)
1257                                         || (CFG_VAR_TYPE(changed->var) == CFG_VAR_STR))
1258                                 ) {
1259                         if (changed->new_val.vp)
1260                                 shm_free(changed->new_val.vp);
1261                 }
1262                 shm_free(changed);
1263         }
1264         ctx->changed_first = NULL;
1265
1266         CFG_CTX_UNLOCK(ctx);
1267
1268         return 0;
1269 }
1270
1271 /* retrieves the value of a variable
1272  * Return value:
1273  *  0 - success
1274  * -1 - error
1275  *  1 - variable exists, but it is not readable
1276  */
1277 int cfg_get_by_name(cfg_ctx_t *ctx, str *group_name, unsigned int *group_id,
1278                 str *var_name, void **val, unsigned int *val_type)
1279 {
1280         cfg_group_t     *group;
1281         cfg_mapping_t   *var;
1282         void            *p;
1283         static str      s;      /* we need the value even
1284                                          * after the function returns */
1285         cfg_group_inst_t        *group_inst;
1286
1287         /* verify the context even if we do not need it now
1288          * to make sure that a cfg driver has called the function
1289          * (very very weak security) */
1290         if (!ctx) {
1291                 LM_ERR("context is undefined\n");
1292                 return -1;
1293         }
1294
1295         /* look-up the group and the variable */
1296         if (cfg_lookup_var(group_name, var_name, &group, &var))
1297                 return -1;
1298
1299         if (var->def->on_change_cb) {
1300                 /* The variable cannot be retrieved, because the fixup
1301                  * function may have changed it, and it is better to return
1302                  * an error than an incorrect value */
1303                 return 1;
1304         }
1305
1306         if (group_id) {
1307                 if (!cfg_local) {
1308                         LM_ERR("Local configuration is missing\n");
1309                         return -1;
1310                 }
1311                 group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, group),
1312                                 group->size,
1313                                 *group_id);
1314                 if (!group_inst) {
1315                         LM_ERR("local group instance %.*s[%u] is not found\n",
1316                                         group_name->len, group_name->s, *group_id);
1317                         return -1;
1318                 }
1319                 p = group_inst->vars + var->offset;
1320
1321         } else {
1322                 /* use the module's handle to access the variable
1323                  * It means that the variable is read from the local config
1324                  * after forking */
1325                 p = *(group->handle) + var->offset;
1326         }
1327
1328         switch (CFG_VAR_TYPE(var)) {
1329                 case CFG_VAR_INT:
1330                         *val = (void *)(long)*(int *)p;
1331                         break;
1332
1333                 case CFG_VAR_STRING:
1334                         *val = (void *)*(char **)p;
1335                         break;
1336
1337                 case CFG_VAR_STR:
1338                         memcpy(&s, p, sizeof(str));
1339                         *val = (void *)&s;
1340                         break;
1341
1342                 case CFG_VAR_POINTER:
1343                         *val = *(void **)p;
1344                         break;
1345
1346         }
1347         *val_type = CFG_VAR_TYPE(var);
1348
1349         return 0;
1350 }
1351
1352 /* retrieves the default value of a variable
1353  * Return value:
1354  *  0 - success
1355  * -1 - error
1356  *  1 - variable exists, but it is not readable
1357  */
1358 int cfg_get_default_value_by_name(cfg_ctx_t *ctx, str *group_name,
1359                 unsigned int *group_id, str *var_name, void **val,
1360                 unsigned int *val_type)
1361 {
1362         cfg_group_t     *group;
1363         cfg_mapping_t   *var;
1364         void    *p;
1365         static str      s;      /* we need the value even
1366                                          * after the function returns */
1367
1368         /* verify the context even if we do not need it now
1369          * to make sure that a cfg driver has called the function
1370          * (very very weak security) */
1371         if (!ctx) {
1372                 LM_ERR("context is undefined\n");
1373                 return -1;
1374         }
1375
1376         /* look-up the group and the variable */
1377         if (cfg_lookup_var(group_name, var_name, &group, &var)) {
1378                 return -1;
1379         } else {
1380                 /* if variables exist then prevents resetting the read-only ones */
1381                 if(var->def->type & CFG_READONLY)
1382                         return -1;
1383         }
1384
1385         if (var->def->on_change_cb) {
1386                 /* The variable cannot be retrieved, because the fixup
1387                  * function may have changed it, and it is better to return
1388                  * an error than an incorrect value */
1389                 return 1;
1390         }
1391
1392         /* use the module's orig_handle to access the default registered value of
1393          * the variable for any group*/
1394         p = (group->orig_handle) + var->offset;
1395
1396         switch (CFG_VAR_TYPE(var)) {
1397                 case CFG_VAR_INT:
1398                         *val = (void *)(long)*(int *)p;
1399                         break;
1400
1401                 case CFG_VAR_STRING:
1402                         *val = (void *)*(char **)p;
1403                         break;
1404
1405                 case CFG_VAR_STR:
1406                         memcpy(&s, p, sizeof(str));
1407                         *val = (void *)&s;
1408                         break;
1409
1410                 case CFG_VAR_POINTER:
1411                         *val = *(void **)p;
1412                         break;
1413
1414         }
1415         *val_type = CFG_VAR_TYPE(var);
1416
1417         return 0;
1418 }
1419
1420
1421 /* returns the description of a variable */
1422 int cfg_help(cfg_ctx_t *ctx, str *group_name, str *var_name,
1423                 char **ch, unsigned int *input_type)
1424 {
1425         cfg_mapping_t   *var;
1426
1427         /* verify the context even if we do not need it now
1428          * to make sure that a cfg driver has called the function
1429          * (very very weak security) */
1430         if (!ctx) {
1431                 LM_ERR("context is undefined\n");
1432                 return -1;
1433         }
1434
1435         /* look-up the group and the variable */
1436         if (cfg_lookup_var(group_name, var_name, NULL, &var))
1437                 return -1;
1438
1439         *ch = var->def->descr;
1440         if (input_type)
1441                 *input_type = CFG_INPUT_TYPE(var);
1442         return 0;
1443 }
1444
1445 /* return the group name and the cfg structure definition,
1446  * and moves the handle to the next group
1447  * Return value:
1448  *      0: no more group
1449  *      1: group exists
1450  */
1451 int cfg_get_group_next(void **h,
1452                 str *gname, cfg_def_t **def)
1453 {
1454         cfg_group_t     *group;
1455
1456         group = (cfg_group_t *)(*h);
1457         if (group == NULL) return 0;
1458
1459         gname->s = group->name;
1460         gname->len = group->name_len;
1461         (*def) = group->mapping->def;
1462
1463         (*h) = (void *)group->next;
1464         return 1;
1465 }
1466
1467 /* Initialize the handle for cfg_diff_next() */
1468 int cfg_diff_init(cfg_ctx_t *ctx,
1469                 void **h)
1470 {
1471         if (!ctx) {
1472                 LM_ERR("context is undefined\n");
1473                 return -1;
1474         }
1475
1476         CFG_CTX_LOCK(ctx);
1477         (*h) = (void *)ctx->changed_first;
1478
1479         return 0;
1480 }
1481
1482 /* return the pending changes that have not been
1483  * committed yet
1484  * return value:
1485  *      1: valid value is found
1486  *      0: no more changed value found
1487  *      -1: error occurred
1488  */
1489 int cfg_diff_next(void **h,
1490                 str *gname, unsigned int **gid, str *vname,
1491                 void **old_val, void **new_val,
1492                 unsigned int *val_type)
1493 {
1494         cfg_changed_var_t       *changed;
1495         cfg_group_inst_t        *group_inst;
1496         union cfg_var_value     *pval_old, *pval_new;
1497         static str      old_s, new_s;   /* we need the value even
1498                                                                  * after the function returns */
1499
1500         changed = (cfg_changed_var_t *)(*h);
1501         if (changed == NULL) return 0;
1502
1503         gname->s = changed->group->name;
1504         gname->len = changed->group->name_len;
1505         *gid = (changed->group_id_set ? &changed->group_id : NULL);
1506         vname->s = changed->var->def->name;
1507         vname->len = changed->var->name_len;
1508
1509         /* use the module's handle to access the variable
1510          * It means that the variable is read from the local config
1511          * after forking */
1512         if (!changed->group_id_set) {
1513                 pval_old = (union cfg_var_value*)
1514                         (*(changed->group->handle) + changed->var->offset);
1515         } else {
1516                 if (!cfg_local) {
1517                         LM_ERR("Local configuration is missing\n");
1518                         return -1;
1519                 }
1520                 group_inst = cfg_find_group(CFG_GROUP_META(cfg_local, changed->group),
1521                                 changed->group->size,
1522                                 changed->group_id);
1523                 if (!group_inst) {
1524                         LM_ERR("local group instance %.*s[%u] is not found\n",
1525                                         changed->group->name_len, changed->group->name,
1526                                         changed->group_id);
1527                         return -1;
1528                 }
1529                 pval_old = (union cfg_var_value*)
1530                         (group_inst->vars + changed->var->offset);
1531         }
1532         if (!changed->del_value)
1533                 pval_new = &changed->new_val;
1534         else
1535                 pval_new = (union cfg_var_value*)
1536                         (*(changed->group->handle) + changed->var->offset);
1537
1538         switch (CFG_VAR_TYPE(changed->var)) {
1539                 case CFG_VAR_INT:
1540                         *old_val = (void *)(long)pval_old->vint;
1541                         *new_val = (void *)(long)pval_new->vint;
1542                         break;
1543
1544                 case CFG_VAR_STRING:
1545                         *old_val = pval_old->vp;
1546                         *new_val = pval_new->vp;
1547                         break;
1548
1549                 case CFG_VAR_STR:
1550                         old_s=pval_old->vstr;
1551                         *old_val = (void *)&old_s;
1552                         new_s=pval_new->vstr;
1553                         *new_val = (void *)&new_s;
1554                         break;
1555
1556                 case CFG_VAR_POINTER:
1557                         *old_val = pval_old->vp;
1558                         *new_val = pval_new->vp;
1559                         break;
1560
1561         }
1562         *val_type = CFG_VAR_TYPE(changed->var);
1563
1564         (*h) = (void *)changed->next;
1565         return 1;
1566 }
1567
1568 /* release the handle of cfg_diff_next() */
1569 void cfg_diff_release(cfg_ctx_t *ctx)
1570 {
1571         if (!ctx) {
1572                 LM_ERR("context is undefined\n");
1573                 return;
1574         }
1575
1576         CFG_CTX_UNLOCK(ctx);
1577 }
1578
1579 /* Add a new instance to an existing group */
1580 int cfg_add_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1581 {
1582         cfg_group_t     *group;
1583         cfg_block_t     *block = NULL;
1584         void            **replaced = NULL;
1585         cfg_group_inst_t        *new_array = NULL, *new_inst;
1586
1587         /* verify the context even if we do not need it now
1588          * to make sure that a cfg driver has called the function
1589          * (very very weak security) */
1590         if (!ctx) {
1591                 LM_ERR("context is undefined\n");
1592                 return -1;
1593         }
1594
1595         if (!cfg_shmized) {
1596                 /* Add a new variable without any value to
1597                  * the linked list of additional values. This variable
1598                  * will force a new group instance to be created. */
1599                 return new_add_var(group_name, group_id,  NULL /* var_name */,
1600                                 NULL /* val */, 0 /* type */);
1601         }
1602
1603         if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1604                 LM_ERR("group not found\n");
1605                 return -1;
1606         }
1607
1608         /* make sure that nobody else replaces the global config
1609          * while the new one is prepared */
1610         CFG_WRITER_LOCK();
1611         if (cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1612                                 group->size,
1613                                 group_id)
1614                         ) {
1615                 LM_DBG("the group instance already exists\n");
1616                 CFG_WRITER_UNLOCK();
1617                 return 0; /* not an error */
1618         }
1619
1620         /* clone the global memory block because the additional array can be
1621          * replaced only together with the block. */
1622         if (!(block = cfg_clone_global()))
1623                 goto error;
1624
1625         /* Extend the array with a new group instance */
1626         if (!(new_array = cfg_extend_array(CFG_GROUP_META(*cfg_global, group), group,
1627                                         group_id,
1628                                         &new_inst))
1629                         )
1630                 goto error;
1631
1632         /* fill in the new group instance with the default data */
1633         memcpy( new_inst->vars,
1634                         CFG_GROUP_DATA(*cfg_global, group),
1635                         group->size);
1636
1637         CFG_GROUP_META(block, group)->array = new_array;
1638         CFG_GROUP_META(block, group)->num++;
1639
1640         if (CFG_GROUP_META(*cfg_global, group)->array) {
1641                 /* prepare the array of the replaced strings,
1642                  * and replaced group instances,
1643                  * they will be freed when the old block is freed */
1644                 replaced = (void **)shm_malloc(sizeof(void *) * 2);
1645                 if (!replaced) {
1646                         SHM_MEM_ERROR;
1647                         goto error;
1648                 }
1649                 replaced[0] = CFG_GROUP_META(*cfg_global, group)->array;
1650                 replaced[1] = NULL;
1651         }
1652         /* replace the global config with the new one */
1653         cfg_install_global(block, replaced, NULL, NULL);
1654         CFG_WRITER_UNLOCK();
1655
1656         LM_INFO("group instance is added: %.*s[%u]\n",
1657                         group_name->len, group_name->s,
1658                         group_id);
1659
1660         /* Make sure that cfg_set_*() sees the change when
1661          * the function is immediately called after the group
1662          * instance has been added. */
1663         cfg_update();
1664
1665         return 0;
1666 error:
1667         CFG_WRITER_UNLOCK();
1668         if (block) cfg_block_free(block);
1669         if (new_array) shm_free(new_array);
1670         if (replaced) shm_free(replaced);
1671
1672         LM_ERR("Failed to add the group instance: %.*s[%u]\n",
1673                         group_name->len, group_name->s,
1674                         group_id);
1675
1676         return -1;
1677 }
1678
1679 /* Delete an instance of a group */
1680 int cfg_del_group_inst(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1681 {
1682         cfg_group_t     *group;
1683         cfg_block_t     *block = NULL;
1684         void            **replaced = NULL;
1685         cfg_group_inst_t        *new_array = NULL, *group_inst;
1686         cfg_mapping_t   *var;
1687         int             i, num;
1688
1689         /* verify the context even if we do not need it now
1690          * to make sure that a cfg driver has called the function
1691          * (very very weak security) */
1692         if (!ctx) {
1693                 LM_ERR("context is undefined\n");
1694                 return -1;
1695         }
1696
1697         if (!cfg_shmized) {
1698                 /* It makes no sense to delete a group instance that has not
1699                  * been created yet */
1700                 return -1;
1701         }
1702
1703         if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1704                 LM_ERR("group not found\n");
1705                 return -1;
1706         }
1707
1708         /* make sure that nobody else replaces the global config
1709          * while the new one is prepared */
1710         CFG_WRITER_LOCK();
1711         if (!(group_inst = cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1712                                         group->size,
1713                                         group_id))
1714                         ) {
1715                 LM_DBG("the group instance does not exist\n");
1716                 goto error;
1717         }
1718
1719         /* clone the global memory block because the additional array can be
1720          * replaced only together with the block. */
1721         if (!(block = cfg_clone_global()))
1722                 goto error;
1723
1724         /* Remove the group instance from the array. */
1725         if (cfg_collapse_array(CFG_GROUP_META(*cfg_global, group), group,
1726                                 group_inst,
1727                                 &new_array))
1728                 goto error;
1729
1730         CFG_GROUP_META(block, group)->array = new_array;
1731         CFG_GROUP_META(block, group)->num--;
1732
1733         if (CFG_GROUP_META(*cfg_global, group)->array) {
1734                 /* prepare the array of the replaced strings,
1735                  * and replaced group instances,
1736                  * they will be freed when the old block is freed */
1737
1738                 /* count the number of strings that has to be freed */
1739                 num = 0;
1740                 for (i = 0; i < group->num; i++) {
1741                         var = &group->mapping[i];
1742                         if (CFG_VAR_TEST(group_inst, var)
1743                                         && ((CFG_VAR_TYPE(var) == CFG_VAR_STRING)
1744                                                 || (CFG_VAR_TYPE(var) == CFG_VAR_STR))
1745                                         && (*(char **)(group_inst->vars + var->offset) != NULL))
1746                                 num++;
1747                 }
1748
1749                 replaced = (void **)shm_malloc(sizeof(void *) * (num + 2));
1750                 if (!replaced) {
1751                         SHM_MEM_ERROR;
1752                         goto error;
1753                 }
1754
1755                 if (num) {
1756                         /* There was at least one string to free, go though the list again */
1757                         num = 0;
1758                         for (i = 0; i < group->num; i++) {
1759                                 var = &group->mapping[i];
1760                                 if (CFG_VAR_TEST(group_inst, var)
1761                                                 && ((CFG_VAR_TYPE(var) == CFG_VAR_STRING)
1762                                                         || (CFG_VAR_TYPE(var) == CFG_VAR_STR))
1763                                                 && (*(char **)(group_inst->vars + var->offset) != NULL)
1764                                                 ) {
1765                                         replaced[num] = *(char **)(group_inst->vars + var->offset);
1766                                         num++;
1767                                 }
1768                         }
1769                 }
1770
1771                 replaced[num] = CFG_GROUP_META(*cfg_global, group)->array;
1772                 replaced[num+1] = NULL;
1773         }
1774         /* replace the global config with the new one */
1775         cfg_install_global(block, replaced, NULL, NULL);
1776         CFG_WRITER_UNLOCK();
1777
1778         LM_INFO("group instance is deleted: %.*s[%u]\n",
1779                         group_name->len, group_name->s,
1780                         group_id);
1781
1782         /* Make sure that cfg_set_*() sees the change when
1783          * the function is immediately called after the group
1784          * instance has been deleted. */
1785         cfg_update();
1786
1787         return 0;
1788 error:
1789         CFG_WRITER_UNLOCK();
1790         if (block) cfg_block_free(block);
1791         if (new_array) shm_free(new_array);
1792         if (replaced) shm_free(replaced);
1793
1794         LM_ERR("Failed to delete the group instance: %.*s[%u]\n",
1795                         group_name->len, group_name->s,
1796                         group_id);
1797
1798         return -1;
1799 }
1800
1801 /* Check the existance of a group instance.
1802  * return value:
1803  *      1: exists
1804  *      0: does not exist
1805  */
1806 int cfg_group_inst_exists(cfg_ctx_t *ctx, str *group_name, unsigned int group_id)
1807 {
1808         cfg_group_t     *group;
1809         cfg_add_var_t   *add_var;
1810         int     found;
1811
1812         /* verify the context even if we do not need it now
1813          * to make sure that a cfg driver has called the function
1814          * (very very weak security) */
1815         if (!ctx) {
1816                 LM_ERR("context is undefined\n");
1817                 return 0;
1818         }
1819
1820         if (!(group = cfg_lookup_group(group_name->s, group_name->len))) {
1821                 LM_ERR("group not found\n");
1822                 return 0;
1823         }
1824
1825         if (!cfg_shmized) {
1826                 /* group instances are stored in the additional variable list
1827                  * before forking */
1828                 found = 0;
1829                 for (add_var = group->add_var;
1830                                 add_var;
1831                                 add_var = add_var->next
1832                         )
1833                         if (add_var->group_id == group_id) {
1834                                 found = 1;
1835                                 break;
1836                         }
1837
1838         } else {
1839                 /* make sure that nobody else replaces the global config meantime */
1840                 CFG_WRITER_LOCK();
1841                 found = (cfg_find_group(CFG_GROUP_META(*cfg_global, group),
1842                                         group->size,
1843                                         group_id)
1844                                 != NULL);
1845                 CFG_WRITER_UNLOCK();
1846         }
1847
1848         return found;
1849 }
1850
1851 /* Apply the changes to a group instance as long as the additional variable
1852  * belongs to the specified group_id. *add_var_p is moved to the next additional
1853  * variable, and all the consumed variables are freed.
1854  * This function can be used only during the cfg shmize process.
1855  * For internal use only!
1856  */
1857 int cfg_apply_list(cfg_group_inst_t *ginst, cfg_group_t *group,
1858                 unsigned int group_id, cfg_add_var_t **add_var_p)
1859 {
1860         cfg_add_var_t   *add_var;
1861         cfg_mapping_t   *var;
1862         void            *val, *v, *p;
1863         str             group_name, var_name, s;
1864         char            *old_string;
1865
1866         group_name.s = group->name;
1867         group_name.len = group->name_len;
1868         while (*add_var_p && ((*add_var_p)->group_id == group_id)) {
1869                 add_var = *add_var_p;
1870
1871                 if (add_var->type == 0)
1872                         goto done; /* Nothing needs to be changed,
1873                                                 * this additional variable only forces a new
1874                                                 * group instance to be created. */
1875                 var_name.s = add_var->name;
1876                 var_name.len = add_var->name_len;
1877
1878                 if (!(var = cfg_lookup_var2(group, add_var->name, add_var->name_len))) {
1879                         LM_ERR("Variable is not found: %.*s.%.*s\n",
1880                                         group->name_len, group->name,
1881                                         add_var->name_len, add_var->name);
1882                         goto error;
1883                 }
1884
1885                 /* check whether the variable is read-only */
1886                 if (var->def->type & CFG_READONLY) {
1887                         LM_ERR("variable is read-only\n");
1888                         goto error;
1889                 }
1890
1891                 /* The additional variable instances having per-child process callback
1892                  * with CFG_CB_ONLY_ONCE flag cannot be rewritten.
1893                  * The reason is that such variables typically set global parameters
1894                  * as opposed to per-process variables. Hence, it is not possible to set
1895                  * the group handle temporary to another block, and then reset it back later. */
1896                 if (var->def->on_set_child_cb
1897                                 && var->def->type & CFG_CB_ONLY_ONCE
1898                                 ) {
1899                         LM_ERR("This variable does not support muliple values.\n");
1900                         goto error;
1901                 }
1902
1903                 switch(add_var->type) {
1904                         case CFG_VAR_INT:
1905                                 val = (void *)(long)add_var->val.i;
1906                                 break;
1907                         case CFG_VAR_STR:
1908                                 val = (str *)&(add_var->val.s);
1909                                 break;
1910                         case CFG_VAR_STRING:
1911                                 val = (char *)add_var->val.ch;
1912                                 break;
1913                         default:
1914                                 LM_ERR("unsupported variable type: %d\n",
1915                                                 add_var->type);
1916                                 goto error;
1917                 }
1918                 /* check whether we have to convert the type */
1919                 if (convert_val(add_var->type, val, CFG_INPUT_TYPE(var), &v))
1920                         goto error;
1921
1922                 if ((CFG_INPUT_TYPE(var) == CFG_INPUT_INT)
1923                                 && (var->def->min || var->def->max)) {
1924                         /* perform a simple min-max check for integers */
1925                         if (((int)(long)v < var->def->min)
1926                                         || ((int)(long)v > var->def->max)) {
1927                                 LM_ERR("integer value is out of range\n");
1928                                 goto error;
1929                         }
1930                 }
1931
1932                 if (var->def->on_change_cb) {
1933                         /* Call the fixup function.
1934                          * The handle can point to the variables of the group instance. */
1935                         if (var->def->on_change_cb(ginst->vars,
1936                                                 &group_name,
1937                                                 &var_name,
1938                                                 &v) < 0) {
1939                                 LM_ERR("fixup failed\n");
1940                                 goto error;
1941                         }
1942                 }
1943
1944                 p = ginst->vars + var->offset;
1945                 old_string = NULL;
1946                 /* set the new value */
1947                 switch (CFG_VAR_TYPE(var)) {
1948                         case CFG_VAR_INT:
1949                                 *(int *)p = (int)(long)v;
1950                                 break;
1951
1952                         case CFG_VAR_STRING:
1953                                 /* clone the string to shm mem */
1954                                 s.s = v;
1955                                 s.len = (s.s) ? strlen(s.s) : 0;
1956                                 if (cfg_clone_str(&s, &s)) goto error;
1957                                 old_string = *(char **)p;
1958                                 *(char **)p = s.s;
1959                                 break;
1960
1961                         case CFG_VAR_STR:
1962                                 /* clone the string to shm mem */
1963                                 s = *(str *)v;
1964                                 if (cfg_clone_str(&s, &s)) goto error;
1965                                 old_string = *(char **)p;
1966                                 memcpy(p, &s, sizeof(str));
1967                                 break;
1968
1969                         case CFG_VAR_POINTER:
1970                                 *(void **)p = v;
1971                                 break;
1972
1973                 }
1974                 if (CFG_VAR_TEST_AND_SET(ginst, var) && old_string)
1975                         shm_free(old_string); /* the string was already in shm memory,
1976                                                                 * it needs to be freed.
1977                                                                 * This can happen when the same variable is set
1978                                                                 * multiple times before forking. */
1979
1980                 if (add_var->type == CFG_VAR_INT)
1981                         LM_INFO("%.*s[%u].%.*s has been set to %d\n",
1982                                         group_name.len, group_name.s,
1983                                         group_id,
1984                                         var_name.len, var_name.s,
1985                                         (int)(long)val);
1986
1987                 else if (add_var->type == CFG_VAR_STRING)
1988                         LM_INFO("%.*s[%u].%.*s has been set to \"%s\"\n",
1989                                         group_name.len, group_name.s,
1990                                         group_id,
1991                                         var_name.len, var_name.s,
1992                                         (char *)val);
1993
1994                 else /* str type */
1995                         LM_INFO("%.*s[%u].%.*s has been set to \"%.*s\"\n",
1996                                         group_name.len, group_name.s,
1997                                         group_id,
1998                                         var_name.len, var_name.s,
1999                                         ((str *)val)->len, ((str *)val)->s);
2000
2001                 convert_val_cleanup();
2002
2003 done:
2004                 *add_var_p = add_var->next;
2005
2006                 if ((add_var->type == CFG_VAR_STR) && add_var->val.s.s)
2007                         pkg_free(add_var->val.s.s);
2008                 else if ((add_var->type == CFG_VAR_STRING) && add_var->val.ch)
2009                         pkg_free(add_var->val.ch);
2010                 pkg_free(add_var);
2011         }
2012         return 0;
2013
2014 error:
2015         LM_ERR("Failed to set the value for: %.*s[%u].%.*s\n",
2016                         group->name_len, group->name,
2017                         group_id,
2018                         add_var->name_len, add_var->name);
2019         convert_val_cleanup();
2020         return -1;
2021 }