changeset 277:bad2424e6d0f

Completed first version of app_test
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 19 Dec 2008 15:07:17 +0900
parents c40eed4b4551
children db74ce92d203
files doc/app_test.conf.sample extensions/app_test/Makefile.am extensions/app_test/app_test.c extensions/app_test/app_test.h extensions/app_test/atst_cli.c extensions/app_test/atst_dict.c extensions/app_test/atst_disp.c extensions/app_test/atst_gram.y extensions/app_test/atst_send.c extensions/app_test/atst_serv.c extensions/app_test/atst_tok.l include/waaad/message-api.h
diffstat 12 files changed, 821 insertions(+), 144 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doc/app_test.conf.sample	Fri Dec 19 15:07:17 2008 +0900
@@ -0,0 +1,58 @@
+#######################
+# This file contains the description of configuration and general information about the
+# "App_test" waaad extension.
+
+# This extension provides a simple way to send a predefined message over the Diameter Network.
+# It may be used to test the Routing or other base mechanisms from the Diameter network.
+
+# In order to enable this extension, the [extensions] section of the main waaad configuration
+# file must contain the following declaration:
+# "app_default" = {
+# 	filename="/path/to/app_default.so";
+#	conffile="/path/to/app_default.conf";
+# };
+# Note that the conffile may be omitted, in which case default parameters will be assumed.
+#######################
+
+
+#######################
+# Configuration of the test message
+
+# This application is defined as a Vendor-Specific application. 
+# Since waaad does not have a IANA-assigned Vendor ID, we let a configurable value here:
+# vendor-id = 999999;
+
+# The application id. Same remark as previously.
+# appli-id = 123456;
+
+# The command code for Test-Request and Test-Answer. Same remark as previously.
+# cmd-id = 234567;
+
+# The AVP id for the test. Same remark as previously.
+# avp-id = 345678;
+
+#######################
+# Configuration of the extension behavior
+
+# The mode for the extension.
+# - server: Answer incoming requests. The signal is ignored.
+# - client: Send a request when the signal is received, and measure the time to receiving answer.
+# - both: acts as client and server
+# mode = both;
+
+#######################
+# Client-specific configuration
+
+# The Destination-Realm for the message
+# (default is sending to same realm as local peer).
+# dest-realm = "foreign.net";
+
+# The Destination-Host for the message.
+# (default is not providing this AVP).
+# dest-host = "server.foreign.net";
+
+# The signal that triggers sending the test message
+# Note: Symbolic names are now recognized yet, you must use integers
+# signal = 10;
+
+
--- a/extensions/app_test/Makefile.am	Fri Dec 19 10:25:29 2008 +0900
+++ b/extensions/app_test/Makefile.am	Fri Dec 19 15:07:17 2008 +0900
@@ -20,5 +20,5 @@
 			atst_tok.l	\
 			atst_sig.c	\
 			atst_dict.c	\
-			atst_disp.c	\
-			atst_send.c
+			atst_serv.c	\
+			atst_cli.c
--- a/extensions/app_test/app_test.c	Fri Dec 19 10:25:29 2008 +0900
+++ b/extensions/app_test/app_test.c	Fri Dec 19 15:07:17 2008 +0900
@@ -50,7 +50,14 @@
 	memset(atst_conf, 0, sizeof(atst_conf_t));
 	
 	/* Set the default values */
-	atst_conf->signal = SIGUSR1;
+	atst_conf->vendor_id  = 999999;
+	atst_conf->appli_id   = 123456;
+	atst_conf->cmd_id     = 234567;
+	atst_conf->avp_id     = 345678;
+	atst_conf->mode       = MODE_SERV | MODE_CLI;
+	atst_conf->dest_realm = strdup(g_pconf->diameter_realm);
+	atst_conf->dest_host  = NULL;
+	atst_conf->signal     = SIGUSR1;
 	
 	return 0;
 }
