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:
"Welcome to our mercurial repository"