# HG changeset patch # User Luke Mewburn # Date 1582068389 -39600 # Node ID b09f1b4c9fad2851b9e6d94d8efbe98fb605eb90 # Parent c8057892e56bc06bd82ae4a34c444bbc32f93fd9 fd_msg_add_result: add function Add fd_msg_add_result() as a superset of fd_msg_rescode_set() to allow setting of either Result-Code or Experimental-Result (Grouped), depending upon whether the supplied vendor is 0 or not. Reimplement fd_msg_rescode_set() in terms of fd_msg_add_result(). diff -r c8057892e56b -r b09f1b4c9fad include/freeDiameter/libfdcore.h --- a/include/freeDiameter/libfdcore.h Wed Feb 19 10:24:13 2020 +1100 +++ b/include/freeDiameter/libfdcore.h Wed Feb 19 10:26:29 2020 +1100 @@ -552,6 +552,30 @@ 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 ); /* + * FUNCTION: fd_msg_add_result + * + * PARAMETERS: + * msg : A msg object -- it must be an answer. + * vendor : Vendor. If 0, add Result-Code else add Experimental-Result. + * restype : DICT_TYPE containing rescode (ex: from TYPE_BY_NAME "Enumerated(Result-Code)"). + * rescode : The name of the returned error code (ex: "DIAMETER_INVALID_AVP"). + * errormsg : (optional) human-readable error message to put in Error-Message AVP. + * optavp : (optional) If provided, the content will be put inside a Failed-AVP. + * type_id : 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host. + * + * DESCRIPTION: + * This function adds a Result-Code AVP (if vendor is 0) or Experimental-Result AVP (vendor is not 0) + * to a message, and optionally + * - sets the 'E' error flag in the header, + * - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs. + * + * RETURN VALUE: + * 0 : Operation complete. + * !0 : an error occurred. + */ +int fd_msg_add_result( struct msg * msg, vendor_id_t vendor, struct dict_object * restype, char * rescode, char * errormsg, struct avp * optavp, int type_id ); + +/* * FUNCTION: fd_msg_rescode_set * * PARAMETERS: @@ -561,14 +585,15 @@ * optavp : (optional) If provided, the content will be put inside a Failed-AVP * type_id : 0 => nothing; 1 => adds Origin-Host and Origin-Realm with local info. 2=> adds Error-Reporting-Host. * - * DESCRIPTION: - * This function adds a Result-Code AVP to a message, and optionally + * DESCRIPTION: + * This function adds a Result-Code AVP to a message, and optionally * - sets the 'E' error flag in the header, * - adds Error-Message, Error-Reporting-Host and Failed-AVP AVPs. + * Uses fd_msg_add_result with vendor 0 and restype for Enumerated(Result-Code). * * RETURN VALUE: - * 0 : Operation complete. - * !0 : an error occurred. + * 0 : Operation complete. + * !0 : an error occurred. */ int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ); diff -r c8057892e56b -r b09f1b4c9fad libfdcore/messages.c --- a/libfdcore/messages.c Wed Feb 19 10:24:13 2020 +1100 +++ b/libfdcore/messages.c Wed Feb 19 10:26:29 2020 +1100 @@ -42,6 +42,9 @@ static struct dict_object * dict_avp_ERH = NULL; /* Error-Reporting-Host */ static struct dict_object * dict_avp_FAVP= NULL; /* Failed-AVP */ static struct dict_object * dict_avp_RC = NULL; /* Result-Code */ +static struct dict_object * dict_avp_ER = NULL; /* Experimental-Result */ +static struct dict_object * dict_avp_VI = NULL; /* Vendor-Id */ +static struct dict_object * dict_avp_ERC = NULL; /* Experimental-Result-Code */ struct dict_object * fd_dict_avp_OSI = NULL; /* Origin-State-Id */ struct dict_object * fd_dict_cmd_CER = NULL; /* Capabilities-Exchange-Request */ struct dict_object * fd_dict_cmd_DWR = NULL; /* Device-Watchdog-Request */ @@ -63,6 +66,9 @@ CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Message", &dict_avp_EM , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Error-Reporting-Host", &dict_avp_ERH , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Failed-AVP", &dict_avp_FAVP, ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &dict_avp_ER, ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dict_avp_VI, ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &dict_avp_ERC, ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Disconnect-Cause", &fd_dict_avp_DC , ENOENT) ); @@ -166,30 +172,26 @@ } -/* Add Result-Code and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */ -int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ) +/* Add Result-Code or Experimental-Result, and eventually Failed-AVP, Error-Message and Error-Reporting-Host AVPs */ +int fd_msg_add_result( struct msg * msg, vendor_id_t vendor, struct dict_object * restype, char * rescode, char * errormsg, struct avp * optavp, int type_id ) { union avp_value val; - struct avp * avp_RC = NULL; - struct avp * avp_EM = NULL; - struct avp * avp_ERH = NULL; - struct avp * avp_FAVP= NULL; uint32_t rc_val = 0; int set_e_bit=0; int std_err_msg=0; - TRACE_ENTRY("%p %s %p %p %d", msg, rescode, errormsg, optavp, type_id); + TRACE_ENTRY("%p %d %p %s %p %p %d", msg, vendor, restype, rescode, errormsg, optavp, type_id); - CHECK_PARAMS( msg && rescode ); + CHECK_PARAMS( msg && restype && rescode ); /* Find the enum value corresponding to the rescode string, this will give the class of error */ { struct dict_object * enum_obj = NULL; + + /* Search in the restype */ struct dict_enumval_request req; memset(&req, 0, sizeof(struct dict_enumval_request)); - - /* First, get the enumerated type of the Result-Code AVP (this is fast, no need to cache the object) */ - CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &(req.type_obj), ENOENT ) ); + req.type_obj = restype; /* Now search for the value given as parameter */ req.search.enum_name = rescode; @@ -207,20 +209,58 @@ CHECK_FCT( fd_msg_add_origin ( msg, 0 ) ); } - /* Create the Result-Code AVP */ - CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); + if (vendor == 0) { + /* Vendor 0; create the Result-Code AVP */ + struct avp * avp_RC = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_RC, 0, &avp_RC ) ); + + /* Set its value */ + memset(&val, 0, sizeof(val)); + val.u32 = rc_val; + CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); + + /* Add it to the message */ + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); + } else { + /* Vendor !0; create the Experimental-Result AVP */ + struct avp * avp_ER = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_ER, 0, &avp_ER ) ); + + /* Create the Vendor-Id AVP and add to Experimental-Result */ + { + struct avp * avp_VI = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_VI, 0, &avp_VI ) ); - /* Set its value */ - memset(&val, 0, sizeof(val)); - val.u32 = rc_val; - CHECK_FCT( fd_msg_avp_setvalue( avp_RC, &val ) ); + /* Set Vendor-Id value to vendor */ + memset(&val, 0, sizeof(val)); + val.u32 = vendor; + CHECK_FCT( fd_msg_avp_setvalue( avp_VI, &val ) ); + + /* Add it to Experimental-Result */ + CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_VI ) ); + } - /* Add it to the message */ - CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_RC ) ); + /* Create the Experimental-Result-Code AVP and add to Experimental-Result */ + { + struct avp * avp_ERC = NULL; + CHECK_FCT( fd_msg_avp_new( dict_avp_ERC, 0, &avp_ERC ) ); + + /* Set Experimental-Result-Code value to rc_val */ + memset(&val, 0, sizeof(val)); + val.u32 = rc_val; + CHECK_FCT( fd_msg_avp_setvalue( avp_ERC, &val ) ); + + /* Add it to Experimental-Result */ + CHECK_FCT( fd_msg_avp_add( avp_ER, MSG_BRW_LAST_CHILD, avp_ERC ) ); + } + + /* Add it to the message */ + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ER ) ); + } if (type_id == 2) { /* Add the Error-Reporting-Host AVP */ - + struct avp * avp_ERH = NULL; CHECK_FCT( fd_msg_avp_new( dict_avp_ERH, 0, &avp_ERH ) ); /* Set its value */ @@ -231,11 +271,11 @@ /* Add it to the message */ CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp_ERH ) ); - } - /* Now add the optavp in a FailedAVP if provided */ + /* Now add the optavp in a Failed-AVP if provided */ if (optavp) { + struct avp * avp_FAVP= NULL; struct avp * optavp_cpy = NULL; struct avp_hdr *opt_hdr, *optcpy_hdr; struct dict_object * opt_model = NULL; @@ -309,7 +349,7 @@ if (std_err_msg || errormsg) { /* Add the Error-Message AVP */ - + struct avp * avp_EM = NULL; CHECK_FCT( fd_msg_avp_new( dict_avp_EM, 0, &avp_EM ) ); /* Set its value */ @@ -331,6 +371,13 @@ return 0; } +int fd_msg_rescode_set( struct msg * msg, char * rescode, char * errormsg, struct avp * optavp, int type_id ) +{ + struct dict_object * restype = NULL; + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, dict_avp_RC, &restype, ENOENT ) ); + return fd_msg_add_result(msg, 0, restype, rescode, errormsg, optavp, type_id); +} + 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 ) { struct msg_hdr *hdr; diff -r c8057892e56b -r b09f1b4c9fad tests/testmesg.c --- a/tests/testmesg.c Wed Feb 19 10:24:13 2020 +1100 +++ b/tests/testmesg.c Wed Feb 19 10:26:29 2020 +1100 @@ -282,6 +282,11 @@ CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Application test", &application, ENOENT ) ); CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_COMMAND, &cmd_data , application, &command ) ); + ADD_RULE(command, 0, "Session-Id", RULE_FIXED_HEAD, 1, 1, 1); + ADD_RULE(command, 0, "Result-Code", RULE_OPTIONAL, 0, 1, 0); + ADD_RULE(command, 0, "Experimental-Result", RULE_OPTIONAL, 0, 1, 0); + ADD_RULE(command, 0, "Origin-Host", RULE_REQUIRED, 1, 1, 0); + ADD_RULE(command, 0, "Origin-Realm", RULE_REQUIRED, 1, 1, 0); } { @@ -316,7 +321,19 @@ CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) ); CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) ); } - + + { + struct dict_object * type = NULL; + struct dict_type_data type_data = { AVP_TYPE_UNSIGNED32, "Enumerated(73565/Experimental-Result-Code)" }; + struct dict_avp_data avp_data = { 73576, 73565, "Experimental-Result-Code", AVP_FLAG_VENDOR, AVP_FLAG_VENDOR, AVP_TYPE_UNSIGNED32 }; + struct dict_enumval_data val1 = { "DIAMETER_TEST_RESULT_1000", { .u32 = 1000 } }; + struct dict_enumval_data val2 = { "DIAMETER_TEST_RESULT_5000", { .u32 = 5000 } }; + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_TYPE, &type_data , NULL, &type ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_AVP, &avp_data , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val1 , type, NULL ) ); + CHECK( 0, fd_dict_new ( fd_g_config->cnf_dict, DICT_ENUMVAL, &val2 , type, NULL ) ); + } + #if 0 { fd_log_debug("%s", fd_dict_dump_object(FD_DUMP_TEST_PARAMS, vendor)); @@ -1477,6 +1494,97 @@ } } + /* Test the fd_msg_add_result function for Result-Code */ + { + struct msg * msg = NULL; + struct dict_object * avp_model = NULL; + struct avp * rc = NULL; + struct avp_hdr * avpdata = NULL; + + { + struct dict_object * cmd_model = NULL; + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Answer", &cmd_model, ENOENT ) ); + + /* Create a message */ + CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) ); + + /* Add a session id */ + CHECK( 0, fd_msg_new_session( msg, (os0_t)"tm2", strlen("tm2") ) ); + + /* Find the DICT_TYPE Enumerated(Result-Code) */ + struct dict_object * restype = NULL; + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_BY_NAME, "Enumerated(Result-Code)", &restype, ENOENT ) ); + + /* Now test the behavior of fd_msg_add_result for Result-Code AVP */ + CHECK( 0, fd_msg_add_result(msg, 0, restype, "DIAMETER_SUCCESS", NULL, NULL, 1) ); + + LOG_D("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1)); + } + + /* Ensure Result-Code is present */ + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &avp_model, ENOENT ) ); + CHECK( 0, fd_msg_search_avp( msg, avp_model, &rc ) ); + + /* Check the Result-Code AVP value is DIAMETER_SUCCESS */ + CHECK( 0, fd_msg_avp_hdr ( rc, &avpdata ) ); + CHECK( ER_DIAMETER_SUCCESS, avpdata->avp_value->u32 ); + + /* Ensure Experimental-Result is missing */ + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &avp_model, ENOENT ) ); + CHECK( ENOENT, fd_msg_search_avp( msg, avp_model, NULL ) ); + + /* Free msg */ + CHECK( 0, fd_msg_free( msg ) ); + } + + /* Test the fd_msg_add_result function for Experimental-Result */ + { + struct msg * msg = NULL; + struct dict_object * avp_model = NULL; + struct avp * er = NULL; + struct avp * erc = NULL; + struct avp_hdr * avpdata = NULL; + + { + struct dict_object * cmd_model = NULL; + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Test-Command-Answer", &cmd_model, ENOENT ) ); + + /* Create a message */ + CHECK( 0, fd_msg_new ( cmd_model, 0, &msg ) ); + + /* Add a session id */ + CHECK( 0, fd_msg_new_session( msg, (os0_t)"tm2", strlen("tm2") ) ); + + /* Find the DICT_TYPE Enumerated(73565/Experimental-Result-Code) */ + struct dict_object * restype = NULL; + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_BY_NAME, "Enumerated(73565/Experimental-Result-Code)", &restype, ENOENT ) ); + + /* Now test the behavior of fd_msg_add_result for Experimental-Result AVP */ + CHECK( 0, fd_msg_add_result(msg, 73565, restype, "DIAMETER_TEST_RESULT_5000", NULL, NULL, 1) ); + + LOG_D("%s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, fd_g_config->cnf_dict, 0, 1)); + } + + /* Ensure Result-Code is missing */ + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &avp_model, ENOENT ) ); + CHECK( ENOENT, fd_msg_search_avp( msg, avp_model, NULL ) ); + + /* Ensure Experimental-Result is present */ + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result", &avp_model, ENOENT ) ); + CHECK( 0, fd_msg_search_avp( msg, avp_model, &er ) ); + + /* Ensure Experimental-Result-Code is present */ + CHECK( 0, fd_dict_search ( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Experimental-Result-Code", &avp_model, ENOENT ) ); + CHECK( 0, fd_msg_search_avp( er, avp_model, &erc ) ); + + /* Check the Experimental-Result-Code AVP value is 5000 */ + CHECK( 0, fd_msg_avp_hdr ( erc, &avpdata ) ); + CHECK( 5000, avpdata->avp_value->u32 ); + + /* Free msg */ + CHECK( 0, fd_msg_free( msg ) ); + } + /* Check IPv4 -> IPv6 and IPv6->IPv4 mapping */ { struct in_addr i4;