changeset 1093:44f3e48dfe27

Align the behavior of all fd_*dump functions wrt final \n
author Sebastien Decugis <sdecugis@freediameter.net>
date Mon, 06 May 2013 16:33:22 +0800
parents e40374ddfeef
children eab8cad30b4c
files include/freeDiameter/libfdproto.h libfdcore/config.c libfdcore/endpoints.c libfdcore/events.c libfdcore/extensions.c libfdcore/peers.c libfdcore/server.c libfdproto/dictionary.c libfdproto/dictionary_functions.c libfdproto/fifo.c libfdproto/messages.c libfdproto/sessions.c libfdproto/utils.c tests/testdict.c tests/testmesg_stress.c
diffstat 15 files changed, 329 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/include/freeDiameter/libfdproto.h	Mon May 06 11:30:34 2013 +0800
+++ b/include/freeDiameter/libfdproto.h	Mon May 06 16:33:22 2013 +0800
@@ -221,24 +221,33 @@
 int fd_log_handler_unregister ( void );
 
 
-/* Helper functions for the *dump functions that add into a buffer */
-char * fd_dump_extend(char ** buf, size_t *len, size_t *offset, const char * format, ... ) _ATTRIBUTE_PRINTFLIKE_(4,5);
-char * fd_dump_extend_hexdump(char ** buf, size_t *len, size_t *offset, uint8_t *data, size_t datalen, size_t trunc, size_t wrap );
-
-/* All dump functions follow the same prototype:
+/* All dump functions follow this same prototype:
  * PARAMETERS:
- *   buf   : *buf can be NULL on entry, it will be malloc'd. Otherwise it can be realloc'd if needed.
+ *   buf   : *buf can be NULL on entry, it will be malloc'd. Otherwise it is realloc'd if needed.
  *   len   : the current size of the buffer (in/out)
  *   offset: (optional) if provided, starts writing dump at offset in the buffer, and updated upon exit. if NULL, starts at offset O.
  *
  * RETURN VALUE:
  *   *buf upon success, NULL upon failure.
- * After the buffer has been used, it should be freed.
+ *
+ * REMARKS:
+ *  - After the buffer has been used, it should be freed.
+ *  - Depending on the function, the created string may be multi-line. However, it should never be terminated with a '\n'.
  */
 #define DECLARE_FD_DUMP_PROTOTYPE( function_name, args... )	\
 	char * function_name(char ** buf, size_t *len, size_t *offset, ##args)
 	
+
+/* Helper functions for the *dump functions that add into a buffer */
+DECLARE_FD_DUMP_PROTOTYPE( fd_dump_extend, const char * format, ... ) _ATTRIBUTE_PRINTFLIKE_(4,5);
+DECLARE_FD_DUMP_PROTOTYPE( fd_dump_extend_hexdump, uint8_t *data, size_t datalen, size_t trunc, size_t wrap );
+
+
+/* Some helpers macro for writing such *_dump routine */
 #define FD_DUMP_STD_PARAMS  buf, len, offset
+#define FD_DUMP_HANDLE_OFFSET()  size_t o = 0; if (!offset) offset = &o
+#define FD_DUMP_HANDLE_TRAIL()	while ((*buf) && (*offset > 0) && ((*buf)[*offset - 1] == '\n')) { *offset -= 1; (*buf)[*offset] = '\0'; }
+
 
 
 /*============================================================*/
@@ -1015,7 +1024,8 @@
 enum {
 	VENDOR_BY_ID = 10,	/* "what" points to a vendor_id_t */
 	VENDOR_BY_NAME,		/* "what" points to a char * */
-	VENDOR_OF_APPLICATION	/* "what" points to a struct dict_object containing an application (see below) */
+	VENDOR_OF_APPLICATION,	/* "what" points to a struct dict_object containing an application (see below) */
+	VENDOR_OF_AVP,		/* "what" points to a struct dict_object containing an avp (see below) */
 };
 
 /***
@@ -1404,8 +1414,10 @@
 #define	AVP_FLAG_RESERVED8	0x01
 
 /* For dumping flags and values */
-#define DUMP_AVPFL_str	"%c%c"
-#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-'
+#define DUMP_AVPFL_str	"%c%c%s%s%s%s%s%s"
+#define DUMP_AVPFL_val(_val) (_val & AVP_FLAG_VENDOR)?'V':'-' , (_val & AVP_FLAG_MANDATORY)?'M':'-',	\
+				(_val & AVP_FLAG_RESERVED3)?"3":"", (_val & AVP_FLAG_RESERVED4)?"4":"", \
+				(_val & AVP_FLAG_RESERVED5)?"5":"", (_val & AVP_FLAG_RESERVED6)?"6":"", (_val & AVP_FLAG_RESERVED7)?"7":"", (_val & AVP_FLAG_RESERVED8)?"8":""
 
 /* Type to hold data associated to an avp */
 struct dict_avp_data {
@@ -1554,8 +1566,9 @@
 #define CMD_FLAG_RESERVED8	0x01
 
 /* For dumping flags and values */
-#define DUMP_CMDFL_str	"%c%c%c%c"
-#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-'
+#define DUMP_CMDFL_str	"%c%c%c%c%s%s%s%s"
+#define DUMP_CMDFL_val(_val) (_val & CMD_FLAG_REQUEST)?'R':'-' , (_val & CMD_FLAG_PROXIABLE)?'P':'-' , (_val & CMD_FLAG_ERROR)?'E':'-' , (_val & CMD_FLAG_RETRANSMIT)?'T':'-', \
+				(_val & CMD_FLAG_RESERVED5)?"5":"", (_val & CMD_FLAG_RESERVED6)?"6":"", (_val & CMD_FLAG_RESERVED7)?"7":"", (_val & CMD_FLAG_RESERVED8)?"8":""
 
 /* Type to hold data associated to a command */
 struct dict_cmd_data {
--- a/libfdcore/config.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdcore/config.c	Mon May 06 16:33:22 2013 +0800
@@ -82,9 +82,7 @@
 
 DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)
 {
-	size_t o=0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{freeDiameter configuration}(@%p): \n", fd_g_config), return NULL);	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Default trace level .... : %+d\n", fd_g_debug_lvl), return NULL);
--- a/libfdcore/endpoints.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdcore/endpoints.c	Mon May 06 16:33:22 2013 +0800
@@ -286,14 +286,12 @@
 
 DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, struct fd_endpoint * ep )
 {
-	size_t o = 0;
-	if (!offset)
-		offset=&o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ep}(@%p): ", ep), return NULL);
 	
 	if (!ep) {
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
 		return *buf;
 	}
 	