@@ -58,50 +65,39 @@
 /* entry point */
 static int entry(char * conffile)
 {
-	int ret = 0;
-	
 	TRACE_ENTRY("%p", conffile);
 	
 	/* Initialize configuration */
-	ret = conf_init();
-	if (ret)
-		goto out;
+	CHECK( conf_init() );
 	
 	/* Parse configuration file */
 	if (conffile != NULL) {
-		ret = conf_parse(conffile);
-		if (ret)
-			goto out;
+		CHECK( conf_parse(conffile) );
 	}
 	
 	/* Install objects definitions for this test application */
-	ret = dict_init();
-	if (ret)
-		goto out;
+	CHECK( dict_init() );
 	
 	/* Install the handlers for incoming messages */
-	ret = disp_init();
-	if (ret)
-		goto out;
+	if (atst_conf->mode & MODE_SERV) {
+		CHECK( serv_init() );
+	}
 	
 	/* Start the signal handler thread */
-	ret = sig_init(send_test_message);
-	if (ret)
-		goto out;
+	if (atst_conf->mode & MODE_CLI) {
+		CHECK( cli_init() );
+	}
 	
-	/* We're done */
-	
-out:
-	if (ret)
-		log_error("Error initializing extension: %s\n", strerror(ret));
-	return ret;
+	return 0;
 }
 
 /* Unload */
 void waaad_ext_fini(void)
 {
-	sig_fini();
-	disp_fini();
+	if (atst_conf->mode & MODE_CLI)
+		cli_fini();
+	if (atst_conf->mode & MODE_SERV)
+		serv_fini();
 }
 
 EXTENSION_API_INIT( API_MODULE_ALL, entry, "app_test");
--- a/extensions/app_test/app_test.h	Fri Dec 19 10:25:29 2008 +0900
+++ b/extensions/app_test/app_test.h	Fri Dec 19 15:07:17 2008 +0900
@@ -44,15 +44,26 @@
 #include <waaad/waaad.h>
 
 #include <pthread.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <signal.h>
+#include <assert.h>
+
+/* Mode for the extension */
+#define MODE_SERV	0x1
+#define	MODE_CLI	0x2
 
 /* The module configuration */
 typedef struct {
-	/* debug level */
-	int 	signal;		/* default: SIGUSR1 */
-	
+	uint32_t	vendor_id;	/* default 999999 */
+	uint32_t	appli_id;	/* default 123456 */
+	uint32_t	cmd_id;		/* default 234567 */
+	uint32_t	avp_id;		/* default 345678 */
+	int		mode;		/* default MODE_SERV | MODE_CLI */
+	char 	*	dest_realm;	/* default g_pconf->realm */
+	char 	*	dest_host;	/* default NULL */
+	int 		signal;		/* default SIGUSR1 */
 } atst_conf_t;
 extern atst_conf_t * atst_conf;
 
@@ -64,15 +75,31 @@
 int sig_init(void (*cb)(void));
 void sig_fini(void);
 
+/* Handle incoming messages (server) */
+int serv_init(void);
+void serv_fini(void);
+
+/* Create outgoing message (client) */
+int cli_init(void);
+void cli_fini(void);
+
 /* Initialize dictionary definitions */
 int dict_init(void);
 
-/* Handle incoming messages */
-int disp_init(void);
-void disp_fini(void);
 
-/* Create outgoing message */
-void send_test_message(void);
+/* Some global variables for dictionary */
+extern dict_object_t * vendor;
+extern dict_object_t * appli;
+extern dict_object_t * cmd_r;
+extern dict_object_t * cmd_a;
+extern dict_object_t * avp;
+
+extern dict_object_t * sess_id;
+extern dict_object_t * origin_host;
+extern dict_object_t * origin_realm;
+extern dict_object_t * dest_host;
+extern dict_object_t * dest_realm;
+extern dict_object_t * res_code;
 
 
 /**********************************************************************************
@@ -91,3 +118,32 @@
 #define TRACE_ENTRY(_format,_args... ) \
 	TRACE_DEBUG(FULL, "Entering ext function (parms: " _format ")", ##_args )
 /**************************************************************************************/
