Browse code

Select fixup is postponed until the config is shmized, if the fixup 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.

Miklos Tirpak authored on 26/02/2008 17:07:35
Showing 3 changed files
... ...
@@ -35,6 +35,100 @@
35 35
 #include "cfg_struct.h"
36 36
 #include "cfg_select.h"
37 37
 
38
+/* It may happen that the select calls cannot be fixed up before shmizing
39
+ * the config, because for example the mapping structures have not been
40
+ * allocated for the dynamic groups yet. So we have to keep track of all the
41
+ * selects that we failed to fix-up, and retry the fixup once more just
42
+ * before forking */
43
+typedef struct _cfg_selects {
44
+	str	gname;
45
+	str	vname;
46
+	void	**group_p;
47
+	void	**var_p;
48
+	struct _cfg_selects	*next;
49
+} cfg_selects_t;
50
+
51
+/* linked list of non-fixed selects */
52
+static cfg_selects_t	*cfg_non_fixed_selects = NULL;
53
+
54
+/* add a new select item to the linked list */
55
+static int cfg_new_select(str *gname, str *vname, void **group_p, void **var_p)
56
+{
57
+	cfg_selects_t	*sel;
58
+
59
+	sel = (cfg_selects_t *)pkg_malloc(sizeof(cfg_selects_t));
60
+	if (!sel) goto error;
61
+	memset(sel, 0, sizeof(cfg_selects_t));
62
+
63
+	sel->gname.s = (char *)pkg_malloc(sizeof(char)*gname->len);
64
+	if (!sel->gname.s) goto error;
65
+	memcpy(sel->gname.s, gname->s, gname->len);
66
+	sel->gname.len = gname->len;
67
+
68
+	sel->vname.s = (char *)pkg_malloc(sizeof(char)*vname->len);
69
+	if (!sel->vname.s) goto error;
70
+	memcpy(sel->vname.s, vname->s, vname->len);
71
+	sel->vname.len = vname->len;
72
+
73
+	sel->group_p = group_p;
74
+	sel->var_p = var_p;
75
+
76
+	sel->next = cfg_non_fixed_selects;
77
+	cfg_non_fixed_selects = sel;
78
+
79
+	return 0;
80
+
81
+error:
82
+	LOG(L_ERR, "ERROR: cfg_new_select(): not enough memory\n");
83
+	if (sel) {
84
+		if (sel->gname.s) pkg_free(sel->gname.s);
85
+		if (sel->vname.s) pkg_free(sel->vname.s);
86
+		pkg_free(sel);
87
+	}
88
+	return -1;
89
+}
90
+
91
+/* free the list of not yet fixed selects */
92
+void cfg_free_selects()
93
+{
94
+	cfg_selects_t	*sel, *next_sel;
95
+
96
+	sel = cfg_non_fixed_selects;
97
+	while (sel) {
98
+		next_sel = sel->next;
99
+
100
+		if (sel->gname.s) pkg_free(sel->gname.s);
101
+		if (sel->vname.s) pkg_free(sel->vname.s);
102
+		pkg_free(sel);
103
+
104
+		sel = next_sel;
105
+	}
106
+	cfg_non_fixed_selects = NULL;
107
+}
108
+
109
+/* fix-up the select calls */
110
+int cfg_fixup_selects()
111
+{
112
+	cfg_selects_t	*sel;
113
+	cfg_group_t	*group;
114
+	cfg_mapping_t	*var;
115
+
116
+	for (sel=cfg_non_fixed_selects; sel; sel=sel->next) {
117
+
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
+	}
127
+	/* the select list is not needed anymore */
128
+	cfg_free_selects();
129
+	return 0;
130
+}
131
+
38 132
 int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