@@ -310,17 +308,15 @@
 DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int indent, struct fd_list * eps  )
 {
 	struct fd_list * li;
-	size_t o = 0;
-	if (!offset)
-		offset=&o;
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{eps}(@%p):\n", indent, "", eps), return NULL);
+	FD_DUMP_HANDLE_OFFSET();
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{eps}(@%p):", indent, "", eps), return NULL);
 	if (eps) {
 		for (li = eps->next; li != eps; li = li->next) {
 			struct fd_endpoint * ep = (struct fd_endpoint *)li;
-			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s", indent+1, ""), return NULL);
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s", indent+1, ""), return NULL);
 			CHECK_MALLOC_DO( fd_ep_dump_one( FD_DUMP_STD_PARAMS, ep ), return NULL);
-			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
 		}
 	}
 }
--- a/libfdcore/events.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdcore/events.c	Mon May 06 16:33:22 2013 +0800
@@ -164,15 +164,13 @@
 DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump)
 {
 	struct fd_list * li;
-	size_t o=0;
-	if (!offset)
-		offset=&o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_POSIX_DO( pthread_rwlock_rdlock(&trig_rwl),  );
 	
 	for (li = trig_list.next; li != &trig_list; li = li->next) {
 		struct trig_item *t = li->o;
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{trigger sig:%d}'%s'->%p ", t->trig_value, t->trig_module, t->cb), break);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{signal:%d}'%s'->%p ", t->trig_value, t->trig_module, t->cb), break);
 	}
 	
 	CHECK_POSIX_DO( pthread_rwlock_unlock(&trig_rwl),  );
--- a/libfdcore/extensions.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdcore/extensions.c	Mon May 06 16:33:22 2013 +0800
@@ -87,7 +87,7 @@
 	for (li = ext_list.next; li != &ext_list; li = li->next)
 	{
 		struct fd_ext_info * ext = (struct fd_ext_info *)li;
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{extension}(@%p): '%s'[%s], %sloaded\n", ext, ext->filename, ext->conffile?:"no conf", ext->handler ? "" : "not "), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{extension}(@%p): '%s'[%s], %sloaded%s", ext, ext->filename, ext->conffile?:"no conf", ext->handler ? "" : "not ", (li->next == &ext_list) ? "":"\n"), return NULL);
 	}
 	return *buf;
 }
--- a/libfdcore/peers.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdcore/peers.c	Mon May 06 16:33:22 2013 +0800
@@ -411,9 +411,7 @@
 /* Dump info of one peer */
 DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details)
 {
-	size_t o=0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{peer}(@%p): ", p), return NULL);
 	
@@ -453,15 +451,15 @@
 DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details)
 {
 	struct fd_list * li;
-	size_t o=0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
 	
 	for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
 		CHECK_MALLOC_DO( fd_peer_dump(FD_DUMP_STD_PARAMS, (struct peer_hdr *)li->o, details), break);
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), break);
+		if (li->next != &fd_g_peers) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), break);
+		}
 	}
 	
 	CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
