changeset 639:95a784729cac

Added new opaque pointer to fd_sess_handler_create and fd_disp_register for usability. Bumped API version number.
author Sebastien Decugis <sdecugis@nict.go.jp>
date Mon, 20 Dec 2010 13:07:06 +0900
parents 9448cba86673
children 237cf6339546
files CMakeLists.txt contrib/debian/changelog doc/dbg_interactive.py.sample extensions/app_acct/app_acct.c extensions/app_diameap/diameap_server.c extensions/app_radgw/rgwx_acct.c extensions/app_radgw/rgwx_auth.c extensions/app_radgw/rgwx_echodrop.c extensions/app_radgw/rgwx_sip.c extensions/app_sip/app_sip.c extensions/app_sip/app_sip.h extensions/app_sip/locationinfo.c extensions/app_sip/locationinfosl.c extensions/app_sip/multimediaauth.c extensions/app_sip/pushprofile.c extensions/app_sip/registrationtermination.c extensions/app_sip/serverassignment.c extensions/app_sip/userauthorization.c extensions/dbg_interactive/dbg_interactive.c extensions/dbg_interactive/dispatch.i extensions/dbg_interactive/sessions.i extensions/test_app/ta_cli.c extensions/test_app/ta_serv.c extensions/test_sip/locationinfo.c extensions/test_sip/locationinfosl.c extensions/test_sip/multimediaauth.c extensions/test_sip/registrationtermination.c extensions/test_sip/serverassignment.c extensions/test_sip/test_sip.c extensions/test_sip/test_sip.h extensions/test_sip/userauthorization.c freeDiameter/tests/testdisp.c freeDiameter/tests/testsess.c include/freeDiameter/libfreeDiameter.h libfreeDiameter/dispatch.c libfreeDiameter/sessions.c
diffstat 36 files changed, 296 insertions(+), 255 deletions(-) [+]
line wrap: on
line diff
--- a/CMakeLists.txt	Fri Dec 17 18:41:19 2010 +0900
+++ b/CMakeLists.txt	Mon Dec 20 13:07:06 2010 +0900
@@ -14,7 +14,7 @@
 SET(FD_PROJECT_VERSION_REV 3)
 
 # Version of the API with the library
-SET(FD_PROJECT_VERSION_API 1)
+SET(FD_PROJECT_VERSION_API 2)
 
 # The test framework, using CTest and CDash.
 INCLUDE(CTest)
--- a/contrib/debian/changelog	Fri Dec 17 18:41:19 2010 +0900
+++ b/contrib/debian/changelog	Mon Dec 20 13:07:06 2010 +0900
@@ -1,5 +1,7 @@
 freediameter (1.0.3) UNRELEASED; urgency=low
 
+  * Added parameters to fd_disp_register and fd_sess_handler_create,
+    Bumped API version number accordingly.
   * Fixed a couple of issues for portability (#21, #22, #23)
   * Fixed issue with ListenOn bit ordering (#20)
   * Added dictionary support for MIPv6 application objects.
--- a/doc/dbg_interactive.py.sample	Fri Dec 17 18:41:19 2010 +0900
+++ b/doc/dbg_interactive.py.sample	Mon Dec 20 13:07:06 2010 +0900
@@ -621,7 +621,7 @@
 # Add this peer into the framework.
 np.add()
 
-# It is possible to specify a callback for when the connection completes or fails to this peer.
+# It is possible to specify a callback for when the connection completes or fails with this peer.
 # The prototype is as follow:
 def add_cb(peer):
     if peer:
--- a/extensions/app_acct/app_acct.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_acct/app_acct.c	Mon Dec 20 13:07:06 2010 +0900
@@ -45,7 +45,7 @@
 
 
 /* Callback for incoming Base Accounting Accounting-Request messages */
-static int acct_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act)
+static int acct_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	struct msg * m;
 	struct avp * a = NULL;
@@ -134,7 +134,7 @@
 	memset(&data, 0, sizeof(data));
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_APPLICATION, APPLICATION_BY_NAME, "Diameter Base Accounting", &data.app, ENOENT) );
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Accounting-Request", &data.command, ENOENT) );
-	CHECK_FCT( fd_disp_register( acct_cb, DISP_HOW_CC, &data, NULL ) );
+	CHECK_FCT( fd_disp_register( acct_cb, DISP_HOW_CC, &data, NULL, NULL ) );
 	
 	/* Advertise the support for the Diameter Base Accounting application in the peer */
 	CHECK_FCT( fd_disp_app_support ( data.app, NULL, 0, 1 ) );
--- a/extensions/app_diameap/diameap_server.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_diameap/diameap_server.c	Mon Dec 20 13:07:06 2010 +0900
@@ -84,7 +84,7 @@
 
 
 
-void diameap_cli_sess_cleanup(void * arg, char * sid)
+void diameap_cli_sess_cleanup(void * arg, char * sid, void * opaque)
 {
 
 	struct diameap_sess_data_sm * diameap_sess_data =
@@ -3059,7 +3059,7 @@
 
 
 static int diameap_server_callback(struct msg ** rmsg, struct avp * ravp,
-		struct session * sess, enum disp_action * action)
+		struct session * sess, void * opaque, enum disp_action * action)
 {
 	TRACE_ENTRY("%p %p %p %p", rmsg, ravp, sess, action);
 
@@ -3388,7 +3388,7 @@
 	struct disp_when when;
 
 	/*create handler for sessions */
-	CHECK_FCT(fd_sess_handler_create(&diameap_server_reg, diameap_cli_sess_cleanup));
+	CHECK_FCT(fd_sess_handler_create(&diameap_server_reg, diameap_cli_sess_cleanup, NULL));
 
 	/* Register the callback */
 	memset(&when, 0, sizeof(when));
@@ -3396,7 +3396,7 @@
 	when.app = dataobj_diameap_app;
 
 	/* Register the callback for EAP Application */
-	CHECK_FCT(fd_disp_register(diameap_server_callback, DISP_HOW_CC, &when,
+	CHECK_FCT(fd_disp_register(diameap_server_callback, DISP_HOW_CC, &when, NULL,
 					&handle));
 
 	if (handle == NULL)
@@ -3409,8 +3409,8 @@
 
 int diameap_stop_server(void)
 {
-	CHECK_FCT(fd_sess_handler_destroy(&diameap_server_reg));
-	CHECK_FCT(fd_disp_unregister(&handle));
+	CHECK_FCT(fd_sess_handler_destroy(&diameap_server_reg, NULL));
+	CHECK_FCT(fd_disp_unregister(&handle, NULL));
 
 	return 0;
 }
--- a/extensions/app_radgw/rgwx_acct.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_radgw/rgwx_acct.c	Mon Dec 20 13:07:06 2010 +0900
@@ -172,7 +172,7 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
 	memset(new, 0, sizeof(struct rgwp_config));
 	
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
 	new->confstr = conffile;
 	
 	if (conffile && strstr(conffile, "nonai"))
@@ -283,7 +283,7 @@
 {
 	TRACE_ENTRY("%p", state);
 	CHECK_PARAMS_DO( state, return );
-	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ),  );
+	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
 	free(state);
 	return;
 }
--- a/extensions/app_radgw/rgwx_auth.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_radgw/rgwx_auth.c	Mon Dec 20 13:07:06 2010 +0900
@@ -138,7 +138,7 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
 	memset(new, 0, sizeof(struct rgwp_config));
 	
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
 	new->confstr = confstr;
 	
 	if (confstr && strstr(confstr, "nonai"))
@@ -224,7 +224,7 @@
 {
 	TRACE_ENTRY("%p", state);
 	CHECK_PARAMS_DO( state, return );
-	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ),  );
+	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
 	free(state);
 	return;
 }
