comparison libfdcore/messages.c @ 1383:0d71c0b2eed4

Be loud, but don't exit on invalid mandatory AVP in Answer
author Thomas Klausner <tk@giga.or.at>
date Mon, 08 Jul 2019 17:46:51 +0200
parents 10143e09abdf
children b09f1b4c9fad
comparison
equal deleted inserted replaced
1382:f62e18dc4800 1383:0d71c0b2eed4
50 50
51 /* Resolve the dictionary objects */ 51 /* Resolve the dictionary objects */
52 int fd_msg_init(void) 52 int fd_msg_init(void)
53 { 53 {
54 TRACE_ENTRY(""); 54 TRACE_ENTRY("");
55 55
56 /* Initialize the dictionary objects that we may use frequently */ 56 /* Initialize the dictionary objects that we may use frequently */
57 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &dict_avp_SI , ENOENT) ); 57 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Session-Id", &dict_avp_SI , ENOENT) );
58 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) ); 58 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) );
59 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) ); 59 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) );
60 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) ); 60 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) );
61 61
62 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) ); 62 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) );
63 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) ); 63 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) );
64 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) ); 64 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) );
65 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) ); 65 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) );
66 66
67 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) ); 67 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) );
68 68
69 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) ); 69 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) );
70 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) ); 70 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) );
71 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) ); 71 CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) );
72 72
73 73
74 return 0; 74 return 0;
75 } 75 }
76 76
77 /* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */ 77 /* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */
78 int fd_msg_add_origin ( struct msg * msg, int osi ) 78 int fd_msg_add_origin ( struct msg * msg, int osi )
79 { 79 {
80 union avp_value val; 80 union avp_value val;
81 struct avp * avp_OH = NULL; 81 struct avp * avp_OH = NULL;
82 struct avp * avp_OR = NULL; 82 struct avp * avp_OR = NULL;
83 struct avp * avp_OSI = NULL; 83 struct avp * avp_OSI = NULL;
84 84
85 TRACE_ENTRY("%p", msg); 85 TRACE_ENTRY("%p", msg);
86 CHECK_PARAMS( msg ); 86 CHECK_PARAMS( msg );
87 87
88 /* Create the Origin-Host AVP */ 88 /* Create the Origin-Host AVP */
89 CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) ); 89 CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) );
90 90
91 /* Set its value */ 91 /* Set its value */
92 memset(&val, 0, sizeof(val)); 92 memset(&val, 0, sizeof(val));
93 val.os.data = (os0_t)fd_g_config->cnf_diamid; 93 val.os.data = (os0_t)fd_g_config->cnf_diamid;
94 val.os.len = fd_g_config->cnf_diamid_len; 94 val.os.len = fd_g_config->cnf_diamid_len;
95 CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) ); 95 CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) );
96 96
97 /* Add it to the message */ 97 /* Add it to the message */
98 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) ); 98 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) );
99 99
100 100
101 /* Create the Origin-Realm AVP */ 101 /* Create the Origin-Realm AVP */
102 CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) ); 102 CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) );
103 103
104 /* Set its value */ 104 /* Set its value */
105 memset(&val, 0, sizeof(val)); 105 memset(&val, 0, sizeof(val));
106 val.os.data = (os0_t)fd_g_config->cnf_diamrlm; 106 val.os.data = (os0_t)fd_g_config->cnf_diamrlm;
107 val.os.len = fd_g_config->cnf_diamrlm_len; 107 val.os.len = fd_g_config->cnf_diamrlm_len;
108 CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) ); 108 CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) );
109 109
110 /* Add it to the message */ 110 /* Add it to the message */
111 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) ); 111 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) );
112 112
113 if (osi) { 113 if (osi) {
114 /* Create the Origin-State-Id AVP */ 114 /* Create the Origin-State-Id AVP */
115 CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) ); 115 CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) );
116 116
117 /* Set its value */ 117 /* Set its value */
120 CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) ); 120 CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) );
121 121
122 /* Add it to the message */ 122 /* Add it to the message */
123 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) ); 123 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) );
124 } 124 }
125 125
126 return 0; 126 return 0;
127 } 127 }
128 128
129 /* Create a new Session-Id and add at the beginning of the message. */ 129 /* Create a new Session-Id and add at the beginning of the message. */
130 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen ) 130 int fd_msg_new_session( struct msg * msg, os0_t opt, size_t optlen )
132 union avp_value val; 132 union avp_value val;
133 struct avp * avp = NULL; 133 struct avp * avp = NULL;
134 struct session * sess = NULL; 134 struct session * sess = NULL;
135 os0_t sid; 135 os0_t sid;
136 size_t sidlen; 136 size_t sidlen;
137 137
138 TRACE_ENTRY("%p %p %zd", msg, opt, optlen); 138 TRACE_ENTRY("%p %p %zd", msg, opt, optlen);
139 CHECK_PARAMS( msg ); 139 CHECK_PARAMS( msg );
140 140
141 /* Check there is not already a session in the message */ 141 /* Check there is not already a session in the message */
142 CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) ); 142 CHECK_FCT( fd_msg_sess_get(fd_g_config->cnf_dict, msg, &sess, NULL) );
143 CHECK_PARAMS( sess == NULL ); 143 CHECK_PARAMS( sess == NULL );
144 144
145 /* Ok, now create the session */ 145 /* Ok, now create the session */
146 CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) ); 146 CHECK_FCT( fd_sess_new ( &sess, fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len, opt, optlen ) );
147 CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) ); 147 CHECK_FCT( fd_sess_getsid( sess, &sid, &sidlen) );
148 148
149 /* Create an AVP to hold it */ 149 /* Create an AVP to hold it */
150 CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) ); 150 CHECK_FCT( fd_msg_avp_new( dict_avp_SI, 0, &avp ) );
151 151
152 /* Set its value */ 152 /* Set its value */
153 memset(&val, 0, sizeof(val)); 153 memset(&val, 0, sizeof(val));
154 val.os.data = sid; 154 val.os.data = sid;
155 val.os.len = sidlen; 155 val.os.len = sidlen;
156 CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); 156 CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
157 157
158 /* Add it to the message */ 158 /* Add it to the message */
159 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) ); 159 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_FIRST_CHILD, avp ) );
160 160
161 /* Save the session associated with the message */ 161 /* Save the session associated with the message */
162 CHECK_FCT( fd_msg_sess_set( msg, sess) ); 162 CHECK_FCT( fd_msg_sess_set( msg, sess) );
163 163
164 /* Done! */ 164 /* Done! */
165 return 0; 165 return 0;
166 } 166 }
167 167
168 168
175 struct avp * avp_ERH = NULL; 175 struct avp * avp_ERH = NULL;
176 struct avp * avp_FAVP= NULL; 176 struct avp * avp_FAVP= NULL;
177 uint32_t rc_val = 0; 177 uint32_t rc_val = 0;
178 int set_e_bit=0; 178 int set_e_bit=0;
179 int std_err_msg=0; 179 int std_err_msg=0;
180 180
181 TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id); 181 TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id);
182 182
183 CHECK_PARAMS( msg && rescode ); 183 CHECK_PARAMS( msg && rescode );
184 184
185 /* Find the enum value corresponding to the rescode string, this will give the class of error */ 185 /* Find the enum value corresponding to the rescode string, this will give the class of error */
186 { 186 {
187 struct dict_object * enum_obj = NULL; 187 struct dict_object * enum_obj = NULL;
188 struct dict_enumval_request req; 188 struct dict_enumval_request req;
189 memset(&req, 0, sizeof(struct dict_enumval_request)); 189 memset(&req, 0, sizeof(struct dict_enumval_request));
190 190
191 /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */ 191 /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */
192 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); 192 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) );
193 193
194 /* Now search for the value given as parameter */ 194 /* Now search for the value given as parameter */
195 req.search.enum_name = rescode; 195 req.search.enum_name = rescode;
196 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP) ); 196 CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP) );
197 197
198 /* finally retrieve its data */ 198 /* finally retrieve its data */
199 CHECK_FCT_DO( fd_dict_getval( enum_obj, &(req.search) ), return EINVAL ); 199 CHECK_FCT_DO( fd_dict_getval( enum_obj, &(req.search) ), return EINVAL );
200 200
201 /* copy the found value, we're done */ 201 /* copy the found value, we're done */
202 rc_val = req.search.enum_value.u32; 202 rc_val = req.search.enum_value.u32;
203 } 203 }
204 204
205 if (type_id == 1) { 205 if (type_id == 1) {
206 /* Add the Origin-Host and Origin-Realm AVP */ 206 /* Add the Origin-Host and Origin-Realm AVP */
207 CHECK_FCT( fd_msg_add_origin ( msg, 0 ) ); 207 CHECK_FCT( fd_msg_add_origin ( msg, 0 ) );
208 } 208 }
209 209
210 /* Create the Result-Code AVP */ 210 /* Create the Result-Code AVP */
211 CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); 211 CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) );
212 212
213 /* Set its value */ 213 /* Set its value */
214 memset(&val, 0, sizeof(val)); 214 memset(&val, 0, sizeof(val));
215 val.u32 = rc_val; 215 val.u32 = rc_val;
216 CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); 216 CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) );
217 217
218 /* Add it to the message */ 218 /* Add it to the message */
219 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); 219 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) );
220 220
221 if (type_id == 2) { 221 if (type_id == 2) {
222 /* Add the Error-Reporting-Host AVP */ 222 /* Add the Error-Reporting-Host AVP */
223 223
224 CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) ); 224 CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) );
225 225
226 /* Set its value */ 226 /* Set its value */
227 memset(&val, 0, sizeof(val)); 227 memset(&val, 0, sizeof(val));
228 val.os.data = (uint8_t *)fd_g_config->cnf_diamid; 228 val.os.data = (uint8_t *)fd_g_config->cnf_diamid;
229 val.os.len = fd_g_config->cnf_diamid_len; 229 val.os.len = fd_g_config->cnf_diamid_len;
230 CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) ); 230 CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) );
231 231
232 /* Add it to the message */ 232 /* Add it to the message */
233 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) ); 233 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) );
234 234
235 } 235 }
236 236
237 /* Now add the optavp in a FailedAVP if provided */ 237 /* Now add the optavp in a FailedAVP if provided */
238 if (optavp) { 238 if (optavp) {
239 struct avp * optavp_cpy = NULL; 239 struct avp * optavp_cpy = NULL;
240 struct avp_hdr *opt_hdr, *optcpy_hdr; 240 struct avp_hdr *opt_hdr, *optcpy_hdr;
241 struct dict_object * opt_model = NULL; 241 struct dict_object * opt_model = NULL;
242 int is_grouped = 0; 242 int is_grouped = 0;
243 243
244 /* Create the Failed-AVP AVP */ 244 /* Create the Failed-AVP AVP */
245 CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) ); 245 CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) );
246 246
247 /* Was this AVP a grouped one? Best effort only here */ 247 /* Was this AVP a grouped one? Best effort only here */
248 if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) { 248 if (!fd_msg_model ( optavp, &opt_model ) && (opt_model != NULL)) {
249 struct dict_avp_data dictdata; 249 struct dict_avp_data dictdata;
250 CHECK_FCT( fd_dict_getval(opt_model, &dictdata) ); 250 CHECK_FCT( fd_dict_getval(opt_model, &dictdata) );
251 if (dictdata.avp_basetype == AVP_TYPE_GROUPED) 251 if (dictdata.avp_basetype == AVP_TYPE_GROUPED)
252 is_grouped = 1; 252 is_grouped = 1;
253 } 253 }
254 254
255 /* Create a new AVP with a copy of the data of the invalid or missing AVP */ 255 /* Create a new AVP with a copy of the data of the invalid or missing AVP */
256 optavp_cpy = optavp; 256 optavp_cpy = optavp;
257 257
258 if (is_grouped) { 258 if (is_grouped) {
259 CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) ); 259 CHECK_FCT( fd_msg_avp_new( opt_model, 0, &optavp_cpy) );
260 } else { 260 } else {
261 CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) ); 261 CHECK_FCT( fd_msg_avp_new( NULL, AVPFL_SET_BLANK_VALUE | AVPFL_SET_RAWDATA_FROM_AVP, &optavp_cpy) );
262 262
263 CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) ); 263 CHECK_FCT( fd_msg_avp_hdr(optavp, &opt_hdr) );
264 CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) ); 264 CHECK_FCT( fd_msg_avp_hdr(optavp_cpy, &optcpy_hdr) );
265 memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr)); 265 memcpy(optcpy_hdr, opt_hdr, sizeof(struct avp_hdr));
266 } 266 }
267 267
268 /* Add the passed AVP inside it */ 268 /* Add the passed AVP inside it */
269 CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) ); 269 CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp_cpy ) );
270 270
271 /* And add to the message */ 271 /* And add to the message */
272 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) ); 272 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) );
273 } 273 }
274 274
275 275
276 /* Deal with the 'E' bit and the error message */ 276 /* Deal with the 'E' bit and the error message */
277 switch (rc_val / 1000) { 277 switch (rc_val / 1000) {
278 case 1: /* Informational */ 278 case 1: /* Informational */
279 case 2: /* Success */ 279 case 2: /* Success */
280 /* Nothing special here: no E bit, no error message unless one is specified */ 280 /* Nothing special here: no E bit, no error message unless one is specified */
281 break; 281 break;
282 282
283 case 3: /* Protocol Errors */ 283 case 3: /* Protocol Errors */
284 set_e_bit = 1; 284 set_e_bit = 1;
285 std_err_msg = 1; 285 std_err_msg = 1;
286 break; 286 break;
287 287
288 case 4: /* Transcient Failure */ 288 case 4: /* Transcient Failure */
289 case 5: /* Permanent Failure */ 289 case 5: /* Permanent Failure */
290 if (rc_val == 5017) /* DIAMETER_NO_COMMON_SECURITY */ { 290 if (rc_val == 5017) /* DIAMETER_NO_COMMON_SECURITY */ {
291 set_e_bit = 1; 291 set_e_bit = 1;
292 } 292 }
293 default: 293 default:
294 std_err_msg = 1; 294 std_err_msg = 1;
295 break; 295 break;
296 296
297 } 297 }
298 298
299 { 299 {
300 struct msg_hdr * hdr = NULL; 300 struct msg_hdr * hdr = NULL;
301 301
302 CHECK_FCT( fd_msg_hdr( msg, &hdr ) ); 302 CHECK_FCT( fd_msg_hdr( msg, &hdr ) );
303 303
304 if (set_e_bit) 304 if (set_e_bit)
305 hdr->msg_flags |= CMD_FLAG_ERROR; 305 hdr->msg_flags |= CMD_FLAG_ERROR;
306 else 306 else
307 hdr->msg_flags &= ~ CMD_FLAG_ERROR; 307 hdr->msg_flags &= ~ CMD_FLAG_ERROR;
308 } 308 }
309 309
310 if (std_err_msg || errormsg) { 310 if (std_err_msg || errormsg) {
311 /* Add the Error-Message AVP */ 311 /* Add the Error-Message AVP */
312 312
313 CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) ); 313 CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) );
314 314
315 /* Set its value */ 315 /* Set its value */
316 memset(&val, 0, sizeof(val)); 316 memset(&val, 0, sizeof(val));
317 317
318 if (errormsg) { 318 if (errormsg) {
319 val.os.data = (uint8_t *)errormsg; 319 val.os.data = (uint8_t *)errormsg;
320 val.os.len = strlen(errormsg); 320 val.os.len = strlen(errormsg);
321 } else { 321 } else {
322 val.os.data = (uint8_t *)rescode; 322 val.os.data = (uint8_t *)rescode;
325 CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) ); 325 CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) );
326 326
327 /* Add it to the message */ 327 /* Add it to the message */
328 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) ); 328 CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) );
329 } 329 }
330 330
331 return 0; 331 return 0;
332 } 332 }
333 333
334 static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout ) 334 static int fd_msg_send_int( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
335 { 335 {
336 struct msg_hdr *hdr; 336 struct msg_hdr *hdr;
337 DiamId_t diamid; 337 DiamId_t diamid;
338 338
339 /* Save the callback in the message, with the timeout */ 339 /* Save the callback in the message, with the timeout */
340 CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout ) ); 340 CHECK_FCT( fd_msg_anscb_associate( *pmsg, anscb, data, expirecb, timeout ) );
341 341
342 /* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */ 342 /* If this is a new request, call the HOOK_MESSAGE_LOCAL hook */
343 if ( (fd_msg_hdr(*pmsg, &hdr) == 0) 343 if ( (fd_msg_hdr(*pmsg, &hdr) == 0)
344 && (hdr->msg_flags & CMD_FLAG_REQUEST) 344 && (hdr->msg_flags & CMD_FLAG_REQUEST)
345 && (fd_msg_source_get(*pmsg, &diamid, NULL) == 0) 345 && (fd_msg_source_get(*pmsg, &diamid, NULL) == 0)
346 && (diamid == NULL)) { 346 && (diamid == NULL)) {
347 fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg)); 347 fd_hook_call(HOOK_MESSAGE_LOCAL, *pmsg, NULL, NULL, fd_msg_pmdl_get(*pmsg));
348 } 348 }
349 349
350 /* Post the message in the outgoing queue */ 350 /* Post the message in the outgoing queue */
351 CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) ); 351 CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) );
352 352
353 return 0; 353 return 0;
354 } 354 }
355 355
356 /* Send a message and optionally register a callback for an answer */ 356 /* Send a message and optionally register a callback for an answer */
357 int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data ) 357 int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data )
358 { 358 {
359 TRACE_ENTRY("%p %p %p", pmsg, anscb, data); 359 TRACE_ENTRY("%p %p %p", pmsg, anscb, data);
360 CHECK_PARAMS( pmsg ); 360 CHECK_PARAMS( pmsg );
361 361
362 return fd_msg_send_int(pmsg, anscb, data, NULL, NULL); 362 return fd_msg_send_int(pmsg, anscb, data, NULL, NULL);
363 } 363 }
364 364
365 /* The variation of the same function with a timeout callback */ 365 /* The variation of the same function with a timeout callback */
366 int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout ) 366 int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, void (*expirecb)(void *, DiamId_t, size_t, struct msg **), const struct timespec *timeout )
367 { 367 {
368 TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout); 368 TRACE_ENTRY("%p %p %p %p %p", pmsg, anscb, data, expirecb, timeout);
369 CHECK_PARAMS( pmsg && expirecb && timeout ); 369 CHECK_PARAMS( pmsg && expirecb && timeout );
370 370
371 return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout); 371 return fd_msg_send_int(pmsg, anscb, data, expirecb, timeout);
372 } 372 }
373 373
374 374
375 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */ 375 /* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
377 { 377 {
378 int ret = 0; 378 int ret = 0;
379 struct msg * m; 379 struct msg * m;
380 struct msg_hdr * hdr = NULL; 380 struct msg_hdr * hdr = NULL;
381 struct fd_pei pei; 381 struct fd_pei pei;
382 382
383 TRACE_ENTRY("%p", msg); 383 TRACE_ENTRY("%p", msg);
384 384
385 CHECK_PARAMS(msg && *msg && error); 385 CHECK_PARAMS(msg && *msg && error);
386 m = *msg; 386 m = *msg;
387 *error = NULL; 387 *error = NULL;
388 388
389 /* Parse the message against our dictionary */ 389 /* Parse the message against our dictionary */
390 ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei); 390 ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei);
391 if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */ 391 if ((ret != EBADMSG) /* Parsing grouped AVP failed / Conflicting rule found */
392 && (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */ 392 && (ret != ENOTSUP)) /* Command is not supported / Mandatory AVP is not supported */
393 return ret; /* 0 or another error */ 393 return ret; /* 0 or another error */
394 394
395 /* Log */ 395 /* Log */
396 fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m)); 396 fd_hook_call(HOOK_MESSAGE_PARSING_ERROR, m, NULL, pei.pei_message ?: pei.pei_errcode, fd_msg_pmdl_get(m));
397 397
398 CHECK_FCT( fd_msg_hdr(m, &hdr) ); 398 CHECK_FCT( fd_msg_hdr(m, &hdr) );
399 399
400 /* Now create an answer error if the message is a query */ 400 /* Now create an answer error if the message is a query */
401 if (hdr->msg_flags & CMD_FLAG_REQUEST) { 401 if (hdr->msg_flags & CMD_FLAG_REQUEST) {
402 402
403 /* Create the error message */ 403 /* Create the error message */
404 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) ); 404 CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, &m, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
405 405
406 /* Set the error code */ 406 /* Set the error code */
407 CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) ); 407 CHECK_FCT( fd_msg_rescode_set(m, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
408 408
409 /* free the pei AVP to avoid memory leak */ 409 /* free the pei AVP to avoid memory leak */
410 if (pei.pei_avp_free) { 410 if (pei.pei_avp_free) {
411 fd_msg_free(pei.pei_avp); 411 fd_msg_free(pei.pei_avp);
412 } 412 }
413 413
414 *msg = NULL; 414 *msg = NULL;
415 *error = m; 415 *error = m;
416 416
417 } else { 417 } else {
418 do { /* Rescue error messages */ 418 do { /* Rescue error messages */
419 struct avp * avp; 419 struct avp * avp;
420 union avp_value * rc = NULL; 420 union avp_value * rc = NULL;
421 421
422 /* Search the Result-Code AVP */ 422 /* Search the Result-Code AVP */
423 CHECK_FCT_DO( fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break ); 423 CHECK_FCT_DO( fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break );
424 while (avp) { 424 while (avp) {
425 struct avp_hdr * ahdr; 425 struct avp_hdr * ahdr;
426 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), break ); 426 CHECK_FCT_DO( fd_msg_avp_hdr( avp, &ahdr ), break );
427 427
428 if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) { 428 if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) {
429 /* Parse this AVP */ 429 /* Parse this AVP */
430 ASSERT( ahdr->avp_value ); 430 if (fd_msg_parse_dict(avp, fd_g_config->cnf_dict, &pei) < 0) {
431 TRACE_DEBUG(INFO, "error parsing Result-Code AVP");
432 rc = NULL;
433 break;
434 }
431 rc = ahdr->avp_value; 435 rc = ahdr->avp_value;
436 if (rc == NULL) {
437 TRACE_DEBUG(INFO, "invalid Result-Code AVP");
438 break;
439 }
432 break; 440 break;
433 } 441 }
434 442
435 /* Go to next AVP */ 443 /* Go to next AVP */
436 CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break ); 444 CHECK_FCT_DO( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break );
437 } 445 }
438 446
439 if (rc) { 447 if (rc) {
440 switch (rc->u32 / 1000) { 448 switch (rc->u32 / 1000) {
441 case 1: /* 1xxx : Informational */ 449 case 1: /* 1xxx : Informational */
442 case 2: /* 2xxx : Sucess */ 450 case 2: /* 2xxx : Sucess */
443 /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */ 451 /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */
444 break; 452 break;
445 453
446 default: /* Other errors */ 454 default: /* Other errors */
447 /* We let the application decide what to do with the message, we rescue it */ 455 /* We let the application decide what to do with the message, we rescue it */
448 *error = m; 456 *error = m;
449 } 457 }
450 } 458 }
451 } while (0); 459 } while (0);
452 } 460 }
453 461
454 return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */ 462 return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */
455 } 463 }
"Welcome to our mercurial repository"