--- a/libfdcore/server.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdcore/server.c	Mon May 06 16:33:22 2013 +0800
@@ -96,15 +96,14 @@
 DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump)
 {
 	struct fd_list * li, *cli;
-	size_t o=0;
-	if (!offset)
-		offset = &o;
+	
+	FD_DUMP_HANDLE_OFFSET();
 	
 	for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
 		struct server * s = (struct server *)li;
 		enum s_state st = get_status(s);
 		
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{server}(@%p)'%s': %s, %s, %s\n", s, fd_cnx_getid(s->conn), 
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{server}(@%p)'%s': %s, %s, %s", s, fd_cnx_getid(s->conn), 
 				IPPROTO_NAME( s->proto ),
 				s->secur ? "Secur" : "NotSecur",
 				(st == NOT_CREATED) ? "Thread not created" :
@@ -116,9 +115,13 @@
 		for (cli = s->clients.next; cli != &s->clients; cli = cli->next) {
 			struct client * c = (struct client *)cli;
 			char bufts[128];
-			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  {client}(@%p)'%s': to:%s\n", c, fd_cnx_getid(c->conn), fd_log_time(&c->ts, bufts, sizeof(bufts))), break);
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n  {client}(@%p)'%s': to:%s", c, fd_cnx_getid(c->conn), fd_log_time(&c->ts, bufts, sizeof(bufts))), break);
 		}
 		CHECK_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), );
+		
+		if (li->next != &FD_SERVERS) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+		}
 	}
 	
 	return *buf;
--- a/libfdproto/dictionary.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdproto/dictionary.c	Mon May 06 16:33:22 2013 +0800
@@ -718,6 +718,21 @@
 		ret = ENOENT;							\
 }
 
+/* For searchs of type "xxx_OF_xxx": if the search object is sentinel list for the "what" object */
+#define SEARCH_sentinel( type_of_what, what_list_nr, sentinel_list_nr ) {			\
+	struct dict_object *__what = (struct dict_object *) what;				\
+	CHECK_PARAMS_DO( verify_object(__what) && 						\
+		(__what->type == (type_of_what)), 						\
+		   {  ret = EINVAL; goto end;  }  );						\
+	ret = 0;										\
+	if (result) {										\
+		/* this is similar to the "container_of" */					\
+		*result = (struct dict_object *)((char *)(__what->list[what_list_nr].head) - 	\
+		   		(size_t)&(((struct dict_object *)0)->list[sentinel_list_nr]));	\
+	}											\
+}
+
+
 static int search_vendor ( struct dictionary * dict, int criteria, const void * what, struct dict_object **result )
 {
 	int ret = 0;
@@ -741,6 +756,11 @@
 			SEARCH_childs_parent( DICT_APPLICATION, &dict->dict_vendors );
 			break;
 		
+		case VENDOR_OF_AVP:
+			/* "what" should be an avp object */
+			SEARCH_sentinel( DICT_AVP, 0, 1 );
+			break;
+		
 		default:
 			/* Invalid criteria */
 			CHECK_PARAMS( criteria = 0 );
@@ -1247,10 +1267,15 @@
 {
 	struct fd_list * li = sentinel;
 	/* We don't lock here, the caller must have taken the dictionary lock for reading already */
-	while (li->next != sentinel)
-	{
-		li = li->next;
-		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, _O(li->o), parents, depth, indent ), return NULL);
+	if (FD_IS_LIST_EMPTY(sentinel)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*s{empty list}", indent, ""), return NULL);
+	} else {
+		while (li->next != sentinel)
+		{
+			li = li->next;
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+			CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, _O(li->o), parents, depth, indent ), return NULL);
+		}
 	}
 }
 
@@ -1259,7 +1284,7 @@
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{dictobj}(@%p): ", indent, "", obj), return NULL);
 	
 	if (!verify_object(obj)) {
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
 		return *buf;
 	}
 	
@@ -1273,10 +1298,8 @@
 		CHECK_MALLOC_DO( _OBINFO(obj).dump_data(FD_DUMP_STD_PARAMS, &obj->data), return NULL);
 	}
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
-	
 	if (parents) {
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*sparent:", indent + 1, ""), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n%*sparent:", indent + 1, ""), return NULL);
 		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, obj->parent, parents-1, 0, 0 ), return NULL);
 	}
 	
@@ -1284,8 +1307,8 @@
 		int i;
 		for (i=0; i<NB_LISTS_PER_OBJ; i++) {
 			if ((obj->list[i].o == NULL) && (obj->list[i].next != &obj->list[i])) {
-				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*slist[%d]:\n", indent + 1, "", i), return NULL);
 				CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &obj->list[i], 0, depth - 1, indent + 2), return NULL);
+				break; /* we get duplicate information sorted by another criteria otherwise, which is not very useful */
 			}
 		}
 	}