--- a/extensions/app_radgw/rgwx_echodrop.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_radgw/rgwx_echodrop.c	Mon Dec 20 13:07:06 2010 +0900
@@ -38,7 +38,7 @@
 #include "rgwx_echodrop.h"
 
 /* If a session is destroyed, empty the list of ed_saved_attribute */
-static void state_delete(void * arg, char * sid) {
+static void state_delete(void * arg, char * sid, void * opaque) {
 	struct fd_list * list = (struct fd_list *)arg;
 	
 	CHECK_PARAMS_DO( list, return );
@@ -68,7 +68,7 @@
 	fd_list_init(&new->attributes, NULL);
 	
 	/* Create the session handler */
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, state_delete ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, state_delete, NULL ) );
 	
 	/* Parse the configuration file */
 	CHECK_FCT( ed_conffile_parse(conffile, new) );
@@ -106,7 +106,7 @@
 {
 	TRACE_ENTRY("%p", state);
 	CHECK_PARAMS_DO( state, return );
-	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ),  );
+	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
 	while (! FD_IS_LIST_EMPTY(&state->attributes) ) {
 		struct fd_list * li = state->attributes.next;
 		fd_list_unlink(li);
--- a/extensions/app_radgw/rgwx_sip.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_radgw/rgwx_sip.c	Mon Dec 20 13:07:06 2010 +0900
@@ -261,7 +261,7 @@
 	CHECK_MALLOC( new = malloc(sizeof(struct rgwp_config)) );
 	memset(new, 0, sizeof(struct rgwp_config));
 	
-	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free ) );
+	CHECK_FCT( fd_sess_handler_create( &new->sess_hdl, free, NULL ) );
 	new->confstr = conffile;
 	
 	/* Resolve all dictionary objects we use */
@@ -315,7 +315,7 @@
 	TRACE_ENTRY("%p", state);
 	CHECK_PARAMS_DO( state, return );
 	
-	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl ),  );
+	CHECK_FCT_DO( fd_sess_handler_destroy( &state->sess_hdl, NULL ),  );
 	
 	nonce_deletelistnonce(state);
 	CHECK_POSIX_DO(pthread_mutex_destroy(&state->nonce_mutex), /*continue*/);
--- a/extensions/app_sip/app_sip.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/app_sip.c	Mon Dec 20 13:07:06 2010 +0900
@@ -58,9 +58,9 @@
 //dictionary of SIP
 struct app_sip_dict sip_dict;
 
-int app_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act)
+int app_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
 {
-	TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
+	TRACE_ENTRY("%p %p %p %p %p", msg, avp, sess, opaque, act);
 	
 	return 0;
 }
@@ -178,41 +178,41 @@
 	
 	if(as_conf->mode==1)
 	{
-	  //**Command Codes
+	  // **Command Codes
 	  //MAR
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Multimedia-Auth-Request", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_MAR_cb, DISP_HOW_CC, &data, &app_sip_MAR_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_MAR_cb, DISP_HOW_CC, &data, NULL, &app_sip_MAR_hdl ) );
 	  //RTA
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Registration-Termination-Answer", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_RTA_cb, DISP_HOW_CC, &data, &app_sip_RTA_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_RTA_cb, DISP_HOW_CC, &data, NULL, &app_sip_RTA_hdl ) );
 	  //PPA
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Push-Profile-Answer", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_PPA_cb, DISP_HOW_CC, &data, &app_sip_PPA_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_PPA_cb, DISP_HOW_CC, &data, NULL, &app_sip_PPA_hdl ) );
 	  //LIR
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Location-Info-Request", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_LIR_cb, DISP_HOW_CC, &data, &app_sip_LIR_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_LIR_cb, DISP_HOW_CC, &data, NULL, &app_sip_LIR_hdl ) );
 	  //UAR
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "User-Authorization-Request", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_UAR_cb, DISP_HOW_CC, &data, &app_sip_UAR_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_UAR_cb, DISP_HOW_CC, &data, NULL, &app_sip_UAR_hdl ) );
 	  //SAR
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Server-Assignment-Request", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_SAR_cb, DISP_HOW_CC, &data, &app_sip_SAR_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_SAR_cb, DISP_HOW_CC, &data, NULL, &app_sip_SAR_hdl ) );
 	}
 	if(as_conf->mode==2)
 	{
 	  //LIR
 	  CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Location-Info-Request", &data.command, ENOENT) );
-	  CHECK_FCT( fd_disp_register( app_sip_SL_LIR_cb, DISP_HOW_CC, &data, &app_sip_SL_LIR_hdl ) );
+	  CHECK_FCT( fd_disp_register( app_sip_SL_LIR_cb, DISP_HOW_CC, &data, NULL, &app_sip_SL_LIR_hdl ) );
 	}
 	//Callback for unexpected messages
-	CHECK_FCT( fd_disp_register( app_sip_default_cb, DISP_HOW_APPID, &data, &app_sip_default_hdl ) );
+	CHECK_FCT( fd_disp_register( app_sip_default_cb, DISP_HOW_APPID, &data, NULL, &app_sip_default_hdl ) );
 	
 	
 	//We start database connection
 	if(start_mysql_connection())
 		return EINVAL;
 	
-	CHECK_FCT(fd_sess_handler_create(&ds_sess_hdl, free));
+	CHECK_FCT(fd_sess_handler_create(&ds_sess_hdl, free, NULL));
 	
 	//Creation of thread for Registration Termination	
 	if(pthread_create(&rtr_thread, NULL,rtr_socket, NULL))
@@ -236,8 +236,8 @@
 {
 	//TODO:unregister other callbacks
 	
-	(void) fd_disp_unregister(&app_sip_MAR_hdl);
-	CHECK_FCT_DO( fd_sess_handler_destroy(&ds_sess_hdl),return);
+	(void) fd_disp_unregister(&app_sip_MAR_hdl, NULL);
+	CHECK_FCT_DO( fd_sess_handler_destroy(&ds_sess_hdl, NULL),return);
 	
 	
 	//We close database connection
--- a/extensions/app_sip/app_sip.h	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/app_sip.h	Mon Dec 20 13:07:06 2010 +0900
@@ -139,17 +139,17 @@
 
 int ds_entry();
 void fd_ext_fini(void);
-int app_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int app_sip_MAR_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int app_sip_RTA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int app_sip_PPA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int app_sip_LIR_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int app_sip_UAR_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int app_sip_SAR_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
+int app_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int app_sip_MAR_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int app_sip_RTA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int app_sip_PPA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int app_sip_LIR_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int app_sip_UAR_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int app_sip_SAR_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
 
 //Suscriber Locator
-int app_sip_SL_LIR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act);
-//int app_sip_SL_SAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act);
+int app_sip_SL_LIR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act);
+//int app_sip_SL_SAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act);
 
 #define SQL_GETPASSWORD "SELECT `password` FROM ds_users WHERE `username` ='%s'"
 #define SQL_GETPASSWORD_LEN sizeof(SQL_GETPASSWORD)-2
--- a/extensions/app_sip/locationinfo.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/locationinfo.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "app_sip.h"
 
 
-int app_sip_LIR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_LIR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	TRACE_ENTRY("%p %p %p %p", msg, paramavp, sess, act);
 	
--- a/extensions/app_sip/locationinfosl.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/locationinfosl.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "app_sip.h"
 
 //This callback is specific to SUSCRIBER LOCATOR. We must look for the "serving" SIP server
-int app_sip_SL_LIR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_SL_LIR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	TRACE_ENTRY("%p %p %p %p", msg, paramavp, sess, act);
 	
--- a/extensions/app_sip/multimediaauth.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/multimediaauth.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "app_sip.h"
 
 
-int app_sip_MAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_MAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	struct msg *ans, *qry;
 	struct avp *avp, *a2, *authdataitem;
--- a/extensions/app_sip/pushprofile.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/pushprofile.c	Mon Dec 20 13:07:06 2010 +0900
@@ -254,7 +254,7 @@
 }
 
 //Called when an PPA arrive
-int app_sip_PPA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_PPA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	//TODO: PPA reception
 /*
--- a/extensions/app_sip/registrationtermination.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/registrationtermination.c	Mon Dec 20 13:07:06 2010 +0900
@@ -257,7 +257,7 @@
 }
 
 //Called when an RTA arrive
-int app_sip_RTA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_RTA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	//TODO: RTA reception
 /*
--- a/extensions/app_sip/serverassignment.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/serverassignment.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "app_sip.h"
 
 
-int app_sip_SAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_SAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	TRACE_ENTRY("%p %p %p %p", msg, paramavp, sess, act);
 	
--- a/extensions/app_sip/userauthorization.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/app_sip/userauthorization.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "app_sip.h"
 
 
-int app_sip_UAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int app_sip_UAR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	TRACE_ENTRY("%p %p %p %p", msg, paramavp, sess, act);
 	
--- a/extensions/dbg_interactive/dbg_interactive.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/dbg_interactive/dbg_interactive.c	Mon Dec 20 13:07:06 2010 +0900
@@ -66,8 +66,10 @@
 	Py_Main(arg ? 2 : 1, dum);
 	
 end:	
-	/* Upon exit, issue the order of terminating to fD */
-	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
+	/* Upon exit, issue the order of terminating to fD, if the interpreter was started without a file */
+	if (!arg) {
+		CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, 0, NULL), );
+	}
 
 	return NULL;
 }
--- a/extensions/dbg_interactive/dispatch.i	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/dbg_interactive/dispatch.i	Mon Dec 20 13:07:06 2010 +0900
@@ -39,17 +39,17 @@
 
 
 %{
-/* store the python callback function here */
-static PyObject * py_dispatch_cb = NULL;
-static int        py_dispatch_cb_n = 0;
 /* call it (will be called from a different thread than the interpreter, when message arrives) */
-static int call_the_python_dispatch_callback(struct msg **msg, struct avp *avp, struct session *session, enum disp_action *action) {
+static int call_the_python_dispatch_callback(struct msg **msg, struct avp *avp, struct session *session, void * pycb, enum disp_action *action) {
 	PyObject *PyMsg, *PyAvp, *PySess;
-	PyObject *result = NULL;
+	PyObject *cb, *result = NULL;
 	int ret = 0;
 	
-	if (!py_dispatch_cb)
+	if (!pycb) {
+		fd_log_debug("Internal error: missing the callback!\n");
 		return ENOTSUP;
+	}
+	cb = pycb;
 	
 	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
 	/* Convert the arguments */
@@ -58,7 +58,7 @@
 	PySess = SWIG_NewPointerObj((void *) session, SWIGTYPE_p_session, 0 );
 	
 	/* Call the function */
-	result = PyEval_CallFunction(py_dispatch_cb, "(OOO)", PyMsg, PyAvp, PySess);
+	result = PyEval_CallFunction(cb, "(OOO)", PyMsg, PyAvp, PySess);
 	
 	/* The result is supposedly composed of: [ ret, *msg, *action ] */
 	if ((result == NULL) || (!PyList_Check(result)) || (PyList_Size(result) != 3)) {
@@ -107,15 +107,10 @@
 	disp_hdl(PyObject * PyCb, enum disp_how how, struct disp_when * when) {
 		struct disp_hdl * hdl = NULL;
 		int ret;
-		if (py_dispatch_cb && (py_dispatch_cb != PyCb)) {
-			DI_ERROR(EINVAL, PyExc_SyntaxError, "Only one dispatch callback is supported at the moment in this extension\n.");
-			return NULL;
-		}
-		py_dispatch_cb = PyCb;
-		py_dispatch_cb_n += 1;
-		Py_XINCREF(py_dispatch_cb);
 		
-		ret = fd_disp_register ( call_the_python_dispatch_callback, how, when, &hdl );
+		Py_XINCREF(PyCb);
+		
+		ret = fd_disp_register ( call_the_python_dispatch_callback, how, when, PyCb, &hdl );
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 			return NULL;
@@ -124,15 +119,12 @@
 	}
 	~disp_hdl() {
 		struct disp_hdl * hdl = self;
-		int ret = fd_disp_unregister(&hdl);
+		PyObject * cb = NULL;
+		int ret = fd_disp_unregister(&hdl, (void *)&cb);
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 		}
-		/* Now free the callback */
-		Py_XDECREF(py_dispatch_cb);
-		py_dispatch_cb_n -= 1;
-		if (!py_dispatch_cb_n)
-			py_dispatch_cb = NULL;
+		Py_XDECREF(cb);
 		return;
 	}
 }
--- a/extensions/dbg_interactive/sessions.i	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/dbg_interactive/sessions.i	Mon Dec 20 13:07:06 2010 +0900
@@ -38,17 +38,17 @@
 /****** SESSIONS *********/
 
 %{
-/* store the python callback function here */
-static PyObject * py_cleanup_cb = NULL;
 /* call it (might be called from a different thread than the interpreter, when session times out) */
-static void call_the_python_cleanup_callback(session_state * state, char * sid) {
+static void call_the_python_cleanup_callback(session_state * state, char * sid, void * cb) {
 	PyObject *result;
-	if (!py_cleanup_cb)
+	if (!cb) {
+		fd_log_debug("Internal error: missing callback object!\n");
 		return;
+	}
 	
 	/* Call the function */
 	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
-	result = PyEval_CallFunction(py_cleanup_cb, "(Os)", state, sid);
+	result = PyEval_CallFunction((PyObject *)cb, "(Os)", state, sid);
 	Py_XDECREF(result);
 	SWIG_PYTHON_THREAD_END_BLOCK;
 	return;
@@ -63,14 +63,10 @@
 	session_handler(PyObject * PyCb) {
 		struct session_handler * hdl = NULL;
 		int ret;
-		if (py_cleanup_cb) {
-			DI_ERROR(EINVAL, PyExc_SyntaxError, "Only one session handler at a time is supported at the moment in this extension\n.");
-			return NULL;
-		}
-		py_cleanup_cb = PyCb;
-		Py_XINCREF(py_cleanup_cb);
 		
-		ret = fd_sess_handler_create_internal ( &hdl, call_the_python_cleanup_callback );
+		Py_XINCREF(PyCb);
+		
+		ret = fd_sess_handler_create_internal ( &hdl, call_the_python_cleanup_callback, PyCb );
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 			return NULL;
@@ -79,13 +75,14 @@
 	}
 	~session_handler() {
 		struct session_handler * hdl = self;
-		int ret = fd_sess_handler_destroy(&hdl);
+		PyObject * cb = NULL;
+		
+		int ret = fd_sess_handler_destroy(&hdl, (void *)&cb);
 		if (ret != 0) {
 			DI_ERROR(ret, NULL, NULL);
 		}
 		/* Now free the callback */
-		Py_XDECREF(py_cleanup_cb);
-		py_cleanup_cb = NULL;
+		Py_XDECREF(cb);
 		return;
 	}
 	void dump() {
--- a/extensions/test_app/ta_cli.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_app/ta_cli.c	Mon Dec 20 13:07:06 2010 +0900
@@ -233,7 +233,7 @@
 
 int ta_cli_init(void)
 {
-	CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, free) );
+	CHECK_FCT( fd_sess_handler_create(&ta_cli_reg, free, NULL) );
 	
 	CHECK_FCT( fd_sig_register(ta_conf->signal, "test_app.cli", ta_cli_test_message ) );
 	
@@ -244,7 +244,7 @@
 {
 	CHECK_FCT_DO( fd_sig_unregister(ta_conf->signal), /* continue */ );
 	
-	CHECK_FCT_DO( fd_sess_handler_destroy(&ta_cli_reg), /* continue */ );
+	CHECK_FCT_DO( fd_sess_handler_destroy(&ta_cli_reg, NULL), /* continue */ );
 	
 	return;
 };
--- a/extensions/test_app/ta_serv.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_app/ta_serv.c	Mon Dec 20 13:07:06 2010 +0900
@@ -41,7 +41,7 @@
 static struct disp_hdl * ta_hdl_tr = NULL; /* handler for Test-Request req cb */
 
 /* Default callback for the application. */
-static int ta_fb_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act)
+static int ta_fb_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	/* This CB should never be called */
 	TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
@@ -52,7 +52,7 @@
 }
 
 /* Callback for incoming Test-Request messages */
-static int ta_tr_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act)
+static int ta_tr_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	struct msg *ans, *qry;
 	struct avp * a;
@@ -119,10 +119,10 @@
 	data.command = ta_cmd_r;
 	
 	/* fallback CB if command != Test-Request received */
-	CHECK_FCT( fd_disp_register( ta_fb_cb, DISP_HOW_APPID, &data, &ta_hdl_fb ) );
+	CHECK_FCT( fd_disp_register( ta_fb_cb, DISP_HOW_APPID, &data, NULL, &ta_hdl_fb ) );
 	
 	/* Now specific handler for Test-Request */
-	CHECK_FCT( fd_disp_register( ta_tr_cb, DISP_HOW_CC, &data, &ta_hdl_tr ) );
+	CHECK_FCT( fd_disp_register( ta_tr_cb, DISP_HOW_CC, &data, NULL, &ta_hdl_tr ) );
 	
 	return 0;
 }
@@ -130,10 +130,10 @@
 void ta_serv_fini(void)
 {
 	if (ta_hdl_fb) {
-		(void) fd_disp_unregister(&ta_hdl_fb);
+		(void) fd_disp_unregister(&ta_hdl_fb, NULL);
 	}
 	if (ta_hdl_tr) {
-		(void) fd_disp_unregister(&ta_hdl_tr);
+		(void) fd_disp_unregister(&ta_hdl_tr, NULL);
 	}
 	
 	return;
--- a/extensions/test_sip/locationinfo.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/locationinfo.c	Mon Dec 20 13:07:06 2010 +0900
@@ -124,7 +124,7 @@
 	return 0;
 }
 
-int test_sip_LIA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int test_sip_LIA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	
 	return 0;
--- a/extensions/test_sip/locationinfosl.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/locationinfosl.c	Mon Dec 20 13:07:06 2010 +0900
@@ -126,7 +126,7 @@
 	return 0;
 }
 
