Mercurial > hg > freeDiameter
changeset 66:dcbd5b5ee55c
Added handling for DWR/DWA
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Mon, 30 Nov 2009 17:28:22 +0900 |
parents | 114fac60bc8e |
children | f0215a3edca9 |
files | freeDiameter/fD.h freeDiameter/messages.c freeDiameter/p_ce.c freeDiameter/p_dw.c freeDiameter/p_psm.c |
diffstat | 5 files changed, 128 insertions(+), 19 deletions(-) [+] |
line wrap: on
line diff
--- a/freeDiameter/fD.h Mon Nov 30 16:16:49 2009 +0900 +++ b/freeDiameter/fD.h Mon Nov 30 17:28:22 2009 +0900 @@ -87,6 +87,10 @@ /* Messages */ int fd_msg_init(void); +struct dict_object * fd_dict_avp_OSI; /* Origin-State-Id */ +struct dict_object * fd_dict_cmd_CER; /* Capabilities-Exchange-Request */ +struct dict_object * fd_dict_cmd_DWR; /* Device-Watchdog-Request */ +struct dict_object * fd_dict_cmd_DPR; /* Disconnect-Peer-Request */ /* Global message queues */ extern struct fifo * fd_g_incoming; /* all messages received from other peers, except local messages (CER, ...) */
--- a/freeDiameter/messages.c Mon Nov 30 16:16:49 2009 +0900 +++ b/freeDiameter/messages.c Mon Nov 30 17:28:22 2009 +0900 @@ -37,11 +37,14 @@ static struct dict_object * dict_avp_OH = NULL; /* Origin-Host */ static struct dict_object * dict_avp_OR = NULL; /* Origin-Realm */ -static struct dict_object * dict_avp_OSI = NULL; /* Origin-State-Id */ -static struct dict_object * dict_avp_RC = NULL; /* Result-Code */ static struct dict_object * dict_avp_EM = NULL; /* Error-Message */ 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 */ +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 */ +struct dict_object * fd_dict_cmd_DPR = NULL; /* Disconnect-Peer-Request */ /* Resolve the dictionary objects */ int fd_msg_init(void) @@ -51,13 +54,18 @@ /* Initialize the dictionary objects that we may use frequently */ CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Host", &dict_avp_OH , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-Realm", &dict_avp_OR , ENOENT) ); - CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &dict_avp_OSI , ENOENT) ); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Origin-State-Id", &fd_dict_avp_OSI , ENOENT) ); CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Result-Code", &dict_avp_RC , ENOENT) ); 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_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &fd_dict_cmd_CER, ENOENT ) ); + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Device-Watchdog-Request", &fd_dict_cmd_DWR, ENOENT ) ); + CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Disconnect-Peer-Request", &fd_dict_cmd_DPR, ENOENT ) ); + + return 0; } @@ -99,7 +107,7 @@ if (osi) { /* Create the Origin-State-Id AVP */ - CHECK_FCT( fd_msg_avp_new( dict_avp_OSI, 0, &avp_OSI ) ); + CHECK_FCT( fd_msg_avp_new( fd_dict_avp_OSI, 0, &avp_OSI ) ); /* Set its value */ memset(&val, 0, sizeof(val));
--- a/freeDiameter/p_ce.c Mon Nov 30 16:16:49 2009 +0900 +++ b/freeDiameter/p_ce.c Mon Nov 30 17:28:22 2009 +0900 @@ -535,13 +535,11 @@ /* Create a CER message for sending */ static int create_CER(struct fd_peer * peer, struct cnxctx * cnx, struct msg ** cer) { - struct dict_object * dictobj = NULL; int isi_tls = 0; int isi_none = 0; /* Find CER dictionary object and create an instance */ - CHECK_FCT( fd_dict_search ( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Capabilities-Exchange-Request", &dictobj, ENOENT ) ); - CHECK_FCT( fd_msg_new ( dictobj, MSGFL_ALLOC_ETEID, cer ) ); + CHECK_FCT( fd_msg_new ( fd_dict_cmd_CER, MSGFL_ALLOC_ETEID, cer ) ); /* Do we need Inband-Security-Id AVPs ? */ if (!fd_cnx_getTLS(cnx)) {
--- a/freeDiameter/p_dw.c Mon Nov 30 16:16:49 2009 +0900 +++ b/freeDiameter/p_dw.c Mon Nov 30 17:28:22 2009 +0900 @@ -37,29 +37,130 @@ /* This file contains code to handle Device Watchdog messages (DWR and DWA) */ +/* Check the value of Origin-State-Id is consistent in a DWR or DWA -- we just log if it is not the case */ +static void check_state_id(struct msg * msg, struct fd_peer * peer) +{ + struct avp * osi; + /* Check if the request contains the Origin-State-Id */ + CHECK_FCT_DO( fd_msg_search_avp ( msg, fd_dict_avp_OSI, &osi ), return ); + if (osi) { + /* Check the value is consistent with the saved one */ + struct avp_hdr * hdr; + CHECK_FCT_DO( fd_msg_avp_hdr( osi, &hdr ), return ); + if (hdr->avp_value == NULL) { + /* This is a sanity check */ + TRACE_DEBUG(NONE, "BUG: Unset value in Origin-State-Id in DWR / DWA"); + fd_msg_dump_one(NONE, osi); + ASSERT(0); /* To check if this really happens, and understand why... */ + } + + if (peer->p_hdr.info.runtime.pir_orstate != hdr->avp_value->u32) { + fd_log_debug("Received a new Origin-State-Id from peer %s! (%x / %x)\n", + peer->p_hdr.info.pi_diamid, + hdr->avp_value->u32, + peer->p_hdr.info.runtime.pir_orstate ); + } + } +} + +/* Create and send a DWR */ +static int send_DWR(struct fd_peer * peer) +{ + struct msg * msg = NULL; + + /* Create a new DWR instance */ + CHECK_FCT( fd_msg_new ( fd_dict_cmd_DWR, MSGFL_ALLOC_ETEID, &msg ) ); + + /* Add the content of the message (only the origin) */ + CHECK_FCT( fd_msg_add_origin ( msg, 1 ) ); + + /* Now send this message */ + CHECK_FCT( fd_out_send(&msg, NULL, peer) ); + + /* And mark the pending DW */ + peer->p_flags.pf_dw_pending = 1; + + return 0; +} /* Handle an incoming message */ int fd_p_dw_handle(struct msg ** msg, int req, struct fd_peer * peer) { - TODO("Handle depending on DWR or DWA and peer state"); + int reset_tmr = 0; + + TRACE_ENTRY("%p %d %p", msg, req, peer); + + /* Check the value of OSI for information */ + check_state_id(*msg, peer); + + if (req) { + /* If we receive a DWR, send back a DWA */ + CHECK_FCT( fd_msg_new_answer_from_req ( fd_g_config->cnf_dict, msg, 0 ) ); + CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_SUCCESS", NULL, NULL, 0 ) ); + CHECK_FCT( fd_msg_add_origin ( *msg, 1 ) ); + CHECK_FCT( fd_out_send( msg, peer->p_cnxctx, peer) ); + + } else { + /* Just discard the DWA */ + CHECK_FCT_DO( fd_msg_free(*msg), /* continue */ ); + *msg = NULL; + + /* And clear the pending DW flag */ + peer->p_flags.pf_dw_pending = 0; + } - return ENOTSUP; + /* Now update timeout */ + if (req) { + /* Update timeout only if we did not already send a DWR ourselves */ + reset_tmr = !peer->p_flags.pf_dw_pending; + } else { + /* Reset the timer */ + reset_tmr = 1; + } + if (reset_tmr) { + fd_psm_next_timeout(peer, 1, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw); + } + + /* If we are in REOPEN state, increment the counter */ + if (peer->p_hdr.info.runtime.pir_state == STATE_REOPEN) { + peer->p_flags.pf_reopen_cnt += 1; + + if (peer->p_flags.pf_reopen_cnt) { + /* Send a new DWR */ + CHECK_FCT( send_DWR(peer) ); + } else { + /* Move to OPEN state */ + CHECK_FCT( fd_psm_change_state(peer, STATE_OPEN) ); + } + } + + return 0; } -/* Handle a timeout in the PSM : send DWR, fail the peer, manage reopen state */ +/* Handle a timeout in the PSM (OPEN or REOPEN state only) */ int fd_p_dw_timeout(struct fd_peer * peer) { - TODO("..."); + if (peer->p_flags.pf_dw_pending) { + /* We have sent a DWR and received no answer during TwTimer */ + CHECK_FCT( fd_psm_change_state(peer, STATE_SUSPECT) ); + fd_psm_next_timeout(peer, 0, 2 * (peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw) ); + } else { + /* The timeout has expired, send a DWR */ + CHECK_FCT( send_DWR(peer) ); + fd_psm_next_timeout(peer, 0, peer->p_hdr.info.config.pic_twtimer ?: fd_g_config->cnf_timer_tw ); + } - return ENOTSUP; + + return 0; } /* Handle DW exchanges after the peer has come alive again */ int fd_p_dw_reopen(struct fd_peer * peer) { - TODO("..."); + peer->p_flags.pf_reopen_cnt = 1; + CHECK_FCT( send_DWR(peer) ); - return ENOTSUP; + return 0; }
--- a/freeDiameter/p_psm.c Mon Nov 30 16:16:49 2009 +0900 +++ b/freeDiameter/p_psm.c Mon Nov 30 17:28:22 2009 +0900 @@ -408,7 +408,7 @@ case STATE_REOPEN: case STATE_SUSPECT: case STATE_CLOSING: - TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state"); + TRACE_DEBUG(FULL, "Accepted a message while not in OPEN state... "); /* The standard situation : */ case STATE_OPEN: /* We received a valid routable message, update the expiry timer */ @@ -628,18 +628,16 @@ goto psm_loop; case STATE_WAITCNXACK_ELEC: - /* Abort the initiating side */ fd_p_cnx_abort(peer, 0); - - /* Handle receiver side */ + /* Process the receiver side */ CHECK_FCT_DO( fd_p_ce_process_receiver(peer), goto psm_end ); goto psm_loop; } } /* Default action : the handling has not yet been implemented. [for debug only] */ - TODO("Missing handler in PSM : '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event)); + TODO("Missing handler in PSM for '%s'\t<-- '%s'", STATE_STR(peer->p_hdr.info.runtime.pir_state), fd_pev_str(event)); goto psm_loop; psm_end: