modules/ims_qos: added patch for flow-description bug when request originates from...
[sip-router] / src / core / cfg / cfg_script.c
1 /*
2  * Copyright (C) 2008 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
24 #include "../mem/mem.h"
25 #include "../ut.h"
26 #include "cfg_struct.h"
27 #include "cfg.h"
28 #include "cfg_ctx.h"
29 #include "cfg_script.h"
30
31 /* allocates memory for a new config script variable
32  * The value of the variable is not set!
33  */
34 cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
35                                         char *descr)
36 {
37         cfg_group_t     *group;
38         cfg_script_var_t        *var;
39         int     gname_len, vname_len, descr_len;
40
41         LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname);
42
43         if (cfg_shmized) {
44                 LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, "
45                         "the config has been already shmized\n");
46                 return NULL;
47         }
48
49         gname_len = strlen(gname);
50         vname_len = strlen(vname);
51         /* the group may have been already declared */
52         group = cfg_lookup_group(gname, gname_len);
53         if (group) {
54                 if (group->dynamic == CFG_GROUP_STATIC) {
55                         /* the group has been already declared by a module or by the core */
56                         LOG(L_ERR, "ERROR: new_cfg_script_var(): "
57                                 "configuration group has been already declared: %s\n",
58                                 gname);
59                         return NULL;
60                 }
61                 /* the dynamic or empty group is found */
62                 /* verify that the variable does not exist */
63                 for (   var = (cfg_script_var_t *)group->vars;
64                         var;
65                         var = var->next
66                 ) {
67                         if ((var->name_len == vname_len) &&
68                         (memcmp(var->name, vname, vname_len) == 0)) {
69                                 LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n",
70                                                 gname, vname);
71                                 return NULL;
72                         }
73                 }
74                 if (group->dynamic == CFG_GROUP_UNKNOWN)
75                         group->dynamic = CFG_GROUP_DYNAMIC;
76
77         } else {
78                 /* create a new group with NULL values, we will fix it later,
79                 when all the variables are known */
80                 group = cfg_new_group(gname, gname_len,
81                                         0 /* num */, NULL /* mapping */,
82                                         NULL /* vars */, 0 /* size */, NULL /* handle */);
83                                         
84                 if (!group) goto error;
85                 group->dynamic = CFG_GROUP_DYNAMIC;
86         }
87
88         switch (type) {
89         case CFG_VAR_INT:
90                 group->size = ROUND_INT(group->size);
91                 group->size += sizeof(int);
92                 break;
93
94         case CFG_VAR_STR:
95                 group->size = ROUND_POINTER(group->size);
96                 group->size += sizeof(str);
97                 break;
98
99         default:
100                 LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n");
101                 return NULL;
102         }
103
104         group->num++;
105         if (group->num > CFG_MAX_VAR_NUM) {
106                 LOG(L_ERR, "ERROR: new_cfg_script_var(): too many variables (%d) within a single group,"
107                         " the limit is %d. Increase CFG_MAX_VAR_NUM, or split the group into multiple"
108                         " definitions.\n",
109                         group->num, CFG_MAX_VAR_NUM);
110                 return NULL;
111         }
112
113         var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
114         if (!var) goto error;
115         memset(var, 0, sizeof(cfg_script_var_t));
116         var->type = type;
117
118         /* add the variable to the group */
119         var->next = (cfg_script_var_t *)(void *)group->vars;
120         group->vars = (char *)(void *)var;
121
122         /* clone the name of the variable */
123         var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1));
124         if (!var->name) goto error;
125         memcpy(var->name, vname, vname_len + 1);
126         var->name_len = vname_len;
127
128         if (descr) {
129                 /* save the description */
130                 descr_len = strlen(descr);
131                 var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1));
132                 if (!var->descr) goto error;
133                 memcpy(var->descr, descr, descr_len + 1);
134         }
135
136         return var;
137
138 error:
139         LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n");
140         return NULL;
141 }
142
143 /* Rewrite the value of an already declared script variable before forking.
144  * Return value:
145  *       0: success
146  *      -1: error
147  *       1: variable not found
148  */
149 int cfg_set_script_var(cfg_group_t *group, str *var_name,
150                         void *val, unsigned int val_type)
151 {
152         cfg_script_var_t        *var;
153         void    *v;
154         str     s;
155
156         if (cfg_shmized || (group->dynamic != CFG_GROUP_DYNAMIC)) {
157                 LOG(L_ERR, "BUG: cfg_set_script_var(): Not a dynamic group before forking\n");
158                 return -1;
159         }
160
161         for (   var = (cfg_script_var_t *)(void *)group->vars;
162                 var;
163                 var = var->next
164         ) {
165                 if ((var->name_len == var_name->len)
166                         && (memcmp(var->name, var_name->s, var_name->len) == 0)
167                 ) {
168                         switch (var->type) {
169                         case CFG_VAR_INT:
170                                 if (convert_val(val_type, val, CFG_INPUT_INT, &v))
171                                         goto error;
172                                 if ((var->min || var->max)
173                                         && ((var->min > (int)(long)v) || (var->max < (int)(long)v))
174                                 ) {
175                                         LOG(L_ERR, "ERROR: cfg_set_script_var(): integer value is out of range\n");
176                                         goto error;
177                                 }
178                                 var->val.i = (int)(long)v;
179                                 break;
180
181                         case CFG_VAR_STR:
182                                 if (convert_val(val_type, val, CFG_INPUT_STR, &v))
183                                         goto error;
184                                 if (((str *)v)->s) {
185                                         s.len = ((str *)v)->len;
186                                         s.s = pkg_malloc(sizeof(char) * (s.len + 1));
187                                         if (!s.s) {
188                                                 LOG(L_ERR, "ERROR: cfg_set_script_var(): not enough memory\n");
189                                                 goto error;
190                                         }
191                                         memcpy(s.s, ((str *)v)->s, s.len);
192                                         s.s[s.len] = '\0';
193                                 } else {
194                                         s.s = NULL;
195                                         s.len = 0;
196                                 }
197                                 if (var->val.s.s)
198                                         pkg_free(var->val.s.s);
199                                 var->val.s = s;
200                                 break;
201
202                         default:
203                                 LOG(L_ERR, "ERROR: cfg_set_script_var(): unsupported variable type\n");
204                                 goto error;
205                         }
206
207                         convert_val_cleanup();
208                         return 0;
209                 }
210         }
211
212         return 1;
213
214 error:
215         LOG(L_ERR, "ERROR: cfg_set_script_var(): failed to set the script variable: %.*s.%.*s\n",
216                         group->name_len, group->name,
217                         var_name->len, var_name->s);
218         return -1;
219 }
220
221 /* fix-up the dynamically declared group:
222  *  - allocate memory for the arrays
223  *  - set the values within the memory block
224  */
225 int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
226 {
227         cfg_mapping_t           *mapping = NULL;
228         cfg_def_t               *def = NULL;
229         void                    **handle = NULL;
230         int                     i, offset;
231         cfg_script_var_t        *script_var, *script_var2;
232         str                     s;
233
234         mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num);
235         if (!mapping) goto error;
236         memset(mapping, 0, sizeof(cfg_mapping_t)*group->num);
237
238         /* The variable definition array must look like as if it was declared
239          * in C code, thus, add an additional slot at the end with NULL values */
240         def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1));
241         if (!def) goto error;
242         memset(def, 0, sizeof(cfg_def_t)*(group->num + 1));
243
244         /* fill the definition and the mapping arrays */
245         offset = 0;
246         for (   i = 0, script_var = (cfg_script_var_t *)group->vars;
247                 script_var;
248                 i++, script_var = script_var->next
249         ) {
250                 /* there has been already memory allocated for the name */
251                 def[i].name = script_var->name;
252                 def[i].type = script_var->type | (script_var->type << CFG_INPUT_SHIFT);
253                 def[i].descr = script_var->descr;
254                 def[i].min = script_var->min;
255                 def[i].max = script_var->max;
256
257                 mapping[i].def = &(def[i]);
258                 mapping[i].name_len = script_var->name_len;
259                 mapping[i].pos = i;
260
261                 switch (script_var->type) {
262                 case CFG_VAR_INT:
263                         offset = ROUND_INT(offset);
264                         mapping[i].offset = offset;
265
266                         *(int *)(block + offset) = script_var->val.i;
267
268                         offset += sizeof(int);
269                         break;
270
271                 case CFG_VAR_STR:
272                         offset = ROUND_POINTER(offset);
273                         mapping[i].offset = offset;
274
275                         if (cfg_clone_str(&(script_var->val.s), &s)) goto error;
276                         memcpy(block + offset, &s, sizeof(str));
277                         mapping[i].flag |= cfg_var_shmized;
278
279                         offset += sizeof(str);
280                         break;
281                 }
282         }
283
284         /* allocate a handle even if it will not be used to
285         directly access the variable, like handle->variable
286         cfg_get_* functions access the memory block via the handle
287         to make sure that it is always safe, thus, it must be created */
288         handle = (void **)pkg_malloc(sizeof(void *));
289         if (!handle) goto error;
290         *handle = NULL;
291         group->handle = handle;
292
293         group->mapping = mapping;
294
295         /* everything went fine, we can free the temporary list */
296         script_var = (cfg_script_var_t *)group->vars;
297         group->vars = NULL;
298         while (script_var) {
299                 script_var2 = script_var->next;
300                 if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
301                         pkg_free(script_var->val.s.s);
302                 pkg_free(script_var);
303                 script_var = script_var2;
304         }
305
306         return 0;
307
308 error:
309         if (mapping) pkg_free(mapping);
310         if (def) pkg_free(def);
311         if (handle) pkg_free(handle);
312
313         LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n");
314         return -1;
315 }
316
317 /* destory a dynamically allocated group definition */
318 void cfg_script_destroy(cfg_group_t *group)
319 {
320         int     i;
321         cfg_script_var_t        *script_var, *script_var2;
322
323         if (group->mapping && group->mapping->def) {
324                 for (i=0; i<group->num; i++) {
325                         if (group->mapping->def[i].name)
326                                 pkg_free(group->mapping->def[i].name);
327                         if (group->mapping->def[i].descr)
328                                 pkg_free(group->mapping->def[i].descr);
329                 }
330                 pkg_free(group->mapping->def);
331         }
332         if (group->mapping) pkg_free(group->mapping);
333         if (group->handle) pkg_free(group->handle);
334
335         /* it may happen that the temporary var list
336         still exists because the fixup failed and did not complete */
337         script_var = (cfg_script_var_t *)group->vars;
338         while (script_var) {
339                 script_var2 = script_var->next;
340                 if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s) 
341                         pkg_free(script_var->val.s.s);
342                 pkg_free(script_var);
343                 script_var = script_var2;
344         }
345 }