-int test_sipSL_LIA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int test_sipSL_LIA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	
 	return 0;
--- a/extensions/test_sip/multimediaauth.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/multimediaauth.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "test_sip.h"
 
 
-int test_sip_MAA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int test_sip_MAA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 /*
 	struct msg *ans, *qry;
--- a/extensions/test_sip/registrationtermination.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/registrationtermination.c	Mon Dec 20 13:07:06 2010 +0900
@@ -36,7 +36,7 @@
 #include "test_sip.h"
 
 
-int test_sip_RTR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int test_sip_RTR_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	
 	return 0;
--- a/extensions/test_sip/serverassignment.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/serverassignment.c	Mon Dec 20 13:07:06 2010 +0900
@@ -167,7 +167,7 @@
 	return 0;
 }
 
-int test_sip_SAA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int test_sip_SAA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	
 	return 0;
--- a/extensions/test_sip/test_sip.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/test_sip.c	Mon Dec 20 13:07:06 2010 +0900
@@ -63,7 +63,7 @@
 //dictionary of SIP
 struct sip_dict sip_dict;
 
-int test_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act)
+int test_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	TRACE_ENTRY("%p %p %p %p", msg, avp, sess, act);
 	
@@ -186,26 +186,26 @@
 	/**/
 	//MAA
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Multimedia-Auth-Answer", &data.command, ENOENT) );
-	CHECK_FCT( fd_disp_register( test_sip_MAA_cb, DISP_HOW_CC, &data, &test_sip_MAA_hdl ) );
+	CHECK_FCT( fd_disp_register( test_sip_MAA_cb, DISP_HOW_CC, &data, NULL, &test_sip_MAA_hdl ) );
 	
 	//UAA
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "User-Authorization-Answer", &data.command, ENOENT) );
-	CHECK_FCT( fd_disp_register( test_sip_UAA_cb, DISP_HOW_CC, &data, &test_sip_UAA_hdl ) );
+	CHECK_FCT( fd_disp_register( test_sip_UAA_cb, DISP_HOW_CC, &data, NULL, &test_sip_UAA_hdl ) );
 	
 	//RTR
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Registration-Termination-Request", &data.command, ENOENT) );
-	CHECK_FCT( fd_disp_register( test_sip_RTR_cb, DISP_HOW_CC, &data, &test_sip_RTR_hdl ) );
+	CHECK_FCT( fd_disp_register( test_sip_RTR_cb, DISP_HOW_CC, &data, NULL, &test_sip_RTR_hdl ) );
 	
 	//LIA
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Location-Info-Answer", &data.command, ENOENT) );
-	CHECK_FCT( fd_disp_register( test_sip_LIA_cb, DISP_HOW_CC, &data, &test_sip_LIA_hdl ) );
+	CHECK_FCT( fd_disp_register( test_sip_LIA_cb, DISP_HOW_CC, &data, NULL, &test_sip_LIA_hdl ) );
 	
 	//LIA
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_COMMAND, CMD_BY_NAME, "Server-Assignment-Answer", &data.command, ENOENT) );
-	CHECK_FCT( fd_disp_register( test_sip_SAA_cb, DISP_HOW_CC, &data, &test_sip_SAA_hdl ) );
+	CHECK_FCT( fd_disp_register( test_sip_SAA_cb, DISP_HOW_CC, &data, NULL, &test_sip_SAA_hdl ) );
 	
 	//Callback for unexpected messages
-	CHECK_FCT( fd_disp_register( test_sip_default_cb, DISP_HOW_APPID, &data, &test_sip_default_hdl ) );
+	CHECK_FCT( fd_disp_register( test_sip_default_cb, DISP_HOW_APPID, &data, NULL, &test_sip_default_hdl ) );
 	
 	/*
 	//We start database connection
@@ -213,7 +213,7 @@
 		return 1;
 	*/
 	
