Mercurial > hg > freeDiameter
changeset 78:a58f0757c06a
Added code for DPR/DPA
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 01 Dec 2009 16:24:06 +0900 |
parents | 33d8bed6a9d7 |
children | d273a2ce19c8 |
files | freeDiameter/fD.h freeDiameter/messages.c freeDiameter/p_ce.c freeDiameter/p_cnx.c freeDiameter/p_dp.c freeDiameter/p_expiry.c freeDiameter/p_psm.c freeDiameter/peers.c include/freeDiameter/freeDiameter.h |
diffstat | 9 files changed, 132 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/freeDiameter/fD.h Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/fD.h Tue Dec 01 16:24:06 2009 +0900 @@ -90,6 +90,7 @@ 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_avp_DC; /* Disconnect-Cause */ struct dict_object * fd_dict_cmd_DPR; /* Disconnect-Peer-Request */ /* Global message queues */ @@ -256,7 +257,7 @@ /* Peer state machine */ int fd_psm_start(); int fd_psm_begin(struct fd_peer * peer ); -int fd_psm_terminate(struct fd_peer * peer ); +int fd_psm_terminate(struct fd_peer * peer, char * reason ); void fd_psm_abord(struct fd_peer * peer ); void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay); int fd_psm_change_state(struct fd_peer * peer, int new_state); @@ -286,7 +287,7 @@ int fd_p_dw_timeout(struct fd_peer * peer); int fd_p_dw_reopen(struct fd_peer * peer); int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer); -int fd_p_dp_initiate(struct fd_peer * peer); +int fd_p_dp_initiate(struct fd_peer * peer, char * reason); /* 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;
--- a/freeDiameter/messages.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/messages.c Tue Dec 01 16:24:06 2009 +0900 @@ -44,6 +44,7 @@ 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_avp_DC = NULL; /* Disconnect-Cause */ struct dict_object * fd_dict_cmd_DPR = NULL; /* Disconnect-Peer-Request */ /* Resolve the dictionary objects */ @@ -61,6 +62,8 @@ 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, "Disconnect-Cause", &fd_dict_avp_DC , 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 ) );
--- a/freeDiameter/p_ce.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/p_ce.c Tue Dec 01 16:24:06 2009 +0900 @@ -762,7 +762,7 @@ CHECK_FCT_DO( (*peer->p_cb2)( &peer->p_hdr.info ), { TRACE_DEBUG(INFO, "Validation callback rejected the peer %s after handshake", peer->p_hdr.info.pi_diamid); - CHECK_FCT( fd_psm_terminate( peer ) ); + CHECK_FCT( fd_psm_terminate( peer, "DO_NOT_WANT_TO_TALK_TO_YOU" ) ); return 0; } ); }
--- a/freeDiameter/p_cnx.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/p_cnx.c Tue Dec 01 16:24:06 2009 +0900 @@ -87,7 +87,7 @@ ret = getaddrinfo(peer->p_hdr.info.pi_diamid, NULL, &hints, &ai); if (ret) { fd_log_debug("Unable to resolve address for peer '%s' (%s), aborting\n", peer->p_hdr.info.pi_diamid, gai_strerror(ret)); - fd_psm_terminate( peer ); + fd_psm_terminate( peer, NULL ); return 0; } @@ -109,7 +109,7 @@ /* Now check we have at least one address to attempt */ if (FD_IS_LIST_EMPTY(&peer->p_hdr.info.pi_endpoints)) { fd_log_debug("No address %savailable to connect to peer '%s', aborting\n", peer->p_hdr.info.config.pic_flags.pro3 ? "in the configured family " : "", peer->p_hdr.info.pi_diamid); - fd_psm_terminate( peer ); + fd_psm_terminate( peer, NULL ); return 0; }
--- a/freeDiameter/p_dp.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/p_dp.c Tue Dec 01 16:24:06 2009 +0900 @@ -40,18 +40,116 @@ /* Handle a received message */ int fd_p_dp_handle(struct msg ** msg, int req, struct fd_peer * peer) { - TODO("Handle depending on DPR or DPA and peer state"); + int delay = 0; + TRACE_ENTRY("%p %d %p", msg, req, peer); - return ENOTSUP; + if (req) { + /* We received a DPR, save the Disconnect-Cause and terminate the connection */ + struct avp * dc; + + CHECK_FCT_DO( fd_msg_search_avp ( *msg, fd_dict_avp_DC, &dc ), return ); + if (dc) { + /* Check the value is consistent with the saved one */ + struct avp_hdr * hdr; + CHECK_FCT_DO( fd_msg_avp_hdr( dc, &hdr ), return ); + if (hdr->avp_value == NULL) { + /* This is a sanity check */ + TRACE_DEBUG(NONE, "BUG: Unset value in Disconnect-Cause in DPR"); + fd_msg_dump_one(NONE, dc); + ASSERT(0); /* To check if this really happens, and understand why... */ + } + + peer->p_hdr.info.runtime.pir_lastDC = hdr->avp_value->u32; + } + if (TRACE_BOOL(INFO)) { + if (dc) { + struct dict_object * dictobj = NULL; + struct dict_enumval_request er; + memset(&er, 0, sizeof(er)); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT ) ); + er.search.enum_value.u32 = peer->p_hdr.info.runtime.pir_lastDC; + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, 0 ) ); + if (dictobj) { + CHECK_FCT( fd_dict_getval( dictobj, &er.search ) ); + fd_log_debug("Peer '%s' sent a DPR with cause: %s\n", peer->p_hdr.info.pi_diamid, er.search.enum_name); + } else { + fd_log_debug("Peer '%s' sent a DPR with unknown cause: %u\n", peer->p_hdr.info.pi_diamid, peer->p_hdr.info.runtime.pir_lastDC); + } + } else { + fd_log_debug("Peer '%s' sent a DPR without Disconnect-Cause AVP\n", peer->p_hdr.info.pi_diamid); + } + } + + /* Now reply with a DPA */ + 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, 0 ) ); + + /* Move to CLOSING state to failover outgoing messages (and avoid failing the DPA...) */ + CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) ); + + /* Now send the DPA */ + CHECK_FCT( fd_out_send( msg, NULL, peer) ); + + } else { + /* We received a DPA */ + if (peer->p_hdr.info.runtime.pir_state != STATE_CLOSING) { + TRACE_DEBUG(INFO, "Ignore DPA received in state %s", STATE_STR(peer->p_hdr.info.runtime.pir_state)); + } + + } + + if (*msg) { + /* In theory, we should control the Result-Code AVP. But since we will not go back to OPEN state here, let's skip it */ + CHECK_FCT_DO( fd_msg_free( *msg ), /* continue */ ); + *msg = NULL; + } + + /* The calling function handles cleaning the PSM and terminating the peer */ + return 0; } /* Start disconnection of a peer: send DPR */ -int fd_p_dp_initiate(struct fd_peer * peer) +int fd_p_dp_initiate(struct fd_peer * peer, char * reason) { - TODO("Create the DPR message"); - TODO("Send it"); - TODO("Mark the peer as CLOSING"); - TODO("Reset the timer"); + struct msg * msg = NULL; + struct dict_object * dictobj = NULL; + struct avp * avp = NULL; + struct dict_enumval_request er; + union avp_value val; + + TRACE_ENTRY("%p %p", peer, reason); + + /* Create a new DWR instance */ + CHECK_FCT( fd_msg_new ( fd_dict_cmd_DPR, MSGFL_ALLOC_ETEID, &msg ) ); + + /* Add the Origin information */ + CHECK_FCT( fd_msg_add_origin ( msg, 0 ) ); + + /* Add the Disconnect-Cause */ + CHECK_FCT( fd_msg_avp_new ( fd_dict_avp_DC, 0, &avp ) ); - return ENOTSUP; + /* Search the value in the dictionary */ + memset(&er, 0, sizeof(er)); + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_TYPE, TYPE_OF_AVP, fd_dict_avp_DC, &er.type_obj, ENOENT ) ); + er.search.enum_name = reason ?: "REBOOTING"; + CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &er, &dictobj, ENOENT ) ); + CHECK_FCT( fd_dict_getval( dictobj, &er.search ) ); + + /* Set the value in the AVP */ + val.u32 = er.search.enum_value.u32; + CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) ); + CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) ); + + /* Save the value also in the peer */ + peer->p_hdr.info.runtime.pir_lastDC = val.u32; + + /* Now send this message */ + CHECK_FCT( fd_out_send(&msg, NULL, peer) ); + + /* Update the peer state and timer */ + CHECK_FCT( fd_psm_change_state(peer, STATE_CLOSING) ); + fd_psm_next_timeout(peer, 0, DPR_TIMEOUT); + + return 0; }
--- a/freeDiameter/p_expiry.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/p_expiry.c Tue Dec 01 16:24:06 2009 +0900 @@ -131,7 +131,7 @@ /* Now, the first peer in the list is expired; signal it */ fd_list_unlink( &first->p_expiry ); - CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, NULL), goto error ); + CHECK_FCT_DO( fd_event_send(first->p_events, FDEVP_TERMINATE, 0, "DO_NOT_WANT_TO_TALK_TO_YOU"), goto error ); } while (1);
--- a/freeDiameter/p_psm.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/p_psm.c Tue Dec 01 16:24:06 2009 +0900 @@ -93,9 +93,8 @@ if (peer->p_cb2) { CHECK_FCT_DO( (*peer->p_cb2)(&peer->p_hdr.info), { - TRACE_DEBUG(FULL, "Validation failed, moving to state CLOSING"); - peer->p_hdr.info.runtime.pir_state = STATE_CLOSING; - fd_psm_terminate(peer); + TRACE_DEBUG(FULL, "Validation failed, terminating the connection"); + fd_psm_terminate(peer, "DO_NOT_WANT_TO_TALK_TO_YOU" ); } ); peer->p_cb2 = NULL; return 0; @@ -160,6 +159,10 @@ } break; + case FDEVP_TERMINATE: + /* Do not free the string since it is a constant */ + break; + case FDEVP_CNX_INCOMING: { struct cnx_incoming * evd = ev->data; CHECK_FCT_DO( fd_msg_free(evd->cer), /* continue */); @@ -215,6 +218,8 @@ /* Set timeout timer of next event */ void fd_psm_next_timeout(struct fd_peer * peer, int add_random, int delay) { + TRACE_DEBUG(FULL, "Peer timeout reset to %d seconds%s", delay, add_random ? " (+/- 2)" : "" ); + /* Initialize the timer */ CHECK_POSIX_DO( clock_gettime( CLOCK_REALTIME, &peer->p_psm_timer ), ASSERT(0) ); @@ -235,8 +240,6 @@ peer->p_psm_timer.tv_sec += delay; - TRACE_DEBUG(FULL, "Peer timeout reset to %d seconds%s", delay, add_random ? " (+/- 2)" : "" ); - #ifdef SLOW_PSM /* temporary for debug */ peer->p_psm_timer.tv_sec += 10; @@ -347,7 +350,7 @@ case STATE_OPEN: case STATE_REOPEN: /* We cannot just close the conenction, we have to send a DPR first */ - CHECK_FCT_DO( fd_p_dp_initiate(peer), goto psm_end ); + CHECK_FCT_DO( fd_p_dp_initiate(peer, ev_data), goto psm_end ); goto psm_loop; /* @@ -470,6 +473,8 @@ case CC_DISCONNECT_PEER: CHECK_FCT_DO( fd_p_dp_handle(&msg, (hdr->msg_flags & CMD_FLAG_REQUEST), peer), goto psm_end ); + if (peer->p_hdr.info.runtime.pir_state == STATE_CLOSING) + goto psm_end; break; case CC_DEVICE_WATCHDOG: @@ -711,13 +716,13 @@ } /* End the PSM (clean ending) */ -int fd_psm_terminate(struct fd_peer * peer ) +int fd_psm_terminate(struct fd_peer * peer, char * reason ) { TRACE_ENTRY("%p", peer); CHECK_PARAMS( CHECK_PEER(peer) ); if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) { - CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, NULL) ); + CHECK_FCT( fd_event_send(peer->p_events, FDEVP_TERMINATE, 0, reason) ); } else { TRACE_DEBUG(FULL, "Peer '%s' was already terminated", peer->p_hdr.info.pi_diamid); }
--- a/freeDiameter/peers.c Tue Dec 01 14:30:29 2009 +0900 +++ b/freeDiameter/peers.c Tue Dec 01 16:24:06 2009 +0900 @@ -254,7 +254,7 @@ struct fd_peer * peer = (struct fd_peer *)li; if (peer->p_hdr.info.runtime.pir_state != STATE_ZOMBIE) { - CHECK_FCT_DO( fd_psm_terminate(peer), /* continue */ ); + CHECK_FCT_DO( fd_psm_terminate(peer, "REBOOTING"), /* continue */ ); } else { li = li->prev; /* to avoid breaking the loop */ fd_list_unlink(&peer->p_hdr.chain);
--- a/include/freeDiameter/freeDiameter.h Tue Dec 01 14:30:29 2009 +0900 +++ b/include/freeDiameter/freeDiameter.h Tue Dec 01 16:24:06 2009 +0900 @@ -337,6 +337,8 @@ struct fd_list pir_apps; /* applications advertised by the remote peer, except relay (pi_flags.relay) */ int pir_isi; /* Inband-Security-Id advertised (PI_SEC_* bits) */ + uint32_t pir_lastDC; /* The last Disconnect-Cause value received */ + int pir_proto; /* The L4 protocol currently used with the peer (IPPROTO_TCP or IPPROTO_SCTP) */ const gnutls_datum_t *pir_cert_list; /* The (valid) credentials that the peer has presented, or NULL if TLS is not used */ /* This is inspired from http://www.gnu.org/software/gnutls/manual/gnutls.html#ex_003ax509_002dinfo