+
+#define ASSERT( _x ) assert( _x )
+
+#define CHECK( _call ) {								\
+	int __ret = ( _call );								\
+	if ( __ret != 0 ) {								\
+		TRACE_DEBUG(INFO, "Error in function call");				\
+		log_error("Error in extension (" #_call "): %s\n", strerror(__ret));	\
+		return __ret;								\
+	}										\
+}
+
+#define CHECK_NEG( _call ) {								\
+	int __ret = ( _call );								\
+	if ( __ret != 0 ) {								\
+		TRACE_DEBUG(INFO, "Error in function call");				\
+		log_error("Error in extension (" #_call "): %s\n", strerror(__ret));	\
+		return - __ret;								\
+	}										\
+}
+
+#define CHECK_VOID( _call ) {								\
+	int __ret = ( _call );								\
+	if ( __ret != 0 ) {								\
+		TRACE_DEBUG(INFO, "Error in function call");				\
+		log_error("Error in extension (" #_call "): %s\n", strerror(__ret));	\
+		return;								\
+	}										\
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/app_test/atst_cli.c	Fri Dec 19 15:07:17 2008 +0900
@@ -0,0 +1,304 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Create and send a message, and receive it */
+
+/* Note that we use both sessions and the argument to answer callback to pass the same value.
+ * This is just for the purpose of checking everything went OK.
+ */
+
+#include "app_test.h"
+
+static sess_reg_t * cli_reg = NULL;
+
+typedef struct {
+	int32_t		randval;	/* a random value to store in Test-AVP */
+	struct timespec ts;		/* Time of sending the message */
+} mess_info_t;
+
+/* Cb called when an answer is received */
+static void cb_ans(void * data, msg_t ** msg)
+{
+	mess_info_t * mi = NULL;
+	struct timespec ts;
+	
+	CHECK_VOID( clock_gettime(CLOCK_REALTIME, &ts) );
+
+	/* Search the session, retrieve its data */
+	{
+		sess_id_t *sess = NULL;
+		msg_avp_t * src = NULL;
+		msg_avp_data_t * data = NULL;
+		int new;
+		
+		CHECK_VOID( msg_search_avp(*msg, sess_id, &src) );
+		CHECK_VOID( msg_avp_data( src, &data ) );
+		
+		CHECK_VOID( sess_fromsid( (char *)data->avp_data->os.data, data->avp_data->os.len, &sess, &new) );
+		ASSERT( new == 0 );
+		
+		CHECK_VOID( sess_data_dereg( sess, cli_reg, (void *)&mi) );
+		
+		ASSERT( (void *)mi == data );
+		
+		CHECK_VOID( sess_unlink( &sess ) );
+	}
+	
+	/* Now log content of the answer */
+	fprintf(stderr, "RECV ");
+	
+	/* Value of Test-AVP */
+	{
+		msg_avp_t * src = NULL;
+		msg_avp_data_t * data = NULL;
+		
+		CHECK_VOID( msg_search_avp(*msg, avp, &src) );
+		if (src) {
+			CHECK_VOID( msg_avp_data( src, &data ) );
+			fprintf(stderr, "%x (%s) ", data->avp_data->i32, (data->avp_data->i32 == mi->randval) ? "Ok" : "PROBLEM");
+		} else {
+			fprintf(stderr, "no_Test-AVP ");
+		}
+	}
+	
+	/* Value of Result Code */
+	{
+		msg_avp_t * src = NULL;
+		msg_avp_data_t * data = NULL;
+		
+		CHECK_VOID( msg_search_avp(*msg, res_code, &src) );
+		if (src) {
+			CHECK_VOID( msg_avp_data( src, &data ) );
+			fprintf(stderr, "Status: %d ", data->avp_data->i32);
+		} else {
+			fprintf(stderr, "no_Result-Code ");
+		}
+	}
+	
+	/* Value of Origin-Host */
+	{
+		msg_avp_t * src = NULL;
+		msg_avp_data_t * data = NULL;
+		
+		CHECK_VOID( msg_search_avp(*msg, origin_host, &src) );
+		if (src) {
+			char * str;
+			CHECK_VOID( msg_avp_data( src, &data ) );
+			str = malloc(data->avp_data->os.len + 1);
+			memcpy(str, data->avp_data->os.data, data->avp_data->os.len);
+			str[data->avp_data->os.len] = '\0';
+			fprintf(stderr, "From '%s' ", str);
+			free(str);
+		} else {
+			fprintf(stderr, "no_Origin-Host ");
+		}
+	}
+	
+	/* Value of Origin-Realm */
+	{
+		msg_avp_t * src = NULL;
+		msg_avp_data_t * data = NULL;
+		
+		CHECK_VOID( msg_search_avp(*msg, origin_realm, &src) );
+		if (src) {
+			char * str;
+			CHECK_VOID( msg_avp_data( src, &data ) );
+			str = malloc(data->avp_data->os.len + 1);
+			memcpy(str, data->avp_data->os.data, data->avp_data->os.len);
+			str[data->avp_data->os.len] = '\0';
+			fprintf(stderr, "('%s') ", str);
+			free(str);
+		} else {
+			fprintf(stderr, "no_Origin-Realm ");
+		}
+	}
+	
+	/* Now compute how long it took */
+	if (ts.tv_nsec > mi->ts.tv_nsec) {
+		fprintf(stderr, "in %d.%06ld sec", 
+				(int)(ts.tv_sec - mi->ts.tv_sec),
+				(long)(ts.tv_nsec - mi->ts.tv_nsec) / 1000);
+	} else {
+		fprintf(stderr, "in %d.%06ld sec", 
+				(int)(ts.tv_sec + 1 - mi->ts.tv_sec),
+				(long)(1000000000 + ts.tv_nsec - mi->ts.tv_nsec) / 1000);
+	}
+	
+	fprintf(stderr, "\n");
+	fflush(stderr);
+	
+	/* Free the message */
+	CHECK_VOID(msg_free(*msg, 1));
+	*msg = NULL;
+	
+	free(mi);
+	
+	return;
+}
+
+static void cli_test_message(void)
+{
+	msg_t * req = NULL;
+	mess_info_t * mi = NULL;
+	sess_id_t *sess = NULL;
+	
+	TRACE_DEBUG(FULL, "Creating a new message for sending.");
+	
+	/* Create the request from template */
+	CHECK_VOID( msg_new( cmd_r, MSGFL_FROM_TEMPLATE | MSGFL_ALLOW_ETEID, &req ) );
+	
+	/* Create a new session */
+	CHECK_VOID( sess_new( &sess, SESSION_NEW_DEFAULT, "app_test" ) );
+	
+	/* Create the random value to store with the session */
+	mi = malloc(sizeof(mess_info_t));
+	if (mi == NULL) {
+		log_error("malloc failed: %s", strerror(errno));
+		return;
+	}
+	
+	mi->randval = (int32_t)random();
+	
+	/* Now set all AVPs values */
+	
+	/* Session-Id */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		CHECK_VOID( msg_search_avp(req, sess_id, &dst) );
+		
+		CHECK_VOID( sess_getsid(sess, (void *)&data.os.data) );
+		data.os.len  = strlen((char *)data.os.data);
+		
+		CHECK_VOID( msg_avp_setvalue( dst, &data) );
+	}
+	
+	/* Set the Destination-Realm AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.os.data = (unsigned char *)(atst_conf->dest_realm);
+		data.os.len  = strlen(atst_conf->dest_realm);
+		
+		CHECK_VOID( msg_search_avp(req, dest_realm, &dst) );
+		CHECK_VOID( msg_avp_setvalue( dst, &data) );
+	}
+	
+	/* Set or delete the Destination-Host AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		CHECK_VOID( msg_search_avp(req, dest_host, &dst) );
+		
+		if (atst_conf->dest_host) {
+			data.os.data = (unsigned char *)(atst_conf->dest_host);
+			data.os.len  = strlen(atst_conf->dest_host);
+
+			CHECK_VOID( msg_avp_setvalue( dst, &data) );
+		} else {
+			CHECK_VOID( msg_free ( dst, 0 ) );
+		}
+	}
+	
+	/* Set the Origin-Host AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.os.data = (unsigned char *)(g_pconf->diameter_identity);
+		data.os.len  = strlen(g_pconf->diameter_identity);
+		
+		CHECK_VOID( msg_search_avp(req, origin_host, &dst) );
+		CHECK_VOID( msg_avp_setvalue( dst, &data) );
+	}
+	
+	/* Set the Origin-Realm AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.os.data = (unsigned char *)(g_pconf->diameter_realm);
+		data.os.len  = strlen(g_pconf->diameter_realm);
+		
+		CHECK_VOID( msg_search_avp(req, origin_realm, &dst) );
+		CHECK_VOID( msg_avp_setvalue( dst, &data) );
+	}
+	
+	/* Set the Test-AVP AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.i32 = mi->randval;
+		
+		CHECK_VOID( msg_search_avp(req, avp, &dst) );
+		CHECK_VOID( msg_avp_setvalue( dst, &data) );
+	}
+	
+	CHECK_VOID( clock_gettime(CLOCK_REALTIME, &mi->ts) );
+	
+	/* Store this value in the session */
+	CHECK_VOID( sess_data_reg ( sess, cli_reg, (void *) mi, (void (*)(void *))free ) ); 
+	
+	/* Log sending the message */
+	fprintf(stderr, "SEND %x to '%s' (%s)\n", mi->randval, atst_conf->dest_realm, atst_conf->dest_host?:"-" );
+	fflush(stderr);
+	
+	/* Send the request */
+	CHECK_VOID( msg_send( &req, cb_ans, (void *)mi ) );
+	
+	return;
+}
+
+int cli_init(void)
+{
+	CHECK( sess_regext(&cli_reg) );
+	
+	CHECK( sig_init(cli_test_message) );
+	
+	return 0;
+}
+
+void cli_fini(void)
+{
+	(void) sess_deregext(cli_reg);
+	
+	sig_fini();
+	
+	return;
+};
--- a/extensions/app_test/atst_dict.c	Fri Dec 19 10:25:29 2008 +0900
+++ b/extensions/app_test/atst_dict.c	Fri Dec 19 15:07:17 2008 +0900
@@ -37,9 +37,121 @@
 
 #include "app_test.h"
 
