- #define CFG_INPUT_SHIFT is used instead of a hardwired value
[sip-router] / cfg / cfg_script.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2008 iptelorg GmbH
5  *
6  * This file is part of ser, a free SIP server.
7  *
8  * ser is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version
12  *
13  * For a license to use the ser software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * ser is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  *
27  * History
28  * -------
29  *  2008-01-24  dynamic groups are introduced in order to make
30  *              variable declaration possible in the script (Miklos)
31  */
32
33 #include <string.h>
34
35 #include "../mem/mem.h"
36 #include "../ut.h"
37 #include "cfg_struct.h"
38 #include "cfg.h"
39 #include "cfg_script.h"
40
41 /* allocates memory for a new config script variable
42  * The value of the variable is not set!
43  */
44 cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
45                                         char *descr)
46 {
47         cfg_group_t     *group;
48         cfg_script_var_t        *var;
49         int     gname_len, vname_len, descr_len;
50
51         LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname);
52
53         if (cfg_shmized) {
54                 LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, "
55                         "the config has been already shmized\n");
56                 return NULL;
57         }
58
59         gname_len = strlen(gname);
60         /* the group may have been already declared */
61         for (   group = cfg_group;
62                 group;
63                 group = group->next
64         ) {
65                 if ((group->name_len == gname_len) &&
66                 (memcmp(group->name, gname, gname_len) == 0)) {
67                         if (group->dynamic == 0) {
68                                 /* the group has been already declared by a module or by the core */
69                                 LOG(L_ERR, "ERROR: new_cfg_script_var(): "
70                                         "configuration group has been already declared: %s\n",
71                                         gname);
72                                 return NULL;
73                         }
74                         /* the dynamic group is found */
75                         break;
76                 }
77         }
78
79         if (!group) {
80                 /* create a new group with NULL values, we will fix it later,
81                 when all the variables are known */
82                 group = cfg_new_group(gname, gname_len,
83                                         0 /* num */, NULL /* mapping */,
84                                         NULL /* vars */, 0 /* size */, NULL /* handle */);
85                                         
86                 if (!group) goto error;
87                 group->dynamic = 1;
88         }
89
90         /* verify that the variable does not exist */
91         vname_len = strlen(vname);
92
93         for (   var = (cfg_script_var_t *)group->vars;
94                 var;
95                 var = var->next
96         ) {
97                 if ((var->name_len == vname_len) &&
98                 (memcmp(var->name, vname, vname_len) == 0)) {
99                         LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n",
100                                         gname, vname);
101                         return NULL;
102                 }
103         }
104
105         switch (type) {
106         case CFG_VAR_INT:
107                 group->size = ROUND_INT(group->size);
108                 group->size += sizeof(int);
109                 break;
110
111         case CFG_VAR_STR:
112                 group->size = ROUND_POINTER(group->size);
113                 group->size += sizeof(str);
114                 break;
115
116         default:
117                 LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n");
118                 return NULL;
119         }
120         group->num++;
121
122         var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
123         if (!var) goto error;
124         memset(var, sizeof(cfg_script_var_t), 0);
125         var->type = type;
126
127         /* add the variable to the group */
128         var->next = (cfg_script_var_t *)(void *)group->vars;
129         group->vars = (char *)(void *)var;
130
131         /* clone the name of the variable */
132         var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1));
133         if (!var->name) goto error;
134         memcpy(var->name, vname, vname_len + 1);
135         var->name_len = vname_len;
136
137         if (descr) {
138                 /* save the description */
139                 descr_len = strlen(descr);
140                 var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1));
141                 if (!var->descr) goto error;
142                 memcpy(var->descr, descr, descr_len + 1);
143         }
144
145         return var;
146
147 error:
148         LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n");
149         return NULL;
150 }
151
152 /* fix-up the dynamically declared group:
153  *  - allocate memory for the arrays
154  *  - set the values within the memory block
155  *  - notify the drivers about the new group
156  */
157 int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
158 {
159         cfg_mapping_t           *mapping = NULL;
160         cfg_def_t               *def = NULL;
161         void                    **handle = NULL;
162         int                     i, offset;
163         cfg_script_var_t        *script_var, *script_var2;
164         str                     s;
165
166         mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num);
167         if (!mapping) goto error;
168         memset(mapping, 0, sizeof(cfg_mapping_t)*group->num);
169
170         /* The variable definition array must look like as if it was declared
171          * in C code, thus, add an additional slot at the end with NULL values */
172         def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1));
173         if (!def) goto error;
174         memset(def, 0, sizeof(cfg_def_t)*(group->num + 1));
175
176         /* fill the definition and the mapping arrays */
177         offset = 0;
178         for (   i = 0, script_var = (cfg_script_var_t *)group->vars;
179                 script_var;
180                 i++, script_var = script_var->next
181         ) {
182                 /* there has been already memory allocated for the name */
183                 def[i].name = script_var->name;
184                 def[i].type = script_var->type | (script_var->type << CFG_INPUT_SHIFT);
185                 def[i].descr = script_var->descr;
186
187                 mapping[i].def = &(def[i]);
188                 mapping[i].name_len = script_var->name_len;
189
190                 switch (script_var->type) {
191                 case CFG_VAR_INT:
192                         offset = ROUND_INT(offset);
193                         mapping[i].offset = offset;
194
195                         memcpy(block + offset, &script_var->val.i, sizeof(int));
196
197                         offset += sizeof(int);
198                         break;
199
200                 case CFG_VAR_STR:
201                         offset = ROUND_POINTER(offset);
202                         mapping[i].offset = offset;
203
204                         if (!(s.s = cfg_clone_str(script_var->val.s))) goto error;
205                         s.len = script_var->val.s.len;
206                         memcpy(block + offset, &s, sizeof(str));
207                         mapping[i].flag |= cfg_var_shmized;
208
209                         offset += sizeof(str);
210                         break;
211                 }
212         }
213
214         /* allocate a handle even if it will not be used to
215         directly access the variable, like handle->variable
216         cfg_get_* functions access the memory block via the handle
217         to make sure that it is always safe, thus, it must be created */
218         handle = (void **)pkg_malloc(sizeof(void *));
219         if (!handle) goto error;
220         *handle = NULL;
221         group->handle = handle;
222
223         group->mapping = mapping;
224
225         /* everything went fine, we can free the temporary list */
226         script_var = (cfg_script_var_t *)group->vars;
227         group->vars = NULL;
228         while (script_var) {
229                 script_var2 = script_var->next;
230                 if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
231                         pkg_free(script_var->val.s.s);
232                 pkg_free(script_var);
233                 script_var = script_var2;
234         }
235
236         return 0;
237
238 error:
239         if (mapping) pkg_free(mapping);
240         if (def) pkg_free(def);
241         if (handle) pkg_free(handle);
242
243         LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n");
244         return -1;
245 }
246
247 /* destory a dynamically allocated group definition */
248 void cfg_script_destroy(cfg_group_t *group)
249 {
250         int     i;
251         cfg_script_var_t        *script_var, *script_var2;
252
253         if (group->mapping && group->mapping->def) {
254                 for (i=0; i<group->num; i++) {
255                         if (group->mapping->def[i].name)
256                                 pkg_free(group->mapping->def[i].name);
257                         if (group->mapping->def[i].descr)
258                                 pkg_free(group->mapping->def[i].descr);
259                 }
260                 pkg_free(group->mapping->def);
261         }
262         if (group->mapping) pkg_free(group->mapping);
263         if (group->handle) pkg_free(group->handle);
264
265         /* it may happen that the the temporary var list
266         still exists because the fixup failed and did not complete */
267         script_var = (cfg_script_var_t *)group->vars;
268         while (script_var) {
269                 script_var2 = script_var->next;
270                 if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s) 
271                         pkg_free(script_var->val.s.s);
272                 pkg_free(script_var);
273                 script_var = script_var2;
274         }
275 }