@@ -1295,10 +1318,7 @@
 
 DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj)
 {
-	size_t o = 0;
-
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_MALLOC_DO( dump_object(FD_DUMP_STD_PARAMS, obj, 1, 2, 0), return NULL);
 	
@@ -1309,38 +1329,40 @@
 {
 	int i;
 	struct fd_list * li;
-	size_t o = 0;
-
-	if (!offset)
-		offset = &o;
+	
+	FD_DUMP_HANDLE_OFFSET();
 		
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{dictionary}(@%p): ", dict), return NULL);
 	
 	if ((dict == NULL) || (dict->dict_eyec != DICT_EYECATCHER)) {
-		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL\n");
+		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL");
 	}
 	
 	CHECK_POSIX_DO(  pthread_rwlock_rdlock( &dict->dict_lock ), /* ignore */  );
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict:%p > vendors, AVPs and related rules}\n", dict), goto error);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : VENDORS / AVP / RULES}\n", dict), goto error);
 	CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, &dict->dict_vendors, 0, 3, 3 ), goto error);
-	for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next)
+	for (li = dict->dict_vendors.list[0].next; li != &dict->dict_vendors.list[0]; li = li->next) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
 		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 3, 3 ), goto error);
+	}
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > applications}\n", dict), goto error);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : APPLICATIONS}\n", dict), goto error);
 	CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, &dict->dict_applications, 0, 1, 3 ), goto error);
-	for (li = dict->dict_applications.list[0].next; li != &dict->dict_applications.list[0]; li = li->next)
+	for (li = dict->dict_applications.list[0].next; li != &dict->dict_applications.list[0]; li = li->next) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
 		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 1, 3 ), goto error);
+	}
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > types}\n", dict), goto error);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : TYPES / ENUMVAL}", dict), goto error);
 	CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_types, 0, 2, 3 ), goto error);
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > commands}\n", dict), goto error);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : COMMANDS / RULES}", dict), goto error);
 	CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_cmd_code, 0, 0, 3 ), goto error);
 	
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > statistics}\n", dict), goto error);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n {dict(%p) : statistics}", dict), goto error);
 	for (i=1; i<=DICT_TYPE_MAX; i++)
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "   %5d: %s\n",  dict->dict_count[i], dict_obj_info[i].name), goto error);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n   %5d: %s",  dict->dict_count[i], dict_obj_info[i].name), goto error);
 	
 	CHECK_POSIX_DO(  pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */  );
 	return *buf;
@@ -1484,10 +1506,8 @@
 	struct dict_object * type = NULL;
 	char * type_name = NULL;
 	char * const_name = NULL;
-	size_t o = 0;
 	
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	/* Check the parameters are correct */
 	CHECK_PARAMS_DO( avp_value && verify_object(model) && (model->type == DICT_AVP), return NULL );
--- a/libfdproto/dictionary_functions.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdproto/dictionary_functions.c	Mon May 06 16:33:22 2013 +0800
@@ -161,10 +161,8 @@
 		sSA6	sin6;
 	} s;
 	uint16_t fam;
-	size_t o = 0;
 	
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	memset(&s, 0, sizeof(s));
 	
