# HG changeset patch # User Sebastien Decugis # Date 1257141282 -32400 # Node ID 6486e97f56ae1a23c9d75909d80ea3521ce5b59d # Parent 0e2b57789361eac0586e5498660f095777636021 Added test for modified message parsing diff -r 0e2b57789361 -r 6486e97f56ae freeDiameter/CMakeLists.txt --- a/freeDiameter/CMakeLists.txt Fri Oct 30 17:23:06 2009 +0900 +++ b/freeDiameter/CMakeLists.txt Mon Nov 02 14:54:42 2009 +0900 @@ -19,6 +19,7 @@ messages.c queues.c peers.c + p_ce.c p_expiry.c p_out.c p_psm.c diff -r 0e2b57789361 -r 6486e97f56ae freeDiameter/fD.h --- a/freeDiameter/fD.h Fri Oct 30 17:23:06 2009 +0900 +++ b/freeDiameter/fD.h Mon Nov 02 14:54:42 2009 +0900 @@ -242,6 +242,9 @@ int fd_p_sr_fetch(struct sr_list * srlist, uint32_t hbh, struct msg **req); void fd_p_sr_failover(struct sr_list * srlist); +/* Capabilities Exchange */ +int fd_p_ce_merge(struct fd_peer * peer, struct msg * cer); + /* Active peers -- routing process should only ever take the read lock, the write lock is managed by PSMs */ extern struct fd_list fd_g_activ_peers; extern pthread_rwlock_t fd_g_activ_peers_rw; /* protect the list */ diff -r 0e2b57789361 -r 6486e97f56ae freeDiameter/p_ce.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/freeDiameter/p_ce.c Mon Nov 02 14:54:42 2009 +0900 @@ -0,0 +1,45 @@ +/********************************************************************************************************* +* Software License Agreement (BSD License) * +* Author: Sebastien Decugis * +* * +* Copyright (c) 2009, WIDE Project and NICT * +* All rights reserved. * +* * +* Redistribution and use of this software in source and binary forms, with or without modification, are * +* permitted provided that the following conditions are met: * +* * +* * Redistributions of source code must retain the above * +* copyright notice, this list of conditions and the * +* following disclaimer. * +* * +* * Redistributions in binary form must reproduce the above * +* copyright notice, this list of conditions and the * +* following disclaimer in the documentation and/or other * +* materials provided with the distribution. * +* * +* * Neither the name of the WIDE Project or NICT nor the * +* names of its contributors may be used to endorse or * +* promote products derived from this software without * +* specific prior written permission of WIDE Project and * +* NICT. * +* * +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED * +* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A * +* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR * +* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * +* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * +* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * +* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * +*********************************************************************************************************/ + +#include "fD.h" + +/* This file contains code to handle Capabilities Exchange messages (CER and CEA) */ + +int fd_p_ce_merge(struct fd_peer * peer, struct msg * cer) +{ + /* Save all information from the CER into the peer structure, after cleaning old information if any */ + + return ENOTSUP; +} diff -r 0e2b57789361 -r 6486e97f56ae freeDiameter/p_out.c --- a/freeDiameter/p_out.c Fri Oct 30 17:23:06 2009 +0900 +++ b/freeDiameter/p_out.c Mon Nov 02 14:54:42 2009 +0900 @@ -154,7 +154,13 @@ cnx = peer->p_cnxctx; /* Do send the message */ - CHECK_FCT( do_send(msg, cnx, hbh, peer ? &peer->p_sr : NULL) ); + CHECK_FCT_DO( do_send(msg, cnx, hbh, peer ? &peer->p_sr : NULL), + { + fd_log_debug("An error occurred while sending this message, it is lost:\n"); + fd_msg_dump_walk(NONE, *msg); + fd_msg_free(*msg); + *msg = NULL; + } ); } return 0; diff -r 0e2b57789361 -r 6486e97f56ae freeDiameter/p_psm.c --- a/freeDiameter/p_psm.c Fri Oct 30 17:23:06 2009 +0900 +++ b/freeDiameter/p_psm.c Mon Nov 02 14:54:42 2009 +0900 @@ -358,11 +358,23 @@ } /* Link-local message: They must be understood by our dictionary */ + { + int ret; + CHECK_FCT_DO( ret = fd_msg_parse_or_error( &msg ), + { + if ((ret == EBADMSG) && (msg != NULL)) { + /* msg now contains an answer message to send back */ + CHECK_FCT_DO( fd_out_send(&msg, peer->p_cnxctx, peer), /* In case of error the message has already been dumped */ ); + } + if (msg) { + CHECK_FCT_DO( fd_msg_free(msg), /* continue */); + } + goto psm_loop; + } ); + } - TODO("Check if it is a local message (CER, DWR, ...)"); - TODO("If not, check we are in OPEN state"); - TODO("Update expiry timer if needed"); - TODO("Handle the message"); + /* Handle the LL message and update the expiry timer appropriately */ + TODO("..."); } /* The connection object is broken */ @@ -400,6 +412,12 @@ case STATE_CLOSED: TODO("Handle the CER, validate the peer if needed (and set expiry), set the alt_fifo in the connection, reply a CEA, eventually handshake, move to OPEN or REOPEN state"); /* In case of error : DIAMETER_UNKNOWN_PEER */ + + CHECK_FCT_DO( fd_p_ce_merge(peer, params->cer), + { + + } ); + break; case STATE_WAITCNXACK: diff -r 0e2b57789361 -r 6486e97f56ae freeDiameter/tests/testmesg.c --- a/freeDiameter/tests/testmesg.c Fri Oct 30 17:23:06 2009 +0900 +++ b/freeDiameter/tests/testmesg.c Mon Nov 02 14:54:42 2009 +0900 @@ -282,7 +282,14 @@ ADD_RULE(gavp, 73565, "AVP Test - os", RULE_REQUIRED, 2, 3, 0); ADD_RULE(gavp, 73565, "AVP Test - enumos", RULE_OPTIONAL, 0, 1, 0); ADD_RULE(gavp, 73565, "AVP Test - grouped", RULE_FIXED_TAIL, -1, 1, 1); - + /* ABNF : + < no vendor - f32 > + < i64 > + < enumi32 > + 2*3 { os } + *1 [ enumos ] + < grouped > + */ #if 0 fd_dict_dump_object ( gavp ); #endif @@ -727,9 +734,9 @@ /* Now test the msg_parse_rule function */ { - struct dict_object * rule; + struct fd_pei pei; - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) ); /* Use the "AVP Test - rules" AVP to test the rules */ { @@ -748,38 +755,50 @@ ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - grouped" ); /* Check the message is still conform */ - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) ); /* The first avp is optional in fixed position, so remove it and check the message is still OK */ CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &childavp, NULL) ); CHECK( 0, fd_msg_free ( childavp ) ); - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) ); ADD_AVP( tavp, MSG_BRW_FIRST_CHILD, childavp, 0, "AVP Test - no vendor - f32" ); /* Now break some rules and check it is detected */ - #define CHECK_CONFLICT( _msg, _ruleavp, _avpvendor ) { \ - struct dict_object * _rule; \ - CHECK( EBADMSG, fd_msg_parse_rules( _msg, fd_g_config->cnf_dict, &_rule ) ); \ - if ((_ruleavp) == NULL) { \ - CHECK( NULL, _rule); \ + #define CHECK_CONFLICT( _msg, _error, _conflictavp_name, _conflictavp_vnd ) { \ + struct fd_pei _pei; \ + CHECK( EBADMSG, fd_msg_parse_rules( _msg, fd_g_config->cnf_dict, &_pei ) ); \ + if (_error) { \ + CHECK( 0, strcmp( _error, _pei.pei_errcode ) ); \ + } \ + if ((_conflictavp_name) == NULL) { \ + CHECK( NULL, _pei.pei_avp); \ } else { \ - struct dict_rule_data _ruledata; \ + struct dict_avp_request _req = { (_conflictavp_vnd), 0, (_conflictavp_name) }; \ struct dict_object * _avp; \ - struct dict_avp_request _req = { (_avpvendor), 0, (_ruleavp) }; \ + struct dict_object * _conflict; \ + CHECK( 1, (_pei.pei_avp) ? 1 : 0 ); \ + CHECK( 0, fd_msg_model( _pei.pei_avp, &_conflict ) ); \ CHECK( 0, fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME_AND_VENDOR, &_req, &_avp, ENOENT)); \ - CHECK( 0, fd_dict_getval( _rule, &_ruledata ) ); \ - CHECK( _avp, _ruledata.rule_avp ); \ + CHECK( _avp, _conflict ); \ } \ } + /* ABNF : + < no vendor - f32 > + < i64 > + < enumi32 > + 2*3 { os } + *1 [ enumos ] + < grouped > + */ { /* Test the FIXED_HEAD rules positions: add another AVP before the third */ CHECK( 0, fd_msg_browse ( tavp, MSG_BRW_FIRST_CHILD, &tempavp, NULL) ); /* tempavp is the novendor avp */ CHECK( 0, fd_msg_browse ( tempavp, MSG_BRW_NEXT, &tempavp, NULL) ); /* tempavp is the i64 avp */ ADD_AVP( tempavp, MSG_BRW_NEXT, childavp, 73565, "AVP Test - os" ); - CHECK_CONFLICT( msg, "AVP Test - enumi32", 73565 ); + CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - enumi32", 73565 ); /* Now remove this AVP */ CHECK( 0, fd_msg_free ( childavp ) ); @@ -789,7 +808,7 @@ CHECK( 0, fd_msg_browse ( tempavp, MSG_BRW_NEXT, &childavp, NULL) ); /* childavp is the enumi32 avp */ CHECK( 0, fd_msg_free ( childavp ) ); - CHECK_CONFLICT( msg, "AVP Test - enumi32", 73565 ); + CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - enumi32", 73565 ); /* Add the AVP back */ ADD_AVP( tempavp, MSG_BRW_NEXT, childavp, 73565, "AVP Test - enumi32" ); @@ -800,7 +819,7 @@ CHECK( 0, fd_msg_browse ( childavp, MSG_BRW_NEXT, &tempavp, NULL) ); /* tempavp is the os avp */ CHECK( 0, fd_msg_free ( tempavp ) ); - CHECK_CONFLICT( msg, "AVP Test - os", 73565 ); /* The rule requires at least 2 AVP, we have only 1 */ + CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - os", 73565 ); /* The rule requires at least 2 AVP, we have only 1 */ /* Now add this AVP */ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" ); @@ -810,7 +829,7 @@ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" ); ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - os" ); - CHECK_CONFLICT( msg, "AVP Test - os", 73565 ); /* The rule requires at most 3 AVP, we have 4 */ + CHECK_CONFLICT( msg, "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES", "AVP Test - os", 73565 ); /* The rule requires at most 3 AVP, we have 4 */ /* Now delete these AVP */ CHECK( 0, fd_msg_free ( tempavp ) ); @@ -823,12 +842,12 @@ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" ); /* The message is still conform */ - CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &rule ) ); + CHECK( 0, fd_msg_parse_rules( msg, fd_g_config->cnf_dict, &pei ) ); /* Now break the rule */ ADD_AVP( childavp, MSG_BRW_NEXT, tempavp, 73565, "AVP Test - enumos" ); - CHECK_CONFLICT( msg, "AVP Test - enumos", 73565 ); /* The rule requires at most 3 AVP, we have 4 */ + CHECK_CONFLICT( msg, "DIAMETER_AVP_OCCURS_TOO_MANY_TIMES", "AVP Test - enumos", 73565 ); /* Now delete this AVP */ CHECK( 0, fd_msg_free ( tempavp ) ); @@ -838,7 +857,7 @@ /* Test the RULE_FIXED_TAIL rules positions: add another AVP at the end */ ADD_AVP( tavp, MSG_BRW_LAST_CHILD, childavp, 73565, "AVP Test - os" ); - CHECK_CONFLICT( msg, "AVP Test - grouped", 73565 ); + CHECK_CONFLICT( msg, "DIAMETER_MISSING_AVP", "AVP Test - grouped", 73565 ); /* Now remove this AVP */ CHECK( 0, fd_msg_free ( childavp ) ); diff -r 0e2b57789361 -r 6486e97f56ae libfreeDiameter/messages.c --- a/libfreeDiameter/messages.c Fri Oct 30 17:23:06 2009 +0900 +++ b/libfreeDiameter/messages.c Mon Nov 02 14:54:42 2009 +0900 @@ -1864,8 +1864,34 @@ /* Create an empty AVP of a given model (to use in Failed-AVP) */ static struct avp * empty_avp(struct dict_object * model_avp) { - TODO("Create the AVP instance and set a 0 value"); - return NULL; + struct avp * avp = NULL; + struct dict_avp_data avp_info; + union avp_value val; + char os[1] = { '\0' }; + + /* Create an instance */ + CHECK_FCT_DO( fd_msg_avp_new(model_avp, 0, &avp ), return NULL ); + + /* Type of the AVP */ + CHECK_FCT_DO( fd_dict_getval(model_avp, &avp_info), return NULL ); + + /* Prepare the empty value */ + memset(&val, 0, sizeof(val)); + switch (avp_info.avp_basetype) { + case AVP_TYPE_OCTETSTRING: + val.os.data = os; + val.os.len = sizeof(os); + case AVP_TYPE_INTEGER32: + case AVP_TYPE_INTEGER64: + case AVP_TYPE_UNSIGNED32: + case AVP_TYPE_UNSIGNED64: + case AVP_TYPE_FLOAT32: + case AVP_TYPE_FLOAT64: + CHECK_FCT_DO( fd_msg_avp_setvalue(avp, &val), return NULL ); + /* For AVP_TYPE_GROUPED we don't do anything */ + } + + return avp; } /* Check that a list of AVPs is compliant with a given rule -- will be iterated on the list of rules */ @@ -2055,12 +2081,12 @@ { TRACE_ENTRY("%p %p %p", object, dict, error_info); + if (error_info) + memset(error_info, 0, sizeof(struct fd_pei)); + /* Resolve the dictionary objects when missing. This also validates the object. */ CHECK_FCT( fd_msg_parse_dict ( object, dict ) ); - if (error_info) - memset(error_info, 0, sizeof(struct fd_pei)); - /* Call the recursive function */ return parserules_do ( dict, object, error_info, 1 ) ; } @@ -2186,7 +2212,7 @@ if (app == NULL) { /* In that case, maybe we should answer a DIAMETER_APPLICATION_UNSUPPORTED error ? Do we do this here ? */ - TRACE_DEBUG(NONE, "Reply DIAMETER_APPLICATION_UNSUPPORTED if it's a request ?"); + TODO("Reply DIAMETER_APPLICATION_UNSUPPORTED if it's a request ?"); } /* So start browsing the message */