-	CHECK_FCT(fd_sess_handler_create(&ts_sess_hdl, free));
+	CHECK_FCT(fd_sess_handler_create(&ts_sess_hdl, free, NULL));
 	//CHECK_FCT( fd_sig_register(30, "test_sip", (void *)test_sipSL_LIR_cb ) );
 	CHECK_FCT( fd_sig_register(30, "test_sip", (void *)test_sip_SAR_cb ) );
 	CHECK_FCT( fd_sig_register(31, "test_sip", (void *)test_sip_LIR_cb ) );
--- a/extensions/test_sip/test_sip.h	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/test_sip.h	Mon Dec 20 13:07:06 2010 +0900
@@ -114,10 +114,10 @@
 int test_sip_SAR_cb();
 int test_sipSL_LIR_cb();
 
-int test_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int test_sip_MAA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int test_sip_RTR_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int test_sip_UAA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int test_sip_LIA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int test_sip_SAA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
-int test_sipSL_LIA_cb( struct msg ** msg, struct avp * avp, struct session * sess, enum disp_action * act);
+int test_sip_default_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int test_sip_MAA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int test_sip_RTR_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int test_sip_UAA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int test_sip_LIA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int test_sip_SAA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
+int test_sipSL_LIA_cb( struct msg ** msg, struct avp * avp, struct session * sess, void * opaque, enum disp_action * act);
--- a/extensions/test_sip/userauthorization.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/extensions/test_sip/userauthorization.c	Mon Dec 20 13:07:06 2010 +0900
@@ -158,7 +158,7 @@
 	return 0;
 }
 
-int test_sip_UAA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, enum disp_action * act)
+int test_sip_UAA_cb( struct msg ** msg, struct avp * paramavp, struct session * sess, void * opaque, enum disp_action * act)
 {
 	
 	return 0;
--- a/freeDiameter/tests/testdisp.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/freeDiameter/tests/testdisp.c	Mon Dec 20 13:07:06 2010 +0900
@@ -35,23 +35,27 @@
 
 #include "tests.h"
 	
-#define Define_cb( __int, __extra )										\
-int cb_##__int( struct msg ** msg, struct avp * avp, struct session * session, enum disp_action * action )	\
-{														\
-	CHECK( 1, msg ? 1 : 0 );										\
-	CHECK( 1, action ? 1 : 0 );										\
-	CHECK( sess, session );											\
-	*action = DISP_ACT_CONT;										\
-	cbcalled[__int] += 1;											\
-	do {													\
-		__extra ;											\
-	} while (0);												\
-	return 0;												\
+#define Define_cb( __int, __extra )												\
+int cb_##__int( struct msg ** msg, struct avp * avp, struct session * session, void * opaque, enum disp_action * action )	\
+{																\
+	CHECK( 1, msg ? 1 : 0 );												\
+	CHECK( 1, action ? 1 : 0 );												\
+	CHECK( sess, session );													\
+	if (opaque) {														\
+		CHECK( 1, opaque == g_opaque ? 1 : 0 );										\
+	}															\
+	*action = DISP_ACT_CONT;												\
+	cbcalled[__int] += 1;													\
+	do {															\
+		__extra ;													\
+	} while (0);														\
+	return 0;														\
 }
 
 #define NB_CB	10
 char cbcalled[NB_CB];
 struct session * sess;
+void * g_opaque = (void *)"test";
 
 /* cb_0 */  Define_cb( 0, );
 /* cb_1 */  Define_cb( 1, );
@@ -141,11 +145,11 @@
 	
 	/* Register first handler, very simple test */
 	{
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, NULL, &hdl[0] ) );
 		CHECK( 1, hdl[0] ? 1 : 0 );
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
 		CHECK( NULL, hdl[0] );
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, NULL, &hdl[0] ) );
 	
 		/* Check this handler is called for a message */
 		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
@@ -156,20 +160,20 @@
 		
 		/* Delete the message */
 		CHECK( 0, fd_msg_free( msg ) );
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
 	}
 	
 	/* Handlers for applications */
 	{
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
 		when.app = app1;
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_APPID, &when, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_APPID, &when, NULL, &hdl[1] ) );
 		when.app = app2;
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_APPID, &when, &hdl[2] ) );
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_APPID, &when, NULL, &hdl[2] ) );
 		when.avp = avp2;
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_APPID, &when, &hdl[3] ) );
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_APPID, &when, NULL, &hdl[3] ) );
 		when.avp = avp1;
-		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_APPID, &when, &hdl[4] ) );
+		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_APPID, &when, NULL, &hdl[4] ) );
 	
 		/* Check the callbacks are called as appropriate */
 		memset(cbcalled, 0, sizeof(cbcalled));
@@ -205,27 +209,27 @@
 		CHECK( DISP_ACT_CONT, action );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[4] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
 	}
 	
 	/* Handlers for commands */
 	{
 		when.app = NULL;
 		when.command = NULL;
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) );
-		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_CC, &when, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
+		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_CC, &when, NULL, &hdl[1] ) );
 		when.command = cmd1;
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_CC, &when, &hdl[1] ) ); /* cmd1 */
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_CC, &when, NULL, &hdl[1] ) ); /* cmd1 */
 		when.app = app2;
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_CC, &when, &hdl[2] ) ); /* app2 + cmd1 */
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_CC, &when, NULL, &hdl[2] ) ); /* app2 + cmd1 */
 		when.command = cmd2;
 		when.app = NULL;
 		when.avp = avp1;
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_CC, &when, &hdl[3] ) ); /* cmd2 (avp1 ignored) */
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_CC, &when, NULL, &hdl[3] ) ); /* cmd2 (avp1 ignored) */
 		
 		/* Check the callbacks are called as appropriate */
 		memset(cbcalled, 0, sizeof(cbcalled));
@@ -268,10 +272,10 @@
 		CHECK( DISP_ACT_CONT, action );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
 	}
 	
 	/* Handlers for AVPs */
@@ -280,30 +284,30 @@
 		when.command = NULL;
 		when.avp = NULL;
 	
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) ); /* all */
-		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP, &when, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) ); /* all */
+		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP, &when, NULL, &hdl[1] ) );
 		
 		when.avp = avp1;
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP, &when, &hdl[1] ) ); /* avp1 */
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP, &when, NULL, &hdl[1] ) ); /* avp1 */
 		
 		when.command = cmd1;
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP, &when, &hdl[2] ) ); /* avp1 + cmd1 */
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP, &when, NULL, &hdl[2] ) ); /* avp1 + cmd1 */
 		
 		when.command = NULL;
 		when.app = app1;
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_AVP, &when, &hdl[3] ) ); /* avp1 + app1 */
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_AVP, &when, NULL, &hdl[3] ) ); /* avp1 + app1 */
 		
 		when.command = cmd1;
-		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_AVP, &when, &hdl[4] ) ); /* avp1 + cmd1 + app1 */
+		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_AVP, &when, NULL, &hdl[4] ) ); /* avp1 + cmd1 + app1 */
 		
 		when.app = NULL;
 		when.command = NULL;
 		when.avp = avp2;
 		when.value = enu1;
-		CHECK( 0, fd_disp_register( cb_5, DISP_HOW_AVP, &when, &hdl[5] ) ); /* avp2 */
+		CHECK( 0, fd_disp_register( cb_5, DISP_HOW_AVP, &when, NULL, &hdl[5] ) ); /* avp2 */
 		
 		when.value = enu2;