+dict_object_t * vendor = NULL;
+dict_object_t * appli = NULL;
+dict_object_t * cmd_r = NULL;
+dict_object_t * cmd_a = NULL;
+dict_object_t * avp = NULL;
+
+dict_object_t * sess_id = NULL;
+dict_object_t * origin_host = NULL;
+dict_object_t * origin_realm = NULL;
+dict_object_t * dest_host = NULL;
+dict_object_t * dest_realm = NULL;
+dict_object_t * res_code = NULL;
+
 int dict_init(void)
 {
 	TRACE_DEBUG(FULL, "Initializing the dictionary for test");
 	
+	/* Create the Test Vendor */
+	{
+		dict_vendor_data_t data;
+		data.vendor_id = atst_conf->vendor_id;
+		data.vendor_name = "app_test vendor";
+		CHECK(dict_new( DICT_VENDOR, &data, NULL, &vendor));
+	}
+	
+	/* Create the Test Application */
+	{
+		dict_application_data_t data;
+		data.application_id = atst_conf->appli_id;
+		data.application_name = "app_test application";
+		CHECK(dict_new( DICT_APPLICATION, &data, vendor, &appli));
+	}
+	
+	/* Create the Test-Request & Test-Answer commands */
+	{
+		dict_cmd_data_t data;
+		data.cmd_code = atst_conf->cmd_id;
+		data.cmd_name = "Test-Request";
+		data.cmd_flag_mask = CMD_FLAG_PROXIABLE | CMD_FLAG_REQUEST;
+		data.cmd_flag_val  = CMD_FLAG_PROXIABLE | CMD_FLAG_REQUEST;
+		CHECK(dict_new( DICT_COMMAND, &data, appli, &cmd_r));
+		data.cmd_name = "Test-Answer";
+		data.cmd_flag_val  = CMD_FLAG_PROXIABLE;
+		CHECK(dict_new( DICT_COMMAND, &data, appli, &cmd_a));
+	}
+	
+	/* Create the Test AVP */
+	{
+		dict_avp_data_t data;
+		data.avp_code = atst_conf->avp_id;
+		data.avp_vendor = atst_conf->vendor_id;
+		data.avp_name = "Test-AVP";
+		data.avp_flag_mask = AVP_FLAG_VENDOR;
+		data.avp_flag_val = AVP_FLAG_VENDOR;
+		data.avp_basetype = AVP_TYPE_INTEGER32;
+		CHECK(dict_new( DICT_AVP, &data, NULL, &avp));
+	}
+	
+	/* Now resolve some other useful AVPs */
+	CHECK( dict_search( DICT_AVP, AVP_BY_NAME, "Session-Id", &sess_id) );
+	ASSERT( sess_id != NULL );
+	CHECK( dict_search( DICT_AVP, AVP_BY_NAME, "Origin-Host", &origin_host) );
+	ASSERT( origin_host != NULL );
+	CHECK( dict_search( DICT_AVP, AVP_BY_NAME, "Origin-Realm", &origin_realm) );
+	ASSERT( origin_realm != NULL );
+	CHECK( dict_search( DICT_AVP, AVP_BY_NAME, "Destination-Host", &dest_host) );
+	ASSERT( dest_host != NULL );
+	CHECK( dict_search( DICT_AVP, AVP_BY_NAME, "Destination-Realm", &dest_realm) );
+	ASSERT( dest_realm != NULL );
+	CHECK( dict_search( DICT_AVP, AVP_BY_NAME, "Result-Code", &res_code) );
+	ASSERT( res_code != NULL );
+	
+	/* Create the rules for Test-Request and Test-Answer */
+	{
+		dict_rule_data_t data;
+		data.rule_min = 1;
+		data.rule_max = 1;
+		data.rule_template = 1;
+		
+		/* Session-Id is in first position */
+		data.rule_avp = sess_id;
+		data.rule_position = RULE_FIXED_HEAD;
+		data.rule_order = 1;
+		CHECK(dict_new( DICT_RULE, &data, cmd_r, NULL));
+		CHECK(dict_new( DICT_RULE, &data, cmd_a, NULL));
+		
+		data.rule_position = RULE_REQUIRED;
+		/* Test-AVP is mandatory */
+		data.rule_avp = avp;
+		CHECK(dict_new( DICT_RULE, &data, cmd_r, NULL));
+		CHECK(dict_new( DICT_RULE, &data, cmd_a, NULL));
+		
+		/* idem for Origin Host and Realm */
+		data.rule_avp = origin_host;
+		CHECK(dict_new( DICT_RULE, &data, cmd_r, NULL));
+		CHECK(dict_new( DICT_RULE, &data, cmd_a, NULL));
+		
+		data.rule_avp = origin_realm;
+		CHECK(dict_new( DICT_RULE, &data, cmd_r, NULL));
+		CHECK(dict_new( DICT_RULE, &data, cmd_a, NULL));
+		
+		/* And Result-Code is mandatory for answers only */
+		data.rule_avp = res_code;
+		CHECK(dict_new( DICT_RULE, &data, cmd_a, NULL));
+		
+		/* And Destination-Realm for requests only */
+		data.rule_avp = dest_realm;
+		CHECK(dict_new( DICT_RULE, &data, cmd_r, NULL));
+		
+		/* And Destination-Host optional for requests only */
+		data.rule_position = RULE_OPTIONAL;
+		data.rule_avp = dest_host;
+		CHECK(dict_new( DICT_RULE, &data, cmd_r, NULL));
+		
+	}
+	
 	return 0;
 }