@@ -212,9 +210,8 @@
 /* Dump the AVP in a natural human-readable format. This dumps the complete length of the AVP, it is up to the caller to truncate if needed */
 DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump, union avp_value * avp_value)
 {
-	size_t o = 0, l;
-	if (!offset)
-		offset = &o;
+	size_t l;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	l = avp_value->os.len;
 	/* Just in case the string ends in invalid UTF-8 chars, we shorten it */
@@ -304,12 +301,10 @@
 
 DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value)
 {
-	size_t o = 0;
 	time_t val;
 	struct tm conv;
 		
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	if (avp_value->os.len != 4) {
 		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
--- a/libfdproto/fifo.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdproto/fifo.c	Mon May 06 16:33:22 2013 +0800
@@ -120,9 +120,7 @@
 /* Dump the content of a queue */
 DECLARE_FD_DUMP_PROTOTYPE(fd_fifo_dump, char * name, struct fifo * queue, fd_fifo_dump_item_cb dump_item)
 {
-	size_t o = 0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	if (name) {
 		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(@%p): ", name, queue), return NULL);	
@@ -131,11 +129,11 @@
 	}
 	
 	if (!CHECK_FIFO( queue )) {
-		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL\n");
+		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL");
 	}
 	
 	CHECK_POSIX_DO(  pthread_mutex_lock( &queue->mtx ), /* continue */  );
-	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "items:%d,%d,%d threads:%d,%d stats:%lld/%ld.%06ld,%ld.%06ld,%ld.%06ld thresholds:%d,%d,%d,%p,%p,%p\n", 
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "items:%d,%d,%d threads:%d,%d stats:%lld/%ld.%06ld,%ld.%06ld,%ld.%06ld thresholds:%d,%d,%d,%p,%p,%p", 
 						queue->count, queue->highest_ever, queue->max,
 						queue->thrs, queue->thrs_push,
 						queue->total_items,(long)queue->total_time.tv_sec,(long)(queue->total_time.tv_nsec/1000),(long)queue->blocking_time.tv_sec,(long)(queue->blocking_time.tv_nsec/1000),(long)queue->last_time.tv_sec,(long)(queue->last_time.tv_nsec/1000),
@@ -147,13 +145,14 @@
 		int i = 0;
 		for (li = queue->list.next; li != &queue->list; li = li->next) {
 			struct fifo_item * fi = (struct fifo_item *)li;
-			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [#%i](@%p)@%ld.%06ld: ", 
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n [#%i](@%p)@%ld.%06ld: ", 
 						i++, fi->item.o, (long)fi->posted_on.tv_sec,(long)(fi->posted_on.tv_nsec/1000)), 
 					 goto error);
 			CHECK_MALLOC_DO( (*dump_item)(FD_DUMP_STD_PARAMS, fi->item.o), goto error);
 		}
 	}
 	CHECK_POSIX_DO(  pthread_mutex_unlock( &queue->mtx ), /* continue */  );
+	
 	return *buf;
 error:
 	CHECK_POSIX_DO(  pthread_mutex_unlock( &queue->mtx ), /* continue */  );
--- a/libfdproto/messages.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdproto/messages.c	Mon May 06 16:33:22 2013 +0800
@@ -720,18 +720,188 @@
 /***************************************************************************************************************/
 /* Debug functions: dumping */
 
-#warning "todo"
-DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
+/* messages and AVP formatters */
+typedef DECLARE_FD_DUMP_PROTOTYPE( (*msg_dump_formatter_msg), struct msg * msg );
+typedef DECLARE_FD_DUMP_PROTOTYPE( (*msg_dump_formatter_avp), struct avp * avp, int level );
+
+/* Core function to process the dumping */
+static DECLARE_FD_DUMP_PROTOTYPE( msg_dump_process, msg_dump_formatter_msg msg_format, msg_dump_formatter_avp avp_format, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
+{
+	FD_DUMP_HANDLE_OFFSET();
+		
+	if (force_parsing) {
+		(void) fd_msg_parse_dict(obj, dict, NULL);
+	}
+	
+	switch (_C(obj)->type) {
+		case MSG_AVP:
+			CHECK_MALLOC_DO( (*avp_format)(FD_DUMP_STD_PARAMS, (struct avp *)obj, 0), return NULL);
+			break;
+
+		case MSG_MSG:
+			CHECK_MALLOC_DO( (*msg_format)(FD_DUMP_STD_PARAMS, (struct msg *)obj), return NULL);
+			break;
+
+		default:
+			ASSERT(0);
+	}
+		
+	if (recurse) {
+		struct avp * avp = NULL;
+		CHECK_FCT_DO(  fd_msg_browse ( obj, MSG_BRW_FIRST_CHILD, &avp, NULL ), avp = NULL );
+		while (avp) {
+			CHECK_MALLOC_DO( (*avp_format)(FD_DUMP_STD_PARAMS, avp, 1), return NULL);
+			CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_NEXT, &avp, NULL ), avp = NULL  );
+		};
+	}
+	
+	/* we remove the final \n if any */
+	FD_DUMP_HANDLE_TRAIL();
+	
+	return *buf;
+}
+
+/*
+ * Tree View message dump
+ */
+
+static DECLARE_FD_DUMP_PROTOTYPE( msg_format_treeview, struct msg * msg )
+{
+	if (!CHECK_MSG(msg)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{message}(@%p): INVALID\n", msg), return NULL);
+		return *buf;
+	}
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{message}(@%p): ", msg), return NULL);
+	if (!msg->msg_model) {
+		if (msg->msg_model_not_found.mnf_code) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not found in dictionary)\n"), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not searched in dictionary)\n"), return NULL);
+		}
+	} else {
+		enum dict_object_type dicttype;
+		struct dict_cmd_data  dictdata;
+		if (fd_dict_gettype(msg->msg_model, &dicttype) || (dicttype != DICT_COMMAND)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(invalid model information)\n"), return NULL);
+		} else if (fd_dict_getval(msg->msg_model, &dictdata)) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(error getting model information)\n"), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'\n", dictdata.cmd_name), return NULL);
+		}
+	}
+		
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Version: 0x%02hhX\n", msg->msg_public.msg_version), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Length: %d\n", msg->msg_public.msg_length), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Flags: 0x%02hhX (" DUMP_CMDFL_str ")\n", msg->msg_public.msg_flags, DUMP_CMDFL_val(msg->msg_public.msg_flags)), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Command Code: %u\n", msg->msg_public.msg_code), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  ApplicationId: %d\n", msg->msg_public.msg_appl), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Hop-by-Hop Identifier: 0x%8X\n", msg->msg_public.msg_hbhid), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  End-to-End Identifier: 0x%8X\n", msg->msg_public.msg_eteid), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "   {debug data}: src:%s(%zd) rwb:%p rt:%d cb:%p,%p(%p) qry:%p asso:%d sess:%p\n", msg->msg_src_id?:"(nil)", msg->msg_src_id_len, msg->msg_rawbuffer, msg->msg_routable, msg->msg_cb.anscb, msg->msg_cb.expirecb, msg->msg_cb.data, msg->msg_query, msg->msg_associated, msg->msg_sess), return NULL);
+	
+	return *buf;
+}
+
+static DECLARE_FD_DUMP_PROTOTYPE( avp_format_treeview, struct avp * avp, int level )
 {
-	return NULL;
+	char * name;
+	struct dict_avp_data  dictdata;
+	struct dict_avp_data *dictinfo = NULL;
+	struct dict_vendor_data  vendordata;
+	struct dict_vendor_data *vendorinfo = NULL;
+	if (!CHECK_AVP(avp)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{avp}(@%p): INVALID\n", avp), return NULL);
+		return *buf;
+	}
+	
+	if (!level) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{avp}(@%p): ", avp), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*sAVP: ", level * 3, ""), return NULL);
+	}
+	
+	if (!avp->avp_model) {
+		if (avp->avp_model_not_found.mnf_code) {
+			name = "(not found in dictionary)";
+		} else {
+			name = "(not searched in dictionary)";
+		}
+	} else {
+		enum dict_object_type dicttype;
+		if (fd_dict_gettype(avp->avp_model, &dicttype) || (dicttype != DICT_AVP)) {
+			name = "(invalid model information)";
+		} else if (fd_dict_getval(avp->avp_model, &dictdata)) {
+			name = "(error getting model information)";
+		} else {
+			name = dictdata.avp_name;
+			dictinfo = &dictdata;
+			if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+				struct dictionary * dict;
+				struct dict_object * vendor;
+				if ((!fd_dict_getdict(avp->avp_model, &dict))
+				&& (!fd_dict_search(dict, DICT_VENDOR, VENDOR_OF_AVP, avp->avp_model, &vendor, ENOENT))
+				&& (!fd_dict_getval(vendor, &vendordata))) {
+					vendorinfo = &vendordata;
+				}
+			}
+		}
+	}
+	
+	if (dictinfo) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%u)", name, avp->avp_public.avp_code), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%u%s", avp->avp_public.avp_code, name), return NULL);
+	}
+	
+	if (avp->avp_public.avp_flags & AVP_FLAG_VENDOR) {
+		if (vendorinfo) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " vend='%s'(%u)", vendorinfo->vendor_name, avp->avp_public.avp_vendor), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " vend=%u", avp->avp_public.avp_vendor), return NULL);
+		}
+	}
+
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " l=%d f=" DUMP_AVPFL_str " val=", avp->avp_public.avp_len, DUMP_AVPFL_val(avp->avp_public.avp_flags)), return NULL);
+	
+	if (dictinfo && (dictinfo->avp_basetype == AVP_TYPE_GROUPED)) {
+		struct avp * inavp = NULL;
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(grouped)\n"), return NULL);
+		CHECK_FCT_DO(  fd_msg_browse ( avp, MSG_BRW_FIRST_CHILD, &inavp, NULL ), inavp = NULL );
+		while (inavp) {
+			CHECK_MALLOC_DO( avp_format_treeview(FD_DUMP_STD_PARAMS, inavp, level + 1), return NULL);
+			CHECK_FCT_DO(  fd_msg_browse ( inavp, MSG_BRW_NEXT, &inavp, NULL ), inavp = NULL  );
+		};
+	} else {
+		if (avp->avp_public.avp_value) {
+			CHECK_MALLOC_DO( fd_dict_dump_avp_value(FD_DUMP_STD_PARAMS, avp->avp_public.avp_value, avp->avp_model, 0, 0), return NULL);
+		} else if (avp->avp_rawdata) {
+			CHECK_MALLOC_DO( fd_dump_extend_hexdump(FD_DUMP_STD_PARAMS, avp->avp_rawdata, avp->avp_rawlen, 0, 0), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(not set)"), return NULL);
+		}
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n"), return NULL);
+	}
+
+	return *buf;
 }
