Navigation


source: freeDiameter/libfdcore/messages.c @ 688:8c3dc8584dab

Last change on this file since 688:8c3dc8584dab was 688:8c3dc8584dab, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Prepared capability for messages logging to separate files / folders

File size: 13.1 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "fdcore-internal.h"
37
38static struct dict_object * dict_avp_OH  = NULL; /* Origin-Host */
39static struct dict_object * dict_avp_OR  = NULL; /* Origin-Realm */
40static struct dict_object * dict_avp_EM  = NULL; /* Error-Message */
41static struct dict_object * dict_avp_ERH = NULL; /* Error-Reporting-Host */
42static struct dict_object * dict_avp_FAVP= NULL; /* Failed-AVP */
43static struct dict_object * dict_avp_RC  = NULL; /* Result-Code */
44struct dict_object * fd_dict_avp_OSI = NULL; /* Origin-State-Id */
45struct dict_object * fd_dict_cmd_CER = NULL; /* Capabilities-Exchange-Request */
46struct dict_object * fd_dict_cmd_DWR = NULL; /* Device-Watchdog-Request */
47struct dict_object * fd_dict_avp_DC  = NULL; /* Disconnect-Cause */
48struct dict_object * fd_dict_cmd_DPR = NULL; /* Disconnect-Peer-Request */
49
50/* Resolve the dictionary objects */
51int fd_msg_init(void)
52{
53        TRACE_ENTRY("");
54       
55        /* Initialize the dictionary objects that we may use frequently */
56        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host",        &dict_avp_OH  , ENOENT)  );
57        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm",       &dict_avp_OR  , ENOENT)  );
58        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id",    &fd_dict_avp_OSI , ENOENT)  );
59       
60        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code",        &dict_avp_RC  , ENOENT)  );
61        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message",      &dict_avp_EM  , ENOENT)  );
62        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT)  );
63        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP",         &dict_avp_FAVP, ENOENT)  );
64       
65        CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause",   &fd_dict_avp_DC , ENOENT)  );
66       
67        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) );
68        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) );
69        CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) );
70       
71       
72        return 0;
73}
74
75/* Add Origin-Host, Origin-Realm, Origin-State-Id AVPS at the end of the message */
76int fd_msg_add_origin ( struct msg * msg, int osi )
77{
78        union avp_value val;
79        struct avp * avp_OH  = NULL;
80        struct avp * avp_OR  = NULL;
81        struct avp * avp_OSI = NULL;
82       
83        TRACE_ENTRY("%p", msg);
84        CHECK_PARAMS(  msg  );
85       
86        /* Create the Origin-Host AVP */
87        CHECK_FCT( fd_msg_avp_new( dict_avp_OH, 0, &avp_OH ) );
88       
89        /* Set its value */
90        memset(&val, 0, sizeof(val));
91        val.os.data = (unsigned char *)fd_g_config->cnf_diamid;
92        val.os.len  = fd_g_config->cnf_diamid_len;
93        CHECK_FCT( fd_msg_avp_setvalue( avp_OH, &val ) );
94       
95        /* Add it to the message */
96        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OH ) );
97       
98       
99        /* Create the Origin-Realm AVP */
100        CHECK_FCT( fd_msg_avp_new( dict_avp_OR, 0, &avp_OR ) );
101       
102        /* Set its value */
103        memset(&val, 0, sizeof(val));
104        val.os.data = (unsigned char *)fd_g_config->cnf_diamrlm;
105        val.os.len  = fd_g_config->cnf_diamrlm_len;
106        CHECK_FCT( fd_msg_avp_setvalue( avp_OR, &val ) );
107       
108        /* Add it to the message */
109        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OR ) );
110       
111        if (osi) {
112                /* Create the Origin-State-Id AVP */
113                CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) );
114
115                /* Set its value */
116                memset(&val, 0, sizeof(val));
117                val.u32 = fd_g_config->cnf_orstateid;
118                CHECK_FCT( fd_msg_avp_setvalue( avp_OSI, &val ) );
119
120                /* Add it to the message */
121                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_OSI ) );
122        }
123       
124        return 0;
125}
126
127/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */
128int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id )
129{
130        union avp_value val;
131        struct avp * avp_RC  = NULL;
132        struct avp * avp_EM  = NULL;
133        struct avp * avp_ERH = NULL;
134        struct avp * avp_FAVP= NULL;
135        uint32_t rc_val = 0;
136        int set_e_bit=0;
137        int std_err_msg=0;
138       
139        TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id);
140               
141        CHECK_PARAMS(  msg && rescode  );
142       
143        /* Find the enum value corresponding to the rescode string, this will give the class of error */
144        {
145                struct dict_object * enum_obj = NULL;
146                struct dict_enumval_request req;
147                memset(&req, 0, sizeof(struct dict_enumval_request));
148               
149                /* First, get the enumerated type of the Result-Code AVP */
150                CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT  )  );
151               
152                /* Now search for the value given as parameter */
153                req.search.enum_name = rescode;
154                CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enum_obj, ENOTSUP)  );
155               
156                /* finally retrieve its data */
157                CHECK_FCT_DO(  fd_dict_getval( enum_obj, &(req.search) ), return EINVAL );
158               
159                /* copy the found value, we're done */
160                rc_val = req.search.enum_value.u32;
161        }
162       
163        if (type_id == 1) {
164                /* Add the Origin-Host and Origin-Realm AVP */
165                CHECK_FCT( fd_msg_add_origin ( msg, 0 ) );
166        }
167       
168        /* Create the Result-Code AVP */
169        CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) );
170       
171        /* Set its value */
172        memset(&val, 0, sizeof(val));
173        val.u32  = rc_val;
174        CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) );
175       
176        /* Add it to the message */
177        CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) );
178       
179        if (type_id == 2) {
180                /* Add the Error-Reporting-Host AVP */
181               
182                CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) );
183
184                /* Set its value */
185                memset(&val, 0, sizeof(val));
186                val.os.data = (unsigned char *)fd_g_config->cnf_diamid;
187                val.os.len  = fd_g_config->cnf_diamid_len;
188                CHECK_FCT( fd_msg_avp_setvalue( avp_ERH, &val ) );
189
190                /* Add it to the message */
191                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) );
192       
193        }
194       
195        /* Now add the optavp in a FailedAVP if provided */
196        if (optavp) {
197                /* Create the Failed-AVP AVP */
198                CHECK_FCT( fd_msg_avp_new( dict_avp_FAVP, 0, &avp_FAVP ) );
199
200                /* Add the passed AVP inside it */
201                CHECK_FCT( fd_msg_avp_add( avp_FAVP, MSG_BRW_LAST_CHILD, optavp ) );
202               
203                /* And add to the message */
204                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_FAVP ) );
205        }
206       
207       
208        /* Deal with the 'E' bit and the error message */
209        switch (rc_val / 1000) {
210                case 1: /* Informational */
211                case 2: /* Success */
212                        /* Nothing special here: no E bit, no error message unless one is specified */
213                        break;
214                       
215                case 3: /* Protocol Errors */
216                        set_e_bit = 1;
217                        std_err_msg = 1;
218                        break;
219                       
220                case 4: /* Transcient Failure */
221                case 5: /* Permanent Failure */
222                default:
223                        std_err_msg = 1;
224                        break;
225                       
226        }
227       
228        {
229                struct msg_hdr * hdr = NULL;
230               
231                CHECK_FCT(  fd_msg_hdr( msg, &hdr )  );
232               
233                if (set_e_bit)
234                        hdr->msg_flags |= CMD_FLAG_ERROR;
235                else
236                        hdr->msg_flags &= ! CMD_FLAG_ERROR;
237        }
238       
239        if (std_err_msg || errormsg) {
240                /* Add the Error-Message AVP */
241               
242                CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) );
243
244                /* Set its value */
245                memset(&val, 0, sizeof(val));
246               
247                if (errormsg) {
248                        val.os.data = (unsigned char *)errormsg;
249                        val.os.len  = strlen(errormsg);
250                } else {
251                        val.os.data = (unsigned char *)rescode;
252                        val.os.len  = strlen(rescode);
253                }
254                CHECK_FCT( fd_msg_avp_setvalue( avp_EM, &val ) );
255
256                /* Add it to the message */
257                CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_EM ) );
258        }
259       
260        return 0;
261}
262
263/* Send a message and optionaly register a callback for an answer */
264int fd_msg_send ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data )
265{
266        TRACE_ENTRY("%p %p %p", pmsg, anscb, data);
267        CHECK_PARAMS( pmsg );
268       
269        /* Save the callback in the message */
270        if (anscb) {
271                CHECK_FCT(  fd_msg_anscb_associate( *pmsg, anscb, data, NULL /* we should maybe use a safeguard here like 1 hour or so? */ )  );
272        }
273       
274        /* Post the message in the outgoing queue */
275        CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) );
276       
277        return 0;
278}
279
280/* The variation of the same function with a timeout callback */
281int fd_msg_send_timeout ( struct msg ** pmsg, void (*anscb)(void *, struct msg **), void * data, const struct timespec *timeout )
282{
283        TRACE_ENTRY("%p %p %p", pmsg, anscb, data, timeout);
284        CHECK_PARAMS( pmsg && anscb && timeout );
285       
286        /* Save the callback in the message, with the timeout */
287        CHECK_FCT(  fd_msg_anscb_associate( *pmsg, anscb, data, timeout )  );
288       
289        /* Post the message in the outgoing queue */
290        CHECK_FCT( fd_fifo_post(fd_g_outgoing, pmsg) );
291       
292        return 0;
293}
294
295
296/* Parse a message against our dictionary, and in case of error log and eventually build the error reply -- returns the parsing status */
297int fd_msg_parse_or_error( struct msg ** msg )
298{
299        int ret = 0;
300        struct msg * m;
301        struct msg_hdr * hdr = NULL;
302        struct fd_pei   pei;
303       
304        TRACE_ENTRY("%p", msg);
305       
306        CHECK_PARAMS(msg && *msg);
307        m = *msg;
308       
309        /* Parse the message against our dictionary */
310        ret = fd_msg_parse_rules ( m, fd_g_config->cnf_dict, &pei);
311        if      ((ret != EBADMSG)       /* Parsing grouped AVP failed / Conflicting rule found */
312                && (ret != ENOTSUP))    /* Command is not supported / Mandatory AVP is not supported */
313                return ret;
314       
315        TRACE_DEBUG(INFO, "A message does not comply to the dictionary and/or rules (%s)", pei.pei_errcode);
316        fd_msg_dump_walk(FULL, m);
317       
318        CHECK_FCT( fd_msg_hdr(m, &hdr) );
319       
320        /* Now create an answer error if the message is a query */
321        if (hdr->msg_flags & CMD_FLAG_REQUEST) {
322               
323                /* Create the error message */
324                CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, pei.pei_protoerr ? MSGFL_ANSW_ERROR : 0 ) );
325               
326                /* Set the error code */
327                CHECK_FCT( fd_msg_rescode_set(*msg, pei.pei_errcode, pei.pei_message, pei.pei_avp, 1 ) );
328               
329        } else {
330                do { /* Rescue error messages */
331                        struct avp * avp;
332                        union avp_value * rc = NULL;
333                       
334                        /* Search the Result-Code AVP */
335                        CHECK_FCT_DO(  fd_msg_browse(*msg, MSG_BRW_FIRST_CHILD, &avp, NULL), break  );
336                        while (avp) {
337                                struct avp_hdr * ahdr;
338                                CHECK_FCT_DO(  fd_msg_avp_hdr( avp, &ahdr ), break  );
339                               
340                                if ((ahdr->avp_code == AC_RESULT_CODE) && (! (ahdr->avp_flags & AVP_FLAG_VENDOR)) ) {
341                                        /* Parse this AVP */
342                                        ASSERT( ahdr->avp_value );
343                                        rc = ahdr->avp_value;
344                                        break;
345                                }
346                               
347                                /* Go to next AVP */
348                                CHECK_FCT_DO(  fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL), break  );
349                        }
350                       
351                        if (rc) {
352                                switch (rc->u32 / 1000) {
353                                        case 1: /* 1xxx : Informational */
354                                        case 2: /* 2xxx : Sucess */
355                                                /* In these cases, we want the message to validate the ABNF, so we will discard the bad message */
356                                                break;
357                                               
358                                        default: /* Other errors */
359                                                /* We let the application decide what to do with the message, we rescue it */
360                                                return 0;
361                                }
362                        }
363                } while (0);
364               
365                /* Just discard */
366                fd_msg_log( FD_MSG_LOG_DROPPED, m, "Answer not compliant to dictionary's ABNF (%s)", pei.pei_errcode  );
367                CHECK_FCT( fd_msg_free( m ) );
368                *msg = NULL;
369        }
370       
371        return EBADMSG; /* We convert ENOTSUP to EBADMSG as well */
372}
Note: See TracBrowser for help on using the repository browser.