--- a/extensions/app_test/atst_disp.c	Fri Dec 19 10:25:29 2008 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,53 +0,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
-*													 *
-* Copyright (c) 2008, WIDE Project and NICT								 *
-* All rights reserved.											 *
-* 													 *
-* Redistribution and use of this software in source and binary forms, with or without modification, are  *
-* permitted provided that the following conditions are met:						 *
-* 													 *
-* * Redistributions of source code must retain the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer.										 *
-*    													 *
-* * Redistributions in binary form must reproduce the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer in the documentation and/or other						 *
-*   materials provided with the distribution.								 *
-* 													 *
-* * Neither the name of the WIDE Project or NICT nor the 						 *
-*   names of its contributors may be used to endorse or 						 *
-*   promote products derived from this software without 						 *
-*   specific prior written permission of WIDE Project and 						 *
-*   NICT.												 *
-* 													 *
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
-* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
-* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
-* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
-* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
-*********************************************************************************************************/
-
-/* Install the dispatch callbacks */
-
-#include "app_test.h"
-
-int disp_init(void)
-{
-	TRACE_DEBUG(FULL, "Initializing dispatch callbacks for test");
-	
-	
-	return 0;
-}
-
-void disp_fini(void)
-{
-	
-	
-	return;
-}
--- a/extensions/app_test/atst_gram.y	Fri Dec 19 10:25:29 2008 +0900
+++ b/extensions/app_test/atst_gram.y	Fri Dec 19 15:07:17 2008 +0900
@@ -116,9 +116,15 @@
 %token 		LEX_ERROR
 
 /* Key words */