+
+/* multi-line human-readable dump similar to wireshark output */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
+{
+	return msg_dump_process(FD_DUMP_STD_PARAMS, msg_format_treeview, avp_format_treeview, obj, dict, force_parsing, recurse);
+}
+
+
+#warning "todo"
 /* one-line dump with all the contents of the message */
 DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_full, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
 {
 	return NULL;
 }
-/* multi-line human-readable dump similar to wireshark output */
-DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
+
+/* This one only prints a short display, does not go into the complete tree */
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse )
 {
 	return NULL;
 }
--- a/libfdproto/sessions.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdproto/sessions.c	Mon May 06 16:33:22 2013 +0800
@@ -876,20 +876,18 @@
 /* Dump functions */
 DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states)
 {
-	size_t o = 0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{session}(@%p): ", session), return NULL);
 	
 	if (!VALIDATE_SI(session)) {
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
 	} else {
 		char timebuf[30];
 		struct tm tm;
 
 		strftime(timebuf, sizeof(timebuf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%zd) h:%x m:%d d:%d to:%s.%06ld\n",
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(%zd) h:%x m:%d d:%d to:%s.%06ld",
 							session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed,
 							timebuf, session->timeout.tv_nsec/1000), 
 				 return NULL);
@@ -901,12 +899,12 @@
 			
 			for (li = session->states.next; li != &session->states; li = li->next) {
 				struct state * st = (struct state *)(li->o);
-				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  {state i:%d}(@%p): \n", st->hdl->id, st), return NULL);
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "\n  {state i:%d}(@%p): ", st->hdl->id, st), return NULL);
 				if (st->hdl->state_dump) {
 					CHECK_MALLOC_DO( (*st->hdl->state_dump)( FD_DUMP_STD_PARAMS, st->state), 
-							fd_dump_extend( FD_DUMP_STD_PARAMS, "[dumper error]\n"));
+							fd_dump_extend( FD_DUMP_STD_PARAMS, "[dumper error]"));
 				} else {
-					CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<%p>\n", st->state), return NULL);
+					CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<%p>", st->state), return NULL);
 				}
 			}
 			