-		CHECK( 0, fd_disp_register( cb_7, DISP_HOW_AVP, &when, &hdl[6] ) ); /* avp2 */
+		CHECK( 0, fd_disp_register( cb_7, DISP_HOW_AVP, &when, NULL, &hdl[6] ) ); /* avp2 */
 		
 		
 		
@@ -395,13 +399,13 @@
 		CHECK( DISP_ACT_CONT, action );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[4] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[5] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[6] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[6], NULL ) );
 	}
 		
 	/* Handlers for enum values */
@@ -411,22 +415,22 @@
 		when.avp = NULL;
 		when.value = NULL;
 		
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) ); /* all */
-		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) ); /* all */
+		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
 		when.value = enu1;
-		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, &hdl[1] ) );
+		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
 		when.avp = avp1;
-		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, &hdl[1] ) );
+		CHECK( EINVAL, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
 		when.avp = avp2;
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, &hdl[1] ) ); /* avp2, enu1 */
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) ); /* avp2, enu1 */
 		
 		when.command = cmd1;
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP_ENUMVAL, &when, &hdl[2] ) ); /* avp2, enu1 + cmd1 */
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[2] ) ); /* avp2, enu1 + cmd1 */
 		
 		when.command = NULL;
 		when.app = app1;
 		when.value = enu2;
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_AVP_ENUMVAL, &when, &hdl[3] ) ); /* avp2, enu2 + app1 */
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[3] ) ); /* avp2, enu2 + app1 */
 		
 		/* Check the callbacks are called as appropriate */
 		memset(cbcalled, 0, sizeof(cbcalled));
@@ -497,19 +501,19 @@
 		CHECK( DISP_ACT_CONT, action );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
 	}
 	
 	/* Test behavior of handlers */
 	{
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) );
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, &hdl[1] ) );
-		CHECK( 0, fd_disp_register( cb_6, DISP_HOW_ANY, &when, &hdl[2] ) );
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, &hdl[3] ) );
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, &hdl[4] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, NULL, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_6, DISP_HOW_ANY, &when, NULL, &hdl[2] ) );
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, NULL, &hdl[3] ) );
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, NULL, &hdl[4] ) );
 		
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
@@ -521,17 +525,17 @@
 		CHECK( 0, cbcalled[3] );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[4] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
 		
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) );
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, &hdl[1] ) );
-		CHECK( 0, fd_disp_register( cb_8, DISP_HOW_ANY, &when, &hdl[2] ) );
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, &hdl[3] ) );
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, &hdl[4] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, NULL, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_8, DISP_HOW_ANY, &when, NULL, &hdl[2] ) );
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, NULL, &hdl[3] ) );
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, NULL, &hdl[4] ) );
 		
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
@@ -543,17 +547,17 @@
 		CHECK( 0, cbcalled[3] );
 		CHECK( NULL, msg );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[4] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
 		
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) );
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, &hdl[1] ) );
-		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_ANY, &when, &hdl[2] ) );
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, &hdl[3] ) );
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, &hdl[4] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_ANY, &when, NULL, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_ANY, &when, NULL, &hdl[2] ) );
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_ANY, &when, NULL, &hdl[3] ) );
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_ANY, &when, NULL, &hdl[4] ) );
 		
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 1, cmd1, avp1, avp2, 1 );
@@ -566,11 +570,11 @@
 		CHECK( DISP_ACT_SEND, action );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[4] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
 	}
 		
 	/* Test order of handlers */
@@ -580,11 +584,11 @@
 		when.avp = avp2;
 		when.value = enu2;
 		
-		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, &hdl[0] ) );
-		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, &hdl[1] ) );
-		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP, &when, &hdl[2] ) );
-		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_CC, &when, &hdl[3] ) );
-		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_APPID, &when, &hdl[4] ) );
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, &when, NULL, &hdl[0] ) );
+		CHECK( 0, fd_disp_register( cb_1, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[1] ) );
+		CHECK( 0, fd_disp_register( cb_2, DISP_HOW_AVP, &when, NULL, &hdl[2] ) );
+		CHECK( 0, fd_disp_register( cb_3, DISP_HOW_CC, &when, NULL, &hdl[3] ) );
+		CHECK( 0, fd_disp_register( cb_4, DISP_HOW_APPID, &when, NULL, &hdl[4] ) );
 		
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
@@ -597,7 +601,7 @@
 		CHECK( 0, cbcalled[9] );
 		CHECK( 0, fd_msg_free( msg ) );
 		
-		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_ANY, &when, &hdl[5] ) );
+		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_ANY, &when, NULL, &hdl[5] ) );
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec ) );
@@ -608,9 +612,9 @@
 		CHECK( 0, cbcalled[4] );
 		CHECK( 1, cbcalled[9] );
 		CHECK( 0, fd_msg_free( msg ) );
-		CHECK( 0, fd_disp_unregister( &hdl[5] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
 		
-		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_AVP_ENUMVAL, &when, &hdl[5] ) );
+		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_AVP_ENUMVAL, &when, NULL, &hdl[5] ) );
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec ) );
@@ -621,9 +625,9 @@
 		CHECK( 0, cbcalled[4] );
 		CHECK( 1, cbcalled[9] );
 		CHECK( 0, fd_msg_free( msg ) );
-		CHECK( 0, fd_disp_unregister( &hdl[5] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
 		
-		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_AVP, &when, &hdl[5] ) );
+		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_AVP, &when, NULL, &hdl[5] ) );
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec ) );
@@ -634,9 +638,9 @@
 		CHECK( 0, cbcalled[4] );
 		CHECK( 1, cbcalled[9] );
 		CHECK( 0, fd_msg_free( msg ) );
-		CHECK( 0, fd_disp_unregister( &hdl[5] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
 		
-		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_CC, &when, &hdl[5] ) );
+		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_CC, &when, NULL, &hdl[5] ) );
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec ) );
@@ -647,9 +651,9 @@
 		CHECK( 0, cbcalled[4] );
 		CHECK( 1, cbcalled[9] );
 		CHECK( 0, fd_msg_free( msg ) );
-		CHECK( 0, fd_disp_unregister( &hdl[5] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
 		
-		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_APPID, &when, &hdl[5] ) );
+		CHECK( 0, fd_disp_register( cb_9, DISP_HOW_APPID, &when, NULL, &hdl[5] ) );
 		memset(cbcalled, 0, sizeof(cbcalled));
 		msg = new_msg( 2, cmd2, avp1, avp2, 2 );
 		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec ) );
@@ -660,13 +664,13 @@
 		CHECK( 1, cbcalled[4] );
 		CHECK( 1, cbcalled[9] );
 		CHECK( 0, fd_msg_free( msg ) );
-		CHECK( 0, fd_disp_unregister( &hdl[5] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[5], NULL ) );
 		
-		CHECK( 0, fd_disp_unregister( &hdl[0] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[1] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[2] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[3] ) );
-		CHECK( 0, fd_disp_unregister( &hdl[4] ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[1], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[2], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[3], NULL ) );
+		CHECK( 0, fd_disp_unregister( &hdl[4], NULL ) );
 	}			
 	
 	/* Test application support advertisement */
@@ -697,6 +701,24 @@
 		#endif
 	}
 	
