all: updated FSF address in GPL text
[sip-router] / cfg / cfg_select.c
1 /*
2  * $Id$
3  *
4  * Copyright (C) 2008 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  * History
23  * -------
24  *  2008-01-10  Initial version (Miklos)
25  */
26 #include <stdio.h>
27
28 #include "../select.h"
29 #include "../ut.h"
30 #include "cfg_struct.h"
31 #include "cfg_ctx.h"
32 #include "cfg_select.h"
33
34 /* It may happen that the select calls cannot be fixed up before shmizing
35  * the config, because for example the mapping structures have not been
36  * allocated for the dynamic groups yet. So we have to keep track of all the
37  * selects that we failed to fix-up, and retry the fixup once more just
38  * before forking */
39 typedef struct _cfg_selects {
40         str     gname;
41         str     vname;
42         void    **group_p;
43         void    **var_p;
44         struct _cfg_selects     *next;
45 } cfg_selects_t;
46
47 /* linked list of non-fixed selects */
48 static cfg_selects_t    *cfg_non_fixed_selects = NULL;
49
50 /* add a new select item to the linked list */
51 static int cfg_new_select(str *gname, str *vname, void **group_p, void **var_p)
52 {
53         cfg_selects_t   *sel;
54
55         sel = (cfg_selects_t *)pkg_malloc(sizeof(cfg_selects_t));
56         if (!sel) goto error;
57         memset(sel, 0, sizeof(cfg_selects_t));
58
59         sel->gname.s = (char *)pkg_malloc(sizeof(char)*gname->len);
60         if (!sel->gname.s) goto error;
61         memcpy(sel->gname.s, gname->s, gname->len);
62         sel->gname.len = gname->len;
63         sel->group_p = group_p;
64
65         if (vname) {
66                 sel->vname.s = (char *)pkg_malloc(sizeof(char)*vname->len);
67                 if (!sel->vname.s) goto error;
68                 memcpy(sel->vname.s, vname->s, vname->len);
69                 sel->vname.len = vname->len;
70
71                 sel->var_p = var_p;
72         }
73
74
75         sel->next = cfg_non_fixed_selects;
76         cfg_non_fixed_selects = sel;
77
78         return 0;
79
80 error:
81         LOG(L_ERR, "ERROR: cfg_new_select(): not enough memory\n");
82         if (sel) {
83                 if (sel->gname.s) pkg_free(sel->gname.s);
84                 if (sel->vname.s) pkg_free(sel->vname.s);
85                 pkg_free(sel);
86         }
87         return -1;
88 }
89
90 /* free the list of not yet fixed selects */
91 void cfg_free_selects()
92 {
93         cfg_selects_t   *sel, *next_sel;
94
95         sel = cfg_non_fixed_selects;
96         while (sel) {
97                 next_sel = sel->next;
98
99                 if (sel->gname.s) pkg_free(sel->gname.s);
100                 if (sel->vname.s) pkg_free(sel->vname.s);
101                 pkg_free(sel);
102
103                 sel = next_sel;
104         }
105         cfg_non_fixed_selects = NULL;
106 }
107
108 /* fix-up the select calls */
109 int cfg_fixup_selects()
110 {
111         cfg_selects_t   *sel;
112         cfg_group_t     *group;
113         cfg_mapping_t   *var;
114
115         for (sel=cfg_non_fixed_selects; sel; sel=sel->next) {
116
117                 if (sel->var_p) {
118                         if (cfg_lookup_var(&sel->gname, &sel->vname, &group, &var)) {
119                                 LOG(L_ERR, "ERROR: cfg_parse_selects(): unknown variable: %.*s.%.*s\n",
120                                         sel->gname.len, sel->gname.s,
121                                         sel->vname.len, sel->vname.s);
122                                 return -1;
123                         }
124                         *(sel->group_p) = (void *)group;
125                         *(sel->var_p) = (void *)var;
126                 } else {
127                         if (!(group = cfg_lookup_group(sel->gname.s, sel->gname.len))) {
128                                 LOG(L_ERR, "ERROR: cfg_parse_selects(): unknown configuration group: %.*s\n",
129                                         sel->gname.len, sel->gname.s);
130                                 return -1;
131                         }
132                         *(sel->group_p) = (void *)group;
133                 }
134         }
135         /* the select list is not needed anymore */
136         cfg_free_selects();
137         return 0;
138 }
139
140 int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
141 {
142         cfg_group_t     *group;
143         cfg_mapping_t   *var;
144         void            *p;
145         int             i;
146         static char     buf[INT2STR_MAX_LEN];
147
148         if (msg == NULL) {
149                 /* fixup call */
150
151                 /* two parameters are mandatory, group name and variable name */
152                 if (s->n < 3) {
153                         LOG(L_ERR, "ERROR: select_cfg_var(): At least two parameters are expected\n");
154                         return -1;
155                 }
156
157                 if ((s->params[1].type != SEL_PARAM_STR)
158                 || (s->params[2].type != SEL_PARAM_STR)) {
159                         LOG(L_ERR, "ERROR: select_cfg_var(): string parameters are expected\n");
160                         return -1;
161                 }
162
163                 /* look-up the group and the variable */
164                 if (cfg_lookup_var(&s->params[1].v.s, &s->params[2].v.s, &group, &var)) {
165                         if (cfg_shmized) {
166                                 LOG(L_ERR, "ERROR: select_cfg_var(): unknown variable: %.*s.%.*s\n",
167                                         s->params[1].v.s.len, s->params[1].v.s.s,
168                                         s->params[2].v.s.len, s->params[2].v.s.s);
169                                 return -1;
170                         }
171                         /* The variable was not found, add it to the non-fixed select list.
172                          * So we act as if the fixup was successful, and we retry it later */
173                         if (cfg_new_select(&s->params[1].v.s, &s->params[2].v.s,
174                                                 &s->params[1].v.p, &s->params[2].v.p))
175                                 return -1;
176
177                         LOG(L_DBG, "DEBUG: select_cfg_var(): select fixup is postponed: %.*s.%.*s\n",
178                                 s->params[1].v.s.len, s->params[1].v.s.s,
179                                 s->params[2].v.s.len, s->params[2].v.s.s);
180
181                         s->params[1].type = SEL_PARAM_PTR;
182                         s->params[1].v.p = NULL;
183
184                         s->params[2].type = SEL_PARAM_PTR;
185                         s->params[2].v.p = NULL;
186
187                         return 0;
188                 }
189
190                 if (var->def->on_change_cb) {
191                         /* fixup function is defined -- safer to return an error
192                         than an incorrect value */
193                         LOG(L_ERR, "ERROR: select_cfg_var(): variable cannot be retrieved\n");
194                         return -1;
195                 }
196
197                 s->params[1].type = SEL_PARAM_PTR;
198                 s->params[1].v.p = (void *)group;
199
200                 s->params[2].type = SEL_PARAM_PTR;
201                 s->params[2].v.p = (void *)var;
202                 return 1;
203         }
204
205         group = (cfg_group_t *)s->params[1].v.p;
206         var = (cfg_mapping_t *)s->params[2].v.p;
207
208         if (!group || !var) return -1;
209
210         /* use the module's handle to access the variable, so the variables
211         are read from the local config */
212         p = *(group->handle) + var->offset;
213         if (p == NULL)
214                 return -1;      /* The group is not yet ready.
215                                  * (Trying to read the value from the
216                                  * main process that has no local configuration) */
217
218         switch (CFG_VAR_TYPE(var)) {
219         case CFG_VAR_INT:
220                 i = *(int *)p;
221                 res->len = snprintf(buf, sizeof(buf)-1, "%d", i);
222                 buf[res->len] = '\0';
223                 res->s = buf;
224                 break;
225
226         case CFG_VAR_STRING:
227                 res->s = *(char **)p;
228                 res->len = (res->s) ? strlen(res->s) : 0;
229                 break;
230
231         case CFG_VAR_STR:
232                 memcpy(res, p, sizeof(str));
233                 break;
234
235         default:
236                 LOG(L_DBG, "DEBUG: select_cfg_var(): unsupported variable type: %d\n",
237                         CFG_VAR_TYPE(var));
238                 return -1;
239         }
240         return 0;
241 }
242
243 /* fake function to eat the first parameter of @cfg_get */
244 ABSTRACT_F(select_cfg_var1)
245
246 /* fix-up function for read_cfg_var()
247  *
248  * return value:
249  * >0 - success
250  *  0 - the variable has not been declared yet, but it will be automatically
251  *      fixed-up later.
252  * <0 - error
253  */
254 int read_cfg_var_fixup(char *gname, char *vname, struct cfg_read_handle *read_handle)
255 {
256         cfg_group_t     *group;
257         cfg_mapping_t   *var;
258         str             group_name, var_name;
259
260         if (!gname || !vname || !read_handle)
261                 return -1;
262
263         group_name.s = gname;
264         group_name.len = strlen(gname);
265         var_name.s = vname;
266         var_name.len = strlen(vname);
267
268         /* look-up the group and the variable */
269         if (cfg_lookup_var(&group_name, &var_name, &group, &var)) {
270                 if (cfg_shmized) {
271                         LOG(L_ERR, "ERROR: read_cfg_var_fixup(): unknown variable: %.*s.%.*s\n",
272                                 group_name.len, group_name.s,
273                                 var_name.len, var_name.s);
274                         return -1;
275                 }
276                 /* The variable was not found, add it to the non-fixed select list.
277                  * So we act as if the fixup was successful, and we retry it later */
278                 if (cfg_new_select(&group_name, &var_name,
279                                         &read_handle->group, &read_handle->var))
280                         return -1;
281
282                 LOG(L_DBG, "DEBUG: read_cfg_var_fixup(): cfg read fixup is postponed: %.*s.%.*s\n",
283                         group_name.len, group_name.s,
284                         var_name.len, var_name.s);
285
286                 read_handle->group = NULL;
287                 read_handle->var = NULL;
288                 return 0;
289         }
290
291         read_handle->group = (void *)group;
292         read_handle->var = (void *)var;
293         return 1;
294 }
295
296 /* read the value of a variable via a group and variable name previously fixed up
297  * Returns the type of the variable
298  */
299 unsigned int read_cfg_var(struct cfg_read_handle *read_handle, void **val)
300 {
301         cfg_group_t     *group;
302         cfg_mapping_t   *var;
303         void            *p;
304         static str      s;
305
306         if (!val || !read_handle || !read_handle->group || !read_handle->var)
307                 return 0;
308
309         group = (cfg_group_t *)(read_handle->group);
310         var = (cfg_mapping_t *)(read_handle->var);
311
312
313         /* use the module's handle to access the variable, so the variables
314         are read from the local config */
315         p = *(group->handle) + var->offset;
316         if (p == NULL)
317                 return 0;       /* The group is not yet ready.
318                                  * (Trying to read the value from the
319                                  * main process that has no local configuration) */
320
321         switch (CFG_VAR_TYPE(var)) {
322         case CFG_VAR_INT:
323                 *val = (void *)(long)*(int *)p;
324                 break;
325
326         case CFG_VAR_STRING:
327                 *val = (void *)*(char **)p;
328                 break;
329
330         case CFG_VAR_STR:
331                 memcpy(&s, p, sizeof(str));
332                 *val = (void *)&s;
333                 break;
334
335         case CFG_VAR_POINTER:
336                 *val = *(void **)p;
337                 break;
338
339         }
340         return CFG_VAR_TYPE(var);
341 }
342
343 /* wrapper function for read_cfg_var() -- convert the value to integer
344  * returns -1 on error, 0 on success
345  */
346 int read_cfg_var_int(struct cfg_read_handle *read_handle, int *val)
347 {
348         unsigned int    type;
349         void            *v1=NULL, *v2=NULL;
350
351         if ((type = read_cfg_var(read_handle, &v1)) == 0)
352                 return -1;
353
354         if (convert_val(type, v1, CFG_INPUT_INT, &v2))
355                 return -1;
356
357         *val = (int)(long)(v2);
358         return 0;
359 }
360
361 /* wrapper function for read_cfg_var() -- convert the value to str
362  * returns -1 on error, 0 on success
363  */
364 int read_cfg_var_str(struct cfg_read_handle *read_handle, str *val)
365 {
366         unsigned int    type;
367         void            *v1=NULL, *v2=NULL;
368
369         if ((type = read_cfg_var(read_handle, &v1)) == 0)
370                 return -1;
371
372         if (convert_val(type, v1, CFG_INPUT_STR, &v2))
373                 return -1;
374
375         *val = *(str *)(v2);
376         return 0;
377 }
378
379 /* return the selected group instance */
380 int cfg_selected_inst(str *res, select_t *s, struct sip_msg *msg)
381 {
382         cfg_group_t     *group;
383         cfg_group_inst_t        *inst;
384
385         if (msg == NULL) {
386                 /* fixup call */
387
388                 /* one parameter is mandatory: group name */
389                 if (s->n != 2) {
390                         LOG(L_ERR, "ERROR: selected_inst(): One parameter is expected\n");
391                         return -1;
392                 }
393
394                 if (s->params[1].type != SEL_PARAM_STR) {
395                         LOG(L_ERR, "ERROR: selected_inst(): string parameter is expected\n");
396                         return -1;
397                 }
398
399                 /* look-up the group and the variable */
400                 if (!(group = cfg_lookup_group(s->params[1].v.s.s, s->params[1].v.s.len))) {
401                         if (cfg_shmized) {
402                                 LOG(L_ERR, "ERROR: selected_inst(): unknown configuration group: %.*s\n",
403                                         s->params[1].v.s.len, s->params[1].v.s.s);
404                                 return -1;
405                         }
406                         /* The group was not found, add it to the non-fixed select list.
407                          * So we act as if the fixup was successful, and we retry it later */
408                         if (cfg_new_select(&s->params[1].v.s, NULL,
409                                                 &s->params[1].v.p, NULL))
410                                 return -1;
411
412                         LOG(L_DBG, "DEBUG: selected_inst(): select fixup is postponed: %.*s\n",
413                                 s->params[1].v.s.len, s->params[1].v.s.s);
414
415                         s->params[1].type = SEL_PARAM_PTR;
416                         s->params[1].v.p = NULL;
417
418                         return 0;
419                 }
420
421                 s->params[1].type = SEL_PARAM_PTR;
422                 s->params[1].v.p = (void *)group;
423
424                 return 1;
425         }
426
427         group = (cfg_group_t *)s->params[1].v.p;
428         if (!group) return -1;
429
430         /* Get the current group instance from the group handle. */
431         inst = CFG_HANDLE_TO_GINST(*(group->handle));
432
433         if (inst) {
434                 res->s = int2str(inst->id, &res->len);
435         } else {
436                 res->s = "";
437                 res->len = 0;
438         }
439         return 0;
440 }
441