@@ -914,21 +912,20 @@
 			CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
 		}
 	}
+	
 	return *buf;
 }
 
 DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler)
 {
-	size_t o = 0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{sesshdl}(@%p): ", handler), return NULL);
 	
 	if (!VALIDATE_SH(handler)) {
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
 	} else {
-		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "i:%d cl:%p d:%p o:%p\n", handler->id, handler->cleanup, handler->state_dump, handler->opaque), return NULL);
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "i:%d cl:%p d:%p o:%p", handler->id, handler->cleanup, handler->state_dump, handler->opaque), return NULL);
 	}
 	return *buf;
 }	
--- a/libfdproto/utils.c	Mon May 06 11:30:34 2013 +0800
+++ b/libfdproto/utils.c	Mon May 06 16:33:22 2013 +0800
@@ -38,9 +38,7 @@
 DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node, sSA * sa, int flags)
 {
 	char addrbuf[INET6_ADDRSTRLEN];
-	size_t o = 0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	if (sa) {
 		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), NULL, 0, flags);
@@ -60,9 +58,7 @@
 {
 	char addrbuf[INET6_ADDRSTRLEN];
 	char servbuf[32];
-	size_t o = 0;
-	if (!offset)
-		offset = &o;
+	FD_DUMP_HANDLE_OFFSET();
 	
 	if (sa) {
 		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), servbuf, sizeof(servbuf), flags);
--- a/tests/testdict.c	Mon May 06 11:30:34 2013 +0800
+++ b/tests/testdict.c	Mon May 06 16:33:22 2013 +0800
@@ -203,6 +203,8 @@
 		
 	}
 	
+	LOG_D( "Dictionary at the end of %s: %s", __FILE__, fd_dict_dump(FD_DUMP_TEST_PARAMS, fd_g_config->cnf_dict) ?: "error");
+	
 	/* That's all for the tests yet */
 	PASSTEST();
 } 
--- a/tests/testmesg_stress.c	Mon May 06 11:30:34 2013 +0800
+++ b/tests/testmesg_stress.c	Mon May 06 16:33:22 2013 +0800
@@ -373,6 +373,8 @@
 		
 		CHECK( 0, fd_msg_bufferize( msg, &buf, NULL ) );
 		
+		LOG_D( "Test message: %s", fd_msg_dump_treeview(FD_DUMP_TEST_PARAMS, msg, NULL, 0, 1));
+		
 		/* Now free the message, we keep only the buffer. */
 		CHECK( 0, fd_msg_free( msg ) );
 		
@@ -389,23 +391,20 @@
 		int i;
 		struct timespec start, end;
 		
-		unsigned char * buf_cpy = NULL;
 		struct msg * msg;
 		
-		#define CPYBUF() {			\
-			buf_cpy = malloc(344);		\
-			CHECK( buf_cpy ? 1 : 0, 1);	\
-			memcpy(buf_cpy, buf, 344);	\
-		}
 		
 		/* Create the copies of the message buffer */
 		stress_array = calloc(test_parameter, sizeof(struct stress_struct));
 		CHECK( stress_array ? 1 : 0, 1);
 		
 		for (i=0; i < test_parameter; i++) {
-			CPYBUF();
-			stress_array[i].b = buf_cpy;
+			stress_array[i].b = malloc(344);
+			if (!stress_array[i].b)
+				break;
+			memcpy(stress_array[i].b, buf, 344);
 		}