+	/* Test opaque pointer management */
+	{
+		void * ptr;
+		CHECK( 0, fd_disp_register( cb_0, DISP_HOW_ANY, NULL, g_opaque, &hdl[0] ) );
+	
+		/* Check this handler is called for a message */
+		msg = new_msg( 0, cmd1, avp1, NULL, 0 );
+		memset(cbcalled, 0, sizeof(cbcalled));
+		CHECK( 0, fd_msg_dispatch ( &msg, sess, &action, &ec ) );
+		CHECK( 1, cbcalled[0] );
+		CHECK( DISP_ACT_CONT, action );
+		
+		/* Delete the message */
+		CHECK( 0, fd_msg_free( msg ) );
+		CHECK( 0, fd_disp_unregister( &hdl[0], &ptr ) );
+		CHECK( 1, ptr == g_opaque ? 1 : 0 );
+	}
+	
 	/* That's all for the tests yet */
 	PASSTEST();
 } 
--- a/freeDiameter/tests/testsess.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/freeDiameter/tests/testsess.c	Mon Dec 20 13:07:06 2010 +0900
@@ -44,9 +44,10 @@
 	int	eyec;	/* TEST_EYEC */
 	char *  sid; 	/* the session with which the data was registered */
 	int  *  freed;	/* location where to write the freed status */
+	void *  opaque; /* if opaque was provided, this is the value we expect */
 };
 
-static void mycleanup( struct mystate * data, char * sid )
+static void mycleanup( struct mystate * data, char * sid, void * opaque )
 {
 	/* sanity */
 	CHECK( 1, sid ? 1 : 0 );
@@ -55,6 +56,9 @@
 	CHECK( 0, strcmp(sid, data->sid) );
 	if (data->freed)
 		*(data->freed) += 1;
+	if (data->opaque) {
+		CHECK( 1, opaque == data->opaque ? 1 : 0 );  
+	}
 	/* Now, free the data */
 	free(data->sid);
 	free(data);
@@ -72,6 +76,8 @@
 	new->freed = freed;
 	return new;
 }
+
+void * g_opaque = (void *)"test";
 	
 
 /* Main test routine */
@@ -87,10 +93,12 @@
 	
 	/* Test functions related to handlers (simple situation) */
 	{
-		CHECK( 0, fd_sess_handler_create ( &hdl1, mycleanup ) );
-		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup ) );
-		CHECK( 0, fd_sess_handler_destroy( &hdl2 ) );
-		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup ) );
+		void * testptr = NULL;
+		CHECK( 0, fd_sess_handler_create ( &hdl1, mycleanup, NULL ) );
+		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup, NULL ) );
+		CHECK( 0, fd_sess_handler_destroy( &hdl2, &testptr ) );
+		CHECK( 1, testptr == NULL ? 1 : 0 );
+		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup, g_opaque ) );
 		#if 0
 		fd_sess_dump_hdl(0, hdl1);
 		fd_sess_dump_hdl(0, hdl2);
@@ -236,6 +244,7 @@
 		struct mystate * ms[6], *tms;
 		int freed[6];
 		struct timespec timeout;
+		void * testptr = NULL;
 		
 		/* Create three sessions */
 		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, NULL, 0 ) );
@@ -266,8 +275,8 @@
 		CHECK( 0, fd_sess_state_retrieve( hdl1, sess2, &tms ) );
 		CHECK( NULL, tms );
 		
-		mycleanup(ms[0], str1);
-		mycleanup(ms[1], str1);
+		mycleanup(ms[0], str1, NULL);
+		mycleanup(ms[1], str1, NULL);
 		
 		/* Now create 6 states */
 		memset(&freed[0], 0, sizeof(freed));
@@ -280,6 +289,7 @@
 		CHECK( 0, fd_sess_getsid(sess3, &str1) );
 		ms[4] = new_state(str1, &freed[4]);
 		ms[5] = new_state(str1, &freed[5]);
+		ms[5]->opaque = g_opaque;
 		str2 = strdup(str1);
 		CHECK( 1, str2 ? 1 : 0 );
 		
@@ -307,13 +317,14 @@
 		CHECK( 1, freed[5] );
 		
 		/* Destroy handler 2 */
-		CHECK( 0, fd_sess_handler_destroy( &hdl2 ) );
+		CHECK( 0, fd_sess_handler_destroy( &hdl2, &testptr ) );
 		CHECK( 0, freed[0] );
 		CHECK( 1, freed[1] );
 		CHECK( 0, freed[2] );
 		CHECK( 1, freed[3] );
 		CHECK( 1, freed[4] );
 		CHECK( 1, freed[5] );
+		CHECK( 1, testptr == g_opaque ? 1 : 0 );
 		
 		#if 1
 		fd_sess_dump(0, sess1);
@@ -348,7 +359,7 @@
 		/* Check the last data can still be retrieved */
 		CHECK( 0, fd_sess_state_retrieve( hdl1, sess1, &tms ) );
 		CHECK( 0, fd_sess_getsid(sess1, &str1) );
-		mycleanup(tms, str1);
+		mycleanup(tms, str1, NULL);
 	}
 	
 	
--- a/include/freeDiameter/libfreeDiameter.h	Fri Dec 17 18:41:19 2010 +0900
+++ b/include/freeDiameter/libfreeDiameter.h	Mon Dec 20 13:07:06 2010 +0900
@@ -1558,6 +1558,7 @@
  * PARAMETERS:
  *  handler	: location where the new handler must be stored.
  *  cleanup	: a callback function that must be called when the session with associated data is destroyed.
+ *  opaque      : A pointer that is passed to the cleanup callback -- the content is never examined by the framework.
  *
  * DESCRIPTION: 
  *  Create a new session handler. This is needed by a module to associate a state with a session object.
@@ -1569,10 +1570,10 @@
  *  EINVAL 	: A parameter is invalid.
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid) );
+int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid, void * opaque), void * opaque );
 /* Macro to avoid casting everywhere */
-#define fd_sess_handler_create( _handler, _cleanup ) \
-	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, char *))(_cleanup) )
+#define fd_sess_handler_create( _handler, _cleanup, _opaque ) \
+	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, char *, void *))(_cleanup), (void *)(_opaque) )
 
 	
 /*
@@ -1580,6 +1581,7 @@
  *
  * PARAMETERS:
  *  handler	: location of an handler created by fd_sess_handler_create.
+ *  opaque      : the opaque pointer registered with the callback is restored here (if ! NULL).
  *
  * DESCRIPTION: 
  *  This destroys a session handler (typically called when an application is shutting down).
@@ -1590,7 +1592,7 @@
  *  EINVAL 	: A parameter is invalid.
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_handler_destroy ( struct session_handler ** handler );
+int fd_sess_handler_destroy ( struct session_handler ** handler, void **opaque );
 
 
 
@@ -2525,6 +2527,7 @@
  *  msg 	: the received message on function entry. may be updated to answer on return (see description)
  *  avp 	: for callbacks registered with DISP_HOW_AVP or DISP_HOW_AVP_ENUMVAL, direct link to the triggering AVP.
  *  session	: if the message contains a Session-Id AVP, the corresponding session object, NULL otherwise.
+ *  opaque      : An opaque pointer that is registered along the session handler.
  *  action	: upon return, this tells the daemon what to do next.
  *
  * DESCRIPTION: 
@@ -2556,6 +2559,7 @@
  *  cb 		  : The callback function to register (see dispatch_callback description above).
  *  how	  	  : How the callback must be registered.
  *  when          : Values that must match, depending on the how argument.
+ *  opaque        : A pointer that is passed back to the handler. The content is not interpreted by the framework.
  *  handle        : On success, a handler to the registered callback is stored here if not NULL. 
  *		   This handler can be used to unregister the cb.
  *
@@ -2567,14 +2571,15 @@
  *  EINVAL 	: A parameter is invalid.
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, enum disp_action *), 
-			enum disp_how how, struct disp_when * when, struct disp_hdl ** handle );
+int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *), 
+			enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle );
 
 /*
  * FUNCTION:	fd_disp_unregister
  *
  * PARAMETERS:
  *  handle       : Location of the handle of the callback that must be unregistered.
+ *  opaque       : If not NULL, the opaque data that was registered is restored here.
  *
  * DESCRIPTION: 
  *   Removes a callback previously registered by fd_disp_register.
@@ -2583,7 +2588,7 @@
  *  0      	: The callback is unregistered.
  *  EINVAL 	: A parameter is invalid.
  */
