Coverage Report

Created: 2024-02-25 06:34

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