+%token 		VENDOR_ID
+%token 		APPLI_ID
+%token 		CMD_ID
+%token 		AVP_ID
+%token 		MODE
+%token 		DEST_REALM
+%token 		DEST_HOST
 %token 		SIGNAL
 
-
 /* Tokens and types for routing table definition */
 /* A (de)quoted string (malloc'd in lex parser; it must be freed after use) */
 %token <string>	QSTRING
@@ -133,10 +139,60 @@
 
 	/* The grammar definition */
 conffile:		/* empty grammar is OK */
+			| conffile vendor
+			| conffile appli
+			| conffile cmd
+			| conffile avp
+			| conffile mode
+			| conffile dstrealm
+			| conffile dsthost
 			| conffile signal
 			;
 
-	/* Defining the extension debug verbosity level */
+vendor:			VENDOR_ID '=' INTEGER ';'
+			{
+				atst_conf->vendor_id = $3;
+			}
+			;
+
+appli:			APPLI_ID '=' INTEGER ';'
+			{
+				atst_conf->appli_id = $3;
+			}
+			;
+
+cmd:			CMD_ID '=' INTEGER ';'
+			{
+				atst_conf->cmd_id = $3;
+			}
+			;
+
+avp:			AVP_ID '=' INTEGER ';'
+			{
+				atst_conf->avp_id = $3;
+			}
+			;
+
+mode:			MODE '=' INTEGER ';'
+			{
+				atst_conf->mode = $3;
+			}
+			;
+
+dstrealm:		DEST_REALM '=' QSTRING ';'
+			{
+				free(atst_conf->dest_realm);
+				atst_conf->dest_realm = $3;
+			}
+			;
+
+dsthost:		DEST_HOST '=' QSTRING ';'
+			{
+				free(atst_conf->dest_host);
+				atst_conf->dest_host = $3;
+			}
+			;
+
 signal:			SIGNAL '=' INTEGER ';'
 			{
 				atst_conf->signal = $3;
--- a/extensions/app_test/atst_send.c	Fri Dec 19 10:25:29 2008 +0900
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*********************************************************************************************************
-* Software License Agreement (BSD License)                                                               *
-* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
-*													 *
-* Copyright (c) 2008, WIDE Project and NICT								 *
-* All rights reserved.											 *
-* 													 *
-* Redistribution and use of this software in source and binary forms, with or without modification, are  *
-* permitted provided that the following conditions are met:						 *
-* 													 *
-* * Redistributions of source code must retain the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer.										 *
-*    													 *
-* * Redistributions in binary form must reproduce the above 						 *
-*   copyright notice, this list of conditions and the 							 *
-*   following disclaimer in the documentation and/or other						 *
-*   materials provided with the distribution.								 *
-* 													 *
-* * Neither the name of the WIDE Project or NICT nor the 						 *
-*   names of its contributors may be used to endorse or 						 *
-*   promote products derived from this software without 						 *
-*   specific prior written permission of WIDE Project and 						 *
-*   NICT.												 *
-* 													 *
-* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
-* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
-* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
-* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
-* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
-* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
-* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
-* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
-*********************************************************************************************************/
-
-/* Create and send a message */
-
-#include "app_test.h"
-
-void send_test_message(void)
-{
-	TRACE_DEBUG(FULL, "Creating a new message for sending.");
-	
-	/* The idea here is to read from a file and the parser directly creates the message and sends it */
-	
-	
-	return;
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extensions/app_test/atst_serv.c	Fri Dec 19 15:07:17 2008 +0900
@@ -0,0 +1,154 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2008, WIDE Project and NICT								 *
+* All rights reserved.											 *
+* 													 *
+* Redistribution and use of this software in source and binary forms, with or without modification, are  *
+* permitted provided that the following conditions are met:						 *
+* 													 *
+* * Redistributions of source code must retain the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer.										 *
+*    													 *
+* * Redistributions in binary form must reproduce the above 						 *
+*   copyright notice, this list of conditions and the 							 *
+*   following disclaimer in the documentation and/or other						 *
+*   materials provided with the distribution.								 *
+* 													 *
+* * Neither the name of the WIDE Project or NICT nor the 						 *
+*   names of its contributors may be used to endorse or 						 *
+*   promote products derived from this software without 						 *
+*   specific prior written permission of WIDE Project and 						 *
+*   NICT.												 *
+* 													 *
+* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
+* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
+* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
+* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
+* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
+* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
+*********************************************************************************************************/
+
+/* Install the dispatch callbacks */
+
+#include "app_test.h"
+
+static disp_cb_hdl_t * hdl_fb = NULL; /* handler for fallback cb */
+static disp_cb_hdl_t * hdl_tr = NULL; /* handler for Test-Request req cb */
+
+/* Default callback for the application. */
+static int fb_cb( msg_t * msg, msg_avp_t * avp, int handled )
+{
+	/* This CB should never be called */
+	TRACE_ENTRY("%p %p %d", msg, avp, handled);
+	
+	log_error("Unexpected message received!\n");
+	
+	return -ENOTSUP;
+}
+
+/* Callback for incoming Test-Request messages */
+static int tr_cb( msg_t * msg, msg_avp_t * avp, int handled )
+{
+	msg_t * ans = msg;
+	
+	TRACE_ENTRY("%p %p %d", msg, avp, handled);
+	
+	/* Create answer header */
+	CHECK_NEG( msg_new_answ(&ans, MSGFL_FROM_TEMPLATE) );
+	
+	/* Set the Session-Id AVP */
+	{
+		msg_avp_t * src = NULL;
+		msg_avp_t * dst = NULL;
+		msg_avp_data_t * data = NULL;
+		
+		CHECK_NEG( msg_search_avp(msg, sess_id, &src) );
+		CHECK_NEG( msg_search_avp(ans, sess_id, &dst) );
+		CHECK_NEG( msg_avp_data( src, &data ) );
+		CHECK_NEG( msg_avp_setvalue( dst, data->avp_data) );
+	}
+	/* Set the Test-AVP AVP */
+	{
+		msg_avp_t * src = NULL;
+		msg_avp_t * dst = NULL;
+		msg_avp_data_t * data = NULL;
+		
+		CHECK_NEG( msg_search_avp(msg, avp, &src) );
+		CHECK_NEG( msg_search_avp(ans, avp, &dst) );
+		CHECK_NEG( msg_avp_data( src, &data ) );
+		CHECK_NEG( msg_avp_setvalue( dst, data->avp_data) );
+	}
+	
+	/* Set the Origin-Host AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.os.data = (unsigned char *)(g_pconf->diameter_identity);
+		data.os.len  = strlen(g_pconf->diameter_identity);
+		
+		CHECK_NEG( msg_search_avp(ans, origin_host, &dst) );
+		CHECK_NEG( msg_avp_setvalue( dst, &data) );
+	}
+	
+	/* Set the Origin-Realm AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.os.data = (unsigned char *)(g_pconf->diameter_realm);
+		data.os.len  = strlen(g_pconf->diameter_realm);
+		
+		CHECK_NEG( msg_search_avp(ans, origin_realm, &dst) );
+		CHECK_NEG( msg_avp_setvalue( dst, &data) );
+	}
+	
+	/* Set the Result-Code AVP */
+	{
+		msg_avp_t * dst = NULL;
+		avp_value_t data;
+		
+		data.u32 = 2001; /* Success */
+		
+		CHECK_NEG( msg_search_avp(ans, res_code, &dst) );
+		CHECK_NEG( msg_avp_setvalue( dst, &data) );
+	}
+	
+	return DISP_CBRET_HANDLED_STOP;
+}
+
+int serv_init(void)
+{
+	disp_reg_val_t data;
+	
+	TRACE_DEBUG(FULL, "Initializing dispatch callbacks for test");
+	
+	data.flags = 3;
+	data.app_id = appli;
+	data.command = cmd_r;
+	
+	/* fallback CB if command != Test-Request received */
+	CHECK( disp_register( fb_cb, DISP_REG_APPID, &data, &hdl_fb ) );
+	
+	/* Now specific handler for Test-Request */
+	CHECK( disp_register( tr_cb, DISP_REG_CC, &data, &hdl_tr ) );
+	
+	return 0;
+}
+
+void serv_fini(void)
+{
+	if (hdl_fb) {
+		(void) disp_unregister(hdl_fb);
+	}
+	if (hdl_tr) {
+		(void) disp_unregister(hdl_tr);
+	}
+	
+	return;
+}
--- a/extensions/app_test/atst_tok.l	Fri Dec 19 10:25:29 2008 +0900
+++ b/extensions/app_test/atst_tok.l	Fri Dec 19 15:07:17 2008 +0900
@@ -100,13 +100,53 @@
 				return QSTRING;
 			}
 			
-	/* Recognize the verbosity string */	
+	/* Recognize the tokens */	
+(?i:"vendor-id")	{
+				return VENDOR_ID;
+			}
+
+(?i:"appli-id")		{
+				return APPLI_ID;
+			}
+
+(?i:"cmd-id")		{
+				return CMD_ID;
+			}
+
+(?i:"avp-id")		{
+				return AVP_ID;
+			}
+
+(?i:"mode")		{
+				return MODE;
+			}
+
+(?i:"server")		{
+				yylval->integer = MODE_SERV;
+				return INTEGER;
+			}
+
+(?i:"client")		{
+				yylval->integer = MODE_CLI;
+				return INTEGER;
+			}
+
+(?i:"both")		{
+				yylval->integer = MODE_SERV | MODE_CLI;
+				return INTEGER;
+			}
+
+(?i:"dest-realm")	{
+				return DEST_REALM;
+			}
+
+(?i:"dest-host")	{
+				return DEST_HOST;
+			}
+
 (?i:"Signal")		{
 				return SIGNAL;
 			}
-	/* Idem for other tokens */
-
-
 
 			
 	/* Valid single characters for yyparse */
--- a/include/waaad/message-api.h	Fri Dec 19 10:25:29 2008 +0900
+++ b/include/waaad/message-api.h	Fri Dec 19 15:07:17 2008 +0900
@@ -283,8 +283,10 @@
  *
  * DESCRIPTION: 
  *   Create a new anwer message corresponding to a query.
- *  Note that upon return, the query object is no longer available. It is anyway safe to keep a copy
+ *   Note that upon return, the query object is no longer available. It is anyway safe to keep a copy
  *  of a pointer to this query, as long as it is not modified or freed.
+ *   Note also that no AVP value is set in the answer. The calling app must create the Session-Id AVP, 
+ *  Origin-Host, and so on...
  *
  * RETURN VALUE:
  *  0      	: The answer message is created.
"Welcome to our mercurial repository"