-int fd_disp_unregister ( struct disp_hdl ** handle );
+int fd_disp_unregister ( struct disp_hdl ** handle, void ** opaque );
 
 /* Destroy all handlers */
 void fd_disp_unregister_all ( void );
--- a/libfreeDiameter/dispatch.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/libfreeDiameter/dispatch.c	Mon Dec 20 13:07:06 2010 +0900
@@ -55,7 +55,8 @@
 	struct fd_list	 parent;/* link in dictionary cb_list or in any_handlers */
 	enum disp_how	 how;	/* Copy of registration parameter */
 	struct disp_when when;	/* Copy of registration parameter */
-	int		(*cb)( struct msg **, struct avp *, struct session *, enum disp_action *);	/* The callback itself */
+	int		(*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *);	/* The callback itself */
+	void            *opaque; /* opaque data passed back to the callback */
 };
 
 #define DISP_EYEC	0xD15241C1
@@ -92,7 +93,7 @@
 			continue;
 		
 		/* We have a match, the cb must be called. */
-		CHECK_FCT( (*hdl->cb)(msg, avp, sess, action) );
+		CHECK_FCT( (*hdl->cb)(msg, avp, sess, hdl->opaque, action) );
 		
 		if (*action != DISP_ACT_CONT)
 			break;
@@ -108,8 +109,8 @@
 /**************************************************************************************/
 
 /* Create a new handler and link it */
-int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, enum disp_action *), 
-			enum disp_how how, struct disp_when * when, struct disp_hdl ** handle )
+int fd_disp_register ( int (*cb)( struct msg **, struct avp *, struct session *, void *, enum disp_action *), 
+			enum disp_how how, struct disp_when * when, void * opaque, struct disp_hdl ** handle )
 {
 	struct fd_list * cb_list = NULL;
 	struct disp_hdl * new;
@@ -170,6 +171,7 @@
 			new->when.app     = when->app;
 	}
 	new->cb = cb;
+	new->opaque = opaque;
 	
 	/* Now, link this new element in the appropriate lists */
 	CHECK_POSIX( pthread_rwlock_wrlock(&fd_disp_lock) );
@@ -185,7 +187,7 @@
 }
 
 /* Delete a handler */
-int fd_disp_unregister ( struct disp_hdl ** handle )
+int fd_disp_unregister ( struct disp_hdl ** handle, void ** opaque )
 {
 	struct disp_hdl * del;
 	TRACE_ENTRY("%p", handle);
@@ -198,6 +200,9 @@
 	fd_list_unlink(&del->parent);
 	CHECK_POSIX( pthread_rwlock_unlock(&fd_disp_lock) );
 	
+	if (opaque)
+		*opaque = del->opaque;
+	
 	free(del);
 	return 0;
 }
@@ -207,7 +212,7 @@
 {
 	TRACE_ENTRY("");
 	while (!FD_IS_LIST_EMPTY(&all_handlers)) {
-		CHECK_FCT_DO( fd_disp_unregister((void *)&(all_handlers.next->o)), /* continue */ );
+		CHECK_FCT_DO( fd_disp_unregister((void *)&(all_handlers.next->o), NULL), /* continue */ );
 	}
 	return;
 }
--- a/libfreeDiameter/sessions.c	Fri Dec 17 18:41:19 2010 +0900
+++ b/libfreeDiameter/sessions.c	Mon Dec 20 13:07:06 2010 +0900
@@ -68,7 +68,8 @@
 struct session_handler {
 	int		  eyec;	/* An eye catcher also used to ensure the object is valid, must be SH_EYEC */
 	int		  id;	/* A unique integer to identify this handler */
-	void 		(*cleanup)(session_state *, char *); /* The cleanup function to be called for cleaning a state */
+	void 		(*cleanup)(session_state *, char *, void *); /* The cleanup function to be called for cleaning a state */
+	void             *opaque; /* a value that is passed as is to the cleanup callback */
 };
 
 static int 		hdl_id = 0;				/* A global counter to initialize the id field */
@@ -252,7 +253,7 @@
 }
 
 /* Create a new handler */
-int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid) )
+int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, char * sid, void * opaque), void * opaque )
 {
 	struct session_handler *new;
 	
@@ -269,6 +270,7 @@
 	
 	new->eyec = SH_EYEC;
 	new->cleanup = cleanup;
+	new->opaque = opaque;
 	
 	*handler = new;
 	return 0;
@@ -276,7 +278,7 @@
 
 /* Destroy a handler, and all states attached to this handler. This operation is very slow but we don't care since it's rarely used. 
  * Note that it's better to call this function after all sessions have been deleted... */
-int fd_sess_handler_destroy ( struct session_handler ** handler )
+int fd_sess_handler_destroy ( struct session_handler ** handler, void ** opaque )
 {
 	struct session_handler * del;
 	/* place to save the list of states to be cleaned up. We do it after finding them to avoid deadlocks. the "o" field becomes a copy of the sid. */
@@ -322,12 +324,15 @@
 	while (!FD_IS_LIST_EMPTY(&deleted_states)) {
 		struct state * st = (struct state *)(deleted_states.next->o);
 		TRACE_DEBUG(FULL, "Calling cleanup handler for session '%s' and data %p", st->sid, st->state);
-		(*del->cleanup)(st->state, st->sid);
+		(*del->cleanup)(st->state, st->sid, del->opaque);
 		free(st->sid);
 		fd_list_unlink(&st->chain);
 		free(st);
 	}
 	
+	if (opaque)
+		*opaque = del->opaque;
+	
 	/* Free the handler */
 	free(del);
 	
@@ -582,7 +587,7 @@
 		struct state * st = (struct state *)(sess->states.next->o);
 		fd_list_unlink(&st->chain);
 		TRACE_DEBUG(FULL, "Calling handler %p cleanup for state registered with session '%s'", st->hdl, sess->sid);
-		(*st->hdl->cleanup)(st->state, sess->sid);
+		(*st->hdl->cleanup)(st->state, sess->sid, st->hdl->opaque);
 		free(st);
 	}
 	
@@ -804,7 +809,7 @@
 	if (!VALIDATE_SH(handler)) {
 		fd_log_debug("\t  %*s  Invalid session handler object\n", level, "");
 	} else {
-		fd_log_debug("\t  %*s  id %d, cleanup %p\n", level, "", handler->id, handler->cleanup);
+		fd_log_debug("\t  %*s  id %d, cleanup %p, opaque %p\n", level, "", handler->id, handler->cleanup, handler->opaque);
 	}
 	fd_log_debug("\t  %*s -- end of handler @%p --\n", level, "", handler);
 }	
"Welcome to our mercurial repository"