diff libfreeDiameter/messages.c @ 7:e5af94b04946

Added dispatch module and tests
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 04 Sep 2009 18:05:25 +0900
parents 883311bf7df3
children 0e2b57789361
line wrap: on
line diff
--- a/libfreeDiameter/messages.c	Thu Sep 03 16:03:25 2009 +0900
+++ b/libfreeDiameter/messages.c	Fri Sep 04 18:05:25 2009 +0900
@@ -2137,3 +2137,97 @@
 }
 
 /***************************************************************************************************************/
+/* Macro to check if further callbacks must be called */
+#define TEST_ACTION_STOP()					\
+	if ((*msg == NULL) || (*action != DISP_ACT_CONT))	\
+		goto no_error;
+
+/* Call all dispatch callbacks for a given message */
+int fd_msg_dispatch ( struct msg ** msg, struct session * session, enum disp_action *action)
+{
+	struct dictionary  * dict;
+	struct dict_object * app;
+	struct dict_object * cmd;
+	struct avp * avp;
+	struct fd_list * cb_list;
+	int ret = 0;
+	
+	TRACE_ENTRY("%p %p %p", msg, session, action);
+	CHECK_PARAMS( msg && CHECK_MSG(*msg) && action);
+	
+	/* Take the dispatch lock */
+	CHECK_FCT( pthread_rwlock_rdlock(&fd_disp_lock) );
+	pthread_cleanup_push( fd_cleanup_rwlock, &fd_disp_lock );
+	
+	/* First, call the DISP_HOW_ANY callbacks */
+	CHECK_FCT_DO( ret = fd_disp_call_cb_int( NULL, msg, NULL, session, action, NULL, NULL, NULL, NULL ), goto error );
+
+	TEST_ACTION_STOP();
+	
+	/* If we don't know the model at this point, we stop cause we cannot get the dictionary. It's invalid: an error should already have been trigged by ANY callbacks */
+	CHECK_PARAMS_DO(cmd = (*msg)->msg_model, { ret = EINVAL; goto error; } );
+	
+	/* Now resolve message application */
+	CHECK_FCT_DO( ret = fd_dict_getdict( cmd, &dict ), goto error );
+	CHECK_FCT_DO( ret = fd_dict_search( dict, DICT_APPLICATION, APPLICATION_BY_ID, &(*msg)->msg_public.msg_appl, &app, 0 ), goto error );
+	
+	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 ?");
+	}
+	
+	/* So start browsing the message */
+	CHECK_FCT_DO( ret = fd_msg_browse( *msg, MSG_BRW_FIRST_CHILD, &avp, NULL ), goto error );
+	while (avp != NULL) {
+		/* Sanity */
+		ASSERT( avp->avp_public.avp_value );
+		
+		/* For unknown AVP, we don't have a callback registered, so just skip */
+		if (avp->avp_model) {
+			struct dict_object * type, * enumval;
+			
+			/* Get the list of callback for this AVP */
+			CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_AVP, avp->avp_model, &cb_list), goto error );
+			
+			/* Check if the AVP has a constant value */
+			CHECK_FCT_DO( ret = fd_dict_search(dict, DICT_TYPE, TYPE_OF_AVP, avp->avp_model, &type, 0), goto error );
+			if (type) {
+				struct dict_enumval_request req;
+				memset(&req, 0, sizeof(struct dict_enumval_request));
+				req.type_obj = type;
+				memcpy( &req.search.enum_value, avp->avp_public.avp_value, sizeof(union avp_value) );
+				CHECK_FCT_DO( ret = fd_dict_search(dict, DICT_ENUMVAL, ENUMVAL_BY_STRUCT, &req, &enumval, 0), goto error );
+			} else {
+				/* No enumerated value in this case */
+				enumval = NULL;
+			}
+			
+			/* Call the callbacks */
+			CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, avp, session, action, app, cmd, avp->avp_model, enumval ), goto error );
+			TEST_ACTION_STOP();
+		}
+		/* Go to next AVP */
+		CHECK_FCT_DO(  ret = fd_msg_browse( avp, MSG_BRW_WALK, &avp, NULL ), goto error );
+	}
+		
+	/* Now call command and application callbacks */
+	CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_COMMAND, cmd, &cb_list), goto error );
+	CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, NULL, session, action, app, cmd, NULL, NULL ), goto error );
+	TEST_ACTION_STOP();
+	
+	if (app) {
+		CHECK_FCT_DO( ret = fd_dict_disp_cb(DICT_APPLICATION, app, &cb_list), goto error );
+		CHECK_FCT_DO( ret = fd_disp_call_cb_int( cb_list, msg, NULL, session, action, app, cmd, NULL, NULL ), goto error );
+		TEST_ACTION_STOP();
+	}
+	
+	pthread_cleanup_pop(0);
+	
+no_error:
+	CHECK_POSIX(pthread_rwlock_unlock(&fd_disp_lock) );
+	return 0;
+	
+error:
+	CHECK_POSIX_DO(pthread_rwlock_unlock(&fd_disp_lock), /* ignore */ );
+	return ret;
+}
"Welcome to our mercurial repository"