Select fixup is postponed until the config is shmized, if the fixup
authorMiklos Tirpak <miklos@iptel.org>
Tue, 26 Feb 2008 17:07:35 +0000 (17:07 +0000)
committerMiklos Tirpak <miklos@iptel.org>
Tue, 26 Feb 2008 17:07:35 +0000 (17:07 +0000)
fails at parsing time. It can happen that the config group is not ready
at parsing time (dynamic group), but a module tries to parse a @cfg_get
select call in mod_init, or when the modparams are parsed.

cfg/cfg_select.c
cfg/cfg_select.h
cfg/cfg_struct.c

index 1c0eb83..72168d7 100644 (file)
 #include "cfg_struct.h"
 #include "cfg_select.h"
 
+/* It may happen that the select calls cannot be fixed up before shmizing
+ * the config, because for example the mapping structures have not been
+ * allocated for the dynamic groups yet. So we have to keep track of all the
+ * selects that we failed to fix-up, and retry the fixup once more just
+ * before forking */
+typedef struct _cfg_selects {
+       str     gname;
+       str     vname;
+       void    **group_p;
+       void    **var_p;
+       struct _cfg_selects     *next;
+} cfg_selects_t;
+
+/* linked list of non-fixed selects */
+static cfg_selects_t   *cfg_non_fixed_selects = NULL;
+
+/* add a new select item to the linked list */
+static int cfg_new_select(str *gname, str *vname, void **group_p, void **var_p)
+{
+       cfg_selects_t   *sel;
+
+       sel = (cfg_selects_t *)pkg_malloc(sizeof(cfg_selects_t));
+       if (!sel) goto error;
+       memset(sel, 0, sizeof(cfg_selects_t));
+
+       sel->gname.s = (char *)pkg_malloc(sizeof(char)*gname->len);
+       if (!sel->gname.s) goto error;
+       memcpy(sel->gname.s, gname->s, gname->len);
+       sel->gname.len = gname->len;
+
+       sel->vname.s = (char *)pkg_malloc(sizeof(char)*vname->len);
+       if (!sel->vname.s) goto error;
+       memcpy(sel->vname.s, vname->s, vname->len);
+       sel->vname.len = vname->len;
+
+       sel->group_p = group_p;
+       sel->var_p = var_p;
+
+       sel->next = cfg_non_fixed_selects;
+       cfg_non_fixed_selects = sel;
+
+       return 0;
+
+error:
+       LOG(L_ERR, "ERROR: cfg_new_select(): not enough memory\n");
+       if (sel) {
+               if (sel->gname.s) pkg_free(sel->gname.s);
+               if (sel->vname.s) pkg_free(sel->vname.s);
+               pkg_free(sel);
+       }
+       return -1;
+}
+
+/* free the list of not yet fixed selects */
+void cfg_free_selects()
+{
+       cfg_selects_t   *sel, *next_sel;
+
+       sel = cfg_non_fixed_selects;
+       while (sel) {
+               next_sel = sel->next;
+
+               if (sel->gname.s) pkg_free(sel->gname.s);
+               if (sel->vname.s) pkg_free(sel->vname.s);
+               pkg_free(sel);
+
+               sel = next_sel;
+       }
+       cfg_non_fixed_selects = NULL;
+}
+
+/* fix-up the select calls */
+int cfg_fixup_selects()
+{
+       cfg_selects_t   *sel;
+       cfg_group_t     *group;
+       cfg_mapping_t   *var;
+
+       for (sel=cfg_non_fixed_selects; sel; sel=sel->next) {
+
+               if (cfg_lookup_var(&sel->gname, &sel->vname, &group, &var)) {
+                       LOG(L_ERR, "ERROR: cfg_parse_selects(): unknown variable: %.*s.%.*s\n",
+                               sel->gname.len, sel->gname.s,
+                               sel->vname.len, sel->vname.s);
+                       return -1;
+               }
+               *(sel->group_p) = (void *)group;
+               *(sel->var_p) = (void *)var;
+       }
+       /* the select list is not needed anymore */
+       cfg_free_selects();
+       return 0;
+}
+
 int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
 {
        cfg_group_t     *group;
@@ -60,8 +154,29 @@ int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
 
                /* look-up the group and the variable */
                if (cfg_lookup_var(&s->params[1].v.s, &s->params[2].v.s, &group, &var)) {
-                       LOG(L_ERR, "ERROR: select_cfg_var(): unknown variable\n");
-                       return -1;
+                       if (cfg_shmized) {
+                               LOG(L_ERR, "ERROR: select_cfg_var(): unknown variable: %.*s.%.*s\n",
+                                       s->params[1].v.s.len, s->params[1].v.s.s,
+                                       s->params[2].v.s.len, s->params[2].v.s.s);
+                               return -1;
+                       }
+                       /* The variable was not found, add it to the non-fixed select list.
+                        * So we act as if the fixup was successful, and we retry it later */
+                       if (cfg_new_select(&s->params[1].v.s, &s->params[2].v.s,
+                                               &s->params[1].v.p, &s->params[2].v.p))
+                               return -1;
+
+                       LOG(L_DBG, "DEBUG: select_cfg_var(): select fixup is postponed: %.*s.%.*s\n",
+                               s->params[1].v.s.len, s->params[1].v.s.s,
+                               s->params[2].v.s.len, s->params[2].v.s.s);
+
+                       s->params[1].type = SEL_PARAM_PTR;
+                       s->params[1].v.p = NULL;
+
+                       s->params[2].type = SEL_PARAM_PTR;
+                       s->params[2].v.p = NULL;
+
+                       return 0;
                }
 
                if (var->def->on_change_cb) {
@@ -82,6 +197,8 @@ int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
        group = (cfg_group_t *)s->params[1].v.p;
        var = (cfg_mapping_t *)s->params[2].v.p;
 
+       if (!group || !var) return -1;
+
        /* use the module's handle to access the variable, so the variables
        are read from private memory */
        p = *(group->handle) + var->offset;
index 544a57c..9f9b186 100644 (file)
 #ifndef _CFG_SELECT_H
 #define _CFG_SELECT_H
 
+#include "../select.h"
+
+/* free the list of not yet fixed selects */
+void cfg_free_selects();
+
+/* fix-up the select calls */
+int cfg_fixup_selects();
+
 int select_cfg_var(str *res, select_t *s, struct sip_msg *msg);
 
 #endif /* _CFG_SELECT_H */
index aa53e88..8d44cc1 100644 (file)
@@ -39,6 +39,7 @@
 #include "../locking.h"
 #include "cfg_ctx.h"
 #include "cfg_script.h"
+#include "cfg_select.h"
 #include "cfg_struct.h"
 
 cfg_group_t    *cfg_group = NULL;      /* linked list of registered cfg groups */
@@ -210,6 +211,8 @@ int cfg_shmize(void)
                                        group->mapping->def);
                }
        }
+       /* try to fixup the selects that failed to be fixed-up previously */
+       if (cfg_fixup_selects()) goto error;
 
        /* install the new config */
        cfg_install_global(block, NULL, NULL, NULL);
@@ -335,6 +338,9 @@ void cfg_destroy(void)
        /* free the list of groups */
        cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
 
+       /* free the select list */
+       cfg_free_selects();
+
        if (cfg_child_cb_first) {
                if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
                shm_free(cfg_child_cb_first);
@@ -460,6 +466,8 @@ int cfg_lookup_var(str *gname, str *vname,
                if ((g->name_len == gname->len)
                && (memcmp(g->name, gname->s, gname->len)==0)) {
 
+                       if (!g->mapping) return -1; /* dynamic group is not ready */
+
                        for (   i = 0;
                                i < g->num;
                                i++