mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
352 lines
9.5 KiB
352 lines
9.5 KiB
/*
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2008 iptelorg GmbH
|
|
*
|
|
* This file is part of SIP-router, a free SIP server.
|
|
*
|
|
* SIP-router is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* SIP-router is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* History
|
|
* -------
|
|
* 2008-01-24 dynamic groups are introduced in order to make
|
|
* variable declaration possible in the script (Miklos)
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "../mem/mem.h"
|
|
#include "../ut.h"
|
|
#include "cfg_struct.h"
|
|
#include "cfg.h"
|
|
#include "cfg_ctx.h"
|
|
#include "cfg_script.h"
|
|
|
|
/* allocates memory for a new config script variable
|
|
* The value of the variable is not set!
|
|
*/
|
|
cfg_script_var_t *new_cfg_script_var(char *gname, char *vname, unsigned int type,
|
|
char *descr)
|
|
{
|
|
cfg_group_t *group;
|
|
cfg_script_var_t *var;
|
|
int gname_len, vname_len, descr_len;
|
|
|
|
LOG(L_DBG, "DEBUG: new_cfg_script_var(): declaring %s.%s\n", gname, vname);
|
|
|
|
if (cfg_shmized) {
|
|
LOG(L_ERR, "ERROR: new_cfg_script_var(): too late variable declaration, "
|
|
"the config has been already shmized\n");
|
|
return NULL;
|
|
}
|
|
|
|
gname_len = strlen(gname);
|
|
vname_len = strlen(vname);
|
|
/* the group may have been already declared */
|
|
group = cfg_lookup_group(gname, gname_len);
|
|
if (group) {
|
|
if (group->dynamic == CFG_GROUP_STATIC) {
|
|
/* the group has been already declared by a module or by the core */
|
|
LOG(L_ERR, "ERROR: new_cfg_script_var(): "
|
|
"configuration group has been already declared: %s\n",
|
|
gname);
|
|
return NULL;
|
|
}
|
|
/* the dynamic or empty group is found */
|
|
/* verify that the variable does not exist */
|
|
for ( var = (cfg_script_var_t *)group->vars;
|
|
var;
|
|
var = var->next
|
|
) {
|
|
if ((var->name_len == vname_len) &&
|
|
(memcmp(var->name, vname, vname_len) == 0)) {
|
|
LOG(L_ERR, "ERROR: new_cfg_script_var(): variable already exists: %s.%s\n",
|
|
gname, vname);
|
|
return NULL;
|
|
}
|
|
}
|
|
if (group->dynamic == CFG_GROUP_UNKNOWN)
|
|
group->dynamic = CFG_GROUP_DYNAMIC;
|
|
|
|
} else {
|
|
/* create a new group with NULL values, we will fix it later,
|
|
when all the variables are known */
|
|
group = cfg_new_group(gname, gname_len,
|
|
0 /* num */, NULL /* mapping */,
|
|
NULL /* vars */, 0 /* size */, NULL /* handle */);
|
|
|
|
if (!group) goto error;
|
|
group->dynamic = CFG_GROUP_DYNAMIC;
|
|
}
|
|
|
|
switch (type) {
|
|
case CFG_VAR_INT:
|
|
group->size = ROUND_INT(group->size);
|
|
group->size += sizeof(int);
|
|
break;
|
|
|
|
case CFG_VAR_STR:
|
|
group->size = ROUND_POINTER(group->size);
|
|
group->size += sizeof(str);
|
|
break;
|
|
|
|
default:
|
|
LOG(L_ERR, "ERROR: new_cfg_script_var(): unsupported variable type\n");
|
|
return NULL;
|
|
}
|
|
|
|
group->num++;
|
|
if (group->num > CFG_MAX_VAR_NUM) {
|
|
LOG(L_ERR, "ERROR: new_cfg_script_var(): too many variables (%d) within a single group,"
|
|
" the limit is %d. Increase CFG_MAX_VAR_NUM, or split the group into multiple"
|
|
" definitions.\n",
|
|
group->num, CFG_MAX_VAR_NUM);
|
|
return NULL;
|
|
}
|
|
|
|
var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
|
|
if (!var) goto error;
|
|
memset(var, 0, sizeof(cfg_script_var_t));
|
|
var->type = type;
|
|
|
|
/* add the variable to the group */
|
|
var->next = (cfg_script_var_t *)(void *)group->vars;
|
|
group->vars = (char *)(void *)var;
|
|
|
|
/* clone the name of the variable */
|
|
var->name = (char *)pkg_malloc(sizeof(char) * (vname_len + 1));
|
|
if (!var->name) goto error;
|
|
memcpy(var->name, vname, vname_len + 1);
|
|
var->name_len = vname_len;
|
|
|
|
if (descr) {
|
|
/* save the description */
|
|
descr_len = strlen(descr);
|
|
var->descr = (char *)pkg_malloc(sizeof(char) * (descr_len + 1));
|
|
if (!var->descr) goto error;
|
|
memcpy(var->descr, descr, descr_len + 1);
|
|
}
|
|
|
|
return var;
|
|
|
|
error:
|
|
LOG(L_ERR, "ERROR: new_cfg_script_var(): not enough memory\n");
|
|
return NULL;
|
|
}
|
|
|
|
/* Rewrite the value of an already declared script variable before forking.
|
|
* Return value:
|
|
* 0: success
|
|
* -1: error
|
|
* 1: variable not found
|
|
*/
|
|
int cfg_set_script_var(cfg_group_t *group, str *var_name,
|
|
void *val, unsigned int val_type)
|
|
{
|
|
cfg_script_var_t *var;
|
|
void *v;
|
|
str s;
|
|
|
|
if (cfg_shmized || (group->dynamic != CFG_GROUP_DYNAMIC)) {
|
|
LOG(L_ERR, "BUG: cfg_set_script_var(): Not a dynamic group before forking\n");
|
|
return -1;
|
|
}
|
|
|
|
for ( var = (cfg_script_var_t *)(void *)group->vars;
|
|
var;
|
|
var = var->next
|
|
) {
|
|
if ((var->name_len == var_name->len)
|
|
&& (memcmp(var->name, var_name->s, var_name->len) == 0)
|
|
) {
|
|
switch (var->type) {
|
|
case CFG_VAR_INT:
|
|
if (convert_val(val_type, val, CFG_INPUT_INT, &v))
|
|
goto error;
|
|
if ((var->min || var->max)
|
|
&& ((var->min > (int)(long)v) || (var->max < (int)(long)v))
|
|
) {
|
|
LOG(L_ERR, "ERROR: cfg_set_script_var(): integer value is out of range\n");
|
|
goto error;
|
|
}
|
|
var->val.i = (int)(long)v;
|
|
break;
|
|
|
|
case CFG_VAR_STR:
|
|
if (convert_val(val_type, val, CFG_INPUT_STR, &v))
|
|
goto error;
|
|
if (((str *)v)->s) {
|
|
s.len = ((str *)v)->len;
|
|
s.s = pkg_malloc(sizeof(char) * (s.len + 1));
|
|
if (!s.s) {
|
|
LOG(L_ERR, "ERROR: cfg_set_script_var(): not enough memory\n");
|
|
goto error;
|
|
}
|
|
memcpy(s.s, ((str *)v)->s, s.len);
|
|
s.s[s.len] = '\0';
|
|
} else {
|
|
s.s = NULL;
|
|
s.len = 0;
|
|
}
|
|
if (var->val.s.s)
|
|
pkg_free(var->val.s.s);
|
|
var->val.s = s;
|
|
break;
|
|
|
|
default:
|
|
LOG(L_ERR, "ERROR: cfg_set_script_var(): unsupported variable type\n");
|
|
goto error;
|
|
}
|
|
|
|
convert_val_cleanup();
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
|
|
error:
|
|
LOG(L_ERR, "ERROR: cfg_set_script_var(): failed to set the script variable: %.*s.%.*s\n",
|
|
group->name_len, group->name,
|
|
var_name->len, var_name->s);
|
|
return -1;
|
|
}
|
|
|
|
/* fix-up the dynamically declared group:
|
|
* - allocate memory for the arrays
|
|
* - set the values within the memory block
|
|
*/
|
|
int cfg_script_fixup(cfg_group_t *group, unsigned char *block)
|
|
{
|
|
cfg_mapping_t *mapping = NULL;
|
|
cfg_def_t *def = NULL;
|
|
void **handle = NULL;
|
|
int i, offset;
|
|
cfg_script_var_t *script_var, *script_var2;
|
|
str s;
|
|
|
|
mapping = (cfg_mapping_t *)pkg_malloc(sizeof(cfg_mapping_t)*group->num);
|
|
if (!mapping) goto error;
|
|
memset(mapping, 0, sizeof(cfg_mapping_t)*group->num);
|
|
|
|
/* The variable definition array must look like as if it was declared
|
|
* in C code, thus, add an additional slot at the end with NULL values */
|
|
def = (cfg_def_t *)pkg_malloc(sizeof(cfg_def_t)*(group->num + 1));
|
|
if (!def) goto error;
|
|
memset(def, 0, sizeof(cfg_def_t)*(group->num + 1));
|
|
|
|
/* fill the definition and the mapping arrays */
|
|
offset = 0;
|
|
for ( i = 0, script_var = (cfg_script_var_t *)group->vars;
|
|
script_var;
|
|
i++, script_var = script_var->next
|
|
) {
|
|
/* there has been already memory allocated for the name */
|
|
def[i].name = script_var->name;
|
|
def[i].type = script_var->type | (script_var->type << CFG_INPUT_SHIFT);
|
|
def[i].descr = script_var->descr;
|
|
def[i].min = script_var->min;
|
|
def[i].max = script_var->max;
|
|
|
|
mapping[i].def = &(def[i]);
|
|
mapping[i].name_len = script_var->name_len;
|
|
mapping[i].pos = i;
|
|
|
|
switch (script_var->type) {
|
|
case CFG_VAR_INT:
|
|
offset = ROUND_INT(offset);
|
|
mapping[i].offset = offset;
|
|
|
|
*(int *)(block + offset) = script_var->val.i;
|
|
|
|
offset += sizeof(int);
|
|
break;
|
|
|
|
case CFG_VAR_STR:
|
|
offset = ROUND_POINTER(offset);
|
|
mapping[i].offset = offset;
|
|
|
|
if (cfg_clone_str(&(script_var->val.s), &s)) goto error;
|
|
memcpy(block + offset, &s, sizeof(str));
|
|
mapping[i].flag |= cfg_var_shmized;
|
|
|
|
offset += sizeof(str);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* allocate a handle even if it will not be used to
|
|
directly access the variable, like handle->variable
|
|
cfg_get_* functions access the memory block via the handle
|
|
to make sure that it is always safe, thus, it must be created */
|
|
handle = (void **)pkg_malloc(sizeof(void *));
|
|
if (!handle) goto error;
|
|
*handle = NULL;
|
|
group->handle = handle;
|
|
|
|
group->mapping = mapping;
|
|
|
|
/* everything went fine, we can free the temporary list */
|
|
script_var = (cfg_script_var_t *)group->vars;
|
|
group->vars = NULL;
|
|
while (script_var) {
|
|
script_var2 = script_var->next;
|
|
if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
|
|
pkg_free(script_var->val.s.s);
|
|
pkg_free(script_var);
|
|
script_var = script_var2;
|
|
}
|
|
|
|
return 0;
|
|
|
|
error:
|
|
if (mapping) pkg_free(mapping);
|
|
if (def) pkg_free(def);
|
|
if (handle) pkg_free(handle);
|
|
|
|
LOG(L_ERR, "ERROR: cfg_script_fixup(): not enough memory\n");
|
|
return -1;
|
|
}
|
|
|
|
/* destory a dynamically allocated group definition */
|
|
void cfg_script_destroy(cfg_group_t *group)
|
|
{
|
|
int i;
|
|
cfg_script_var_t *script_var, *script_var2;
|
|
|
|
if (group->mapping && group->mapping->def) {
|
|
for (i=0; i<group->num; i++) {
|
|
if (group->mapping->def[i].name)
|
|
pkg_free(group->mapping->def[i].name);
|
|
if (group->mapping->def[i].descr)
|
|
pkg_free(group->mapping->def[i].descr);
|
|
}
|
|
pkg_free(group->mapping->def);
|
|
}
|
|
if (group->mapping) pkg_free(group->mapping);
|
|
if (group->handle) pkg_free(group->handle);
|
|
|
|
/* it may happen that the temporary var list
|
|
still exists because the fixup failed and did not complete */
|
|
script_var = (cfg_script_var_t *)group->vars;
|
|
while (script_var) {
|
|
script_var2 = script_var->next;
|
|
if ((script_var->type == CFG_VAR_STR) && script_var->val.s.s)
|
|
pkg_free(script_var->val.s.s);
|
|
pkg_free(script_var);
|
|
script_var = script_var2;
|
|
}
|
|
}
|