+		CHECK( test_parameter, i ); /* if false, a malloc failed */
 		
 	/* fd_msg_parse_buffer */
 		
@@ -413,8 +412,10 @@
 		
 		/* Test the msg_parse_buffer function */
 		for (i=0; i < test_parameter; i++) {
-			CHECK( 0, fd_msg_parse_buffer( &stress_array[i].b, 344, &stress_array[i].m) );
+			if (0 != fd_msg_parse_buffer( &stress_array[i].b, 344, &stress_array[i].m) )
+				break;
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
 		display_result(test_parameter, &start, &end, "fd_msg_parse_buffer", "buffers", "parsed");
@@ -425,8 +426,10 @@
 		
 		/* Test the fd_msg_parse_dict function */
 		for (i=0; i < test_parameter; i++) {
-			CHECK( 0, fd_msg_parse_dict( stress_array[i].m, fd_g_config->cnf_dict, NULL ) );
+			if (0 != fd_msg_parse_dict( stress_array[i].m, fd_g_config->cnf_dict, NULL ) )
+				break;
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
 		display_result(test_parameter, &start, &end, "fd_msg_parse_dict", "messages", "parsed");
@@ -438,8 +441,10 @@
 		
 		/* Test the fd_msg_parse_rules function */
 		for (i=0; i < test_parameter; i++) {
-			CHECK( 0, fd_msg_parse_rules( stress_array[i].m, fd_g_config->cnf_dict, NULL ) );
+			if (0 != fd_msg_parse_rules( stress_array[i].m, fd_g_config->cnf_dict, NULL ) )
+				break;
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
 		display_result(test_parameter, &start, &end, "fd_msg_parse_rules", "messages", "parsed");
@@ -451,8 +456,10 @@
 		
 		/* Test the fd_msg_new_answer_from_req function */
 		for (i=0; i < test_parameter; i++) {
-			CHECK( 0, fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, 0 ) );
+			if (0 != fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, 0 ) )
+				break;
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
 		display_result(test_parameter, &start, &end, "new_answer(normal)", "messages", "created");
@@ -460,10 +467,13 @@
 		/* unlink answers and go back to request messages */
 		for (i=0; i < test_parameter; i++) {
 			struct msg * ans = stress_array[i].m;
-			CHECK( 0, fd_msg_answ_getq( ans, &stress_array[i].m ) );
-			CHECK( 0, fd_msg_answ_detach( ans ) );
+			if (0 != fd_msg_answ_getq( ans, &stress_array[i].m ) )
+				break;
+			if (0 != fd_msg_answ_detach( ans ) )
+				break;
 			fd_msg_free( ans );
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		
 	/* fd_msg_new_answer_from_req (MSGFL_ANSW_ERROR) */
@@ -472,8 +482,10 @@
 		
 		/* Test the fd_msg_new_answer_from_req function */
 		for (i=0; i < test_parameter; i++) {
-			CHECK( 0, fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, MSGFL_ANSW_ERROR ) );
+			if ( 0 != fd_msg_new_answer_from_req( fd_g_config->cnf_dict, &stress_array[i].m, MSGFL_ANSW_ERROR ) )
+				break;
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
 		display_result(test_parameter, &start, &end, "new_answer(error)", "messages", "created");
@@ -481,8 +493,10 @@
 		/* unlink answers and go back to request messages */
 		for (i=0; i < test_parameter; i++) {
 			struct msg * ans = stress_array[i].m;
-			CHECK( 0, fd_msg_answ_getq( ans, &stress_array[i].m ) );
-			CHECK( 0, fd_msg_answ_detach( ans ) );
+			if (0 != fd_msg_answ_getq( ans, &stress_array[i].m ) )
+				break;
+			if (0 != fd_msg_answ_detach( ans ) )
+				break;
 			fd_msg_free( ans );
 		}
 		
@@ -495,8 +509,10 @@
 		/* Test the fd_msg_bufferize function */
 		for (i=0; i < test_parameter; i++) {
 			size_t len = 0;
-			CHECK( 0, fd_msg_bufferize( stress_array[i].m, &stress_array[i].b, &len ) );
+			if (0 != fd_msg_bufferize( stress_array[i].m, &stress_array[i].b, &len ) )
+				break;
 		}
+		CHECK( test_parameter, i ); /* if false, a call failed */
 		
 		CHECK( 0, clock_gettime(CLOCK_REALTIME, &end) );
 		display_result(test_parameter, &start, &end, "fd_msg_bufferize", "buffers", "created");
"Welcome to our mercurial repository"