Mercurial > hg > freeDiameter
annotate extensions/rt_rewrite/rt_rewrite_conf.y @ 1562:6219359a36a9 default tip
Merge latest changes from proposed branch
author | Sebastien Decugis <sdecugis@freediameter.net> |
---|---|
date | Mon, 21 Jun 2021 19:08:18 +0800 |
parents | edfb2b662b91 |
children |
rev | line source |
---|---|
1341 | 1 /********************************************************************************************************* |
2 * Software License Agreement (BSD License) * | |
3 * Author: Thomas Klausner <tk@giga.or.at> * | |
4 * * | |
5 * Copyright (c) 2018, Thomas Klausner * | |
6 * All rights reserved. * | |
7 * * | |
8 * Written under contract by Effortel Technologies SA, http://effortel.com/ * | |
9 * * | |
10 * Redistribution and use of this software in source and binary forms, with or without modification, are * | |
11 * permitted provided that the following conditions are met: * | |
12 * * | |
13 * * Redistributions of source code must retain the above * | |
14 * copyright notice, this list of conditions and the * | |
15 * following disclaimer. * | |
16 * * | |
17 * * Redistributions in binary form must reproduce the above * | |
18 * copyright notice, this list of conditions and the * | |
19 * following disclaimer in the documentation and/or other * | |
20 * materials provided with the distribution. * | |
21 * * | |
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * | |
23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * | |
24 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * | |
25 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * | |
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * | |
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * | |
28 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * | |
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * | |
30 *********************************************************************************************************/ | |
31 | |
32 /* Yacc extension's configuration parser. | |
33 */ | |
34 | |
35 /* For development only : */ | |
36 %debug | |
37 %error-verbose | |
38 | |
39 /* The parser receives the configuration file filename as parameter */ | |
40 %parse-param {char * conffile} | |
41 | |
42 /* Keep track of location */ | |
43 %locations | |
44 %pure-parser | |
45 | |
46 %{ | |
47 #include "rt_rewrite.h" | |
48 #include "rt_rewrite_conf.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */ | |
49 | |
50 /* Forward declaration */ | |
51 int yyparse(char * conffile); | |
52 void rt_rewrite_confrestart(FILE *input_file); | |
53 | |
54 /* copied from libfdproto/dictionary.c because the symbol is not public */ | |
55 static const char * type_base_name[] = { /* must keep in sync with dict_avp_basetype */ | |
56 "Grouped", /* AVP_TYPE_GROUPED */ | |
57 "Octetstring", /* AVP_TYPE_OCTETSTRING */ | |
58 "Integer32", /* AVP_TYPE_INTEGER32 */ | |
59 "Integer64", /* AVP_TYPE_INTEGER64 */ | |
60 "Unsigned32", /* AVP_TYPE_UNSIGNED32 */ | |
61 "Unsigned64", /* AVP_TYPE_UNSIGNED64 */ | |
62 "Float32", /* AVP_TYPE_FLOAT32 */ | |
63 "Float64" /* AVP_TYPE_FLOAT64 */ | |
64 }; | |
65 | |
66 static struct avp_match *avp_match_new(char *name); | |
67 | |
68 static struct avp_match *source_target = NULL, *drop_target = NULL; | |
69 static struct avp_target *dest_target = NULL; | |
70 | |
71 static void print_target(struct avp_target *target, char *prefix) | |
72 { | |
73 char *output = NULL; | |
74 if (asprintf(&output, "%s -> /TOP/%s", prefix, target->name) == -1) { | |
75 fd_log_error("rt_rewrite: print_target: setup: asprintf failed: %s", strerror(errno)); | |
76 return; | |
77 } | |
78 for (target=target->child; target != NULL; target=target->child) { | |
79 char *new_output = NULL; | |
80 if (asprintf(&new_output, "%s/%s", output, target->name) == -1) { | |
81 fd_log_error("rt_rewrite: print_target: asprintf failed: %s", strerror(errno)); | |
82 free(output); | |
83 return; | |
84 } | |
85 free(output); | |
86 output = new_output; | |
87 new_output = NULL; | |
88 } | |
89 fd_log_debug(output); | |
90 free(output); | |
91 return; | |
92 } | |
93 | |
94 static void compare_avp_type(const char *source, const char *dest) | |
95 { | |
96 struct dict_object *model_source, *model_dest; | |
97 struct dict_avp_data dictdata_source, dictdata_dest; | |
98 | |
99 if (fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, source, &model_source, ENOENT) != 0) { | |
100 fd_log_error("Unable to find '%s' AVP in the loaded dictionaries", source); | |
101 return; | |
102 } | |
103 if (fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, dest, &model_dest, ENOENT) != 0) { | |
104 fd_log_error("Unable to find '%s' AVP in the loaded dictionaries", dest); | |
105 return; | |
106 } | |
107 fd_dict_getval(model_source, &dictdata_source); | |
108 fd_dict_getval(model_dest, &dictdata_dest); | |
109 if (dictdata_source.avp_basetype != dictdata_dest.avp_basetype) { | |
1548
edfb2b662b91
rt_rewrite: octetstring object cannot be mapped to any other type
Thomas Klausner <tk@giga.or.at>
parents:
1341
diff
changeset
|
110 if (dictdata_source.avp_basetype == AVP_TYPE_OCTETSTRING) { |
edfb2b662b91
rt_rewrite: octetstring object cannot be mapped to any other type
Thomas Klausner <tk@giga.or.at>
parents:
1341
diff
changeset
|
111 fd_log_error("rt_rewrite: type mismatch: %s (type %s) mapped to %s (type %s): OctetString cannot be mapped to non-OctetString type", source, type_base_name[dictdata_source.avp_basetype], dest, type_base_name[dictdata_dest.avp_basetype]); |
edfb2b662b91
rt_rewrite: octetstring object cannot be mapped to any other type
Thomas Klausner <tk@giga.or.at>
parents:
1341
diff
changeset
|
112 return; |
edfb2b662b91
rt_rewrite: octetstring object cannot be mapped to any other type
Thomas Klausner <tk@giga.or.at>
parents:
1341
diff
changeset
|
113 } |
edfb2b662b91
rt_rewrite: octetstring object cannot be mapped to any other type
Thomas Klausner <tk@giga.or.at>
parents:
1341
diff
changeset
|
114 fd_log_error("rt_rewrite: type mismatch: %s (type %s) mapped to %s (type %s) (continuing anyway)", source, type_base_name[dictdata_source.avp_basetype], dest, type_base_name[dictdata_dest.avp_basetype]); |
1341 | 115 } |
116 return; | |
117 } | |
118 | |
119 static void compare_avp_types(struct avp_match *start) | |
120 { | |
121 struct avp_match *iter; | |
122 for (iter=start; iter != NULL; iter=iter->next) { | |
123 compare_avp_types(iter->children); | |
124 if (iter->target) { | |
125 struct avp_target *final; | |
126 final = iter->target; | |
127 while (final->child) { | |
128 final = final->child; | |
129 } | |
130 compare_avp_type(iter->name, final->name); | |
131 } | |
132 } | |
133 return; | |
134 } | |
135 | |
136 static void dump_config(struct avp_match *start, char *prefix) | |
137 { | |
138 char *new_prefix = NULL; | |
139 struct avp_match *iter; | |
140 for (iter=start; iter != NULL; iter=iter->next) { | |
141 if (asprintf(&new_prefix, "%s/%s", prefix, iter->name) == -1) { | |
142 fd_log_error("rt_rewrite: dump_config: asprintf failed: %s", strerror(errno)); | |
143 return; | |
144 } | |
145 dump_config(iter->children, new_prefix); | |
146 if (iter->target) { | |
147 print_target(iter->target, new_prefix); | |
148 } | |
149 if (iter->drop) { | |
150 fd_log_debug("%s -> DROP", new_prefix); | |
151 } | |
152 free(new_prefix); | |
153 new_prefix = NULL; | |
154 } | |
155 return; | |
156 } | |
157 | |
158 /* Parse the configuration file */ | |
159 int rt_rewrite_conf_handle(char * conffile) | |
160 { | |
161 extern FILE * rt_rewrite_confin; | |
162 int ret; | |
163 char *top; | |
164 | |
165 TRACE_ENTRY("%p", conffile); | |
166 | |
167 TRACE_DEBUG (FULL, "Parsing configuration file: '%s'", conffile); | |
168 | |
169 /* to match other entries */ | |
170 if ((top=strdup("TOP")) == NULL) { | |
171 fd_log_error("strdup error: %s", strerror(errno)); | |
172 return EINVAL; | |
173 } | |
174 if ((avp_match_start=avp_match_new(top)) == NULL) { | |
175 fd_log_error("malloc error: %s", strerror(errno)); | |
176 free(top); | |
177 return EINVAL; | |
178 } | |
179 rt_rewrite_confin = fopen(conffile, "r"); | |
180 if (rt_rewrite_confin == NULL) { | |
181 ret = errno; | |
182 fd_log_debug("Unable to open extension configuration file '%s' for reading: %s", conffile, strerror(ret)); | |
183 TRACE_DEBUG (INFO, "rt_rewrite: error occurred, message logged -- configuration file."); | |
184 avp_match_free(avp_match_start); | |
185 avp_match_start = NULL; | |
186 return ret; | |
187 } | |
188 | |
189 rt_rewrite_confrestart(rt_rewrite_confin); | |
190 ret = yyparse(conffile); | |
191 | |
192 fclose(rt_rewrite_confin); | |
193 | |
194 if (ret != 0) { | |
195 TRACE_DEBUG(INFO, "rt_rewrite: unable to parse the configuration file."); | |
196 avp_match_free(avp_match_start); | |
197 avp_match_start = NULL; | |
198 return EINVAL; | |
199 } | |
200 | |
201 compare_avp_types(avp_match_start); | |
202 dump_config(avp_match_start, ""); | |
203 | |
204 return 0; | |
205 } | |
206 | |
207 static int verify_avp(const char *name) | |
208 { | |
209 struct dict_object *model; | |
210 struct dict_avp_data dictdata; | |
211 | |
212 if (fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, name, &model, ENOENT) != 0) { | |
213 fd_log_error("Unable to find '%s' AVP in the loaded dictionaries", name); | |
214 return -1; | |
215 } | |
216 fd_dict_getval(model, &dictdata); | |
217 if (dictdata.avp_basetype == AVP_TYPE_GROUPED) { | |
218 return 1; | |
219 } | |
220 return 0; | |
221 } | |
222 | |
223 static struct avp_match *avp_match_new(char *name) { | |
224 struct avp_match *ret; | |
225 | |
226 if ((ret=malloc(sizeof(*ret))) == NULL) { | |
227 fd_log_error("malloc error"); | |
228 return NULL; | |
229 } | |
230 ret->name = name; | |
231 ret->next = NULL; | |
232 ret->children = NULL; | |
233 ret->target = NULL; | |
234 ret->drop = 0; | |
235 return ret; | |
236 } | |
237 | |
238 static void avp_target_free(struct avp_target *target) { | |
239 struct avp_target *iter; | |
240 | |
241 for (iter=target; iter != NULL; ) { | |
242 struct avp_target *next; | |
243 free(iter->name); | |
244 next = iter->child; | |
245 free(iter); | |
246 iter = next; | |
247 } | |
248 } | |
249 | |
250 void avp_match_free(struct avp_match *match) { | |
251 struct avp_match *iter; | |
252 | |
253 for (iter=match; iter != NULL; ) { | |
254 struct avp_match *next; | |
255 free(iter->name); | |
256 next = iter->next; | |
257 avp_match_free(iter->children); | |
258 avp_target_free(iter->target); | |
259 free(iter); | |
260 iter = next; | |
261 } | |
262 } | |
263 | |
264 static struct avp_target *target_new(char *name) { | |
265 struct avp_target *ret; | |
266 | |
267 if ((ret=malloc(sizeof(*ret))) == NULL) { | |
268 fd_log_error("malloc error"); | |
269 return NULL; | |
270 } | |
271 ret->name = name; | |
272 ret->child = NULL; | |
273 return ret; | |
274 } | |
275 | |
276 static struct avp_match *add_avp_next_to(char *name, struct avp_match *target) | |
277 { | |
278 struct avp_match *iter, *prev; | |
279 | |
280 if (target == NULL) { | |
281 return avp_match_new(name); | |
282 } | |
283 | |
284 for (prev=iter=target; iter != NULL; iter=iter->next) { | |
285 if (strcmp(iter->name, name) == 0) { | |
286 return iter; | |
287 } | |
288 prev = iter; | |
289 } | |
290 prev->next = avp_match_new(name); | |
291 return prev->next; | |
292 } | |
293 | |
294 static int add(struct avp_match **target, char *name) | |
295 { | |
296 struct avp_match *temp; | |
297 if (verify_avp(name) < 0) { | |
298 return -1; | |
299 } | |
300 temp = add_avp_next_to(name, (*target)->children); | |
301 if ((*target)->children == NULL) { | |
302 (*target)->children = temp; | |
303 } | |
304 *target = temp; | |
305 return 0; | |
306 } | |
307 | |
308 /* build tree for source */ | |
309 static int source_add(char *name) | |
310 { | |
311 if (source_target == NULL) { | |
312 source_target = avp_match_start; | |
313 } | |
314 return add(&source_target, name); | |
315 } | |
316 | |
317 /* build tree for destination */ | |
318 static int dest_add(char *name) | |
319 { | |
320 struct avp_target *temp; | |
321 | |
322 if (verify_avp(name) < 0) { | |
323 return -1; | |
324 } | |
325 if ((temp=target_new(name)) == NULL) { | |
326 dest_target = NULL; | |
327 source_target = NULL; | |
328 return -1; | |
329 } | |
330 if (dest_target == NULL) { | |
331 dest_target = temp; | |
332 source_target->target = dest_target; | |
333 source_target = NULL; | |
334 return 0; | |
335 } | |
336 dest_target->child = temp; | |
337 dest_target = temp; | |
338 return 0; | |
339 } | |
340 | |
341 static void dest_finish(void) | |
342 { | |
343 dest_target = NULL; | |
344 } | |
345 | |
346 /* same as source_add, but for drop */ | |
347 static int drop_add(char *name) | |
348 { | |
349 if (drop_target == NULL) { | |
350 drop_target = avp_match_start; | |
351 } | |
352 return add(&drop_target, name); | |
353 } | |
354 | |
355 /* mark as to-drop */ | |
356 static void drop_finish(void) | |
357 { | |
358 drop_target->drop = 1; | |
359 drop_target = NULL; | |
360 } | |
361 | |
362 /* The Lex parser prototype */ | |
363 int rt_rewrite_conflex(YYSTYPE *lvalp, YYLTYPE *llocp); | |
364 | |
365 /* Function to report the errors */ | |
366 void yyerror (YYLTYPE *ploc, char * conffile, char const *s) | |
367 { | |
368 TRACE_DEBUG(INFO, "rt_rewrite: error in configuration parsing"); | |
369 | |
370 if (ploc->first_line != ploc->last_line) | |
371 fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); | |
372 else if (ploc->first_column != ploc->last_column) | |
373 fd_log_debug("%s:%d.%d-%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s); | |
374 else | |
375 fd_log_debug("%s:%d.%d : %s", conffile, ploc->first_line, ploc->first_column, s); | |
376 } | |
377 | |
378 %} | |
379 | |
380 /* Values returned by lex for token */ | |
381 %union { | |
382 char *string; /* The string is allocated by strdup in lex.*/ | |
383 } | |
384 | |
385 /* In case of error in the lexical analysis */ | |
386 %token LEX_ERROR | |
387 | |
388 /* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */ | |
389 %token <string> QSTRING | |
390 | |
391 /* Tokens */ | |
392 %token MAP | |
393 %token DROP | |
394 | |
395 | |
396 /* -------------------------------------- */ | |
397 %% | |
398 | |
399 /* The grammar definition */ | |
400 rules: /* empty ok */ | |
401 | rules map | |
402 | rules drop | |
403 ; | |
404 | |
405 /* source -> destination mapping */ | |
406 map: MAP '=' source_part '>' dest_part { dest_finish(); } | |
407 ';' | |
408 ; | |
409 | |
410 source_part: source_part ':' QSTRING { if (source_add($3) < 0) { YYERROR; } } | |
411 | QSTRING { if (source_add($1) < 0) { YYERROR; } } | |
412 ; | |
413 | |
414 dest_part: dest_part ':' QSTRING { if (dest_add($3) < 0) { YYERROR; } } | |
415 | QSTRING { if (dest_add($1) < 0) { YYERROR; } } | |
416 ; | |
417 | |
418 /* for dropping an AVP */ | |
419 drop: DROP '=' drop_part { drop_finish(); } | |
420 ';' | |
421 ; | |
422 | |
423 drop_part: drop_part ':' QSTRING { if (drop_add($3) < 0) { YYERROR; } } | |
424 | QSTRING { if (drop_add($1) < 0) { YYERROR; } } | |
425 ; |