39 133
 {
40 134
 	cfg_group_t	*group;
... ...
@@ -60,8 +154,29 @@ int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
60 60
 
61 61
 		/* look-up the group and the variable */
62 62
 		if (cfg_lookup_var(&s->params[1].v.s, &s->params[2].v.s, &group, &var)) {
63
-			LOG(L_ERR, "ERROR: select_cfg_var(): unknown variable\n");
64
-			return -1;
63
+			if (cfg_shmized) {
64
+				LOG(L_ERR, "ERROR: select_cfg_var(): unknown variable: %.*s.%.*s\n",
65
+					s->params[1].v.s.len, s->params[1].v.s.s,
66
+					s->params[2].v.s.len, s->params[2].v.s.s);
67
+				return -1;
68
+			}
69
+			/* The variable was not found, add it to the non-fixed select list.
70
+			 * So we act as if the fixup was successful, and we retry it later */
71
+			if (cfg_new_select(&s->params[1].v.s, &s->params[2].v.s,
72
+						&s->params[1].v.p, &s->params[2].v.p))
73
+				return -1;
74
+
75
+			LOG(L_DBG, "DEBUG: select_cfg_var(): select fixup is postponed: %.*s.%.*s\n",
76
+				s->params[1].v.s.len, s->params[1].v.s.s,
77
+				s->params[2].v.s.len, s->params[2].v.s.s);
78
+
79
+			s->params[1].type = SEL_PARAM_PTR;
80
+			s->params[1].v.p = NULL;
81
+
82
+			s->params[2].type = SEL_PARAM_PTR;
83
+			s->params[2].v.p = NULL;
84
+
85
+			return 0;
65 86
 		}
66 87
 
67 88
 		if (var->def->on_change_cb) {
... ...
@@ -82,6 +197,8 @@ int select_cfg_var(str *res, select_t *s, struct sip_msg *msg)
82 82
 	group = (cfg_group_t *)s->params[1].v.p;
83 83
 	var = (cfg_mapping_t *)s->params[2].v.p;
84 84
 
85
+	if (!group || !var) return -1;
86
+
85 87
 	/* use the module's handle to access the variable, so the variables
86 88
 	are read from private memory */
87 89
 	p = *(group->handle) + var->offset;
... ...
@@ -32,6 +32,14 @@
32 32
 #ifndef _CFG_SELECT_H
33 33
 #define _CFG_SELECT_H
34 34
 
35
+#include "../select.h"
36
+
37
+/* free the list of not yet fixed selects */
38
+void cfg_free_selects();
39
+
40
+/* fix-up the select calls */
41
+int cfg_fixup_selects();
42
+
35 43
 int select_cfg_var(str *res, select_t *s, struct sip_msg *msg);
36 44
 
37 45
 #endif /* _CFG_SELECT_H */
... ...
@@ -39,6 +39,7 @@
39 39
 #include "../locking.h"
40 40
 #include "cfg_ctx.h"
41 41
 #include "cfg_script.h"
42
+#include "cfg_select.h"
42 43
 #include "cfg_struct.h"
43 44
 
44 45
 cfg_group_t	*cfg_group = NULL;	/* linked list of registered cfg groups */
... ...
@@ -210,6 +211,8 @@ int cfg_shmize(void)
210 210
 					group->mapping->def);
211 211
 		}
212 212
 	}
213
+	/* try to fixup the selects that failed to be fixed-up previously */
214
+	if (cfg_fixup_selects()) goto error;
213 215
 
214 216
 	/* install the new config */
215 217
 	cfg_install_global(block, NULL, NULL, NULL);
... ...
@@ -335,6 +338,9 @@ void cfg_destroy(void)
335 335
 	/* free the list of groups */
336 336
 	cfg_destory_groups(cfg_global ? (*cfg_global)->vars : NULL);
337 337
 
338
+	/* free the select list */
339
+	cfg_free_selects();
340
+
338 341
 	if (cfg_child_cb_first) {
339 342
 		if (*cfg_child_cb_first) cfg_child_cb_free(*cfg_child_cb_first);
340 343
 		shm_free(cfg_child_cb_first);
... ...
@@ -460,6 +466,8 @@ int cfg_lookup_var(str *gname, str *vname,
460 460
 		if ((g->name_len == gname->len)
461 461
 		&& (memcmp(g->name, gname->s, gname->len)==0)) {
462 462
 
463
+			if (!g->mapping) return -1; /* dynamic group is not ready */
464
+
463 465
 			for (	i = 0;
464 466
 				i < g->num;
465 467
 				i++