Mercurial > hg > freeDiameter
comparison extensions/rt_ereg/rtereg_conf.y @ 1338:f1b65381c1e7
rt_ereg: Support config reload. Support grouped AVPs. Support multiple separate AVPs.
Written for Effortel Technologies SA, published with their consent.
author | Thomas Klausner <tk@giga.or.at> |
---|---|
date | Tue, 09 Apr 2019 15:48:45 +0200 |
parents | 1af09cc156d6 |
children | fedc9eea70bc |
comparison
equal
deleted
inserted
replaced
1337:d66f60e29b22 | 1338:f1b65381c1e7 |
---|---|
35 | 35 |
36 /* Yacc extension's configuration parser. | 36 /* Yacc extension's configuration parser. |
37 */ | 37 */ |
38 | 38 |
39 /* For development only : */ | 39 /* For development only : */ |
40 %debug | 40 %debug |
41 %error-verbose | 41 %error-verbose |
42 | 42 |
43 /* The parser receives the configuration file filename as parameter */ | 43 /* The parser receives the configuration file filename as parameter */ |
44 %parse-param {char * conffile} | 44 %parse-param {char * conffile} |
45 | 45 |
46 /* Keep track of location */ | 46 /* Keep track of location */ |
47 %locations | 47 %locations |
48 %pure-parser | 48 %pure-parser |
49 | 49 |
50 %{ | 50 %{ |
51 #include "rtereg.h" | 51 #include "rtereg.h" |
52 #include "rtereg_conf.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */ | 52 #include "rtereg_conf.tab.h" /* bison is not smart enough to define the YYLTYPE before including this code, so... */ |
53 | 53 |
54 /* Forward declaration */ | 54 /* Forward declaration */ |
55 int yyparse(char * conffile); | 55 int yyparse(char * conffile); |
56 void rtereg_confrestart(FILE *input_file); | |
56 | 57 |
57 /* Parse the configuration file */ | 58 /* Parse the configuration file */ |
58 int rtereg_conf_handle(char * conffile) | 59 int rtereg_conf_handle(char * conffile) |
59 { | 60 { |
60 extern FILE * rtereg_confin; | 61 extern FILE * rtereg_confin; |
61 int ret; | 62 int ret; |
62 | 63 |
63 TRACE_ENTRY("%p", conffile); | 64 TRACE_ENTRY("%p", conffile); |
64 | 65 |
65 TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile); | 66 TRACE_DEBUG (FULL, "Parsing configuration file: %s...", conffile); |
66 | 67 |
67 rtereg_confin = fopen(conffile, "r"); | 68 rtereg_confin = fopen(conffile, "r"); |
68 if (rtereg_confin == NULL) { | 69 if (rtereg_confin == NULL) { |
69 ret = errno; | 70 ret = errno; |
70 fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret)); | 71 fd_log_debug("Unable to open extension configuration file %s for reading: %s", conffile, strerror(ret)); |
71 TRACE_DEBUG (INFO, "Error occurred, message logged -- configuration file."); | 72 TRACE_DEBUG (INFO, "rt_ereg: error occurred, message logged -- configuration file."); |
72 return ret; | 73 return ret; |
73 } | 74 } |
74 | 75 |
76 rtereg_confrestart(rtereg_confin); | |
75 ret = yyparse(conffile); | 77 ret = yyparse(conffile); |
76 | 78 |
77 fclose(rtereg_confin); | 79 fclose(rtereg_confin); |
78 | 80 |
81 if (rtereg_conf[rtereg_conf_size-1].finished == 0) { | |
82 TRACE_DEBUG(INFO, "rt_ereg: configuration invalid, AVP ended without OCTETSTRING AVP"); | |
83 return EINVAL; | |
84 } | |
85 | |
79 if (ret != 0) { | 86 if (ret != 0) { |
80 TRACE_DEBUG (INFO, "Unable to parse the configuration file."); | 87 TRACE_DEBUG(INFO, "rt_ereg: unable to parse the configuration file."); |
81 return EINVAL; | 88 return EINVAL; |
82 } else { | 89 } else { |
83 TRACE_DEBUG(FULL, "[rt-ereg] Added %d rules successfully.", rtereg_conf.rules_nb); | 90 int i, sum = 0; |
84 } | 91 for (i=0; i<rtereg_conf_size; i++) { |
85 | 92 sum += rtereg_conf[i].rules_nb; |
93 } | |
94 TRACE_DEBUG(FULL, "[rt-ereg] Added %d rules successfully.", sum); | |
95 } | |
96 | |
97 return 0; | |
98 } | |
99 | |
100 int avp_add(const char *name) | |
101 { | |
102 void *ret; | |
103 int level; | |
104 | |
105 if (rtereg_conf[rtereg_conf_size-1].finished) { | |
106 if ((ret = realloc(rtereg_conf, sizeof(*rtereg_conf)*(rtereg_conf_size+1))) == NULL) { | |
107 TRACE_DEBUG(INFO, "rt_ereg: realloc failed"); | |
108 return -1; | |
109 } | |
110 rtereg_conf_size++; | |
111 rtereg_conf = ret; | |
112 memset(&rtereg_conf[rtereg_conf_size-1], 0, sizeof(*rtereg_conf)); | |
113 TRACE_DEBUG(INFO, "rt_ereg: New AVP group found starting with %s", name); | |
114 } | |
115 level = rtereg_conf[rtereg_conf_size-1].level + 1; | |
116 | |
117 if ((ret = realloc(rtereg_conf[rtereg_conf_size-1].avps, sizeof(*rtereg_conf[rtereg_conf_size-1].avps)*level)) == NULL) { | |
118 TRACE_DEBUG(INFO, "rt_ereg: realloc failed"); | |
119 return -1; | |
120 } | |
121 rtereg_conf[rtereg_conf_size-1].avps = ret; | |
122 | |
123 CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, name, &rtereg_conf[rtereg_conf_size-1].avps[level-1], ENOENT ), | |
124 { | |
125 TRACE_DEBUG(INFO, "rt_ereg: Unable to find '%s' AVP in the loaded dictionaries.", name); | |
126 return -1; | |
127 } ); | |
128 | |
129 /* Now check the type */ | |
130 { | |
131 struct dict_avp_data data; | |
132 CHECK_FCT( fd_dict_getval( rtereg_conf[rtereg_conf_size-1].avps[level-1], &data) ); | |
133 if (data.avp_basetype == AVP_TYPE_OCTETSTRING) { | |
134 rtereg_conf[rtereg_conf_size-1].finished = 1; | |
135 } else if (data.avp_basetype != AVP_TYPE_GROUPED) { | |
136 TRACE_DEBUG(INFO, "rt_ereg: '%s' AVP is not an OCTETSTRING nor GROUPED AVP (%d).", name, data.avp_basetype); | |
137 return -1; | |
138 } | |
139 } | |
140 rtereg_conf[rtereg_conf_size-1].level = level; | |
86 return 0; | 141 return 0; |
87 } | 142 } |
88 | 143 |
89 /* The Lex parser prototype */ | 144 /* The Lex parser prototype */ |
90 int rtereg_conflex(YYSTYPE *lvalp, YYLTYPE *llocp); | 145 int rtereg_conflex(YYSTYPE *lvalp, YYLTYPE *llocp); |
91 | 146 |
92 /* Function to report the errors */ | 147 /* Function to report the errors */ |
93 void yyerror (YYLTYPE *ploc, char * conffile, char const *s) | 148 void yyerror (YYLTYPE *ploc, char * conffile, char const *s) |
94 { | 149 { |
95 TRACE_DEBUG(INFO, "Error in configuration parsing"); | 150 TRACE_DEBUG(INFO, "rt_ereg: error in configuration parsing"); |
96 | 151 |
97 if (ploc->first_line != ploc->last_line) | 152 if (ploc->first_line != ploc->last_line) |
98 fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); | 153 fd_log_debug("%s:%d.%d-%d.%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_line, ploc->last_column, s); |
99 else if (ploc->first_column != ploc->last_column) | 154 else if (ploc->first_column != ploc->last_column) |
100 fd_log_debug("%s:%d.%d-%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s); | 155 fd_log_debug("%s:%d.%d-%d : %s", conffile, ploc->first_line, ploc->first_column, ploc->last_column, s); |
101 else | 156 else |
123 | 178 |
124 /* -------------------------------------- */ | 179 /* -------------------------------------- */ |
125 %% | 180 %% |
126 | 181 |
127 /* The grammar definition */ | 182 /* The grammar definition */ |
128 conffile: rules avp rules | 183 conffile: avp rules |
129 ; | 184 | conffile avp rules |
130 | 185 ; |
186 | |
131 /* a server entry */ | 187 /* a server entry */ |
132 avp: AVP '=' QSTRING ';' | 188 avp: AVP '=' avp_part ';' |
133 { | 189 ; |
134 if (rtereg_conf.avp != NULL) { | 190 |
135 yyerror(&yylloc, conffile, "Only one AVP can be specified"); | 191 avp_part: avp_part ':' QSTRING { if (avp_add($3) < 0) { YYERROR; } } |
136 YYERROR; | 192 | QSTRING { if (avp_add($1) < 0) { YYERROR; } } |
137 } | 193 ; |
138 | 194 |
139 CHECK_FCT_DO( fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, $3, &rtereg_conf.avp, ENOENT ), | |
140 { | |
141 TRACE_DEBUG(INFO, "Unable to find '%s' AVP in the loaded dictionaries.", $3); | |
142 yyerror (&yylloc, conffile, "Invalid AVP value."); | |
143 YYERROR; | |
144 } ); | |
145 | |
146 /* Now check the type */ | |
147 { | |
148 struct dict_avp_data data; | |
149 CHECK_FCT( fd_dict_getval( rtereg_conf.avp, &data) ); | |
150 CHECK_PARAMS_DO (data.avp_basetype == AVP_TYPE_OCTETSTRING, | |
151 { | |
152 TRACE_DEBUG(INFO, "'%s' AVP in not an OCTETSTRING AVP (%d).", $3, data.avp_basetype); | |
153 yyerror (&yylloc, conffile, "AVP in not an OCTETSTRING type."); | |
154 YYERROR; | |
155 } ); | |
156 } | |
157 } | |
158 ; | |
159 | |
160 rules: /* empty OK */ | 195 rules: /* empty OK */ |
161 | rules rule | 196 | rules rule |
162 ; | 197 ; |
163 | 198 |
164 rule: QSTRING ':' QSTRING '+' '=' INTEGER ';' | 199 rule: QSTRING ':' QSTRING '+' '=' INTEGER ';' |
165 { | 200 { |
166 struct rtereg_rule * new; | 201 struct rtereg_rule * new; |
167 int err; | 202 int err; |
168 | 203 |
169 /* Add new rule in the array */ | 204 /* Add new rule in the array */ |
170 rtereg_conf.rules_nb += 1; | 205 rtereg_conf[rtereg_conf_size-1].rules_nb += 1; |
171 CHECK_MALLOC_DO(rtereg_conf.rules = realloc(rtereg_conf.rules, rtereg_conf.rules_nb * sizeof(struct rtereg_rule)), | 206 CHECK_MALLOC_DO(rtereg_conf[rtereg_conf_size-1].rules = realloc(rtereg_conf[rtereg_conf_size-1].rules, rtereg_conf[rtereg_conf_size-1].rules_nb * sizeof(struct rtereg_rule)), |
172 { | 207 { |
173 yyerror (&yylloc, conffile, "Not enough memory to store the configuration..."); | 208 yyerror (&yylloc, conffile, "Not enough memory to store the configuration..."); |
174 YYERROR; | 209 YYERROR; |
175 } ); | 210 } ); |
176 | 211 |
177 new = &rtereg_conf.rules[rtereg_conf.rules_nb - 1]; | 212 new = &rtereg_conf[rtereg_conf_size-1].rules[rtereg_conf[rtereg_conf_size-1].rules_nb - 1]; |
178 | 213 |
179 new->pattern = $1; | 214 new->pattern = $1; |
180 new->server = $3; | 215 new->server = $3; |
181 new->score = $6; | 216 new->score = $6; |
182 | 217 |
183 /* Attempt to compile the regex */ | 218 /* Attempt to compile the regex */ |
184 CHECK_FCT_DO( err=regcomp(&new->preg, new->pattern, REG_EXTENDED | REG_NOSUB), | 219 CHECK_FCT_DO( err=regcomp(&new->preg, new->pattern, REG_EXTENDED | REG_NOSUB), |
185 { | 220 { |
186 char * buf; | 221 char * buf; |
187 size_t bl; | 222 size_t bl; |
188 | 223 |
189 /* Error while compiling the regex */ | 224 /* Error while compiling the regex */ |
190 TRACE_DEBUG(INFO, "Error while compiling the regular expression '%s':", new->pattern); | 225 TRACE_DEBUG(INFO, "rt_ereg: error while compiling the regular expression '%s':", new->pattern); |
191 | 226 |
192 /* Get the error message size */ | 227 /* Get the error message size */ |
193 bl = regerror(err, &new->preg, NULL, 0); | 228 bl = regerror(err, &new->preg, NULL, 0); |
194 | 229 |
195 /* Alloc the buffer for error message */ | 230 /* Alloc the buffer for error message */ |
196 CHECK_MALLOC( buf = malloc(bl) ); | 231 CHECK_MALLOC( buf = malloc(bl) ); |
197 | 232 |
198 /* Get the error message content */ | 233 /* Get the error message content */ |
199 regerror(err, &new->preg, buf, bl); | 234 regerror(err, &new->preg, buf, bl); |
200 TRACE_DEBUG(INFO, "\t%s", buf); | 235 TRACE_DEBUG(INFO, "\t%s", buf); |
201 | 236 |
202 /* Free the buffer, return the error */ | 237 /* Free the buffer, return the error */ |
203 free(buf); | 238 free(buf); |
204 | 239 |
205 yyerror (&yylloc, conffile, "Invalid regular expression."); | 240 yyerror (&yylloc, conffile, "Invalid regular expression."); |
206 YYERROR; | 241 YYERROR; |
207 } ); | 242 } ); |
208 } | 243 } |
209 ; | 244 ; |