... | ... |
@@ -126,8 +126,6 @@ Requirements: |
126 | 126 |
- libsnmp9 - libs and devel headers - if you want SNMP client functionality |
127 | 127 |
(SNMP AgentX subagent) for Kamailio |
128 | 128 |
- libldap libs and devel headers v2.1 or greater - if you want LDAP support |
129 |
-- libconfuse and devel headers - if you want to compile the carrierroute |
|
130 |
- module |
|
131 | 129 |
- libpcre libs and devel headers - if you want to compile the lcr and dialplan |
132 | 130 |
modules |
133 | 131 |
- libsctp devel headers - if you want to compile the SCTP transport in the core |
... | ... |
@@ -9,23 +9,6 @@ include ../../Makefile.defs |
9 | 9 |
auto_gen= |
10 | 10 |
NAME=carrierroute.so |
11 | 11 |
|
12 |
-ifeq ($(CROSS_COMPILE),) |
|
13 |
-CONFUSE_BUILDER = $(shell \ |
|
14 |
- if which confuse-config &>/dev/null;then \ |
|
15 |
- echo 'confuse-config'; \ |
|
16 |
- elif pkg-config --exists libconfuse; then \ |
|
17 |
- echo 'pkg-config libconfuse'; \ |
|
18 |
- fi) |
|
19 |
-endif |
|
20 |
- |
|
21 |
-ifeq ($(CONFUSE_BUILDER),) |
|
22 |
- DEFS += -I$(LOCALBASE)/include |
|
23 |
- LIBS += -L$(LOCALBASE)/lib -lconfuse |
|
24 |
-else |
|
25 |
- DEFS += $(shell $(CONFUSE_BUILDER) --cflags) |
|
26 |
- LIBS += $(shell $(CONFUSE_BUILDER) --libs) |
|
27 |
-endif |
|
28 |
- |
|
29 | 12 |
DEFS+=-DKAMAILIO_MOD_INTERFACE |
30 | 13 |
|
31 | 14 |
SERLIBPATH=../../lib |
... | ... |
@@ -20,14 +20,13 @@ |
20 | 20 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
21 | 21 |
*/ |
22 | 22 |
|
23 |
-/** |
|
23 |
+/*! |
|
24 | 24 |
* \file cr_config.c |
25 | 25 |
* \brief Functions for load and save routing data from a config file. |
26 | 26 |
* \ingroup carrierroute |
27 | 27 |
* - Module; \ref carrierroute |
28 | 28 |
*/ |
29 | 29 |
|
30 |
-#include <confuse.h> |
|
31 | 30 |
#include <sys/types.h> |
32 | 31 |
#include <sys/stat.h> |
33 | 32 |
#include <unistd.h> |
... | ... |
@@ -42,87 +41,76 @@ |
42 | 41 |
#include "cr_rule.h" |
43 | 42 |
#include "cr_domain.h" |
44 | 43 |
#include "cr_carrier.h" |
44 |
+#include "parser_carrierroute.h" |
|
45 | 45 |
|
46 |
+enum target_opt_ids { TO_ID_COMMENT = 0, TO_ID_STRIP, TO_ID_REWR_PREFIX, TO_ID_PROB, TO_ID_HASH_INDEX, |
|
47 |
+ TO_ID_REWR_SUFFIX, TO_ID_STATUS, TO_ID_BACKED_UP, TO_ID_BACKUP, TO_MAX_IDS }; |
|
48 |
+enum prefix_opt_ids { PO_MAX_TARGETS = 0, PO_MAX_IDS }; |
|
46 | 49 |
|
47 |
-/** |
|
48 |
- * reports errors during config file parsing using LOG macro |
|
49 |
- * |
|
50 |
- * @param cfg points to the current config data structure |
|
51 |
- * @param fmt a format string |
|
52 |
- * @param ap format arguments |
|
53 |
- */ |
|
54 |
-static void conf_error(cfg_t *cfg, const char * fmt, va_list ap) { |
|
55 |
- int ret; |
|
56 |
- static char buf[1024]; |
|
57 |
- |
|
58 |
- ret = vsnprintf(buf, sizeof(buf), fmt, ap); |
|
59 |
- if (ret < 0 || ret >= sizeof(buf)) { |
|
60 |
- LM_ERR("could not print error message\n"); |
|
61 |
- } else { |
|
62 |
- // FIXME this don't seems to work reliable in all cases, charset |
|
63 |
- // problems |
|
64 |
- LM_GEN1(L_ERR, "%s", buf); |
|
50 |
+option_description target_options[TO_MAX_IDS]; |
|
51 |
+option_description prefix_options[PO_MAX_IDS]; |
|
52 |
+ |
|
53 |
+static void reset_opts(option_description * opts, int size){ |
|
54 |
+ int i; |
|
55 |
+ if ( NULL == opts){ |
|
56 |
+ LM_ERR("Trying to init a NULL pointer location \n"); |
|
57 |
+ return; |
|
65 | 58 |
} |
59 |
+ for (i=0; i < size; i++){ |
|
60 |
+ memset(&(opts[i].value),'\0', sizeof(union opt_data)); |
|
61 |
+ opts[i].visited = 0; |
|
62 |
+ opts[i].no_elems = 0; |
|
63 |
+ if ( CFG_STR == opts[i].type ){ |
|
64 |
+ opts[i].value.string_data.s = opts[i].str_buf; |
|
65 |
+ strcpy(opts[i].str_buf,""); |
|
66 |
+ opts[i].value.string_data.len = 0; |
|
67 |
+ } |
|
68 |
+ } |
|
69 |
+ return; |
|
66 | 70 |
} |
67 | 71 |
|
68 |
- |
|
69 |
-/** |
|
70 |
- * Parses the config file |
|
71 |
- * |
|
72 |
- * @return a pointer to the configuration data structure, NULL on failure |
|
73 |
- */ |
|
74 |
-static cfg_t * parse_config(void) { |
|
75 |
- cfg_t * cfg = NULL; |
|
76 |
- |
|
77 |
- cfg_opt_t target_opts[] = { |
|
78 |
- CFG_STR("comment", 0, CFGF_NONE), |
|
79 |
- CFG_INT("strip", 0, CFGF_NONE), |
|
80 |
- CFG_STR("rewrite_prefix", 0, CFGF_NONE), |
|
81 |
- CFG_FLOAT("prob", 0, CFGF_NONE), |
|
82 |
- CFG_INT("hash_index", 0, CFGF_NONE), |
|
83 |
- CFG_STR("rewrite_suffix", 0, CFGF_NONE), |
|
84 |
- CFG_INT("status", 1, CFGF_NONE), |
|
85 |
- CFG_INT_LIST("backed_up", NULL, CFGF_NONE), |
|
86 |
- CFG_INT("backup", -1, CFGF_NONE), |
|
87 |
- CFG_END() |
|
88 |
- }; |
|
89 |
- |
|
90 |
- cfg_opt_t prefix_opts[] = { |
|
91 |
- CFG_SEC("target", target_opts, CFGF_MULTI | CFGF_TITLE), |
|
92 |
- CFG_INT("max_targets", -1, CFGF_NONE), |
|
93 |
- CFG_END() |
|
94 |
- }; |
|
95 |
- |
|
96 |
- cfg_opt_t domain_opts[] = { |
|
97 |
- CFG_SEC("prefix", prefix_opts, CFGF_MULTI | CFGF_TITLE), |
|
98 |
- CFG_END() |
|
99 |
- }; |
|
100 |
- |
|
101 |
- cfg_opt_t opts[] = { |
|
102 |
- CFG_SEC("domain", domain_opts, CFGF_MULTI | CFGF_TITLE), |
|
103 |
- CFG_END() |
|
104 |
- }; |
|
105 |
- |
|
106 |
- cfg = cfg_init(opts, CFGF_NONE); |
|
107 |
- if (cfg == NULL) { |
|
108 |
- LM_ERR("could not initialize configuration\n"); |
|
109 |
- return NULL; |
|
72 |
+static int init_target_opts(option_description * opts){ |
|
73 |
+ if ( NULL == opts){ |
|
74 |
+ LM_DBG("Trying to init a NULL pointer location \n"); |
|
75 |
+ return -1; |
|
110 | 76 |
} |
77 |
+ memset(opts, '\0', sizeof(option_description) * TO_MAX_IDS); |
|
78 |
+ |
|
79 |
+ strcpy((char*)(opts[TO_ID_COMMENT].name), "comment"); |
|
80 |
+ strcpy((char*)(opts[TO_ID_STRIP].name), "strip"); |
|
81 |
+ strcpy((char*)(opts[TO_ID_REWR_PREFIX].name),"rewrite_prefix"); |
|
82 |
+ strcpy((char*)(opts[TO_ID_PROB].name), "prob"); |
|
83 |
+ strcpy((char*)(opts[TO_ID_HASH_INDEX].name), "hash_index"); |
|
84 |
+ strcpy((char*)(opts[TO_ID_REWR_SUFFIX].name),"rewrite_suffix"); |
|
85 |
+ strcpy((char*)(opts[TO_ID_STATUS].name), "status"); |
|
86 |
+ strcpy((char*)(opts[TO_ID_BACKED_UP].name), "backed_up"); |
|
87 |
+ strcpy((char*)(opts[TO_ID_BACKUP].name), "backup"); |
|
88 |
+ |
|
89 |
+ opts[TO_ID_COMMENT ].type=CFG_STR; |
|
90 |
+ opts[TO_ID_STRIP ].type=CFG_INT; |
|
91 |
+ opts[TO_ID_REWR_PREFIX].type=CFG_STR; |
|
92 |
+ opts[TO_ID_PROB ].type=CFG_FLOAT; |
|
93 |
+ opts[TO_ID_HASH_INDEX ].type=CFG_INT; |
|
94 |
+ opts[TO_ID_REWR_SUFFIX].type=CFG_STR; |
|
95 |
+ opts[TO_ID_STATUS ].type=CFG_INT; |
|
96 |
+ opts[TO_ID_BACKED_UP ].type=CFG_INT_LIST; |
|
97 |
+ opts[TO_ID_BACKUP ].type=CFG_INT; |
|
98 |
+ |
|
99 |
+ reset_opts(opts, TO_MAX_IDS); |
|
100 |
+ return 0; |
|
101 |
+} |
|
111 | 102 |
|
112 |
- cfg_set_error_function(cfg, conf_error); |
|
113 |
- |
|
114 |
- switch (cfg_parse(cfg, config_file)) { |
|
115 |
- case CFG_FILE_ERROR: LM_ERR("file not found: %s\n", config_file); |
|
116 |
- return NULL; |
|
117 |
- case CFG_PARSE_ERROR: LM_ERR("error while parsing %s in line %i, section %s\n", |
|
118 |
- cfg->filename, cfg->line, cfg->name); |
|
119 |
- return NULL; |
|
120 |
- case CFG_SUCCESS: break; |
|
103 |
+static int init_prefix_opts(option_description * opts){ |
|
104 |
+ if ( NULL == opts){ |
|
105 |
+ LM_DBG("Trying to init a NULL pointer location \n"); |
|
106 |
+ return -1; |
|
121 | 107 |
} |
122 |
- return cfg; |
|
108 |
+ memset(opts, '\0', sizeof(option_description) * PO_MAX_IDS); |
|
109 |
+ strcpy((char*)(opts[PO_MAX_TARGETS].name), "max_targets"); |
|
110 |
+ opts[PO_MAX_TARGETS].type=CFG_INT; |
|
111 |
+ return 0; |
|
123 | 112 |
} |
124 | 113 |
|
125 |
- |
|
126 | 114 |
static int backup_config(void) { |
127 | 115 |
FILE * from, * to; |
128 | 116 |
char * backup_file, ch; |
... | ... |
@@ -188,10 +176,11 @@ errout: |
188 | 176 |
return -1; |
189 | 177 |
} |
190 | 178 |
|
191 |
- |
|
192 | 179 |
/** |
193 | 180 |
* Loads the routing data from the config file given in global |
194 | 181 |
* variable config_data and stores it in routing tree rd. |
182 |
+ * The function mixes code parsing calls with rd structure |
|
183 |
+ * completion. |
|
195 | 184 |
* |
196 | 185 |
* @param rd Pointer to the route data tree where the routing data |
197 | 186 |
* shall be loaded into |
... | ... |
@@ -200,173 +189,277 @@ errout: |
200 | 189 |
* |
201 | 190 |
*/ |
202 | 191 |
int load_config(struct route_data_t * rd) { |
203 |
- cfg_t * cfg = NULL; |
|
204 |
- int m, o, i, j, k,l, status, hash_index, max_targets, strip; |
|
205 |
- cfg_t * d, * p, * t; |
|
192 |
+ FILE * file; |
|
193 |
+ |
|
194 |
+ int ret_domain, ret_prefix, ret_target, ret_prefix_opts, ret_target_opts; |
|
195 |
+ int domain_id, allocated_domain_num = DEFAULT_DOMAIN_NUM; |
|
196 |
+ str domain_name, prefix_name, rewrite_host; |
|
197 |
+ char domain_buf[CR_MAX_LINE_SIZE], prefix_buf[CR_MAX_LINE_SIZE], rewrite_buf[CR_MAX_LINE_SIZE]; |
|
198 |
+ |
|
199 |
+ str rewrite_prefix, rewrite_suffix, comment; |
|
200 |
+ struct domain_data_t *domain_data = NULL; |
|
206 | 201 |
struct carrier_data_t * tmp_carrier_data; |
207 |
- int domain_id; |
|
208 |
- str domain, prefix, rewrite_prefix, rewrite_suffix, rewrite_host, comment; |
|
202 |
+ int hash_index, max_targets = 0, strip; |
|
209 | 203 |
double prob; |
210 | 204 |
int * backed_up = NULL; |
211 |
- int backed_up_size, backup; |
|
212 |
- backed_up_size = backup = 0; |
|
205 |
+ int backed_up_size = 0, backup = 0, status; |
|
206 |
+ void* p_realloc; |
|
207 |
+ int i=0, l, k; |
|
208 |
+ |
|
209 |
+ domain_name.s = domain_buf; domain_name.len = CR_MAX_LINE_SIZE; |
|
210 |
+ prefix_name.s = prefix_buf; prefix_name.len = CR_MAX_LINE_SIZE; |
|
211 |
+ rewrite_host.s = rewrite_buf; rewrite_host.len = CR_MAX_LINE_SIZE; |
|
213 | 212 |
|
214 |
- if ((cfg = parse_config()) == NULL) { |
|
213 |
+ /* open configuration file */ |
|
214 |
+ if ((file = fopen(config_file, "rb"))==NULL) { |
|
215 |
+ LM_ERR("Cannot open source file.\n"); |
|
215 | 216 |
return -1; |
216 | 217 |
} |
217 | 218 |
|
218 | 219 |
rd->carrier_num = 1; |
219 | 220 |
rd->first_empty_carrier = 0; |
220 |
- rd->domain_num = cfg_size(cfg, "domain"); |
|
221 |
+ rd->domain_num = 0; |
|
221 | 222 |
|
222 | 223 |
if ((rd->carriers = shm_malloc(sizeof(struct carrier_data_t *))) == NULL) { |
223 | 224 |
SHM_MEM_ERROR; |
224 |
- return -1; |
|
225 |
+ goto errclose; |
|
225 | 226 |
} |
226 | 227 |
memset(rd->carriers, 0, sizeof(struct carrier_data_t *)); |
227 | 228 |
|
228 | 229 |
/* Create carrier map */ |
229 | 230 |
if ((rd->carrier_map = shm_malloc(sizeof(struct name_map_t))) == NULL) { |
230 | 231 |
SHM_MEM_ERROR; |
231 |
- return -1; |
|
232 |
+ goto errclose; |
|
232 | 233 |
} |
234 |
+ |
|
233 | 235 |
memset(rd->carrier_map, 0, sizeof(struct name_map_t)); |
234 | 236 |
rd->carrier_map[0].id = 1; |
235 | 237 |
rd->carrier_map[0].name.len = default_tree.len; |
236 | 238 |
rd->carrier_map[0].name.s = shm_malloc(rd->carrier_map[0].name.len); |
239 |
+ |
|
237 | 240 |
if (rd->carrier_map[0].name.s == NULL) { |
238 | 241 |
SHM_MEM_ERROR; |
239 |
- return -1; |
|
242 |
+ goto errclose; |
|
240 | 243 |
} |
241 | 244 |
memcpy(rd->carrier_map[0].name.s, default_tree.s, rd->carrier_map[0].name.len); |
242 | 245 |
|
243 | 246 |
/* Create domain map */ |
244 |
- if ((rd->domain_map = shm_malloc(sizeof(struct name_map_t) * rd->domain_num)) == NULL) { |
|
247 |
+ if ((rd->domain_map = shm_malloc(sizeof(struct name_map_t) * allocated_domain_num)) == NULL) { |
|
245 | 248 |
SHM_MEM_ERROR; |
246 |
- return -1; |
|
249 |
+ goto errclose; |
|
247 | 250 |
} |
248 |
- memset(rd->domain_map, 0, sizeof(struct name_map_t) * rd->domain_num); |
|
249 |
- for (i=0; i<rd->domain_num; i++) { |
|
250 |
- d = cfg_getnsec(cfg, "domain", i); |
|
251 |
- domain.s = (char *)cfg_title(d); |
|
252 |
- if (domain.s==NULL) domain.s=""; |
|
253 |
- domain.len = strlen(domain.s); |
|
254 |
- rd->domain_map[i].id = i+1; |
|
255 |
- rd->domain_map[i].name.len = domain.len; |
|
256 |
- rd->domain_map[i].name.s = shm_malloc(rd->domain_map[i].name.len); |
|
257 |
- if (rd->domain_map[i].name.s == NULL) { |
|
258 |
- SHM_MEM_ERROR; |
|
259 |
- return -1; |
|
260 |
- } |
|
261 |
- memcpy(rd->domain_map[i].name.s, domain.s, rd->domain_map[i].name.len); |
|
262 |
- } |
|
263 |
- /* sort domain map by id for faster access */ |
|
264 |
- qsort(rd->domain_map, rd->domain_num, sizeof(rd->domain_map[0]), compare_name_map); |
|
251 |
+ memset(rd->domain_map, 0, sizeof(struct name_map_t) * allocated_domain_num); |
|
265 | 252 |
|
266 | 253 |
/* Create and insert carrier data structure */ |
267 |
- tmp_carrier_data = create_carrier_data(1, &rd->carrier_map[0].name, rd->domain_num); |
|
254 |
+ tmp_carrier_data = create_carrier_data(1, &rd->carrier_map[0].name, allocated_domain_num); |
|
255 |
+ tmp_carrier_data->domain_num = 0; |
|
256 |
+ tmp_carrier_data->id = 1; |
|
257 |
+ tmp_carrier_data->name = &(rd->carrier_map[0].name); |
|
258 |
+ |
|
268 | 259 |
if (tmp_carrier_data == NULL) { |
269 | 260 |
LM_ERR("can't create new carrier\n"); |
270 |
- return -1; |
|
261 |
+ goto errclose; |
|
271 | 262 |
} |
272 | 263 |
if (add_carrier_data(rd, tmp_carrier_data) < 0) { |
273 | 264 |
LM_ERR("couldn't add carrier data\n"); |
274 | 265 |
destroy_carrier_data(tmp_carrier_data); |
275 |
- return -1; |
|
266 |
+ goto errclose; |
|
276 | 267 |
} |
277 | 268 |
|
278 |
- /* add all routes */ |
|
279 |
- for (i = 0; i < rd->domain_num; i++) { |
|
280 |
- d = cfg_getnsec(cfg, "domain", i); |
|
281 |
- domain.s = (char *)cfg_title(d); |
|
282 |
- if (domain.s==NULL) domain.s=""; |
|
283 |
- domain.len = strlen(domain.s); |
|
284 |
- m = cfg_size(d, "prefix"); |
|
285 |
- |
|
286 |
- LM_INFO("loading domain %.*s\n", domain.len, domain.s); |
|
287 |
- for (j = 0; j < m; j++) { |
|
288 |
- p = cfg_getnsec(d, "prefix", j); |
|
289 |
- prefix.s = (char *)cfg_title(p); |
|
290 |
- if (prefix.s==NULL) prefix.s=""; |
|
291 |
- prefix.len = strlen(prefix.s); |
|
292 |
- if (str_strcasecmp(&prefix, &CR_EMPTY_PREFIX) == 0) { |
|
293 |
- prefix.s = ""; |
|
294 |
- prefix.len = 0; |
|
269 |
+ init_prefix_opts(prefix_options); |
|
270 |
+ init_target_opts(target_options); |
|
271 |
+ |
|
272 |
+ /* add all routes by parsing the route conf file */ |
|
273 |
+ /* while there are domain structures, get name and parse the structure*/ |
|
274 |
+ while ((ret_domain = parse_struct_header(file, "domain", &domain_name)) |
|
275 |
+ == SUCCESSFUL_PARSING) { |
|
276 |
+ |
|
277 |
+ domain_id = ++rd->domain_num; |
|
278 |
+ tmp_carrier_data->domain_num++; |
|
279 |
+ |
|
280 |
+ /* (re)allocate memory for a maximum of MAX_DOMAIN_NUM domains |
|
281 |
+ rd is not fully allocated from the start as this would require the preparsing |
|
282 |
+ of the entire route file */ |
|
283 |
+ if ( rd->domain_num > allocated_domain_num){ |
|
284 |
+ |
|
285 |
+ if (MAX_DOMAIN_NUM <= allocated_domain_num){ |
|
286 |
+ LM_ERR("Maximum number of domains reached"); |
|
287 |
+ break; |
|
295 | 288 |
} |
296 | 289 |
|
297 |
- LM_INFO("loading prefix %.*s\n", prefix.len, prefix.s); |
|
298 |
- max_targets = cfg_getint(p, "max_targets"); |
|
299 |
- o = cfg_size(p, "target"); |
|
300 |
- for (k = 0; k < o; k++) { |
|
301 |
- t = cfg_getnsec(p, "target", k); |
|
302 |
- rewrite_host.s = (char *)cfg_title(t); |
|
303 |
- if (rewrite_host.s==NULL) rewrite_host.s=""; |
|
304 |
- rewrite_host.len = strlen(rewrite_host.s); |
|
290 |
+ LM_INFO("crt_alloc_size=%d must be increased \n", allocated_domain_num); |
|
291 |
+ allocated_domain_num *= 2; |
|
292 |
+ |
|
293 |
+ if ( ( p_realloc = shm_realloc(rd->domain_map, |
|
294 |
+ sizeof(struct name_map_t) * allocated_domain_num) ) == NULL) |
|
295 |
+ { |
|
296 |
+ SHM_MEM_ERROR; |
|
297 |
+ goto errclose; |
|
298 |
+ } |
|
299 |
+ |
|
300 |
+ rd->domain_map = (struct name_map_t *)p_realloc; |
|
301 |
+ |
|
302 |
+ if (( p_realloc = shm_realloc( rd->carriers[0]->domains, |
|
303 |
+ sizeof(struct domain_data_t *) * allocated_domain_num)) == NULL) { |
|
304 |
+ SHM_MEM_ERROR; |
|
305 |
+ goto errclose; |
|
306 |
+ } |
|
307 |
+ rd->carriers[0]->domains = (struct domain_data_t **)p_realloc; |
|
308 |
+ |
|
309 |
+ for (i=0; i<rd->domain_num-1; i++){ |
|
310 |
+ rd->carriers[0]->domains[i]->name = &(rd->domain_map[i].name); |
|
311 |
+ } |
|
312 |
+ }// end of mem (re)allocation for domains |
|
313 |
+ |
|
314 |
+ /*insert domain in domain map*/ |
|
315 |
+ rd->domain_map[domain_id-1].id = domain_id; |
|
316 |
+ rd->domain_map[domain_id-1].name.len = domain_name.len; |
|
317 |
+ rd->domain_map[domain_id-1].name.s = shm_malloc(rd->domain_map[domain_id-1].name.len); |
|
318 |
+ if (rd->domain_map[domain_id-1].name.s == NULL) { |
|
319 |
+ SHM_MEM_ERROR; |
|
320 |
+ goto errclose; |
|
321 |
+ } |
|
322 |
+ memcpy(rd->domain_map[domain_id-1].name.s, domain_name.s, rd->domain_map[domain_id-1].name.len); |
|
323 |
+ |
|
324 |
+ /* create new domain data */ |
|
325 |
+ if ((domain_data = create_domain_data(domain_id,&(rd->domain_map[domain_id-1].name))) == NULL) { |
|
326 |
+ LM_ERR("could not create new domain data\n"); |
|
327 |
+ goto errclose; |
|
328 |
+ } |
|
329 |
+ |
|
330 |
+ if (add_domain_data(tmp_carrier_data, domain_data, domain_id-1) < 0) { |
|
331 |
+ LM_ERR("could not add domain data\n"); |
|
332 |
+ destroy_domain_data(domain_data); |
|
333 |
+ goto errclose; |
|
334 |
+ } |
|
335 |
+ LM_DBG("added domain %d '%.*s' to carrier %d '%.*s'\n", |
|
336 |
+ domain_id, domain_name.len, domain_name.s, |
|
337 |
+ tmp_carrier_data->id, tmp_carrier_data->name->len, tmp_carrier_data->name->s); |
|
338 |
+ |
|
339 |
+ /* while there are prefix structures, get name and parse the structure */ |
|
340 |
+ while ((ret_prefix = parse_struct_header(file, "prefix", &prefix_name)) |
|
341 |
+ == SUCCESSFUL_PARSING) { |
|
342 |
+ |
|
343 |
+ reset_opts(prefix_options, PO_MAX_IDS); |
|
344 |
+ if (str_strcasecmp(&prefix_name, &CR_EMPTY_PREFIX) == 0) { |
|
345 |
+ prefix_name.s[0] = '\0'; |
|
346 |
+ prefix_name.len = 0; |
|
347 |
+ } |
|
348 |
+ |
|
349 |
+ /* look for max_targets = value which is described in prefix_options */ |
|
350 |
+ if ((ret_prefix_opts = parse_options(file, prefix_options, |
|
351 |
+ PO_MAX_IDS, "target")) != SUCCESSFUL_PARSING) { |
|
352 |
+ LM_ERR("Error in parsing \n"); |
|
353 |
+ goto errclose; |
|
354 |
+ } |
|
355 |
+ |
|
356 |
+ max_targets = prefix_options[PO_MAX_TARGETS].value.int_data; |
|
357 |
+ /* look for max_targets target structures */ |
|
358 |
+ for ( k = 0; k < max_targets; k++) { |
|
359 |
+ /* parse the target header, get name and continue*/ |
|
360 |
+ ret_target = parse_struct_header(file, "target", &rewrite_host); |
|
361 |
+ if (ret_target != SUCCESSFUL_PARSING) { |
|
362 |
+ LM_ERR("Error in parsing \n"); |
|
363 |
+ goto errclose; |
|
364 |
+ } |
|
365 |
+ |
|
366 |
+ reset_opts(target_options, TO_MAX_IDS); |
|
367 |
+ /* look for the target options: prob, hash index, status, etc*/ |
|
368 |
+ ret_target_opts = parse_options(file, target_options, TO_MAX_IDS, "}"); |
|
369 |
+ if ( SUCCESSFUL_PARSING == ret_target_opts ){ |
|
370 |
+ /* parsing target structure closing bracket*/ |
|
371 |
+ parse_struct_stop(file); |
|
372 |
+ }else{ |
|
373 |
+ LM_ERR("Error in parsing in target options \n"); |
|
374 |
+ goto errclose; |
|
375 |
+ } |
|
376 |
+ /* intermediary variables for more lisibility */ |
|
305 | 377 |
if (str_strcasecmp(&rewrite_host, &CR_EMPTY_PREFIX) == 0) { |
306 |
- rewrite_host.s = ""; |
|
378 |
+ rewrite_host.s[0] = '\0'; |
|
307 | 379 |
rewrite_host.len = 0; |
308 | 380 |
} |
309 |
- |
|
310 |
- LM_INFO("loading target %.*s\n", rewrite_host.len, rewrite_host.s); |
|
311 |
- prob = cfg_getfloat(t, "prob"); |
|
312 |
- strip = cfg_getint(t, "strip"); |
|
313 |
- rewrite_prefix.s = (char *)cfg_getstr(t, "rewrite_prefix"); |
|
314 |
- if (rewrite_prefix.s==NULL) rewrite_prefix.s=""; |
|
315 |
- rewrite_prefix.len = strlen(rewrite_prefix.s); |
|
316 |
- rewrite_suffix.s = (char *)cfg_getstr(t, "rewrite_suffix"); |
|
317 |
- if (rewrite_suffix.s==NULL) rewrite_suffix.s=""; |
|
318 |
- rewrite_suffix.len = strlen(rewrite_suffix.s); |
|
319 |
- hash_index = cfg_getint(t, "hash_index"); |
|
320 |
- comment.s = (char *)cfg_getstr(t, "comment"); |
|
321 |
- if (comment.s==NULL) comment.s=""; |
|
322 |
- comment.len = strlen(comment.s); |
|
323 |
- status = cfg_getint(t, "status"); |
|
324 |
- |
|
325 |
- if ((backed_up_size = cfg_size(t, "backed_up")) > 0) { |
|
381 |
+ LM_DBG("loading target %.*s\n", rewrite_host.len, rewrite_host.s); |
|
382 |
+ prob = target_options[TO_ID_PROB].value.float_data; |
|
383 |
+ strip = target_options[TO_ID_STRIP].value.int_data; |
|
384 |
+ rewrite_prefix.s = target_options[TO_ID_REWR_PREFIX].value.string_data.s; |
|
385 |
+ rewrite_prefix.len = target_options[TO_ID_REWR_PREFIX].value.string_data.len; |
|
386 |
+ rewrite_suffix.s = target_options[TO_ID_REWR_SUFFIX].value.string_data.s; |
|
387 |
+ rewrite_suffix.len = target_options[TO_ID_REWR_SUFFIX].value.string_data.len; |
|
388 |
+ hash_index = target_options[TO_ID_HASH_INDEX].value.int_data; |
|
389 |
+ comment.s = target_options[TO_ID_COMMENT].value.string_data.s; |
|
390 |
+ comment.len = target_options[TO_ID_COMMENT].value.string_data.len; |
|
391 |
+ status = target_options[TO_ID_STATUS].value.int_data; |
|
392 |
+ |
|
393 |
+ if ( (backed_up_size = target_options[TO_ID_BACKED_UP].no_elems) > 0){ |
|
326 | 394 |
if ((backed_up = pkg_malloc(sizeof(int) * (backed_up_size + 1))) == NULL) { |
327 | 395 |
PKG_MEM_ERROR; |
328 |
- return -1; |
|
396 |
+ goto errclose; |
|
329 | 397 |
} |
330 | 398 |
for (l = 0; l < backed_up_size; l++) { |
331 |
- backed_up[l] = cfg_getnint(t, "backed_up", l); |
|
399 |
+ backed_up[l] = target_options[TO_ID_BACKED_UP].value.int_list[l]; |
|
332 | 400 |
} |
333 | 401 |
backed_up[backed_up_size] = -1; |
334 | 402 |
} |
335 |
- backup = cfg_getint(t, "backup"); |
|
336 |
- |
|
337 |
- domain_id = map_name2id(rd->domain_map, rd->domain_num, &domain); |
|
338 |
- if (domain_id < 0) { |
|
339 |
- LM_ERR("cannot find id for domain '%.*s'", domain.len, domain.s); |
|
340 |
- if (backed_up) { |
|
341 |
- pkg_free(backed_up); |
|
342 |
- } |
|
343 |
- return -1; |
|
344 |
- } |
|
345 |
- |
|
346 |
- LM_INFO("adding route for prefix %.*s, to host %.*s, prob %f, backed up: %i, backup: %i\n", |
|
347 |
- prefix.len, prefix.s, rewrite_host.len, rewrite_host.s, prob, backed_up_size, backup); |
|
348 |
- if (add_route(rd, 1, domain_id, &prefix, 0, 0, max_targets, prob, &rewrite_host, |
|
349 |
- strip, &rewrite_prefix, &rewrite_suffix, status, |
|
350 |
- hash_index, backup, backed_up, &comment) < 0) { |
|
403 |
+ backup = target_options[TO_ID_BACKUP].value.int_data; |
|
404 |
+ |
|
405 |
+ LM_ERR("\n Adding route to tree <'%.*s'>: prefix_name:%s\n," |
|
406 |
+ " max_targets =%d\n, prob=%f\n, rewr_host=%s\n," |
|
407 |
+ " strip=%i\n, rwr_prefix=%s\n, rwr_suff=%s\n," |
|
408 |
+ " status=%i\n, hash_index=%i\n, comment=%s \n", |
|
409 |
+ domain_data->name->len, domain_data->name->s, prefix_name.s, |
|
410 |
+ max_targets, prob, rewrite_host.s, strip, rewrite_prefix.s, |
|
411 |
+ rewrite_suffix.s, status, hash_index, comment.s); |
|
412 |
+ |
|
413 |
+ if (add_route_to_tree(domain_data->tree, &prefix_name, 0, 0, |
|
414 |
+ &prefix_name, max_targets, prob, &rewrite_host, |
|
415 |
+ strip, &rewrite_prefix, &rewrite_suffix, status, |
|
416 |
+ hash_index, backup, backed_up, &comment) < 0) { |
|
351 | 417 |
LM_INFO("Error while adding route\n"); |
352 | 418 |
if (backed_up) { |
353 | 419 |
pkg_free(backed_up); |
354 | 420 |
} |
355 |
- return -1; |
|
421 |
+ goto errclose; |
|
356 | 422 |
} |
423 |
+ |
|
357 | 424 |
if (backed_up) { |
358 | 425 |
pkg_free(backed_up); |
359 | 426 |
} |
360 | 427 |
backed_up = NULL; |
361 | 428 |
} |
429 |
+ |
|
430 |
+ if (k != prefix_options[0].value.int_data ) { |
|
431 |
+ LM_ERR("Error in parsing: max_targets =%i, actual targets =%i \n", |
|
432 |
+ prefix_options[0].value.int_data, i); |
|
433 |
+ goto errclose; |
|
434 |
+ } |
|
435 |
+ /* parsing prefix structure closing bracket */ |
|
436 |
+ if (parse_struct_stop(file) != SUCCESSFUL_PARSING) { |
|
437 |
+ LM_ERR("Error in parsing targets, expecting } \n"); |
|
438 |
+ goto errclose; |
|
439 |
+ |
|
440 |
+ } |
|
441 |
+ } // END OF PREFIX part |
|
442 |
+ |
|
443 |
+ /* parsing domain structure closing bracket */ |
|
444 |
+ if (parse_struct_stop(file) != SUCCESSFUL_PARSING) { |
|
445 |
+ LM_ERR("Error in parsing targets, expecting } \n"); |
|
446 |
+ goto errclose; |
|
362 | 447 |
} |
448 |
+ } |
|
363 | 449 |
|
450 |
+ if (EOF_REACHED != ret_domain){ |
|
451 |
+ LM_ERR("Error appeared while parsing domain header \n"); |
|
452 |
+ goto errclose; |
|
364 | 453 |
} |
365 |
- cfg_free(cfg); |
|
454 |
+ |
|
455 |
+ LM_ERR("File parsed successfully \n"); |
|
456 |
+ fclose(file); |
|
366 | 457 |
return 0; |
458 |
+errclose: |
|
459 |
+ fclose(file); |
|
460 |
+ return -1; |
|
367 | 461 |
} |
368 | 462 |
|
369 |
- |
|
370 | 463 |
/** |
371 | 464 |
* Does the work for save_config, traverses the routing data tree |
372 | 465 |
* and writes each rule to file. |
... | ... |
@@ -95,21 +95,6 @@ |
95 | 95 |
</itemizedlist> |
96 | 96 |
</para> |
97 | 97 |
</section> |
98 |
- <section> |
|
99 |
- <title>External Libraries or Applications</title> |
|
100 |
- <para> |
|
101 |
- The following libraries or applications must be installed before running |
|
102 |
- &kamailio; with this module loaded: |
|
103 |
- <itemizedlist> |
|
104 |
- <listitem> |
|
105 |
- <para> |
|
106 |
- <emphasis>libconfuse</emphasis>, a configuration file parser library. |
|
107 |
- ( http://www.nongnu.org/confuse/ ) |
|
108 |
- </para> |
|
109 |
- </listitem> |
|
110 |
- </itemizedlist> |
|
111 |
- </para> |
|
112 |
- </section> |
|
113 | 98 |
</section> |
114 | 99 |
<section> |
115 | 100 |
<title>Parameters</title> |
116 | 101 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,411 @@ |
1 |
+/* |
|
2 |
+ * $Id$ |
|
3 |
+ * |
|
4 |
+ * Copyright (C) 1&1 Internet AG |
|
5 |
+ * |
|
6 |
+ * This file is part of SIP-router, a free SIP server. |
|
7 |
+ * |
|
8 |
+ * SIP-router is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License as published by |
|
10 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
11 |
+ * (at your option) any later version |
|
12 |
+ * |
|
13 |
+ * SIP-router is distributed in the hope that it will be useful, |
|
14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
+ * GNU General Public License for more details. |
|
17 |
+ * |
|
18 |
+ * You should have received a copy of the GNU General Public License |
|
19 |
+ * along with this program; if not, write to the Free Software |
|
20 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
21 |
+ */ |
|
22 |
+ |
|
23 |
+/*! |
|
24 |
+ * \file parser_carrierroute.c |
|
25 |
+ * \brief Functions for parsing the config file of cr when using file mode. |
|
26 |
+ * \ingroup carrierroute |
|
27 |
+ * - Module; \ref carrierroute |
|
28 |
+ */ |
|
29 |
+ |
|
30 |
+#include <stdio.h> |
|
31 |
+#include <string.h> |
|
32 |
+#include <ctype.h> |
|
33 |
+#include <stdlib.h> |
|
34 |
+#include <limits.h> |
|
35 |
+#include <float.h> |
|
36 |
+#include <math.h> |
|
37 |
+#include <errno.h> |
|
38 |
+#include "parser_carrierroute.h" |
|
39 |
+ |
|
40 |
+#include "../../ut.h" |
|
41 |
+#include "../../trim.h" |
|
42 |
+ |
|
43 |
+#define assert_not_null(s) do { \ |
|
44 |
+ if ( NULL == (s) ){ \ |
|
45 |
+ LM_INFO("Unexpected null option \n"); \ |
|
46 |
+ return ERROR_IN_PARSING;\ |
|
47 |
+ } \ |
|
48 |
+} while (0) |
|
49 |
+ |
|
50 |
+ |
|
51 |
+/** |
|
52 |
+ * Gets index of given option inside option list |
|
53 |
+ * |
|
54 |
+ * @param opt_name name of option |
|
55 |
+ * @param opt_list points to the option list |
|
56 |
+ * @param no_options size of option list |
|
57 |
+ * |
|
58 |
+ * @return index of option inside option list, -1 not found |
|
59 |
+ */ |
|
60 |
+int get_option_position(char* opt_name, option_description* opt_list, int no_options){ |
|
61 |
+ int i; |
|
62 |
+ for (i = 0; i<no_options; i++){ |
|
63 |
+ if (strcmp(opt_name, opt_list[i].name) == 0){ |
|
64 |
+ return i; |
|
65 |
+ } |
|
66 |
+ } |
|
67 |
+ return -1; |
|
68 |
+} |
|
69 |
+ |
|
70 |
+ |
|
71 |
+/** |
|
72 |
+ * Fills special structure with params from src string |
|
73 |
+ * |
|
74 |
+ * @param int_list string of type {INT_VAL [, INT_VAL]*} |
|
75 |
+ * @param opts destination option_description variable |
|
76 |
+ * |
|
77 |
+ * @return number of integers in int_list, on success |
|
78 |
+ * ERROR_IN_PARSING, on error |
|
79 |
+ */ |
|
80 |
+int parse_int_list(char *int_list, option_description* opts){ |
|
81 |
+ char *pch, *endptr; |
|
82 |
+ long val; |
|
83 |
+ |
|
84 |
+ pch = strtok (int_list,", \t"); |
|
85 |
+ |
|
86 |
+ while ( pch != NULL ) |
|
87 |
+ { |
|
88 |
+ LM_DBG("Parsing [%s] \n", pch); |
|
89 |
+ if ( INT_LIST_MAX_SIZE == opts->no_elems){ |
|
90 |
+ LM_ERR("INT LIST exceeds max allowed size of: %d \n", INT_LIST_MAX_SIZE); |
|
91 |
+ return ERROR_IN_PARSING; |
|
92 |
+ } |
|
93 |
+ |
|
94 |
+ endptr = NULL; |
|
95 |
+ val = strtol(pch, &endptr, 10); |
|
96 |
+ |
|
97 |
+ if ( val < 0 || val> INT_MAX){ |
|
98 |
+ LM_ERR("Parsed value is out of bounds \n"); |
|
99 |
+ return ERROR_IN_PARSING; |
|
100 |
+ } |
|
101 |
+ |
|
102 |
+ if (*endptr != '\0'){ |
|
103 |
+ LM_ERR("Parsed value is not integer \n"); |
|
104 |
+ return ERROR_IN_PARSING; |
|
105 |
+ } |
|
106 |
+ |
|
107 |
+ opts->value.int_list[opts->no_elems] = (int) val; |
|
108 |
+ opts->no_elems ++; |
|
109 |
+ pch = strtok (NULL, ", \t"); |
|
110 |
+ } |
|
111 |
+ |
|
112 |
+ if ( 0 == opts->no_elems ){ |
|
113 |
+ LM_ERR("The number of int elements cannot be 0 \n"); |
|
114 |
+ return ERROR_IN_PARSING; |
|
115 |
+ } |
|
116 |
+ return opts->no_elems; |
|
117 |
+} |
|
118 |
+ |
|
119 |
+/** |
|
120 |
+ * Tries to parse right value string into an option |
|
121 |
+ * |
|
122 |
+ * @param src str source |
|
123 |
+ * @param opt the option to be filled |
|
124 |
+ * |
|
125 |
+ * @return SUCCESSFUL_PARSING, ERROR_IN_PARSING |
|
126 |
+ */ |
|
127 |
+int parse_rv_option(str src, option_description* opt){ |
|
128 |
+ long l_val; |
|
129 |
+ double d_val; |
|
130 |
+ char* endptr; |
|
131 |
+ int i, ret = ERROR_IN_PARSING; |
|
132 |
+ |
|
133 |
+ switch (opt->type) |
|
134 |
+ { |
|
135 |
+ case CFG_INT: |
|
136 |
+ l_val = strtol(src.s, &endptr, 10); |
|
137 |
+ |
|
138 |
+ if (errno == ERANGE && (l_val == LONG_MAX || l_val == LONG_MIN)) { |
|
139 |
+ LM_ERR("Conversion error for %s\n", src.s); |
|
140 |
+ }else |
|
141 |
+ if (*endptr != '\0'){ |
|
142 |
+ LM_ERR("Value is not integer \n"); |
|
143 |
+ }else |
|
144 |
+ if ( l_val < 0 || l_val> INT_MAX){ |
|
145 |
+ LM_ERR("The number is out of bounds \n"); |
|
146 |
+ } |
|
147 |
+ else{// successful rv conversion |
|
148 |
+ opt->value.int_data = l_val; |
|
149 |
+ LM_DBG("Key=<%s>, value=<%i> \n", opt->name, opt->value.int_data); |
|
150 |
+ ret = SUCCESSFUL_PARSING; |
|
151 |
+ } |
|
152 |
+ break; |
|
153 |
+ case CFG_FLOAT: |
|
154 |
+ d_val = strtod(src.s, &endptr); |
|
155 |
+ |
|
156 |
+ if (errno == ERANGE && (d_val == -HUGE_VAL || d_val == HUGE_VAL)) { |
|
157 |
+ LM_ERR("Conversion error for %s\n", src.s); |
|
158 |
+ }else |
|
159 |
+ if (*endptr != '\0'){ |
|
160 |
+ LM_ERR("Value is not float \n"); |
|
161 |
+ }else |
|
162 |
+ if ( d_val < 0.0 || d_val> FLT_MAX){ |
|
163 |
+ LM_ERR("The number is out of bounds \n"); |
|
164 |
+ }else{ |
|
165 |
+ opt->value.float_data = d_val; |
|
166 |
+ LM_DBG("Key=<%s>, value=<%f> \n", opt->name, opt->value.float_data); |
|
167 |
+ ret = SUCCESSFUL_PARSING; |
|
168 |
+ } |
|
169 |
+ break; |
|
170 |
+ case CFG_STR: |
|
171 |
+ if ((src.s[0] != '"') && (src.s[src.len-1] != '"')){ |
|
172 |
+ LM_ERR("Not a string \n"); |
|
173 |
+ } |
|
174 |
+ else{ |
|
175 |
+ // we now expect a string with NO " inside |
|
176 |
+ for (i=1; i< src.len-2; i++) |
|
177 |
+ if (src.s[i] == '"') { |
|
178 |
+ LM_ERR("Not a string \n"); |
|
179 |
+ return ERROR_IN_PARSING; |
|
180 |
+ } |
|
181 |
+ strcpy( opt->value.string_data.s, src.s); |
|
182 |
+ opt->value.string_data.len = src.len; |
|
183 |
+ LM_DBG("String Key=<%s>, value=<%s> \n", opt->name, opt->value.string_data.s); |
|
184 |
+ ret = SUCCESSFUL_PARSING; |
|
185 |
+ } |
|
186 |
+ break; |
|
187 |
+ case CFG_INT_LIST: |
|
188 |
+ // int list looks like: lv = {NO1 [,NO]*} |
|
189 |
+ if ((src.len == 2) || ((src.s[0] != '{') && (src.s[src.len-1] != '}'))){ |
|
190 |
+ LM_ERR("Not an int list \n"); |
|
191 |
+ } |
|
192 |
+ else{ |
|
193 |
+ src.s[src.len-1]='\0';src.s++; src.len = src.len-2; |
|
194 |
+ //parse a list of comma separated integers |
|
195 |
+ if ( parse_int_list(src.s, opt) != ERROR_IN_PARSING ){ |
|
196 |
+ // dbg printing of parsed values |
|
197 |
+ LM_DBG("The number of elements in int_list: %d \n", opt->no_elems); |
|
198 |
+ for ( i =0; i< opt->no_elems; i++ ){ |
|
199 |
+ LM_DBG(" value=<%d> \n", opt->value.int_list[i]); |
|
200 |
+ } |
|
201 |
+ ret = SUCCESSFUL_PARSING; |
|
202 |
+ } |
|
203 |
+ } |
|
204 |
+ break; |
|
205 |
+ default: |
|
206 |
+ break; |
|
207 |
+ } |
|
208 |
+ |
|
209 |
+ opt->visited = VISITED; |
|
210 |
+ return ret; |
|
211 |
+} |
|
212 |
+ |
|
213 |
+/** |
|
214 |
+ * Parses the options part in a file and populates a destination structure. |
|
215 |
+ * The end of the options part should be signaled by end_str string. |
|
216 |
+ * |
|
217 |
+ * @param file pointer to source file |
|
218 |
+ * @param opts destiation option structure to be populated |
|
219 |
+ * @param no_options expected number of options |
|
220 |
+ * @param end_str the delimiter that signals end of options zone |
|
221 |
+ * |
|
222 |
+ * @return SUCCESSFUL_PARSING on success, ERROR_IN_PARSING on error |
|
223 |
+ */ |
|
224 |
+int parse_options(FILE* file, option_description* opts, int no_options, char* end_str){ |
|
225 |
+ str data, lv_str, rv_str; |
|
226 |
+ char *pch, buf[CR_MAX_LINE_SIZE], lv[CR_MAX_LINE_SIZE], rv[CR_MAX_LINE_SIZE]; |
|
227 |
+ int opt_pos, full_line_len, ret; |
|
228 |
+ |
|
229 |
+ ret = ERROR_IN_PARSING; |
|
230 |
+ data.s = buf; |
|
231 |
+ |
|
232 |
+ /* refactor data.s = buf using get_non_blank_line */ |
|
233 |
+ while ( get_non_blank_line( &data, CR_MAX_LINE_SIZE, file, &full_line_len) == 0 ) /* read a line */ |
|
234 |
+ { |
|
235 |
+ LM_DBG("Parsing line: %.*s \n", data.len, data.s); |
|
236 |
+ |
|
237 |
+ /* parsing stops when end_str is reached: e.g: }, target */ |
|
238 |
+ if ( strncmp(data.s, end_str, strlen(end_str)) == 0){ |
|
239 |
+ LM_DBG("End of options list received \n"); |
|
240 |
+ fseek(file, -full_line_len, SEEK_CUR); |
|
241 |
+ ret = SUCCESSFUL_PARSING; |
|
242 |
+ break; |
|
243 |
+ } |
|
244 |
+ |
|
245 |
+ /* Line must be of type lv = rv */ |
|
246 |
+ if ( (pch = strchr(data.s,'=')) == NULL){ |
|
247 |
+ LM_ERR("Parsed line does not contain = delimiter \n"); |
|
248 |
+ break; |
|
249 |
+ } |
|
250 |
+ else{ /* parse lv, rv */ |
|
251 |
+ strncpy(lv, data.s, pch-data.s); lv[pch-data.s]='\0'; |
|
252 |
+ strncpy(rv, pch+1, CR_MAX_LINE_SIZE-1); rv[CR_MAX_LINE_SIZE-1]='\0'; |
|
253 |
+ LM_DBG("lv=%s, rv=%s\n", lv, rv); |
|
254 |
+ lv_str.s=lv; lv_str.len=(int)strlen(lv); trim(&lv_str); lv_str.s[lv_str.len] = '\0'; |
|
255 |
+ rv_str.s=rv; rv_str.len=(int)strlen(rv); trim(&rv_str); rv_str.s[rv_str.len] = '\0'; |
|
256 |
+ |
|
257 |
+ if ( (lv_str.len == 0) || (rv_str.len == 0)){ |
|
258 |
+ LM_ERR("String is not lv = rv \n"); |
|
259 |
+ break; |
|
260 |
+ } |
|
261 |
+ |
|
262 |
+ /* Parsing lv */ |
|
263 |
+ if ( (opt_pos = get_option_position(lv_str.s, opts, no_options )) < 0){ |
|
264 |
+ LM_ERR("Unexpected option received: %s \n", lv); |
|
265 |
+ break; |
|
266 |
+ } |
|
267 |
+ |
|
268 |
+ if ( VISITED == opts[opt_pos].visited ){ |
|
269 |
+ LM_ERR("Duplicate option definition %s \n", opts[opt_pos].name); |
|
270 |
+ break; |
|
271 |
+ } |
|
272 |
+ |
|
273 |
+ /* Parsing rv: this is the only case the options parsing continues */ |
|
274 |
+ if ( (rv_str.len != 0 ) && (parse_rv_option(rv_str, &opts[opt_pos]) == ERROR_IN_PARSING )) |
|
275 |
+ { |
|
276 |
+ LM_ERR("Error in parsing rv value \n"); |
|
277 |
+ break; |
|
278 |
+ } |
|
279 |
+ } |
|
280 |
+ } |
|
281 |
+ return ret; |
|
282 |
+} |
|
283 |
+ |
|
284 |
+ |
|
285 |
+/** |
|
286 |
+ * Searches for next content line in the src file |
|
287 |
+ * |
|
288 |
+ * @param data the destination trimmed non blank line |
|
289 |
+ * @param size maximum accepted line length |
|
290 |
+ * @param file source file |
|
291 |
+ * @param p_full_len initial lenght of contents line |
|
292 |
+ * |
|
293 |
+ * @return 0 on success, -1 on error, 1 on EOF |
|
294 |
+ */ |
|
295 |
+int get_non_blank_line(str* line, int size, FILE* file, int* pFull_len ){ |
|
296 |
+ char* buf = line->s; |
|
297 |
+ |
|
298 |
+ while ( line->s = buf, fgets( line->s, size, file) != NULL ) /* read a line */ |
|
299 |
+ { |
|
300 |
+ *pFull_len = line->len = strlen(line->s); |
|
301 |
+ LM_DBG("line is %s ", line->s); |
|
302 |
+ /* missing newline indicates the line length was too big */ |
|
303 |
+ if ( line->s[line->len-1] != '\n' ){ |
|
304 |
+ LM_ERR("Unaccepted line length \n"); |
|
305 |
+ return -1; |
|
306 |
+ } |
|
307 |
+ trim(line); |
|
308 |
+ if( line->len != 0 ){ /* we have a non blank line */ |
|
309 |
+ line->s[line->len] = '\0'; /* just mark end of string*/ |
|
310 |
+ return 0; |
|
311 |
+ } |
|
312 |
+ } |
|
313 |
+ //EOF |
|
314 |
+ return 1; |
|
315 |
+} |
|
316 |
+ |
|
317 |
+ |
|
318 |
+/** |
|
319 |
+ * Parses the header of structure part in the source file and retrieves name. |
|
320 |
+ * |
|
321 |
+ * @param file pointer to source file |
|
322 |
+ * @param expected_struct_type name of expected structure |
|
323 |
+ * @param struct_name the parsed name of the structure. |
|
324 |
+ * |
|
325 |
+ * @return SUCCESSFUL_PARSING, EOF_REACHED, ERROR_IN_PARSING |
|
326 |
+ */ |
|
327 |
+int parse_struct_header(FILE* file, char* expected_struct_type, str* struct_name){ |
|
328 |
+ str data; |
|
329 |
+ char buf[CR_MAX_LINE_SIZE], name[CR_MAX_LINE_SIZE]; |
|
330 |
+ char str2[CR_MAX_LINE_SIZE], format[CR_MAX_LINE_SIZE]; |
|
331 |
+ int no_toks, full_line_len, ret; |
|
332 |
+ |
|
333 |
+ ret = ERROR_IN_PARSING; |
|
334 |
+ |
|
335 |
+ data.s = buf; |
|
336 |
+ if( get_non_blank_line( &data, CR_MAX_LINE_SIZE, file, &full_line_len) == 1 ) {/* read a line */ |
|
337 |
+ LM_DBG("Graceful exit out of parse struct \n"); |
|
338 |
+ return EOF_REACHED; |
|
339 |
+ } |
|
340 |
+ |
|
341 |
+ snprintf(format, CR_MAX_LINE_SIZE-1, " %s %%s %%s %%*s", expected_struct_type); |
|
342 |
+ no_toks = sscanf(data.s, format, name, str2); |
|
343 |
+ LM_DBG("no_tok=<%d>, name=<%s> , delim=<%s>\n", no_toks, name, str2); |
|
344 |
+ |
|
345 |
+ switch (no_toks) { |
|
346 |
+ /* With 1 token parsed, correct is: "domain_name" OR "domain_name{" */ |
|
347 |
+ case 1: |
|
348 |
+ if ( name[strlen(name)-1] == '{' ) { |
|
349 |
+ if (strlen(name) > 1) { |
|
350 |
+ name[strlen(name)-1]='\0'; |
|
351 |
+ ret = SUCCESSFUL_PARSING; |
|
352 |
+ } |
|
353 |
+ else { |
|
354 |
+ LM_ERR("Domain name seems to be empty \n"); |
|
355 |
+ } |
|
356 |
+ } |
|
357 |
+ else{ /* is the following non blank line a "{" ? */ |
|
358 |
+ str new_line; |
|
359 |
+ char new_line_buf[CR_MAX_LINE_SIZE]; |
|
360 |
+ new_line.s = new_line_buf; |
|
361 |
+ |
|
362 |
+ if ( get_non_blank_line(&new_line, CR_MAX_LINE_SIZE, file, &full_line_len) != 0 ) { |
|
363 |
+ LM_ERR("Unexpected end of file while waiting for { \n"); |
|
364 |
+ } else |
|
365 |
+ if ( strncmp(new_line.s, "{", 1) != 0) { |
|
366 |
+ LM_ERR("Unexpected token while waiting for { \n"); |
|
367 |
+ } |
|
368 |
+ else |
|
369 |
+ ret = SUCCESSFUL_PARSING; |
|
370 |
+ } |
|
371 |
+ break; |
|
372 |
+ /* with 2 tokens parsed, the second must be "{" */ |
|
373 |
+ case 2: |
|
374 |
+ if (( strncmp(str2, "{", 1) != 0)) |
|
375 |
+ LM_ERR("Wrongly formatted line: %s\n", data.s); |
|
376 |
+ else |
|
377 |
+ ret = SUCCESSFUL_PARSING; |
|
378 |
+ break; |
|
379 |
+ default: |
|
380 |
+ LM_ERR("Wrong number of tokens in line: %s\n", data.s); |
|
381 |
+ } |
|
382 |
+ |
|
383 |
+ if ( SUCCESSFUL_PARSING == ret ){ |
|
384 |
+ LM_DBG( "Sucessfully parsed struct %s - <%s> header\n", expected_struct_type, name); |
|
385 |
+ struct_name->len = strlen(name); |
|
386 |
+ memcpy(struct_name->s, name, struct_name->len); |
|
387 |
+ struct_name->s[struct_name->len]='\0'; |
|
388 |
+ } |
|
389 |
+ else |
|
390 |
+ fseek(file, -full_line_len, SEEK_CUR); |
|
391 |
+ |
|
392 |
+ return ret; |
|
393 |
+} |
|
394 |
+ |
|
395 |
+int parse_struct_stop(FILE* file){ |
|
396 |
+ char buf[CR_MAX_LINE_SIZE]; |
|
397 |
+ str data; |
|
398 |
+ int full_line_len; |
|
399 |
+ data.s = buf; |
|
400 |
+ |
|
401 |
+ if ( get_non_blank_line(&data, CR_MAX_LINE_SIZE, file, &full_line_len) == -1 ) { |
|
402 |
+ LM_INFO("EOF received \n"); |
|
403 |
+ return ERROR_IN_PARSING; |
|
404 |
+ } |
|
405 |
+ |
|
406 |
+ if (strcmp(data.s, "}") != 0){ |
|
407 |
+ LM_INFO("Unexpected <%s> while waiting for } \n", data.s); |
|
408 |
+ return ERROR_IN_PARSING; |
|
409 |
+ } |
|
410 |
+ return SUCCESSFUL_PARSING; |
|
411 |
+} |
0 | 412 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,92 @@ |
1 |
+/* |
|
2 |
+ * $Id$ |
|
3 |
+ * |
|
4 |
+ * Copyright (C) 1&1 Internet AG |
|
5 |
+ * |
|
6 |
+ * This file is part of SIP-router, a free SIP server. |
|
7 |
+ * |
|
8 |
+ * SIP-router is free software; you can redistribute it and/or modify |
|
9 |
+ * it under the terms of the GNU General Public License as published by |
|
10 |
+ * the Free Software Foundation; either version 2 of the License, or |
|
11 |
+ * (at your option) any later version |
|
12 |
+ * |
|
13 |
+ * SIP-router is distributed in the hope that it will be useful, |
|
14 |
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
15 |
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
16 |
+ * GNU General Public License for more details. |
|
17 |
+ * |
|
18 |
+ * You should have received a copy of the GNU General Public License |
|
19 |
+ * along with this program; if not, write to the Free Software |
|
20 |
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
21 |
+ */ |
|
22 |
+ |
|
23 |
+/*! |
|
24 |
+ * \file parser_carrierroute.h |
|
25 |
+ * \brief Functions for parsing the config file of cr when using file mode. |
|
26 |
+ * \ingroup carrierroute |
|
27 |
+ * - Module; \ref carrierroute |
|
28 |
+ */ |
|
29 |
+ |
|
30 |
+#ifndef PARSER_CARRIERROUTE_H_ |
|
31 |
+#define PARSER_CARRIERROUTE_H_ |
|
32 |
+ |
|
33 |
+#include <stdio.h> |
|
34 |
+#include <string.h> |
|
35 |
+#include <ctype.h> |
|
36 |
+#include <stdlib.h> |
|
37 |
+#include <limits.h> |
|
38 |
+#include <float.h> |
|
39 |
+#include <math.h> |
|
40 |
+#include <errno.h> |
|
41 |
+#include "../../str.h" |
|
42 |
+#include "../../mem/shm_mem.h" |
|
43 |
+#include "../../mem/mem.h" |
|
44 |
+ |
|
45 |
+#define CR_MAX_LINE_SIZE 256 |
|
46 |
+#define MAX_FIELD_NAME 60 |
|
47 |
+#define INT_LIST_MAX_SIZE 10 |
|
48 |
+ |
|
49 |
+#define NOT_VISITED 0 |
|
50 |
+#define VISITED 1 |
|
51 |
+ |
|
52 |
+#define EXPECTED_END_OF_OPTS 0 |
|
53 |
+#define ERROR_IN_PARSING -1 |
|
54 |
+#define SUCCESSFUL_PARSING 1 |
|
55 |
+#define EOF_REACHED 2 |
|
56 |
+ |
|
57 |
+#define DEFAULT_DOMAIN_NUM 16 |
|
58 |
+#define MAX_DOMAIN_NUM 64 // must be a power of 2 |
|
59 |
+ |
|
60 |
+enum opt_type { CFG_STR=0, CFG_INT, CFG_FLOAT, CFG_INT_LIST, MAX_OPTS}; |
|
61 |
+ |
|
62 |
+union opt_data{ |
|
63 |
+ int int_data; |
|
64 |
+ float float_data; |
|
65 |
+ str string_data; |
|
66 |
+ int int_list[INT_LIST_MAX_SIZE]; |
|
67 |
+}; |
|
68 |
+ |
|
69 |
+typedef struct { |
|
70 |
+ char name[MAX_FIELD_NAME]; |
|
71 |
+ enum opt_type type; |
|
72 |
+ union opt_data value; |
|
73 |
+ int visited; |
|
74 |
+ int no_elems; // TBD: name should suggest int_list_no_elems |
|
75 |
+ char str_buf[CR_MAX_LINE_SIZE]; |
|
76 |
+} option_description; |
|
77 |
+ |
|
78 |
+int get_non_blank_line(str* data, int size, FILE* file, int* full_line_len); |
|
79 |
+ |
|
80 |
+int get_option_position(const char* opt_name, const option_description* opt_list, int no_options); |
|
81 |
+ |
|
82 |
+int parse_options(FILE* file, option_description* opts, int no_options, char* end_str); |
|
83 |
+ |
|
84 |
+int parse_struct_header(FILE* file, char* expected_struct_type, str* struct_name); |
|
85 |
+ |
|
86 |
+int next_token_is_eof(FILE* file); |
|
87 |
+ |
|
88 |
+int next_token_is_struct_stop(FILE* file); |
|
89 |
+ |
|
90 |
+int parse_struct_stop(FILE* file); |
|
91 |
+ |
|
92 |
+#endif /* PARSER_CARRIERROUTE_H_ */ |