c718f5a2c71d02e0d4fed966955b6838857d3126
[sip-router] / cfg / cfg.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2007 iptelorg GmbH
5  *
6  * This file is part of SIP-router, a free SIP server.
7  *
8  * SIP-router is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * SIP-router is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * History
23  * -------
24  *  2007-12-03  Initial version (Miklos)
25  */
26
27 #include <string.h>
28
29 #include "../ut.h"
30 #include "../mem/mem.h"
31 #include "cfg_struct.h"
32 #include "cfg_ctx.h"
33 #include "cfg_script.h"
34 #include "cfg.h"
35
36 /*! \brief declares a new cfg group
37  *
38  * handler is set to the memory area where the variables are stored
39  * \return value is -1 on error
40  */
41 int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
42                         void **handle)
43 {
44         int     i, num, size, group_name_len;
45         cfg_mapping_t   *mapping = NULL;
46         int types;
47
48         /* check the number of the variables */
49         for (num=0; def[num].name; num++);
50
51         mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*num);
52         if (!mapping) {
53                 LOG(L_ERR, "ERROR: register_cfg_def(): not enough memory\n");
54                 goto error;
55         }
56         memset(mapping, 0, sizeof(cfg_mapping_t)*num);
57         types=0;
58         /* calculate the size of the memory block that has to
59         be allocated for the cfg variables, and set the content of the 
60         cfg_mapping array the same time */
61         for (i=0, size=0; i<num; i++) {
62                 mapping[i].def = &(def[i]);
63                 mapping[i].name_len = strlen(def[i].name);
64                 mapping[i].pos = i;
65                 /* record all the types for sanity checks */
66                 types|=1 << CFG_VAR_MASK(def[i].type);
67
68                 /* padding depends on the type of the next variable */
69                 switch (CFG_VAR_MASK(def[i].type)) {
70
71                 case CFG_VAR_INT:
72                         size = ROUND_INT(size);
73                         mapping[i].offset = size;
74                         size += sizeof(int);
75                         break;
76
77                 case CFG_VAR_STRING:
78                 case CFG_VAR_POINTER:
79                         size = ROUND_POINTER(size);
80                         mapping[i].offset = size;
81                         size += sizeof(char *);
82                         break;
83
84                 case CFG_VAR_STR:
85                         size = ROUND_POINTER(size);
86                         mapping[i].offset = size;
87                         size += sizeof(str);
88                         break;
89
90                 default:
91                         LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: unsupported variable type\n",
92                                         group_name, def[i].name);
93                         goto error;
94                 }
95
96                 /* verify the type of the input */
97                 if (CFG_INPUT_MASK(def[i].type)==0) {
98                         def[i].type |= def[i].type << CFG_INPUT_SHIFT;
99                 } else {
100                         if ((CFG_INPUT_MASK(def[i].type) != CFG_VAR_MASK(def[i].type) << CFG_INPUT_SHIFT)
101                         && (def[i].on_change_cb == 0)) {
102                                 LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: variable and input types are "
103                                         "different, but no callback is defined for conversion\n",
104                                         group_name, def[i].name);
105                                 goto error;
106                         }
107                 }
108
109                 if (CFG_INPUT_MASK(def[i].type) > CFG_INPUT_STR) {
110                         LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: unsupported input type\n",
111                                         group_name, def[i].name);
112                         goto error;
113                 }
114
115                 if (def[i].type & CFG_ATOMIC) {
116                         if (CFG_VAR_MASK(def[i].type) != CFG_VAR_INT) {
117                                 LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: atomic change is allowed "
118                                                 "only for integer types\n",
119                                                 group_name, def[i].name);
120                                 goto error;
121                         }
122                         if (def[i].on_set_child_cb) {
123                                 LOG(L_ERR, "ERROR: register_cfg_def(): %s.%s: per-child process callback "
124                                                 "does not work together with atomic change\n",
125                                                 group_name, def[i].name);
126                                 goto error;
127                         }
128                 }
129         }
130
131         /* fix the computed size (char*, str or pointer members will force 
132            structure padding to multiple of sizeof(pointer)) */
133         if (types & ((1<<CFG_VAR_STRING)|(1<<CFG_VAR_STR)|(1<<CFG_VAR_POINTER)))
134                 size=ROUND_POINTER(size);
135         /* minor validation */
136         if (size != def_size) {
137                 LOG(L_ERR, "ERROR: register_cfg_def(): the specified size (%i) of the config "
138                         "structure does not equal with the calculated size (%i), check whether "
139                         "the variable types are correctly defined!\n", def_size, size);
140                 goto error;
141         }
142
143         group_name_len = strlen(group_name);
144         /* check for duplicates */
145         if (cfg_lookup_group(group_name, group_name_len)) {
146                 LOG(L_ERR, "ERROR: register_cfg_def(): "
147                         "configuration group has been already declared: %s\n",
148                         group_name);
149                 goto error;
150         }
151
152         /* create a new group
153         I will allocate memory in shm mem for the variables later in a single block,
154         when we know the size of all the registered groups. */
155         if (!cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle))
156                 goto error;
157
158         /* The cfg variables are ready to use, let us set the handle
159         before passing the new definitions to the drivers.
160         We make the interface usable for the fixup functions
161         at this step */
162         *handle = values;
163
164         /* notify the drivers about the new config definition */
165         cfg_notify_drivers(group_name, group_name_len, def);
166
167         LOG(L_DBG, "DEBUG: register_cfg_def(): "
168                 "new config group has been registered: '%s' (num=%d, size=%d)\n",
169                 group_name, num, size);
170
171         return 0;
172
173 error:
174         if (mapping) pkg_free(mapping);
175         LOG(L_ERR, "ERROR: register_cfg_def(): Failed to register the config group: %s\n",
176                         group_name);
177
178         return -1;
179 }
180
181 /* declares a single variable with integer type */
182 int cfg_declare_int(char *group_name, char *var_name,
183                 int val, int min, int max, char *descr)
184 {
185         cfg_script_var_t        *var;
186
187         if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr)) == NULL)
188                 return -1;
189
190         var->val.i = val;
191         var->min = min;
192         var->max = max;
193
194         return 0;
195 }
196
197 /* declares a single variable with str type */
198 int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
199 {
200         cfg_script_var_t        *var;
201         int     len;
202
203         if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr)) == NULL)
204                 return -1;
205
206         if (val) {
207                 len = strlen(val);
208                 var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
209                 if (!var->val.s.s) {
210                         LOG(L_ERR, "ERROR: cfg_declare_str(): not enough memory\n");
211                         return -1;
212                 }
213                 memcpy(var->val.s.s, val, len + 1);
214                 var->val.s.len = len;
215         } else {        
216                 var->val.s.s = NULL;
217                 var->val.s.len = 0;
218         }
219
220         return 0;
221 }
222
223 /* returns the handle of a cfg group */
224 void **cfg_get_handle(char *gname)
225 {
226         cfg_group_t     *group;
227
228         group = cfg_lookup_group(gname, strlen(gname));
229         if (!group || group->dynamic) return NULL;
230
231         return group->handle;
232 }