comparison extensions/rt_rewrite/rt_rewrite_conf.y @ 1341:b0401251d8c0

rt_rewrite: new extension This extension allows rewriting messages: putting data from one AVP into another, or removing AVPs altogether. Written for Effortel Technologies SA and published with their consent.
author Thomas Klausner <tk@giga.or.at>
date Tue, 09 Apr 2019 16:01:29 +0200
parents
children edfb2b662b91
comparison
equal deleted inserted replaced
1340:daf61e573fee 1341:b0401251d8c0
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) {
110 fd_log_notice("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]);
111 }
112 return;
113 }
114
115 static void compare_avp_types(struct avp_match *start)
116 {
117 struct avp_match *iter;
118 for (iter=start; iter != NULL; iter=iter->next) {
119 compare_avp_types(iter->children);
120 if (iter->target) {
121 struct avp_target *final;
122 final = iter->target;
123 while (final->child) {
124 final = final->child;
125 }
126 compare_avp_type(iter->name, final->name);
127 }
128 }
129 return;
130 }
131
132 static void dump_config(struct avp_match *start, char *prefix)
133 {
134 char *new_prefix = NULL;
135 struct avp_match *iter;
136 for (iter=start; iter != NULL; iter=iter->next) {
137 if (asprintf(&new_prefix, "%s/%s", prefix, iter->name) == -1) {
138 fd_log_error("rt_rewrite: dump_config: asprintf failed: %s", strerror(errno));
139 return;
140 }
141 dump_config(iter->children, new_prefix);
142 if (iter->target) {
143 print_target(iter->target, new_prefix);
144 }
145 if (iter->drop) {
146 fd_log_debug("%s -> DROP", new_prefix);
147 }
148 free(new_prefix);
149 new_prefix = NULL;
150 }
151 return;
152 }
153
154 /* Parse the configuration file */
155 int rt_rewrite_conf_handle(char * conffile)
156 {
157 extern FILE * rt_rewrite_confin;
158 int ret;
159 char *top;
160
161 TRACE_ENTRY("%p", conffile);
162
163 TRACE_DEBUG (FULL, "Parsing configuration file: '%s'", conffile);
164
165 /* to match other entries */
166 if ((top=strdup("TOP")) == NULL) {
167 fd_log_error("strdup error: %s", strerror(errno));
168 return EINVAL;
169 }
170 if ((avp_match_start=avp_match_new(top)) == NULL) {
171 fd_log_error("malloc error: %s", strerror(errno));
172 free(top);
173 return EINVAL;
174 }
175 rt_rewrite_confin = fopen(conffile, "r");
176 if (rt_rewrite_confin == NULL) {
177 ret = errno;
178 fd_log_debug("Unable to open extension configuration file '%s' for reading: %s", conffile, strerror(ret));
179 TRACE_DEBUG (INFO, "rt_rewrite: error occurred, message logged -- configuration file.");
180 avp_match_free(avp_match_start);
181 avp_match_start = NULL;
182 return ret;
183 }
184
185 rt_rewrite_confrestart(rt_rewrite_confin);
186 ret = yyparse(conffile);
187
188 fclose(rt_rewrite_confin);
189
190 if (ret != 0) {
191 TRACE_DEBUG(INFO, "rt_rewrite: unable to parse the configuration file.");
192 avp_match_free(avp_match_start);
193 avp_match_start = NULL;
194 return EINVAL;
195 }
196
197 compare_avp_types(avp_match_start);
198 dump_config(avp_match_start, "");
199
200 return 0;
201 }
202
203 static int verify_avp(const char *name)
204 {
205 struct dict_object *model;
206 struct dict_avp_data dictdata;
207
208 if (fd_dict_search(fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_ALL_VENDORS, name, &model, ENOENT) != 0) {
209 fd_log_error("Unable to find '%s' AVP in the loaded dictionaries", name);
210 return -1;
211 }
212 fd_dict_getval(model, &dictdata);
213 if (dictdata.avp_basetype == AVP_TYPE_GROUPED) {
214 return 1;
215 }
216 return 0;
217 }
218
219 static struct avp_match *avp_match_new(char *name) {
220 struct avp_match *ret;
221
222 if ((ret=malloc(sizeof(*ret))) == NULL) {
223 fd_log_error("malloc error");
224 return NULL;
225 }
226 ret->name = name;
227 ret->next = NULL;
228 ret->children = NULL;
229 ret->target = NULL;
230 ret->drop = 0;
231 return ret;
232 }
233
234 static void avp_target_free(struct avp_target *target) {
235 struct avp_target *iter;
236
237 for (iter=target; iter != NULL; ) {
238 struct avp_target *next;
239 free(iter->name);
240 next = iter->child;
241 free(iter);
242 iter = next;
243 }
244 }
245
246 void avp_match_free(struct avp_match *match) {
247 struct avp_match *iter;
248
249 for (iter=match; iter != NULL; ) {
250 struct avp_match *next;
251 free(iter->name);
252 next = iter->next;
253 avp_match_free(iter->children);
254 avp_target_free(iter->target);
255 free(iter);
256 iter = next;
257 }
258 }
259
260 static struct avp_target *target_new(char *name) {
261 struct avp_target *ret;
262
263 if ((ret=malloc(sizeof(*ret))) == NULL) {
264 fd_log_error("malloc error");
265 return NULL;
266 }
267 ret->name = name;
268 ret->child = NULL;
269 return ret;
270 }
271
272 static struct avp_match *add_avp_next_to(char *name, struct avp_match *target)
273 {
274 struct avp_match *iter, *prev;
275
276 if (target == NULL) {
277 return avp_match_new(name);
278 }
279
280 for (prev=iter=target; iter != NULL; iter=iter->next) {
281 if (strcmp(iter->name, name) == 0) {
282 return iter;
283 }
284 prev = iter;
285 }
286 prev->next = avp_match_new(name);
287 return prev->next;
288 }
289
290 static int add(struct avp_match **target, char *name)
291 {
292 struct avp_match *temp;
293 if (verify_avp(name) < 0) {
294 return -1;
295 }
296 temp = add_avp_next_to(name, (*target)->children);
297 if ((*target)->children == NULL) {
298 (*target)->children = temp;
299 }
300 *target = temp;
301 return 0;
302 }
303
304 /* build tree for source */
305 static int source_add(char *name)
306 {
307 if (source_target == NULL) {
308 source_target = avp_match_start;
309 }
310 return add(&source_target, name);
311 }
312
313 /* build tree for destination */
314 static int dest_add(char *name)
315 {
316 struct avp_target *temp;
317
318 if (verify_avp(name) < 0) {
319 return -1;
320 }
321 if ((temp=target_new(name)) == NULL) {
322 dest_target = NULL;
323 source_target = NULL;
324 return -1;
325 }
326 if (dest_target == NULL) {
327 dest_target = temp;
328 source_target->target = dest_target;
329 source_target = NULL;
330 return 0;
331 }
332 dest_target->child = temp;
333 dest_target = temp;
334 return 0;
335 }
336
337 static void dest_finish(void)
338 {
339 dest_target = NULL;
340 }
341
342 /* same as source_add, but for drop */
343 static int drop_add(char *name)
344 {
345 if (drop_target == NULL) {
346 drop_target = avp_match_start;
347 }
348 return add(&drop_target, name);
349 }
350
351 /* mark as to-drop */
352 static void drop_finish(void)
353 {
354 drop_target->drop = 1;
355 drop_target = NULL;
356 }
357
358 /* The Lex parser prototype */
359 int rt_rewrite_conflex(YYSTYPE *lvalp, YYLTYPE *llocp);
360
361 /* Function to report the errors */
362 void yyerror (YYLTYPE *ploc, char * conffile, char const *s)
363 {
364 TRACE_DEBUG(INFO, "rt_rewrite: error in configuration parsing");
365
366 if (ploc->first_line != ploc->last_line)
367 fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s);
368 else if (ploc->first_column != ploc->last_column)
369 fd_log_debug("%s:%d.%d-%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s);
370 else
371 fd_log_debug("%s:%d.%d : %s", conffile, ploc->first_line, ploc->first_column, s);
372 }
373
374 %}
375
376 /* Values returned by lex for token */
377 %union {
378 char *string; /* The string is allocated by strdup in lex.*/
379 }
380
381 /* In case of error in the lexical analysis */
382 %token LEX_ERROR
383
384 /* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */
385 %token <string> QSTRING
386
387 /* Tokens */
388 %token MAP
389 %token DROP
390
391
392 /* -------------------------------------- */
393 %%
394
395 /* The grammar definition */
396 rules: /* empty ok */
397 | rules map
398 | rules drop
399 ;
400
401 /* source -> destination mapping */
402 map: MAP '=' source_part '>' dest_part { dest_finish(); }
403 ';'
404 ;
405
406 source_part: source_part ':' QSTRING { if (source_add($3) < 0) { YYERROR; } }
407 | QSTRING { if (source_add($1) < 0) { YYERROR; } }
408 ;
409
410 dest_part: dest_part ':' QSTRING { if (dest_add($3) < 0) { YYERROR; } }
411 | QSTRING { if (dest_add($1) < 0) { YYERROR; } }
412 ;
413
414 /* for dropping an AVP */
415 drop: DROP '=' drop_part { drop_finish(); }
416 ';'
417 ;
418
419 drop_part: drop_part ':' QSTRING { if (drop_add($3) < 0) { YYERROR; } }
420 | QSTRING { if (drop_add($1) < 0) { YYERROR; } }
421 ;
"Welcome to our mercurial repository"