* 2007-10-10 added DNS_SEARCH_FMATCH (mma)
* 2007-11-28 added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
* LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
+ * 2008-01-24 added CFG_DESCRIPTION used by cfg_var (Miklos)
*/
STUN_ALLOW_STUN "stun_allow_stun"
STUN_ALLOW_FP "stun_allow_fp"
+CFG_DESCRIPTION "description"|"descr"|"desc"
+
LOADMODULE loadmodule
MODPARAM modparam
return PMTU_DISCOVERY; }
<INITIAL>{KILL_TIMEOUT} { count(); yylval.strval=yytext;
return KILL_TIMEOUT; }
+<INITIAL>{CFG_DESCRIPTION} { count(); yylval.strval=yytext; return CFG_DESCRIPTION; }
<INITIAL>{LOADMODULE} { count(); yylval.strval=yytext; return LOADMODULE; }
<INITIAL>{MODPARAM} { count(); yylval.strval=yytext; return MODPARAM; }
* 2007-10-10 added DNS_SEARCH_FMATCH (mma)
* 2007-11-28 added TCP_OPT_{FD_CACHE, DEFER_ACCEPT, DELAYED_ACK, SYNCNT,
* LINGER2, KEEPALIVE, KEEPIDLE, KEEPINTVL, KEEPCNT} (andrei)
+ * 2008-01-24 added cfg_var definition (Miklos)
*/
%{
#include "config.h"
#include "cfg_core.h"
+#include "cfg/cfg.h"
#ifdef CORE_TLS
#include "tls/tls_config.h"
#endif
%token TOS
%token PMTU_DISCOVERY
%token KILL_TIMEOUT
+%token CFG_DESCRIPTION
%token FLAGS_DECL
%token AVPFLAGS_DECL
| STUN_ALLOW_STUN EQUAL error{ yyerror("number expected"); }
| STUN_ALLOW_FP EQUAL NUMBER { IF_STUN(stun_allow_fp=$3) ; }
| STUN_ALLOW_FP EQUAL error{ yyerror("number expected"); }
+ | cfg_var
| error EQUAL { yyerror("unknown config variable"); }
;
+cfg_var:
+ ID DOT ID EQUAL NUMBER {
+ cfg_declare_int($1, $3, $5, NULL);
+ }
+ | ID DOT ID EQUAL STRING {
+ cfg_declare_str($1, $3, $5, NULL);
+ }
+ | ID DOT ID EQUAL NUMBER CFG_DESCRIPTION STRING {
+ cfg_declare_int($1, $3, $5, $7);
+ }
+ | ID DOT ID EQUAL STRING CFG_DESCRIPTION STRING {
+ cfg_declare_str($1, $3, $5, $7);
+ }
+ | ID DOT ID EQUAL error { yyerror("number or string expected"); }
+ ;
module_stm:
LOADMODULE STRING {
DBG("loading module %s\n", $2);
#include "../mem/mem.h"
#include "cfg_struct.h"
#include "cfg_ctx.h"
+#include "cfg_script.h"
#include "cfg.h"
/* declares a new cfg group
int cfg_declare(char *group_name, cfg_def_t *def, void *values, int def_size,
void **handle)
{
- int i, num, size;
+ int i, num, size, group_name_len;
cfg_mapping_t *mapping = NULL;
/* check the number of the variables */
goto error;
}
+ group_name_len = strlen(group_name);
/* create a new group
I will allocate memory in shm mem for the variables later in a single block,
when we know the size of all the registered groups. */
- if (cfg_new_group(group_name, num, mapping, values, size, handle))
+ if (!cfg_new_group(group_name, group_name_len, num, mapping, values, size, handle))
goto error;
/* The cfg variables are ready to use, let us set the handle
*handle = values;
/* notify the drivers about the new config definition */
- cfg_notify_drivers(group_name, def);
+ cfg_notify_drivers(group_name, group_name_len, def);
LOG(L_DBG, "DEBUG: register_cfg_def(): "
"new config group has been registered: '%s' (num=%d, size=%d)\n",
group_name, num, size);
- /* TODO: inform the drivers about the new definition */
-
return 0;
error:
return -1;
}
+
+/* declares a single variable with integer type */
+int cfg_declare_int(char *group_name, char *var_name, int val, char *descr)
+{
+ cfg_script_var_t *var;
+
+ if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_INT, descr)) == NULL)
+ return -1;
+
+ var->val.i = val;
+
+ return 0;
+}
+
+/* declares a single variable with str type */
+int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr)
+{
+ cfg_script_var_t *var;
+ int len;
+
+ if ((var = new_cfg_script_var(group_name, var_name, CFG_VAR_STR, descr)) == NULL)
+ return -1;
+
+ if (val) {
+ len = strlen(val);
+ var->val.s.s = (char *)pkg_malloc(sizeof(char) * (len + 1));
+ if (!var->val.s.s) {
+ LOG(L_ERR, "ERROR: cfg_declare_str(): not enough memory\n");
+ return -1;
+ }
+ memcpy(var->val.s.s, val, len + 1);
+ var->val.s.len = len;
+ } else {
+ var->val.s.s = NULL;
+ var->val.s.len = 0;
+ }
+
+ return 0;
+}
typedef int (*cfg_on_change)(void *, str *, void **);
typedef void (*cfg_on_set_child)(str *);
-/* strutrure to be used buy the module interface */
+/* strutrure to be used by the module interface */
typedef struct _cfg_def {
char *name;
unsigned int type;
#define cfg_get(gname, handle, var) \
((struct cfg_group_##gname *)handle)->var
+/* declares a single variable with integer type */
+int cfg_declare_int(char *group_name, char *var_name, int val, char *descr);
+
+/* declares a single variable with str type */
+int cfg_declare_str(char *group_name, char *var_name, char *val, char *descr);
+
#endif /* _CFG_H */
group;
group = group->next
) {
+ /* dynamic groups are not ready, the callback
+ will be called later when the group is fixed-up */
+ if (group->dynamic) continue;
+
gname.s = group->name;
gname.len = group->name_len;
on_declare_cb(&gname, group->mapping->def);
}
/* notify the drivers about the new config definition */
-void cfg_notify_drivers(char *group_name, cfg_def_t *def)
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def)
{
cfg_ctx_t *ctx;
str gname;
gname.s = group_name;
- gname.len = strlen(group_name);
+ gname.len = group_name_len;
for ( ctx = cfg_ctx_list;
ctx;
p = block->vars+group->offset+var->offset;
} else {
- /* we are allowed to rewrite the value on-the-fly */
- p = group->vars + var->offset;
+ /* we are allowed to rewrite the value on-the-fly
+ The handle either points to group->vars, or to the
+ shared memory block (dynamic group) */
+ p = *(group->handle) + var->offset;
}
/* set the new value */
cfg_install_global(block, replaced, child_cb, child_cb);
CFG_WRITER_UNLOCK();
} else {
+ /* cfg_set() may be called more than once before forking */
+ if (old_string && (var->flag & cfg_var_shmized))
+ shm_free(old_string);
+
/* flag the variable because there is no need
to shmize it again */
var->flag |= cfg_var_shmized;
char **ch, unsigned int *input_type);
/* notify the drivers about the new config definition */
-void cfg_notify_drivers(char *group_name, cfg_def_t *def);
+void cfg_notify_drivers(char *group_name, int group_name_len, cfg_def_t *def);
/* initialize the handle for cfg_get_group_next() */
#define cfg_get_group_init(handle) \
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ * info@iptel.org
+ *
+ * ser 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_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);
+ /* the group may have been already declared */
+ for ( group = cfg_group;
+ group;
+ group = group->next
+ ) {
+ if ((group->name_len == gname_len) &&
+ (memcmp(group->name, gname, gname_len) == 0)) {
+ if (group->dynamic == 0) {
+ /* 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 group is found */
+ break;
+ }
+ }
+
+ if (!group) {
+ /* 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 = 1;
+ }
+
+ /* verify that the variable does not exist */
+ vname_len = strlen(vname);
+
+ 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;
+ }
+ }
+
+ 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++;
+
+ var = (cfg_script_var_t *)pkg_malloc(sizeof(cfg_script_var_t));
+ if (!var) goto error;
+ memset(var, sizeof(cfg_script_var_t), 0);
+ 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;
+}
+
+/* fix-up the dynamically declared group:
+ * - allocate memory for the arrays
+ * - set the values within the memory block
+ * - notify the drivers about the new group
+ */
+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 << 3);
+ def[i].descr = script_var->descr;
+
+ mapping[i].def = &(def[i]);
+ mapping[i].name_len = script_var->name_len;
+
+ switch (script_var->type) {
+ case CFG_VAR_INT:
+ offset = ROUND_INT(offset);
+ mapping[i].offset = offset;
+
+ memcpy(block + offset, &script_var->val.i, sizeof(int));
+
+ offset += sizeof(int);
+ break;
+
+ case CFG_VAR_STR:
+ offset = ROUND_POINTER(offset);
+ mapping[i].offset = offset;
+
+ if (!(s.s = cfg_clone_str(script_var->val.s))) goto error;
+ s.len = script_var->val.s.len;
+ 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 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;
+ }
+}
--- /dev/null
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ *
+ * This file is part of ser, a free SIP server.
+ *
+ * ser 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
+ *
+ * For a license to use the ser software under conditions
+ * other than those described here, or to purchase support for this
+ * software, please contact iptel.org by e-mail at the following addresses:
+ * info@iptel.org
+ *
+ * ser 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)
+ */
+
+#ifndef _CFG_SCRIPT_H
+#define _CFG_SCRIPT_H
+
+#include "../str.h"
+
+/* structure used for temporary storing the variables
+ * which are declared in the script */
+typedef struct _cfg_script_var {
+ unsigned int type;
+ union {
+ str s;
+ int i;
+ } val;
+ struct _cfg_script_var *next;
+ int name_len;
+ char *name;
+ char *descr;
+} cfg_script_var_t;
+
+/* 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);
+
+/* fix-up the dynamically declared group */
+int cfg_script_fixup(cfg_group_t *group, unsigned char *block);
+
+/* destory a dynamically allocated group definition */
+void cfg_script_destroy(cfg_group_t *group);
+
+#endif /* _CFG_SCRIPT_H */
* History
* -------
* 2007-12-03 Initial version (Miklos)
+ * 2008-01-24 dynamic groups are introduced in order to make
+ * variable declaration possible in the script (Miklos)
*/
#include <string.h>
#include "../ut.h"
#include "../locking.h"
#include "cfg_ctx.h"
+#include "cfg_script.h"
#include "cfg_struct.h"
cfg_group_t *cfg_group = NULL; /* linked list of registered cfg groups */
cfg_child_cb_t *cfg_child_cb = NULL; /* pointer to the previously executed cb */
/* creates a new cfg group, and adds it to the linked list */
-int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
+cfg_group_t *cfg_new_group(char *name, int name_len,
+ int num, cfg_mapping_t *mapping,
char *vars, int size, void **handle)
{
cfg_group_t *group;
- int len;
if (cfg_shmized) {
LOG(L_ERR, "ERROR: cfg_new_group(): too late config declaration\n");
- return -1;
+ return NULL;
}
- len = strlen(name);
- group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+len-1);
+ group = (cfg_group_t *)pkg_malloc(sizeof(cfg_group_t)+name_len-1);
if (!group) {
LOG(L_ERR, "ERROR: cfg_new_group(): not enough memory\n");
- return -1;
+ return NULL;
}
- memset(group, 0, sizeof(cfg_group_t)+len-1);
+ memset(group, 0, sizeof(cfg_group_t)+name_len-1);
group->num = num;
group->mapping = mapping;
group->vars = vars;
group->size = size;
group->handle = handle;
- group->name_len = len;
- memcpy(&group->name, name, len);
+ group->name_len = name_len;
+ memcpy(&group->name, name, name_len);
/* add the new group to the beginning of the list */
group->next = cfg_group;
cfg_group = group;
- return 0;
+ return group;
}
/* clones a string to shared memory */
group;
group=group->next
) {
- /* clone the strings to shm mem */
- if (cfg_shmize_strings(group)) goto error;
-
- /* copy the values to the new block,
- and update the module's handle */
- memcpy(block->vars+group->offset, group->vars, group->size);
- *(group->handle) = block->vars+group->offset;
+ if (group->dynamic == 0) {
+ /* clone the strings to shm mem */
+ if (cfg_shmize_strings(group)) goto error;
+
+ /* copy the values to the new block,
+ and update the module's handle */
+ memcpy(block->vars+group->offset, group->vars, group->size);
+ *(group->handle) = block->vars+group->offset;
+ } else {
+ /* The group was declared with NULL values,
+ * we have to fix it up.
+ * The fixup function takes care about the values,
+ * it fills up the block */
+ if (cfg_script_fixup(group, block->vars+group->offset)) goto error;
+ *(group->handle) = block->vars+group->offset;
+
+ /* notify the drivers about the new config definition */
+ cfg_notify_drivers(group->name, group->name_len,
+ group->mapping->def);
+ }
}
/* install the new config */
return -1;
}
+/* deallocate the list of groups, and the shmized strings */
+static void cfg_destory_groups(unsigned char *block)
+{
+ cfg_group_t *group, *group2;
+ cfg_mapping_t *mapping;
+ cfg_def_t *def;
+ void *old_string;
+ int i;
+
+ group = cfg_group;
+ while(group) {
+ mapping = group->mapping;
+ def = mapping ? mapping->def : NULL;
+
+ /* destory the shmized strings in the block */
+ if (block && def)
+ for (i=0; i<group->num; i++)
+ if (((CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STRING) ||
+ (CFG_VAR_TYPE(&mapping[i]) == CFG_VAR_STR)) &&
+ mapping[i].flag & cfg_var_shmized) {
+
+ memcpy( &old_string,
+ block + group->offset + mapping[i].offset,
+ sizeof(char *));
+ shm_free(old_string);
+ }
+
+ if (group->dynamic) {
+ /* the group was dynamically allocated */
+ cfg_script_destroy(group);
+ } else {
+ /* only the mapping was allocated, all the other
+ pointers are just set to static variables */
+ if (mapping) pkg_free(mapping);
+ }
+
+ group2 = group->next;
+ pkg_free(group);
+ group = group2;
+ }
+}
+
/* initiate the cfg framework */
int cfg_init(void)
{
/* free the contexts */
cfg_ctx_destroy();
+ /* free the list of groups */
+ cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
+
if (cfg_child_cb_first) {
if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
shm_free(cfg_child_cb_first);
* History
* -------
* 2007-12-03 Initial version (Miklos)
+ * 2008-01-24 dynamic groups are introduced in order to make
+ * variable declaration possible in the script (Miklos)
*/
#ifndef _CFG_STRUCT_H
It is registered when the group is created,
and updated every time the block is replaced */
+ unsigned char dynamic; /* indicates whether the variables within the group
+ are dynamically allocated or not */
struct _cfg_group *next;
int name_len;
char name[1];
void cfg_child_destroy(void);
/* creates a new cfg group, and adds it to the linked list */
-int cfg_new_group(char *name, int num, cfg_mapping_t *mapping,
+cfg_group_t *cfg_new_group(char *name, int name_len,
+ int num, cfg_mapping_t *mapping,
char *vars, int size, void **handle);
/* copy the variables to shm mem */