changeset 1085:7d7266115a34

Cleaning of the traces in progress
author Sebastien Decugis <sdecugis@freediameter.net>
date Fri, 03 May 2013 19:20:56 +0800
parents 6b7966ea27fb
children f2f4b9ddd8e5
files include/freeDiameter/libfdcore.h include/freeDiameter/libfdproto.h libfdcore/config.c libfdcore/core.c libfdcore/endpoints.c libfdcore/events.c libfdcore/extensions.c libfdcore/fdcore-internal.h libfdcore/p_psm.c libfdcore/peers.c libfdcore/server.c libfdcore/tcp.c libfdproto/dictionary.c libfdproto/dictionary_functions.c libfdproto/fdproto-internal.h libfdproto/fifo.c libfdproto/log.c libfdproto/messages.c libfdproto/sessions.c libfdproto/utils.c
diffstat 20 files changed, 941 insertions(+), 912 deletions(-) [+]
line wrap: on
line diff
--- a/include/freeDiameter/libfdcore.h	Fri May 03 15:33:57 2013 +0800
+++ b/include/freeDiameter/libfdcore.h	Fri May 03 19:20:56 2013 +0800
@@ -57,23 +57,36 @@
 
 
 /* Check the return value of a GNUTLS function, log and propagate */
-#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {						\
-	int __ret__;										\
-	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: %s", #__call__ );				\
-	__ret__ = (__call__);									\
-	if (__ret__ < 0) {									\
-		TRACE_DEBUG(INFO, "Error in '%s':\t%s", #__call__ , gnutls_strerror(__ret__));	\
-		__fallback__;									\
-	}											\
+#define CHECK_GNUTLS_GEN( faillevel, __call__, __fallback__  ) { 					\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			LOG(faillevel, "ERROR: in '%s' :\t%s",  #__call__ ,  gnutls_strerror(__ret__)); \
+			__fallback__;									\
+		}											\
 }
 
-/* For GNUTLS routines that do not return a value */
+/* we use this macro to help debugging gnutls usage issues -- just change the content to display what you need */
 #define GNUTLS_TRACE( __call__) {					\
-	TRACE_DEBUG(GNUTLS_DBG_LEVEL, "GNUTLS call: " #__call__ );	\
+	TRACE_CALL("Check: %s", #__call__ );				\
 	(__call__);							\
 }
 
 
+#ifndef EXCLUDE_DEPRECATED
+/* Macro for transition, replace with CHECK_GNUTLS_GEN */
+#define CHECK_GNUTLS_DO( __call__, __fallback__ ) {						        \
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ ,  gnutls_strerror(__ret__));    \
+			__fallback__;									\
+		}											\
+}
+
+#endif /* EXCLUDE_DEPRECATED */
+
+
 /*============================================================*/
 /*                      INITIALIZATION                        */
 /*============================================================*/
@@ -777,12 +790,6 @@
 /* Daemon's codespace: 1000->1999 (1500->1999 defined in fdcore-internal.h) */
 enum {
 	 FDEV_TERMINATE	= 1000	/* request to terminate */
-	,FDEV_DUMP_DICT		/* Dump the content of the dictionary */
-	,FDEV_DUMP_EXT		/* Dump state of extensions */
-	,FDEV_DUMP_SERV		/* Dump the server socket status */
-	,FDEV_DUMP_QUEUES	/* Dump the message queues */
-	,FDEV_DUMP_CONFIG	/* Dump the configuration */
-	,FDEV_DUMP_PEERS	/* Dump the list of peers */
 	,FDEV_TRIGGER		/* Trigger available for extensions. size is sizeof(int), data is int * */
 };
 
@@ -794,8 +801,15 @@
 
 /* for extensions */
 int fd_event_trig_regcb(int trigger_val, const char * module, void (*cb)(void));
-void fd_event_trig_dump();
+
+DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump);
 
+/* The "old" FD_EV_DUMP_* events are replaced with direct calls to the following dump functions */
+DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump);
+DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump);
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details);
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details);
+DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump);
 
 /*============================================================*/
 /*                         ENDPOINTS                          */
@@ -831,8 +845,8 @@
 int fd_ep_filter_family( struct fd_list * list, int af );
 int fd_ep_filter_list( struct fd_list * list, struct fd_list * exclude_list );
 int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
-void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep );
-void fd_ep_dump( int indent, struct fd_list * eps );
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, struct fd_endpoint * ep );
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int indent, struct fd_list * eps  );
 
 
 /*============================================================*/
--- a/include/freeDiameter/libfdproto.h	Fri May 03 15:33:57 2013 +0800
+++ b/include/freeDiameter/libfdproto.h	Fri May 03 19:20:56 2013 +0800
@@ -132,12 +132,9 @@
 
 /*
  * FUNCTION:	fd_log
- * MACRO:	fd_log_debug
- * MACRO:	fd_log_notice
- * MACRO:	fd_log_error
  *
  * PARAMETERS:
- *  loglevel	: Integer, how important the message is
+ *  loglevel	: Integer, how important the message is. Valid values are macros FD_LOG_*
  *  format 	: Same format string as in the printf function
  *  ...		: Same list as printf
  *
@@ -150,11 +147,7 @@
  *  None.
  */
 void fd_log ( int, const char *, ... ) _ATTRIBUTE_PRINTFLIKE_(2,3);
-#define fd_log_debug(format,args...)  fd_log(FD_LOG_DEBUG, format, ## args)
-#define fd_log_notice(format,args...) fd_log(FD_LOG_NOTICE, format, ## args)
-#define fd_log_error(format,args...)  fd_log(FD_LOG_ERROR, format, ## args)
-
-void fd_log_debug_fstr( FILE *, const char *, ... );
+void fd_log_va( int, const char *, va_list args );
 
 /* these are internal objects of the debug facility, 
 might be useful to control the behavior from outside */
@@ -228,6 +221,25 @@
 int fd_log_handler_unregister ( void );
 
 
+/* Helper function 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);
+
+/* All dump functions follow the same prototype:
+ * PARAMETERS:
+ *   buf   : *buf can be NULL on entry, it will be malloc'd. Otherwise it can be 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.
+ */
+#define DECLARE_FD_DUMP_PROTOTYPE( function_name, args... )	\
+	char * function_name(char ** buf, size_t *len, size_t *offset, ##args)
+	
+#define FD_DUMP_STD_PARAMS  buf, len, offset
+
+
 /*============================================================*/
 /*                    DEBUG MACROS                            */
 /*============================================================*/
@@ -236,20 +248,14 @@
 #define ASSERT(x) assert(x)
 #endif /* ASSERT */
 
-/* log levels definitions */
-#define FD_LOG_DEBUG  0  /* Verbose information for developers use */
-#define FD_LOG_NOTICE 3  /* Normal execution states worth noting */
-#define FD_LOG_ERROR  5  /* Error conditions, both recoverable or not */
-
-/* print level definitions */
-#define NONE 0	/* Display no debug message */
-#define INFO 1	/* Display errors only */
-#define FULL 2  /* Display additional information to follow code execution */
-#define ANNOYING 4 /* Very verbose, for example in loops */
-#define FCTS 6  /* Display entry parameters of most functions */
-#define CALL 9  /* Display calls to most functions (with CHECK macros) */
-
-/* A global level, changed by configuration or cmd line for example. Default is INFO (in libfdproto/log.c). */
+/* log levels definitions, that are passed to the logger */
+#define FD_LOG_ANNOYING  0  /* very verbose loops and such "overkill" traces. Only active when the framework is compiled in DEBUG mode. */
+#define FD_LOG_DEBUG     1  /* Get a detailed sense of what is going on in the framework. Use this level for normal debug */
+#define FD_LOG_NOTICE    3  /* Normal execution states worth noting */
+#define FD_LOG_ERROR     5  /* Recoverable or expected error conditions */
+#define FD_LOG_FATAL     6  /* Unrecoverable error, e.g. malloc fail, etc. that requires the framework to shutdown */
+
+/* The level used by the default logger, can be changed by command-line arguments. Ignored for other loggers. */
 extern int fd_g_debug_lvl;
 
 /* Some portability code to get nice function name in __PRETTY_FUNCTION__ */
@@ -264,121 +270,321 @@
 #define __PRETTY_FUNCTION__ __func__
 #endif /* __PRETTY_FUNCTION__ */
 
-#ifdef DEBUG
 /* A version of __FILE__ without the full path */
 static char * file_bname = NULL;
 static char * file_bname_init(char * full) { file_bname = basename(full); return file_bname; }
 #define __STRIPPED_FILE__	(file_bname ?: file_bname_init((char *)__FILE__))
 
-/* Boolean for tracing at a certain level */
-#define TRACE_BOOL(_level_) ( ((_level_) <= fd_g_debug_lvl) 					\
-				|| (fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) 	\
-				|| (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) )
-#else /* DEBUG */
-#define TRACE_BOOL(_level_) ((_level_) <= fd_g_debug_lvl)
-#define __STRIPPED_FILE__ __FILE__
-#endif /* DEBUG */
-
-
-#define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
-/*************
- The general debug macro, each call results in two lines of debug messages (change the macro for more compact output) 
- *************/
+
+
+/* In DEBUG mode, we add meta-information along each trace. This makes multi-threading problems easier to debug. */
 #ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE(printlevel,level,format,args... ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		const char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		fd_log((printlevel), STD_TRACE_FMT_STRING format, 								\
-					__thn, __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__, ## args); 			\
-	}															\
-}
+# define STD_TRACE_FMT_STRING "pid:%s in %s@%s:%d: "
+# define STD_TRACE_FMT_ARGS   , ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed"), __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__
 #else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case */
-#define TRACE(printlevel,level,format,args... ) {					\
-	if ( TRACE_BOOL(level) ) {							\
-		fd_log((printlevel), format, ## args);    				\
-	}										\
-}
+# define STD_TRACE_FMT_STRING ""
+# define STD_TRACE_FMT_ARGS
 #endif /* DEBUG */
 
-/* Report debug information */
-#define TRACE_DEBUG(level,format,args... ) \
-	TRACE(FD_LOG_DEBUG,(level),format,##args)
+/*************************
+  The general debug macro
+ *************************/
+#define LOG(printlevel,format,args... ) \
+	fd_log((printlevel), STD_TRACE_FMT_STRING format STD_TRACE_FMT_ARGS, ## args)
+
+/*
+ * Use the following macros in the code to get traces with location & pid in debug mode: 
+ */
+#ifdef DEBUG
+# define LOG_A(format,args... ) \
+		LOG(FD_LOG_ANNOYING,format,##args)
+#else /* DEBUG */
+# define LOG_A(format,args... ) /* not defined in release */
+#endif /* DEBUG */
+
+/* Debug information useful to follow in detail what is going on */
+#define LOG_D(format,args... ) \
+		LOG(FD_LOG_DEBUG, format, ##args)
 
 /* Report a normal message that is useful for normal admin monitoring */
-#define TRACE_NOTICE(format,args... ) \
-	TRACE(FD_LOG_NOTICE,INFO,format,##args)
+#define LOG_N(format,args... ) \
+		LOG(FD_LOG_NOTICE, format,##args)
 
 /* Report an error */
-#define TRACE_ERROR(format,args... ) \
-	TRACE(FD_LOG_ERROR, NONE, format, ##args)
-
-/* 
-TRACE_NOTICE(...) and fd_log_notice(...) are equivalent when the code is not compiled in DEBUG mode,
-but there is more contextual information when compiled in DEBUG with the TRACE_NOTICE macro,
-hence it is recommended to use this one except for formatted output (e.g. fd_*_dump function)
-
-resp. TRACE_DEBUG and TRACE_ERROR.
-*/
+#define LOG_E(format,args... ) \
+		LOG(FD_LOG_ERROR, format, ##args)
+
+/* Report a fatal error */
+#define LOG_F(format,args... ) \
+		LOG(FD_LOG_FATAL, format, ##args)
+
 
 /*************
- Derivatives for debug
+ Derivatives
  ************/
+/* Trace a binary buffer content */
+#define LOG_BUFFER(printlevel, prefix, buf, bufsz, suffix ) {								\
+	int __i;													\
+	size_t __sz = (size_t)(bufsz);											\
+	uint8_t * __buf = (uint8_t *)(buf);										\
+	char __strbuf[1024+1];												\
+	for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) {						\
+		sprintf(__strbuf + (2 * __i), "%02hhx", __buf[__i]);     						\
+	}														\
+        fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s" STD_TRACE_FMT_ARGS,  						\
+               (prefix), __strbuf, (suffix));										\
+}
+
 /* Helper for function entry -- for very detailed trace of the execution */
 #define TRACE_ENTRY(_format,_args... ) \
-	TRACE_DEBUG(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
+		LOG_A(FCTS, "[enter] %s(" _format ") {" #_args "}", __PRETTY_FUNCTION__, ##_args );
 
 /* Helper for debugging by adding traces -- for debuging a specific location of the code */
 #define TRACE_HERE()	\
-	TRACE_DEBUG(NONE, " -- debug checkpoint %d -- ", fd_breakhere());
+		LOG_F(" -- debug checkpoint %d -- ", fd_breakhere());
 int fd_breakhere(void);
 
 /* Helper for tracing the CHECK_* macros below -- very very verbose code execution! */
-#define TRACE_DEBUG_ALL( str... ) 	\
-	TRACE_DEBUG(CALL, str );
+#define TRACE_CALL( str... ) 	\
+		if ((fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__)) 	\
+		 || (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ) ) {		\
+		 	LOG_A( str );									\
+		}
 
 /* For development only, to keep track of TODO locations in the code */
 #ifndef ERRORS_ON_TODO
-#define TODO( _msg, _args... ) \
-	TRACE_DEBUG(NONE, "TODO: " _msg , ##_args);
+# define TODO( _msg, _args... ) \
+		LOG_F( "TODO: " _msg , ##_args);
 #else /* ERRORS_ON_TODO */
-#define TODO( _msg, _args... ) \
-	"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
+# define TODO( _msg, _args... ) \
+		"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
 #endif /* ERRORS_ON_TODO */
 
-/* Trace a binary buffer content */
-#ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
-	if ( TRACE_BOOL(level) ) {												\
+
+/*============================================================*/
+/*                  ERROR CHECKING MACRO                      */
+/*============================================================*/
+
+/* Macros to check a return value and branch out in case of error.
+ * These macro additionally provide the logging information.
+ *
+ * The name "__ret__" is always available in the __fallback__ parameter and contains the error code.
+ */
+ 
+#define CHECK_PRELUDE(__call__) 			\
+		int __ret__; 				\
+		TRACE_CALL("Check: %s", #__call__ );	\
+		__ret__ = (__call__)
+	
+#define DEFAULT_FB	return __ret__;
+
+/* System check: error case if < 0, error value in errno */
+#define CHECK_SYS_GEN( faillevel, __call__, __fallback__  ) { 						\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			LOG(faillevel, "ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));    	\
+			__fallback__;									\
+		}											\
+}
+
+
+/* Check the return value of a function and execute fallback in case of error or special value */
+#define CHECK_FCT_GEN2( faillevel, __call__, __speval__, __fallback1__, __fallback2__ ) {		\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ != 0) {									\
+			if (__ret__ == (__speval__)) {							\
+				__fallback1__;								\
+			} else {									\
+				LOG(faillevel, "ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__));	\
+				__fallback2__;								\
+			}										\
+		}											\
+}
+
+/* Check the return value of a function and execute fallback in case of error (return value different from 0) */
+#define CHECK_FCT_GEN( faillevel, __call__, __fallback__) \
+	       CHECK_FCT_GEN2( faillevel, (__call__), 0, , (__fallback__) )
+
+/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
+#define CHECK_MALLOC_GEN( faillevel, __call__, __fallback__ ) { 				       \
+	       void *  __ptr__; 								       \
+	       TRACE_CALL("Check: %s", #__call__ );						       \
+	       __ptr__ = (void *)(__call__);							       \
+	       if (__ptr__ == NULL) {								       \
+		       int __ret__ = errno;							       \
+		       LOG(faillevel, "ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));         \
+		       __fallback__;								       \
+	       }										       \
+}
+
+/* Check parameters at function entry, execute fallback on error */
+#define CHECK_PARAMS_GEN( faillevel, __bool__, __fallback__ ) {					       \
+	       TRACE_CALL("Check: %s", #__bool__ );						       \
+	       if ( ! (__bool__) ) {								       \
+		       int __ret__ = EINVAL;							       \
+		       LOG(faillevel, "ERROR: invalid parameter '%s'",  #__bool__ );  	       	       \
+		       __fallback__;								       \
+	       }										       \
+}
+
+
+/*============================================================*/
+/*          COMPATIBILITY MACROS, TO BE REMOVED		      */
+/*============================================================*/
+/* Redefine the old macros for transition of the code */
+#ifndef EXCLUDE_DEPRECATED
+
+#define MARK_DEPRECATED	/* __attribute__ ((deprecated)) */
+
+enum old_levels {
+	NONE = 0,
+	INFO = 1,
+	FULL = 2,
+	ANNOYING = 4,
+	FCTS = 6,
+	CALL = 9
+} MARK_DEPRECATED;
+
+static __inline__ int TRACE_BOOL( enum old_levels level ) MARK_DEPRECATED
+{ 
+	return (level <= fd_g_debug_lvl)
+		|| (fd_debug_one_function && !strcmp(fd_debug_one_function, __PRETTY_FUNCTION__))
+		|| (fd_debug_one_file && !strcmp(fd_debug_one_file, __STRIPPED_FILE__) ); 
+}
+
+static __inline__ void fd_log_deprecated( int level, const char *format, ... ) MARK_DEPRECATED
+{ 
+	va_list ap;
+	va_start(ap, format);
+	fd_log_va(level, format, ap);
+	va_end(ap);	
+}
+static __inline__ void replace_me() MARK_DEPRECATED { }
+
+#define TRACE_sSA(...) replace_me();
+#define sSA_DUMP_NODE_SERV(...) replace_me();
+#define sSA_DUMP_NODE(...) replace_me();
+#define TRACE_BUFFER(...) replace_me();
+#define TRACE_NOTICE(...) replace_me();
+
+
+/* Use the LOG_* instead, or use the new *_dump functions when dumping an object */
+#define fd_log_debug(format,args...)  fd_log_deprecated(FD_LOG_DEBUG, format, ## args)
+#define fd_log_notice(format,args...) fd_log_deprecated(FD_LOG_NOTICE, format, ## args)
+#define fd_log_error(format,args...)  fd_log_deprecated(FD_LOG_ERROR, format, ## args)
+
+/* old macro for traces. To be replaced by appropriate LOG_* macros. */
+# define TRACE_DEBUG(oldlevel, format,args... ) {					\
+		if (TRACE_BOOL(oldlevel)) {						\
+			if      (oldlevel == NONE) { LOG_E(format,##args); }		\
+			else if (oldlevel == INFO) { LOG_N(format,##args); }		\
+			else                       { LOG_D(format,##args); }		\
+}		}
+
+/* the following macro must be replaced with LOG_E or LOG_F */
+# define TRACE_ERROR	fd_log_error
+
+
+/* The following macros are missing the faillevel information, which indicates at what log level the error case should be displayed. */
+# define CHECK_SYS_DO( __call__, __fallback__  ) { 							\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ < 0) {									\
+			__ret__ = errno;								\
+			TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));    	\
+			__fallback__;									\
+		}											\
+}
+
+# define CHECK_SYS( __call__  ) \
+		CHECK_SYS_DO( (__call__), return __ret__  )
+
+
+# define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) {			\
+		CHECK_PRELUDE(__call__);								\
+		if (__ret__ != 0) {									\
+			if (__ret__ == (__speval__)) {							\
+				__fallback1__;								\
+			} else {									\
+				TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , strerror(__ret__));	\
+				__fallback2__;								\
+			}										\
+		}											\
+}
+
+# define CHECK_POSIX_DO( __call__, __fallback__ )	\
+		CHECK_POSIX_DO2( (__call__), 0, , __fallback__ )
+
+# define CHECK_POSIX( __call__ )	\
+		CHECK_POSIX_DO( (__call__), return __ret__ )
+		
+# define CHECK_MALLOC_DO( __call__, __fallback__ ) { 				   		       \
+	       void *  __ptr__; 								       \
+	       TRACE_CALL("Check: %s", #__call__ );						       \
+	       __ptr__ = (void *)(__call__);							       \
+	       if (__ptr__ == NULL) {								       \
+		       int __ret__ = errno;							       \
+		      TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ , strerror(__ret__));             \
+		       __fallback__;								       \
+	       }										       \
+}
+
+# define CHECK_MALLOC( __call__ )	\
+		CHECK_MALLOC_DO( (__call__), return __ret__ )
+	
+# define CHECK_PARAMS_DO( __bool__, __fallback__ ) {					       	       \
+	       TRACE_CALL("Check: %s", #__bool__ );						       \
+	       if ( ! (__bool__) ) {								       \
+		       int __ret__ = EINVAL;							       \
+		       TRACE_ERROR("ERROR: invalid parameter '%s'",  #__bool__ );  	               \
+		       __fallback__;								       \
+	       }										       \
+}
+
+# define CHECK_PARAMS( __bool__ )	\
+		CHECK_PARAMS_DO( (__bool__), return __ret__ )
+
+# define CHECK_FCT_DO	CHECK_POSIX_DO
+# define CHECK_FCT	CHECK_POSIX
+
+#endif /* EXCLUDE_DEPRECATED */
+	       
+
+/*============================================================*/
+/*	Optimized code: remove all debugging code	      */
+/*============================================================*/
+#ifdef STRIP_DEBUG_CODE
+#undef LOG_D
+#undef LOG_N
+#undef LOG_E
+#undef LOG_F
+#undef LOG_BUFFER
+
+#define LOG_D(format,args... ) /* noop */
+#define LOG_N(format,args...) fd_log(FD_LOG_NOTICE, format, ## args)
+#define LOG_E(format,args...) fd_log(FD_LOG_ERROR, format, ## args)
+#define LOG_F(format,args...) fd_log(FD_LOG_FATAL, format, ## args)
+#define LOG_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
+	if (printlevel > FD_LOG_DEBUG) {											\
 		int __i;													\
 		size_t __sz = (size_t)(bufsz);											\
 		uint8_t * __buf = (uint8_t *)(buf);										\
-		char __strbuf[1024+1];												\
-		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) {						\
-			sprintf(__strbuf + (2 * __i), "%2.2hhx", __buf[__i]);     						\
+		char * __strbuf[1024+1];											\
+		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2); __i++) {						\
+			sprintf(__strbuf + (2 * __i), "%02.2hhx", __buf[__i]);     						\
 		}														\
-                fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s",      								\
-                       __thn, __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__, (prefix), __strbuf, (suffix));			\
-	}															\
-}
-#else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case */
-#define TRACE_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
-	if ( TRACE_BOOL(level) ) {												\
-		int __i;													\
-		size_t __sz = (size_t)(bufsz);											\
-		uint8_t * __buf = (uint8_t *)(buf);										\
-		char __strbuf[1024+1];												\
-		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2)); __i++) {						\
-			sprintf(__strbuf + (2 * __i), "%2.2hhx", __buf[__i]);     						\
-		}														\
-                fd_log(printlevel, "%s%s%s", (prefix), __strbuf, (suffix));							\
-	}															\
-}
-#endif /* DEBUG */
+                fd_log(printlevel, prefix"%s"suffix, __strbuf);									\
+	}
+#endif /* STRIP_DEBUG_CODE */
+
+/*============================================================*/
+/*		    OTHER MACROS			      */
+/*============================================================*/
+/* helper macros (pre-processor hacks to allow macro arguments) */
+#define __tostr( arg )  #arg
+#define _stringize( arg ) __tostr( arg )
+#define __agr( arg1, arg2 ) arg1 ## arg2
+#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
 
 /* Some aliases to socket addresses structures */
 #define sSS	struct sockaddr_storage
@@ -392,217 +598,8 @@
 				((((sSA *)_sa_)->sa_family == AF_INET6) ? (sizeof(sSA6)) :	\
 					0 ) ) )
 
-/* Dump one sockaddr Node information */
-#define sSA_DUMP_NODE( buf, bufsize, sa, flag ) {                	\
-	sSA * __sa = (sSA *)(sa);					\
-	char __addrbuf[INET6_ADDRSTRLEN];				\
-	if (__sa) {							\
-	  int __rc = getnameinfo(__sa, 					\
-	  		sSAlen(__sa),					\
-			__addrbuf,					\
-			sizeof(__addrbuf),				\
-			NULL,						\
-			0,						\
-			(flag));					\
-	  if (__rc)							\
-		snprintf(buf, bufsize, "%s", gai_strerror(__rc));	\
-	  else								\
-		snprintf(buf, bufsize, "%s", &__addrbuf[0]);       	\
-	} else {							\
-		snprintf(buf, bufsize, "(NULL / ANY)");             	\
-	}								\
-}
-/* Same but with the port (service) also */
-#define sSA_DUMP_NODE_SERV( buf, bufsize, sa, flag ) {                  \
-	sSA * __sa = (sSA *)(sa);					\
-	char __addrbuf[INET6_ADDRSTRLEN];				\
-	char __servbuf[32];						\
-	if (__sa) {							\
-	  int __rc = getnameinfo(__sa, 					\
-	  		sSAlen(__sa),					\
-			__addrbuf,					\
-			sizeof(__addrbuf),				\
-			__servbuf,					\
-			sizeof(__servbuf),				\
-			(flag));					\
-	  if (__rc)							\
-		snprintf(buf, bufsize, "%s", gai_strerror(__rc));  \
-	  else								\
-		snprintf(buf, bufsize, "[%s]:%s", &__addrbuf[0],&__servbuf[0]); \
-	} else {							\
-		snprintf(buf, bufsize,"(NULL / ANY)");         \
-	}								\
-}
-
-#ifdef DEBUG
-/* In DEBUG mode, we add (a lot of) meta-information along each trace. This makes multi-threading problems easier to debug. */
-#define TRACE_sSA(printlevel, level, prefix, sa, flags, suffix ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		char __buf[1024]; 												\
-		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
-		sSA_DUMP_NODE_SERV(__buf, sizeof(__buf), sa, flags );       							\
-		fd_log(printlevel, STD_TRACE_FMT_STRING "%s%s%s" ,     								\
-                       __thn, __PRETTY_FUNCTION__, __STRIPPED_FILE__, __LINE__, (prefix), __buf, (suffix)); 			\
-	}															\
-}
-#else /* DEBUG */
-/* Do not print thread, function, ... only the message itself in this case */
-#define TRACE_sSA(printlevel, level, prefix, sa, flags, suffix ) {										\
-	if ( TRACE_BOOL(level) ) {												\
-		char __buf[1024]; 												\
-		sSA_DUMP_NODE_SERV(__buf, sizeof(__buf), sa, flags );       							\
-		fd_log(printlevel, "%s%s%s" , (prefix), __buf, (suffix)); 							\
-	}															\
-}
-#endif /* DEBUG */
-
-/******************
- Optimized code: remove all debugging code
- **/
-#ifdef STRIP_DEBUG_CODE
-#undef TRACE_DEBUG
-#undef TRACE_NOTICE
-#undef TRACE_ERROR
-#undef TRACE_BOOL
-#undef TRACE_BUFFER
-#undef TRACE_sSA
-
-#define TRACE_DEBUG(level,format,args... ) /* noop */
-#define TRACE_BOOL(_level_) (0)	/* always false */
-#define TRACE_NOTICE fd_log_notice
-#define TRACE_ERROR fd_log_error
-#define TRACE_BUFFER(printlevel, level, prefix, buf, bufsz, suffix ) {								\
-	if (printlevel > FD_LOG_DEBUG) {											\
-		int __i;													\
-		size_t __sz = (size_t)(bufsz);											\
-		uint8_t * __buf = (uint8_t *)(buf);										\
-		char * __strbuf[1024+1];											\
-		for (__i = 0; (__i < __sz) && (__i<(sizeof(__strbuf)/2); __i++) {						\
-			sprintf(__strbuf + (2 * __i), "%02.2hhx", __buf[__i]);     						\
-		}														\
-                fd_log(printlevel, prefix"%s"suffix, __strbuf);									\
-	}
-#define TRACE_sSA(printlevel, level, prefix, sa, flags, suffix )  {								\
-	if (printlevel > FD_LOG_DEBUG) {											\
-		char __buf[1024]; 												\
-		sSA_DUMP_NODE_SERV(__buf, sizeof(__buf), sa, flags );       							\
-		fd_log(printlevel, prefix "%s" suffix, __buf);				 					\
-	}
-#endif /* STRIP_DEBUG_CODE */
-
-
-/*============================================================*/
-/*                  ERROR CHECKING MACRO                      */
-/*============================================================*/
-
-/* Macros to check a return value and branch out in case of error.
- * These macro should be used only when errors are improbable, not for expected errors.
- */
-
-/* Check the return value of a system function and execute fallback in case of error */
-#define CHECK_SYS_DO( __call__, __fallback__  ) { 					\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check SYS: %s", #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		TRACE_ERROR("ERROR: in '%s' :\t%s",  #__call__ , strerror(__err__));    \
-		__fallback__;								\
-	}										\
-}
-/* Check the return value of a system function, return error code on error */
-#define CHECK_SYS( __call__  ) { 							\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check SYS: %s", #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ < 0) {								\
-		int __err__ = errno;	/* We may handle EINTR here */			\
-		TRACE_ERROR("ERROR: in '%s' :\t%s", #__call__ , strerror(__err__));     \
-		return __err__;								\
-	}										\
-}
-
-/* Check the return value of a POSIX function and execute fallback in case of error or special value */
-#define CHECK_POSIX_DO2( __call__, __speval__, __fallback1__, __fallback2__ ) {			\
-	int __ret__;										\
-	TRACE_DEBUG_ALL( "Check POSIX: %s", #__call__ );					\
-	__ret__ = (__call__);									\
-	if (__ret__ != 0) {									\
-		if (__ret__ == (__speval__)) {							\
-			__fallback1__;								\
-		} else {									\
-			TRACE_ERROR("ERROR: in '%s':\t%s", #__call__, strerror(__ret__));	\
-			__fallback2__;								\
-		}										\
-	}											\
-}
-
-/* Check the return value of a POSIX function and execute fallback in case of error */
-#define CHECK_POSIX_DO( __call__, __fallback__ ) 					\
-	CHECK_POSIX_DO2( (__call__), 0, , __fallback__ );
-
-/* Check the return value of a POSIX function and return it if error */
-#define CHECK_POSIX( __call__ ) { 							\
-	int __v__;									\
-	CHECK_POSIX_DO( __v__ = (__call__), return __v__ );				\
-}
-
-/* Check that a memory allocator did not return NULL, otherwise log an error and execute fallback */
-#define CHECK_MALLOC_DO( __call__, __fallback__ ) { 					\
-	void *  __ret__;								\
-	TRACE_DEBUG_ALL( "Check MALLOC: %s", #__call__ );				\
-	__ret__ = (void *)( __call__ );							\
-	if (__ret__ == NULL) {								\
-		int __err__ = errno;							\
-		TRACE_ERROR("ERROR: in '%s':\t%s", #__call__, strerror(__err__));	\
-		__fallback__;								\
-	}										\
-}
-
-/* Check that a memory allocator did not return NULL, otherwise return ENOMEM */
-#define CHECK_MALLOC( __call__ )							\
-	CHECK_MALLOC_DO( __call__, return ENOMEM );
-
-
-/* Check parameters at function entry, execute fallback on error */
-#define CHECK_PARAMS_DO( __bool__, __fallback__ )						\
-	TRACE_DEBUG_ALL( "Check PARAMS: %s", #__bool__ );					\
-	if ( ! (__bool__) ) {									\
-		TRACE_ERROR("Warning: Invalid parameter received in '%s'", #__bool__);		\
-		__fallback__;									\
-	}
-/* Check parameters at function entry, return EINVAL if the boolean is false (similar to assert) */
-#define CHECK_PARAMS( __bool__ )							\
-	CHECK_PARAMS_DO( __bool__, return EINVAL );
-
-/* Check the return value of an internal function, log and propagate */
-#define CHECK_FCT_DO( __call__, __fallback__ ) {					\
-	int __ret__;									\
-	TRACE_DEBUG_ALL( "Check FCT: %s", #__call__ );					\
-	__ret__ = (__call__);								\
-	if (__ret__ != 0) {								\
-		TRACE_ERROR("ERROR: in '%s':\t%s", #__call__, strerror(__ret__));	\
-		__fallback__;								\
-	}										\
-}
-/* Check the return value of a function call, return any error code */
-#define CHECK_FCT( __call__ ) {								\
-	int __v__;									\
-	CHECK_FCT_DO( __v__ = (__call__), return __v__ );				\
-}
-
-
-
-/*============================================================*/
-/*                  OTHER MACROS                              */
-/*============================================================*/
-
-
-/* helper macros (pre-processor hacks to allow macro arguments) */
-#define __tostr( arg )  #arg
-#define _stringize( arg ) __tostr( arg )
-#define __agr( arg1, arg2 ) arg1 ## arg2
-#define _aggregate( arg1, arg2 ) __agr( arg1, arg2 )
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node, sSA * sa, int flags);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node_serv, sSA * sa, int flags);
 
 
 /* A l4 protocol name (TCP / SCTP) */
@@ -983,8 +980,8 @@
 int fd_dict_getdict ( struct dict_object * object, struct dictionary ** dict);
 
 /* Debug functions */
-void fd_dict_dump_object(struct dict_object * obj);
-void fd_dict_dump(struct dictionary * dict);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump, struct dictionary * dict);
 
 /* Function to access full contents of the dictionary, see doc in dictionary.c */
 int fd_dict_getlistof(int criteria, void * parent, struct fd_list ** sentinel);
@@ -1222,7 +1219,7 @@
 	char *	 		 type_name;	/* The name of this type */
 	dict_avpdata_interpret	 type_interpret;/* cb to convert the AVP value in more comprehensive format (or NULL) */
 	dict_avpdata_encode	 type_encode;	/* cb to convert formatted data into an AVP value (or NULL) */
-	char * 			(*type_dump)(union avp_value * val);	/* cb called by fd_msg_dump_one for this type of data (if != NULL). Returned string must be freed.  */
+	DECLARE_FD_DUMP_PROTOTYPE((*type_dump), union avp_value * val); /* cb called by fd_msg_dump_one for this type of data (if != NULL). Returned string must be freed.  */
 };
 
 /* The criteria for searching a type object in the dictionary */
@@ -1239,15 +1236,15 @@
 /* Convert an Address type AVP into a struct sockaddr_storage */
 int fd_dictfct_Address_encode(void * data, union avp_value * avp_value);
 int fd_dictfct_Address_interpret(union avp_value * avp_value, void * interpreted);
-char * fd_dictfct_Address_dump(union avp_value * avp_value);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump, union avp_value * avp_value);
 
 /* Display the content of an AVP of type UTF8String in the log file */
-char * fd_dictfct_UTF8String_dump(union avp_value * avp_value);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_UTF8String_dump, union avp_value * avp_value);
 
 /* For Time AVPs, map with time_t value directly */
 int fd_dictfct_Time_encode(void * data, union avp_value * avp_value);
 int fd_dictfct_Time_interpret(union avp_value * avp_value, void * interpreted);
-char * fd_dictfct_Time_dump(union avp_value * avp_value);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value);
 
 
 
@@ -1821,6 +1818,8 @@
 /* The state information that a module associate with a session -- each module defines its own data format */
 typedef void session_state;
 
+typedef DECLARE_FD_DUMP_PROTOTYPE(session_state_dump, session_state * st);
+
 /* The following function must be called to activate the session expiry mechanism */
 int fd_sess_start(void);
 
@@ -1830,6 +1829,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.
+ *  dumper      : if not NULL, will be called during fd_sess_dump to display the data associated with a session. NULL otherwise.
  *  opaque      : A pointer that is passed to the cleanup callback -- the content is never examined by the framework.
  *
  * DESCRIPTION: 
@@ -1842,10 +1842,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, os0_t sid, void * opaque), void * opaque );
+int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state * state, os0_t sid, void * opaque), session_state_dump dumper, void * opaque );
 /* Macro to avoid casting everywhere */
-#define fd_sess_handler_create( _handler, _cleanup, _opaque ) \
-	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, os0_t, void *))(_cleanup), (void *)(_opaque) )
+#define fd_sess_handler_create( _handler, _cleanup, _dumper, _opaque ) \
+	fd_sess_handler_create_internal( (_handler), (void (*)(session_state *, os0_t, void *))(_cleanup), _dumper, (void *)(_opaque) )
 
 	
 /*
@@ -2045,8 +2045,8 @@
 
 
 /* For debug */
-void fd_sess_dump(int level, struct session * session);
-void fd_sess_dump_hdl(int level, struct session_handler * handler);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states);
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler);
 
 /* For statistics / monitoring: get the number of struct session in memory */
 int fd_sess_getcount(uint32_t *cnt);
@@ -2327,33 +2327,26 @@
  * FUNCTION:	fd_msg_dump_*
  *
  * PARAMETERS:
- *  level	: the log level (INFO, FULL, ...) at which the object is dumped
- *  obj		: A msg or avp object.
+ *  see definition of DECLARE_FD_DUMP_PROTOTYPE,
+ *  obj		 : A msg or avp object to dump.
+ *  dict         : the dictionary to use if parsing is requested (optional)
+ *  force_parsing: by default these functions do not parse the object but dump hexa values in that case.
+ *                 use !0 to force parsing. If parsing fails, the hexa dump is still provided.
+ *  recurse      : allow the function to go through the children objects if any to dump more information. might require parsing.
  *
  * DESCRIPTION: 
- *   These functions dump the content of a message to the debug log
+ *   These functions dump the content of a message or avp into a buffer
  * either recursively or only the object itself.
  *
  * RETURN VALUE:
- *   -
- */
-void fd_msg_dump_walk ( int level, msg_or_avp *obj );
-void fd_msg_dump_one  ( int level, msg_or_avp *obj );
-
-/* Helper functions to get a dump of an object in the logs. Several formats are available.
- *  buf   : a buffer that can be reallocated if needed. *buf==NULL is also accepted for first allocation
- *  buflen: the length of the buffer buf.
- *  dict  : optional, the dictionary to use for resolving objects, if force_parsing != 0
- *  obj   : the message or AVP to dump.
- *
- * After use, the buf pointer should be freed.
+ *   - see DECLARE_FD_DUMP_PROTOTYPE,
  */
 /* one-line dump with only short information */
-void fd_msg_dump_summary( char ** buf, size_t buflen, struct dictionary *dict, msg_or_avp *obj, int force_parsing);
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_summary, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
 /* one-line dump with all the contents of the message */
-void fd_msg_dump_full( char ** buf, size_t buflen, struct dictionary *dict, msg_or_avp *obj, int force_parsing);
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_full, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
 /* multi-line human-readable dump similar to wireshark output */
-void fd_msg_dump_treeview( char ** buf, size_t buflen, struct dictionary *dict, msg_or_avp *obj, int force_parsing);
+DECLARE_FD_DUMP_PROTOTYPE( fd_msg_dump_treeview, msg_or_avp *obj, struct dictionary *dict, int force_parsing, int recurse );
 
 
 /*********************************************/
@@ -3140,7 +3133,8 @@
 	fd_fifo_timedget_int((queue), (void *)(item), (abstime))
 
 /* Dump a fifo list and optionally its inner elements -- beware of deadlocks! */
-void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item));
+typedef DECLARE_FD_DUMP_PROTOTYPE((*fd_fifo_dump_item_cb), void * item); /* This function should be 1 line if possible, or use indent level. Ends with '\n' */
+DECLARE_FD_DUMP_PROTOTYPE(fd_fifo_dump, char * name, struct fifo * queue, fd_fifo_dump_item_cb dump_item);
 
 #ifdef __cplusplus
 }
--- a/libfdcore/config.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/config.c	Fri May 03 19:20:56 2013 +0800
@@ -80,68 +80,71 @@
 	return 0;
 }
 
-void fd_conf_dump()
+DECLARE_FD_DUMP_PROTOTYPE(fd_conf_dump)
 {
-	if (!TRACE_BOOL(INFO))
-		return;
+	size_t o=0;
+	if (!offset)
+		offset = &o;
 	
-	fd_log_debug("-- Configuration :");
-	fd_log_debug("  Debug trace level ...... : %+d", fd_g_debug_lvl);
-	fd_log_debug("  Configuration file ..... : %s", fd_g_config->cnf_file);
-	fd_log_debug("  Diameter Identity ...... : %s (l:%Zi)", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len);
-	fd_log_debug("  Diameter Realm ......... : %s (l:%Zi)", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len);
-	fd_log_debug("  Tc Timer ............... : %u", fd_g_config->cnf_timer_tc);
-	fd_log_debug("  Tw Timer ............... : %u", fd_g_config->cnf_timer_tw);
-	fd_log_debug("  Local port ............. : %hu", fd_g_config->cnf_port);
-	fd_log_debug("  Local secure port ...... : %hu", fd_g_config->cnf_port_tls);
-	fd_log_debug("  Number of SCTP streams . : %hu", fd_g_config->cnf_sctp_str);
-	fd_log_debug("  Number of server threads : %hu", fd_g_config->cnf_dispthr);
+	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);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Configuration file ..... : %s\n", fd_g_config->cnf_file), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Diameter Identity ...... : %s (l:%Zi)\n", fd_g_config->cnf_diamid, fd_g_config->cnf_diamid_len), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Diameter Realm ......... : %s (l:%Zi)\n", fd_g_config->cnf_diamrlm, fd_g_config->cnf_diamrlm_len), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Tc Timer ............... : %u\n", fd_g_config->cnf_timer_tc), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Tw Timer ............... : %u\n", fd_g_config->cnf_timer_tw), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local port ............. : %hu\n", fd_g_config->cnf_port), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local secure port ...... : %hu\n", fd_g_config->cnf_port_tls), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of SCTP streams . : %hu\n", fd_g_config->cnf_sctp_str), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Number of server threads : %hu\n", fd_g_config->cnf_dispthr), return NULL);
 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
-		fd_log_debug("  Local endpoints ........ : Default (use all available)");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : Default (use all available)\n"), return NULL);
 	} else {
-		fd_log_debug("  Local endpoints ........ : ");
-		fd_ep_dump( 29, &fd_g_config->cnf_endpoints );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local endpoints ........ : \n"), return NULL);
+		CHECK_MALLOC_DO( fd_ep_dump( FD_DUMP_STD_PARAMS, 29, &fd_g_config->cnf_endpoints ), return NULL);
 	}
 	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_apps)) {
-		fd_log_debug("  Local applications ..... : (none)");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local applications ..... : (none)\n"), return NULL);
 	} else {
 		struct fd_list * li = fd_g_config->cnf_apps.next;
-		fd_log_debug("  Local applications ..... : ");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Local applications ..... : \n"), return NULL);
 		while (li != &fd_g_config->cnf_apps) {
 			struct fd_app * app = (struct fd_app *)li;
-			if (li != fd_g_config->cnf_apps.next) fd_log_debug("                             ");
-			fd_log_debug("App: %u\t%s%s\tVnd: %u", 
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "                             App: %u\t%s%s\tVnd: %u\n", 
 					app->appid,
 					app->flags.auth ? "Au" : "--",
 					app->flags.acct ? "Ac" : "--",
-					app->vndid);
+					app->vndid), return NULL);
 			li = li->next;
 		}
 	}
 	
-	fd_log_debug("  Flags : - IP ........... : %s", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled");
-	fd_log_debug("          - IPv6 ......... : %s", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled");
-	fd_log_debug("          - Relay app .... : %s", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled");
-	fd_log_debug("          - TCP .......... : %s", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Flags : - IP ........... : %s\n", fd_g_config->cnf_flags.no_ip4 ? "DISABLED" : "Enabled"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - IPv6 ......... : %s\n", fd_g_config->cnf_flags.no_ip6 ? "DISABLED" : "Enabled"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Relay app .... : %s\n", fd_g_config->cnf_flags.no_fwd ? "DISABLED" : "Enabled"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TCP .......... : %s\n", fd_g_config->cnf_flags.no_tcp ? "DISABLED" : "Enabled"), return NULL);
 	#ifdef DISABLE_SCTP
-	fd_log_debug("          - SCTP ......... : DISABLED (at compilation)");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - SCTP ......... : DISABLED (at compilation)\n"), return NULL);
 	#else /* DISABLE_SCTP */
-	fd_log_debug("          - SCTP ......... : %s", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - SCTP ......... : %s\n", fd_g_config->cnf_flags.no_sctp ? "DISABLED" : "Enabled"), return NULL);
 	#endif /* DISABLE_SCTP */
-	fd_log_debug("          - Pref. proto .. : %s", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP");
-	fd_log_debug("          - TLS method ... : %s", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port");
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Pref. proto .. : %s\n", fd_g_config->cnf_flags.pr_tcp ? "TCP" : "SCTP"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - TLS method ... : %s\n", fd_g_config->cnf_flags.tls_alg ? "INBAND" : "Separate port"), return NULL);
 	
-	fd_log_debug("  TLS :   - Certificate .. : %s", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)");
-	fd_log_debug("          - Private key .. : %s", fd_g_config->cnf_sec_data.key_file ?: "(NONE)");
-	fd_log_debug("          - CA (trust) ... : %s (%d certs)", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr);
-	fd_log_debug("          - CRL .......... : %s", fd_g_config->cnf_sec_data.crl_file ?: "(none)");
-	fd_log_debug("          - Priority ..... : %s", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')");
-	if (fd_g_config->cnf_sec_data.dh_file)
-		fd_log_debug("          - DH file ...... : %s", fd_g_config->cnf_sec_data.dh_file);
-	else
-		fd_log_debug("          - DH bits ...... : %d", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  TLS :   - Certificate .. : %s\n", fd_g_config->cnf_sec_data.cert_file ?: "(NONE)"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Private key .. : %s\n", fd_g_config->cnf_sec_data.key_file ?: "(NONE)"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - CA (trust) ... : %s (%d certs)\n", fd_g_config->cnf_sec_data.ca_file ?: "(none)", fd_g_config->cnf_sec_data.ca_file_nr), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - CRL .......... : %s\n", fd_g_config->cnf_sec_data.crl_file ?: "(none)"), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - Priority ..... : %s\n", fd_g_config->cnf_sec_data.prio_string ?: "(default: '" GNUTLS_DEFAULT_PRIORITY "')"), return NULL);
+	if (fd_g_config->cnf_sec_data.dh_file) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - DH file ...... : %s\n", fd_g_config->cnf_sec_data.dh_file), return NULL);
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "          - DH bits ...... : %d\n", fd_g_config->cnf_sec_data.dh_bits ?: GNUTLS_DEFAULT_DHBITS), return NULL);
+	}
 	
-	fd_log_debug("  Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "  Origin-State-Id ........ : %u", fd_g_config->cnf_orstateid), return NULL);
+	
+	return *buf;
 }
 
 /* read contents of a file opened in "rb" mode and alloc this data into a gnutls_datum_t (must be freed afterwards) */
--- a/libfdcore/core.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/core.c	Fri May 03 19:20:56 2013 +0800
@@ -84,32 +84,6 @@
 		int code; size_t sz; void * data;
 		CHECK_FCT_DO(  fd_event_get(fd_g_config->cnf_main_ev, &code, &sz, &data),  break  );
 		switch (code) {
-			case FDEV_DUMP_DICT:
-				fd_dict_dump(fd_g_config->cnf_dict);
-				break;
-			
-			case FDEV_DUMP_EXT:
-				fd_ext_dump();
-				break;
-			
-			case FDEV_DUMP_SERV:
-				fd_servers_dump();
-				break;
-			
-			case FDEV_DUMP_QUEUES:
-				fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk);
-				fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk);
-				fd_fifo_dump(0, "Local messages",    fd_g_local,    fd_msg_dump_walk);
-				break;
-			
-			case FDEV_DUMP_CONFIG:
-				fd_conf_dump();
-				break;
-			
-			case FDEV_DUMP_PEERS:
-				fd_peer_dump_list(FULL);
-				break;
-			
 			case FDEV_TRIGGER:
 				{
 					int tv, *p;
@@ -181,7 +155,7 @@
 		return ret;
 	}
 	
-	TRACE_DEBUG(INFO, "libfdproto initialized.");
+	LOG_D("libfdproto initialized.");
 	
 	/* Name this thread */
 	fd_log_threadname("Main");
@@ -224,6 +198,10 @@
 /* Parse the freeDiameter.conf configuration file, load the extensions */
 int fd_core_parseconf(const char * conffile)
 {
+	char * buf = NULL, *b;
+	size_t len = 0, offset=0;
+	
+	
 	TRACE_ENTRY("%p", conffile);
 	
 	/* Conf file */
@@ -239,11 +217,17 @@
 	CHECK_FCT(  fd_ext_load()  );
 	
 	/* Display configuration */
-	fd_conf_dump();
+	b = fd_conf_dump(&buf, &len, NULL);
+	LOG_N("%s\n", b ?: "Error during configuration dump...");
 	
 	/* Display registered triggers for FDEV_TRIGGER */
-	fd_event_trig_dump();
+	b = fd_event_trig_dump(&buf, &len, &offset);
+	if (!b || offset) {
+		LOG_N("%s\n", b ?: "Error during triggers dump...");
+	}
 	
+	free(buf);	
+		
 	return 0;
 }
 
--- a/libfdcore/endpoints.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/endpoints.c	Fri May 03 19:20:56 2013 +0800
@@ -57,19 +57,6 @@
 		fd_list_init(list, NULL);
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		char buf[1024];
-		sSA_DUMP_NODE_SERV( buf, sizeof(buf), sa, NI_NUMERICHOST | NI_NUMERICSERV );
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Current list:");
-		fd_ep_dump( 4, list );
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Adding:");
-		fd_log_debug("    %s {%s%s%s%s%s}", buf,
-				(flags & EP_FL_CONF) 	? "C" : "-",
-				(flags & EP_FL_DISC)	    ? "D" : "-",
-				(flags & EP_FL_ADV)	    ? "A" : "-",
-				(flags & EP_FL_LL)	    ? "L" : "-",
-				(flags & EP_FL_PRIMARY)     ? "P" : "-");
-	}
 	ptr.sa = sa;
 	
 	/* Filter out a bunch of invalid addresses */
@@ -81,9 +68,7 @@
 				    /* the next one filters both EXPERIMENTAL, BADCLASS and MULTICAST. */
 				 || ((ntohl(ptr.sin->sin_addr.s_addr) & 0xe0000000) == 0xe0000000)
 				 || (ptr.sin->sin_addr.s_addr == INADDR_BROADCAST)) {
-					if (TRACE_BOOL(ANNOYING + 1)) {
-						TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
-					}
+					LOG_A("  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
 					return 0;
 				}
 			}
@@ -97,9 +82,7 @@
 				 || IN6_IS_ADDR_MULTICAST(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_LINKLOCAL(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_SITELOCAL(&ptr.sin6->sin6_addr)) {
-					if (TRACE_BOOL(ANNOYING + 1)) {
-						TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
-					}
+					LOG_A("  DEBUG:fd_ep_add_merge  Address was ignored, not added.");
 					return 0;
 				}
 			}
@@ -107,9 +90,7 @@
 			break;
 
 		default:
-			if (TRACE_BOOL(ANNOYING + 1)) {
-				TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  Address family was unknown, not added.");
-			}
+			LOG_A("  DEBUG:fd_ep_add_merge  Address family was unknown, not added.");
 			return 0;
 	}
 
@@ -174,10 +155,6 @@
 	/* Merge the flags */
 	ep->flags |= flags;
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_add_merge  New list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 }
 
@@ -189,10 +166,6 @@
 	TRACE_ENTRY("%p %x", list, flags);
 	CHECK_PARAMS(list);
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter  Filter this list for flags %x:", flags);
-		fd_ep_dump( 4, list );
-	}
 	for (li = list->next; li != list; li = li->next) {
 		struct fd_endpoint * ep = (struct fd_endpoint *)li;
 		
@@ -203,10 +176,6 @@
 		}
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter  Resulting list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 }
 
@@ -218,10 +187,6 @@
 	TRACE_ENTRY("%p %d", list, af);
 	CHECK_PARAMS(list);
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_family  Filter this list for family %d:", af);
-		fd_ep_dump( 4, list );
-	}
 	for (li = list->next; li != list; li = li->next) {
 		struct fd_endpoint * ep = (struct fd_endpoint *)li;
 		
@@ -232,10 +197,6 @@
 		}
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_family  Resulting list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 }
 
@@ -252,12 +213,6 @@
 	li_out = list->next;
 	li_ex = exclude_list->next;
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_list  Filter this list ");
-		fd_ep_dump( 4, list );
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_list  Removing from list");
-		fd_ep_dump( 6, exclude_list );
-	}
 	/* Now browse both lists in parallel */
 	while ((li_out != list) && (li_ex != exclude_list)) {
 		int cmp;
@@ -303,10 +258,6 @@
 		free(li);
 	}
 	
-	if (TRACE_BOOL(ANNOYING + 1)) {
-		TRACE_DEBUG(ANNOYING, "  DEBUG:fd_ep_filter_list  Resulting list:");
-		fd_ep_dump( 4, list );
-	}
 	return 0;
 
 }
@@ -333,26 +284,44 @@
 	return 0;
 }
 
-void fd_ep_dump_one( char * prefix, struct fd_endpoint * ep )
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump_one, struct fd_endpoint * ep )
 {
-	char buf[1024];
+	size_t o = 0;
+	if (!offset)
+		offset=&o;
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{ep}(@%p): ", ep), return NULL);
 	
-	sSA_DUMP_NODE_SERV( buf, sizeof(buf), &ep->sa, NI_NUMERICHOST | NI_NUMERICSERV );
-	fd_log_debug("%s%s {%s%s%s%s}%s", prefix ?: "", buf,
+	if (!ep) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
+		return *buf;
+	}
+	
+	CHECK_MALLOC_DO( fd_sa_dump_node_serv( FD_DUMP_STD_PARAMS, &ep->sa, NI_NUMERICHOST | NI_NUMERICSERV ), return NULL);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {%s%s%s%s%s}",
 			(ep->flags & EP_FL_CONF) 	? "C" : "-",
 			(ep->flags & EP_FL_DISC) 	? "D" : "-",
 			(ep->flags & EP_FL_ADV) 	? "A" : "-",
 			(ep->flags & EP_FL_LL) 		? "L" : "-",
-			(ep->flags & EP_FL_PRIMARY) 	? "P" : "-");
+			(ep->flags & EP_FL_PRIMARY) 	? "P" : "-"), return NULL);
+	return *buf;
 }
 
-void fd_ep_dump( int indent, struct fd_list * eps )
+DECLARE_FD_DUMP_PROTOTYPE(fd_ep_dump, int indent, struct fd_list * eps  )
 {
 	struct fd_list * li;
-	for (li = eps->next; li != eps; li = li->next) {
-		struct fd_endpoint * ep = (struct fd_endpoint *)li;
-		fd_log_debug("%*s", indent, "");
-		fd_ep_dump_one( NULL, ep );
+	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);
+	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_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	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/events.c	Fri May 03 19:20:56 2013 +0800
@@ -105,12 +105,6 @@
 	#define case_str( _val )\
 		case _val : return #_val
 		case_str(FDEV_TERMINATE);
-		case_str(FDEV_DUMP_DICT);
-		case_str(FDEV_DUMP_EXT);
-		case_str(FDEV_DUMP_SERV);
-		case_str(FDEV_DUMP_QUEUES);
-		case_str(FDEV_DUMP_CONFIG);
-		case_str(FDEV_DUMP_PEERS);
 		case_str(FDEV_TRIGGER);
 		
 		default:
@@ -167,20 +161,22 @@
 	return 0;
 }
 
-void fd_event_trig_dump()
+DECLARE_FD_DUMP_PROTOTYPE(fd_event_trig_dump)
 {
 	struct fd_list * li;
-	if (!TRACE_BOOL(FULL))
-		return;
+	size_t o=0;
+	if (!offset)
+		offset=&o;
 	
 	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;
-		fd_log_debug("  Trigger %d, module '%s': %p", t->trig_value, t->trig_module, t->cb);
+		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_POSIX_DO( pthread_rwlock_unlock(&trig_rwl),  );
+	return *buf;
 }
 
 static void *call_cb_detached(void * arg)
--- a/libfdcore/extensions.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/extensions.c	Fri May 03 19:20:56 2013 +0800
@@ -77,17 +77,19 @@
 }
 
 /* Dump the list */
-void fd_ext_dump(void)
+DECLARE_FD_DUMP_PROTOTYPE(fd_ext_dump)
 {
 	struct fd_list * li;
-	
-	fd_log_debug("Dumping extensions list :");
+	size_t o=0;
+	if (!offset)
+		offset = &o;
 	
 	for (li = ext_list.next; li != &ext_list; li = li->next)
 	{
 		struct fd_ext_info * ext = (struct fd_ext_info *)li;
-		fd_log_debug(" - '%s'[%s] is %sloaded", ext->filename, ext->conffile?:"no conf", ext->handler ? "" : "not ");
+		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);
 	}
+	return *buf;
 }
 
 /* Check the dependencies. The object must have been dlopened already. */
--- a/libfdcore/fdcore-internal.h	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/fdcore-internal.h	Fri May 03 19:20:56 2013 +0800
@@ -85,7 +85,6 @@
 /* Configuration */
 int fd_conf_init();
 int fd_conf_deinit();
-void fd_conf_dump();
 int fd_conf_parse();
 int fddparse(struct fd_config * conf); /* yacc generated */
 int fd_conf_stream_to_gnutls_datum(FILE * pemfile, gnutls_datum_t *out);
@@ -94,7 +93,6 @@
 /* Extensions */
 int fd_ext_add( char * filename, char * conffile );
 int fd_ext_load();
-void fd_ext_dump(void);
 int fd_ext_term(void);
 
 /* Messages */
@@ -217,11 +215,8 @@
 
 /* Events codespace for struct fd_peer->p_events */
 enum {
-	/* Dump all info about this peer in the debug log */
-	 FDEVP_DUMP_ALL = 1500
-	
 	/* request to terminate this peer : disconnect, requeue all messages */
-	,FDEVP_TERMINATE
+	FDEVP_TERMINATE = 1500
 	
 	/* A connection object has received a message. (data contains the buffer + struct timespec piggytailed -- unaligned) */
 	,FDEVP_CNX_MSG_RECV
@@ -249,13 +244,12 @@
 	
 };
 #define CHECK_PEVENT( _e ) \
-	(((int)(_e) >= FDEVP_DUMP_ALL) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
+	(((int)(_e) >= FDEVP_TERMINATE) && ((int)(_e) <= FDEVP_PSM_TIMEOUT))
 /* The following macro is actually called in p_psm.c -- another solution would be to declare it static inline */
 #define DECLARE_PEV_STR()				\
 const char * fd_pev_str(int event)			\
 {							\
 	switch (event) {				\
-		case_str(FDEVP_DUMP_ALL);		\
 		case_str(FDEVP_TERMINATE);		\
 		case_str(FDEVP_CNX_MSG_RECV);		\
 		case_str(FDEVP_CNX_ERROR);		\
@@ -280,8 +274,6 @@
 
 /* Functions */
 int  fd_peer_fini();
-void fd_peer_dump_list(int details);
-void fd_peer_dump(struct fd_peer * peer, int details);
 int  fd_peer_alloc(struct fd_peer ** ptr);
 int  fd_peer_free(struct fd_peer ** ptr);
 int fd_peer_handle_newCER( struct msg ** cer, struct cnxctx ** cnx );
@@ -338,7 +330,6 @@
 
 
 /* Server sockets */
-void fd_servers_dump();
 int  fd_servers_start();
 int  fd_servers_stop();
 
--- a/libfdcore/p_psm.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/p_psm.c	Fri May 03 19:20:56 2013 +0800
@@ -453,12 +453,6 @@
 		goto psm_loop;
 	}
 
-	/* Handle the (easy) debug event now */
-	if (event == FDEVP_DUMP_ALL) {
-		fd_peer_dump(peer, ANNOYING);
-		goto psm_loop;
-	}
-
 	/* Requests to terminate the peer object */
 	if (event == FDEVP_TERMINATE) {
 		switch (cur_state) {
@@ -711,11 +705,12 @@
 		/* Get the new ones */
 		CHECK_FCT_DO( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
 		
-		/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints)*/
-		
-		if (TRACE_BOOL(ANNOYING)) {
-			TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" );
-			fd_ep_dump(6, &peer->p_hdr.info.pi_endpoints);
+		/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints) */
+		{
+			char * buf = NULL;
+			size_t len = 0;
+			LOG_D("New remote endpoint(s): %s",  fd_ep_dump(&buf, &len, NULL, 6, &peer->p_hdr.info.pi_endpoints) ?: "error");
+			free(buf);
 		}
 		
 		/* Done */
--- a/libfdcore/peers.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/peers.c	Fri May 03 19:20:56 2013 +0800
@@ -409,53 +409,63 @@
 }
 
 /* Dump info of one peer */
-void fd_peer_dump(struct fd_peer * peer, int details)
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump, struct peer_hdr * p, int details)
 {
-	char buf[1024];
-	if (peer->p_eyec != EYEC_PEER) {
-		fd_log_debug("  Invalid peer @ %p !", peer);
-		return;
-	}
-
-	snprintf(buf, sizeof(buf), ">  %s\t%s\t[%ldsr,%ldpa]", STATE_STR(fd_peer_getstate(peer)), peer->p_hdr.info.pi_diamid, peer->p_sr.cnt, peer->p_reqin_count);
-	if (details > INFO) {
-		snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\t(rlm:%s)", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>");
-		if (peer->p_hdr.info.runtime.pir_prodname)
-			snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "\t['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev);
+	size_t o=0;
+	if (!offset)
+		offset = &o;
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{peer}(@%p): ", p), return NULL);
+	
+	if (!CHECK_PEER(p)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL"), return NULL);
+	} else {
+		struct fd_peer * peer = (struct fd_peer *)p;
+		
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s [%s, cnt:%ldsr,%ldpa]", peer->p_hdr.info.pi_diamid, STATE_STR(fd_peer_getstate(peer)), peer->p_sr.cnt, peer->p_reqin_count), return NULL);
+		if (details > 0) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " rlm:%s", peer->p_hdr.info.runtime.pir_realm ?: "<unknown>"), return NULL);
+			if (peer->p_hdr.info.runtime.pir_prodname) {
+				CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " ['%s' %u]", peer->p_hdr.info.runtime.pir_prodname, peer->p_hdr.info.runtime.pir_firmrev), return NULL);
+			}
+		}
+		if (details > 1) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [from:%s] flags:%s%s%s%s%s%s%s lft:%ds", 
+				peer->p_dbgorig ?: "unset",
+				peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "-" :
+					(peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "4" : "6"),
+				peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "-" :
+					(peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "T" : "S"),
+				peer->p_hdr.info.config.pic_flags.alg ? "P" : "-",
+				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "N" :"-",
+				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "O" :"-",
+				peer->p_hdr.info.config.pic_flags.exp ? "E" : "-",
+				peer->p_hdr.info.config.pic_flags.persist ? "P" : "-",
+				peer->p_hdr.info.config.pic_lft), return NULL);
+		}
+	
 	}
-	fd_log_debug("%s", buf);
-	if (details > FULL) {
-		/* Dump all info */
-		fd_log_debug("\tEntry origin : %s", peer->p_dbgorig?: "not set");
-		fd_log_debug("\tConfig flags : %s%s%s - %s%s - %s%s", 
-				peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_DEFAULT ? "." :
-					(peer->p_hdr.info.config.pic_flags.pro3 == PI_P3_IP ? "IP" : "IPv6"),
-				peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_DEFAULT ? "." :
-					(peer->p_hdr.info.config.pic_flags.pro4 == PI_P4_TCP ? "TCP" : "SCTP"),
-				peer->p_hdr.info.config.pic_flags.alg ? "PrefTCP" : ".",
-				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_NONE ? "NoTLSok" :".",
-				peer->p_hdr.info.config.pic_flags.sec & PI_SEC_TLS_OLD ? "OldTLS" :".",
-				peer->p_hdr.info.config.pic_flags.exp ? "Expire" : ".",
-				peer->p_hdr.info.config.pic_flags.persist ? "Persist" : "."
-				);
-		fd_log_debug("\tLifetime : %d sec", peer->p_hdr.info.config.pic_lft);
-	}
+	
+	return *buf;
 }
 
 /* Dump the list of peers */
-void fd_peer_dump_list(int details)
+DECLARE_FD_DUMP_PROTOTYPE(fd_peer_dump_list, int details)
 {
 	struct fd_list * li;
+	size_t o=0;
+	if (!offset)
+		offset = &o;
 	
-	fd_log_debug("Dumping list of peers :");
 	CHECK_FCT_DO( pthread_rwlock_rdlock(&fd_g_peers_rw), /* continue */ );
 	
 	for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
-		struct fd_peer * np = (struct fd_peer *)li->o;
-		fd_peer_dump(np, details);
+		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);
 	}
 	
 	CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
+	return *buf;
 }
 
 static struct dict_object *avp_oh_model = NULL;
--- a/libfdcore/server.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/server.c	Fri May 03 19:20:56 2013 +0800
@@ -93,33 +93,35 @@
 
 
 /* Dump all servers information */
-void fd_servers_dump()
+DECLARE_FD_DUMP_PROTOTYPE(fd_servers_dump)
 {
 	struct fd_list * li, *cli;
+	size_t o=0;
+	if (!offset)
+		offset = &o;
 	
-	fd_log_debug("Dumping servers list :");
 	for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
 		struct server * s = (struct server *)li;
 		enum s_state st = get_status(s);
-		fd_log_debug("  Serv %p '%s': %s, %s, %s", 
-				s, fd_cnx_getid(s->conn), 
+		
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{server}(@%p)'%s': %s, %s, %s\n", s, fd_cnx_getid(s->conn), 
 				IPPROTO_NAME( s->proto ),
 				s->secur ? "Secur" : "NotSecur",
 				(st == NOT_CREATED) ? "Thread not created" :
 				((st == RUNNING) ? "Thread running" :
 				((st == TERMINATED) ? "Thread terminated" :
-							  "Thread status unknown")));
+							  "Thread status unknown"))), return NULL);
 		/* Dump the client list of this server */
 		CHECK_POSIX_DO( pthread_mutex_lock(&s->clients_mtx), );
 		for (cli = s->clients.next; cli != &s->clients; cli = cli->next) {
 			struct client * c = (struct client *)cli;
 			char bufts[128];
-			fd_log_debug("     Connected: '%s' (timeout: %s)",
-					fd_cnx_getid(c->conn),
-					fd_log_time(&c->ts, bufts, sizeof(bufts)));
+			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_POSIX_DO( pthread_mutex_unlock(&s->clients_mtx), );
 	}
+	
+	return *buf;
 }
 
 
@@ -392,9 +394,14 @@
 			return EINVAL;
 		}
 	}
-	if (TRACE_BOOL(FULL)){
-		fd_log_debug("  Local server address(es) :");
-		fd_ep_dump( 5, &fd_g_config->cnf_endpoints );
+	
+	{
+		char * buf = NULL;
+		size_t len = 0, offset = 0;
+		CHECK_MALLOC_DO( fd_dump_extend( &buf, &len, &offset , "Local server address(es): "), );
+		CHECK_MALLOC_DO( fd_ep_dump(  &buf, &len, &offset, 5, &fd_g_config->cnf_endpoints ), );
+		LOG_N("%s", buf ?: "Error dumping addresses");
+		free(buf);
 	}
 	return 0;
 }
--- a/libfdcore/tcp.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdcore/tcp.c	Fri May 03 19:20:56 2013 +0800
@@ -123,6 +123,7 @@
 {
 	int ret = 0;
 	int s;
+	char * buf = NULL; size_t len = 0;
 	
 	TRACE_ENTRY("%p %p %d", sock, sa, salen);
 	CHECK_PARAMS( sock && (*sock <= 0) && sa && salen );
@@ -136,7 +137,8 @@
 	/* Cleanup if we are cancelled */
 	pthread_cleanup_push(fd_cleanup_socket, &s);
 	
-	TRACE_sSA(FD_LOG_DEBUG, FULL, "Attempting TCP connection with peer: ", sa, NI_NUMERICHOST | NI_NUMERICSERV, "..." );
+	LOG_D( "Attempting TCP connection to %s...", fd_sa_dump_node(&buf, &len, NULL, sa, NI_NUMERICHOST | NI_NUMERICSERV)?:"<error>" );
+	free(buf);
 	
 	/* Try connecting to the remote address */
 	ret = connect(s, sa, salen);
--- a/libfdproto/dictionary.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/dictionary.c	Fri May 03 19:20:56 2013 +0800
@@ -147,13 +147,13 @@
 };
 
 /* Forward declarations of dump functions */
-static void dump_vendor_data 	  ( void * data );
-static void dump_application_data ( void * data );
-static void dump_type_data 	  ( void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data );
   /* the dump function for enum has a different prototype since it need the datatype */
-static void dump_avp_data 	  ( void * data );
-static void dump_command_data 	  ( void * data );
-static void dump_rule_data 	  ( void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data );
 
 /* Forward declarations of search functions */
 static int search_vendor 	( struct dictionary * dict, int criteria, const void * what, struct dict_object **result );
@@ -172,7 +172,7 @@
 	int			parent;		/* 0: never; 1: may; 2: must */
 	enum dict_object_type	parenttype;	/* The type of the parent, when relevant */
 	int			eyecatcher;	/* A kind of signature for this object */
-	void 		      (*dump_data)(void * data );	/* The function to dump the data section */
+	DECLARE_FD_DUMP_PROTOTYPE( (*dump_data), void * data );	/* The function to dump the data section */
 	int 		      (*search_fct)(struct dictionary * dict, int criteria, const void * what, struct dict_object **result );;	/* The function to search an object of this type */
 	int			haslist[NB_LISTS_PER_OBJ];	/* Tell if this list is used */
 } dict_obj_info[] = { { 0, "(error)", 0, 0, 0, 0, NULL, NULL, {0, 0, 0} }
@@ -1149,29 +1149,29 @@
 /*******************************************************************************************************/
 /*******************************************************************************************************/
 /* The following functions are used to debug the module, and allow to print out the content of the dictionary */
-static void dump_vendor_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_vendor_data, void * data )
 {
 	struct dict_vendor_data * vendor = (struct dict_vendor_data *)data;
 	
-	fd_log_debug("data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-6u \"%s\"", vendor->vendor_id, vendor->vendor_name);
 }
-static void dump_application_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_application_data, void * data )
 {
 	struct dict_application_data * appli = (struct dict_application_data *) data;
-	fd_log_debug("data: %-6u \"%s\"", appli->application_id, appli->application_name);
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-6u \"%s\"", appli->application_id, appli->application_name);
 }
-static void dump_type_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_type_data, void * data )
 {
 	struct dict_type_data * type = ( struct dict_type_data * ) data;
 	
-	fd_log_debug("data: %-12s \"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: %-12s \"%s\"", 
 			type_base_name[type->type_base], 
 			type->type_name);
 }
-static void dump_enumval_data ( struct dict_enumval_data * enumval, enum dict_avp_basetype type )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_enumval_data, struct dict_enumval_data * enumval, enum dict_avp_basetype type )
 {
 	const int LEN_MAX = 20;
-	fd_log_debug("data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name);
+	CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "data: (%-12s) \"%s\" -> ", type_base_name[type], enumval->enum_name), return NULL);
 	switch (type) {
 		case AVP_TYPE_OCTETSTRING:
 			{
@@ -1179,60 +1179,61 @@
 				if (enumval->enum_value.os.len < LEN_MAX)
 					n = enumval->enum_value.os.len;
 				for (i=0; i < n; i++)
-					fd_log_debug("0x%2hhX/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i]));
+					CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "0x%2hhX/'%c' ", enumval->enum_value.os.data[i], ASCII(enumval->enum_value.os.data[i])), return NULL);
 				if (n == LEN_MAX)
-					fd_log_debug("...");
+					CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "..."), return NULL);
 			}
 			break;
 		
 		case AVP_TYPE_INTEGER32:
-			fd_log_debug("%i", enumval->enum_value.i32);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%i", enumval->enum_value.i32), return NULL);
 			break;
 
 		case AVP_TYPE_INTEGER64:
-			fd_log_debug("%"PRId64, enumval->enum_value.i64);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%"PRId64, enumval->enum_value.i64), return NULL);
 			break;
 
 		case AVP_TYPE_UNSIGNED32:
-			fd_log_debug("%u", enumval->enum_value.u32);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%u", enumval->enum_value.u32), return NULL);
 			break;
 
 		case AVP_TYPE_UNSIGNED64:
-			fd_log_debug("%"PRIu64, enumval->enum_value.u64);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%"PRIu64, enumval->enum_value.u64), return NULL);
 			break;
 
 		case AVP_TYPE_FLOAT32:
-			fd_log_debug("%f", enumval->enum_value.f32);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%f", enumval->enum_value.f32), return NULL);
 			break;
 
 		case AVP_TYPE_FLOAT64:
-			fd_log_debug("%g", enumval->enum_value.f64);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "%g", enumval->enum_value.f64), return NULL);
 			break;
 		
 		default:
-			fd_log_debug("??? (ERROR unknown type %d)", type);
+			CHECK_MALLOC_DO(fd_dump_extend( FD_DUMP_STD_PARAMS, "??? (ERROR unknown type %d)", type), return NULL);
 	}
+	return *buf;
 }
-static void dump_avp_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_data, void * data )
 {
 	struct dict_avp_data * avp = (struct dict_avp_data * ) data;
-	fd_log_debug("data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: v/m:" DUMP_AVPFL_str "/" DUMP_AVPFL_str ", %12s, %-6u \"%s\"", 
 			DUMP_AVPFL_val(avp->avp_flag_val), 
 			DUMP_AVPFL_val(avp->avp_flag_mask), 
 			type_base_name[avp->avp_basetype], 
 			avp->avp_code, 
 			avp->avp_name );
 }
-static void dump_command_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_command_data, void * data )
 {
 	struct dict_cmd_data * cmd = (struct dict_cmd_data *) data;
-	fd_log_debug("data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: v/m:" DUMP_CMDFL_str "/" DUMP_CMDFL_str ", %-6u \"%s\"", 
 			DUMP_CMDFL_val(cmd->cmd_flag_val), DUMP_CMDFL_val(cmd->cmd_flag_mask), cmd->cmd_code, cmd->cmd_name);
 }
-static void dump_rule_data ( void * data )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_rule_data, void * data )
 {
 	struct dict_rule_data * rule = (struct dict_rule_data * )data;
-	fd_log_debug("data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"", 
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "data: pos:%d ord:%d m/M:%2d/%2d avp:\"%s\"",
 			rule->rule_position, 
 			rule->rule_order, 
 			rule->rule_min, 
@@ -1240,158 +1241,166 @@
 			rule->rule_avp->data.avp.avp_name);
 }
 
-static void dump_object ( struct dict_object * obj, int parents, int depth, int indent );
+static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent );
 
-static void dump_list ( struct fd_list * sentinel, int parents, int depth, int indent )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_list, struct fd_list * sentinel, int parents, int depth, int indent )
 {
 	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;
-		dump_object( _O(li->o), parents, depth, indent );
+		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, _O(li->o), parents, depth, indent ), return NULL);
 	}
 }
 
-static void dump_object ( struct dict_object * obj, int parents, int depth, int indent )
+static DECLARE_FD_DUMP_PROTOTYPE(dump_object, struct dict_object * obj, int parents, int depth, int indent )
 {
-	if (obj == NULL)
-		return;
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%*s{dictobj}(@%p): ", indent, "", obj), return NULL);
 	
-	if (parents)
-		dump_object (obj->parent, parents-1, 0, indent + 1 );
+	if (!verify_object(obj)) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
+		return *buf;
+	}
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s p:%p ", 
+								_OBINFO(obj).name, 
+								obj->parent), return NULL);
 	
-	fd_log_debug("%*s@%p: %s%s (p:%-9p) ", 
-			indent,
-			"",
-			obj, 
-			verify_object(obj) ? "" : "INVALID ", 
-			_OBINFO(obj).name, 
-			obj->parent);
+	if (obj->type == DICT_ENUMVAL) {
+		CHECK_MALLOC_DO( dump_enumval_data ( FD_DUMP_STD_PARAMS, &obj->data.enumval, obj->parent->data.type.type_base ), return NULL);
+	} else {
+		CHECK_MALLOC_DO( _OBINFO(obj).dump_data(FD_DUMP_STD_PARAMS, &obj->data), return NULL);
+	}
 	
-	if (obj->type == DICT_ENUMVAL)
-		dump_enumval_data ( &obj->data.enumval, obj->parent->data.type.type_base );
-	else
-		_OBINFO(obj).dump_data(&obj->data);
+	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( dump_object (FD_DUMP_STD_PARAMS, obj->parent, parents-1, 0, 0 ), return NULL);
+	}
 	
 	if (depth) {
 		int i;
 		for (i=0; i<NB_LISTS_PER_OBJ; i++) {
 			if ((obj->list[i].o == NULL) && (obj->list[i].next != &obj->list[i])) {
-				fd_log_debug("%*s>%p: list[%d]:", indent, "", obj, i);
-				dump_list(&obj->list[i], parents, depth - 1, indent + 2);
+				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);
 			}
 		}
 	}
+	
+	return *buf;
 }
 
-void fd_dict_dump_object(struct dict_object * obj)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_object, struct dict_object * obj)
 {
-	fd_log_debug("Dictionary object %p dump:", obj);
-	dump_object( obj, 1, 2, 2 );
+	size_t o = 0;
+
+	if (!offset)
+		offset = &o;
+	
+	CHECK_MALLOC_DO( dump_object(FD_DUMP_STD_PARAMS, obj, 1, 2, 0), return NULL);
+	
+	return *buf;
 }
 
-void fd_dict_dump(struct dictionary * dict)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump, struct dictionary * dict)
 {
 	int i;
 	struct fd_list * li;
+	size_t o = 0;
+
+	if (!offset)
+		offset = &o;
+		
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{dictionary}(@%p): ", dict), return NULL);
 	
-	CHECK_PARAMS_DO(dict && (dict->dict_eyec == DICT_EYECATCHER), return);
+	if ((dict == NULL) || (dict->dict_eyec != DICT_EYECATCHER)) {
+		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL\n");
+	}
 	
 	CHECK_POSIX_DO(  pthread_rwlock_rdlock( &dict->dict_lock ), /* ignore */  );
 	
-	fd_log_debug("######################################################");
-	fd_log_debug("###### Dumping vendors, AVPs and related rules #######");
-	
-	dump_object( &dict->dict_vendors, 0, 3, 0 );
+	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( 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)
-		dump_object( li->o, 0, 3, 0 );
+		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 3, 3 ), goto error);
 	
-	fd_log_debug("######          Dumping applications           #######");
-
-	dump_object( &dict->dict_applications, 0, 1, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {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)
-		dump_object( li->o, 0, 1, 0 );
+		CHECK_MALLOC_DO( dump_object (FD_DUMP_STD_PARAMS, li->o, 0, 1, 3 ), goto error);
 	
-	fd_log_debug("######             Dumping types               #######");
-
-	dump_list( &dict->dict_types, 0, 2, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > types}\n", dict), goto error);
+	CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_types, 0, 2, 3 ), goto error);
 	
-	fd_log_debug("######      Dumping commands per name          #######");
-
-	dump_list( &dict->dict_cmd_name, 0, 2, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > commands}\n", dict), goto error);
+	CHECK_MALLOC_DO( dump_list(FD_DUMP_STD_PARAMS, &dict->dict_cmd_code, 0, 0, 3 ), goto error);
 	
-	fd_log_debug("######   Dumping commands per code and flags   #######");
-
-	dump_list( &dict->dict_cmd_code, 0, 0, 0 );
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " {dict:%p > statistics}\n", 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);
 	
-	fd_log_debug("######             Statistics                  #######");
-
-	for (i=1; i<=DICT_TYPE_MAX; i++)
-		fd_log_debug(" %5d objects of type %s", dict->dict_count[i], dict_obj_info[i].name);
-	
-	fd_log_debug("######################################################");
-	
+	CHECK_POSIX_DO(  pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */  );
+	return *buf;
+error:	
 	/* Free the rwlock */
 	CHECK_POSIX_DO(  pthread_rwlock_unlock( &dict->dict_lock ), /* ignore */  );
+	return NULL;
 }
 
 /**************************** Dump AVP values ********************************/
 
 /* Default dump functions */
-static int dump_val_os(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_os, union avp_value * value)
 {
 	int i;
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "<") );
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<"), return NULL);
 	for (i = 0; i < value->os.len; i++) {
 		if (i == 1024) { /* Dump only up to 1024 bytes of the buffer */
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "[...] (len=%zd)", value->os.len) );
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "[...] (len=%zd)", value->os.len), return NULL);
 			break;
 		}
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s%02.2X", (i==0 ? "" : " "), value->os.data[i]) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s%02hhX", (i==0 ? "" : " "), value->os.data[i]), return NULL);
 	}
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, ">") );
-	return 0;
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ">"), return NULL);
+	return *buf;
 }
 
-static int dump_val_i32(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_i32, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%i (0x%x)", value->i32, value->i32) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%i (0x%x)", value->i32, value->i32);
 }
 
-static int dump_val_i64(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_i64, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%lli (0x%llx)", value->i64, value->i64) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%" PRId64 " (0x%" PRIx64 ")", value->i64, value->i64);
 }
 
-static int dump_val_u32(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_u32, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%u (0x%x)", value->u32, value->u32) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%u (0x%x)", value->u32, value->u32);
 }
 
-static int dump_val_u64(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_u64, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%llu (0x%llx)", value->u64, value->u64) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%" PRIu64 " (0x%" PRIx64 ")", value->u64, value->u64);
 }
 
-static int dump_val_f32(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_f32, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%f", value->f32) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%f", value->f32);
 }
 
-static int dump_val_f64(union avp_value * value, char **outstr, size_t *offset, size_t *outlen)
+static DECLARE_FD_DUMP_PROTOTYPE(dump_val_f64, union avp_value * value)
 {
-	CHECK_FCT( dump_add_str(outstr, offset, outlen, "%g", value->f64) );
-	return 0;
+	return fd_dump_extend( FD_DUMP_STD_PARAMS, "%g", value->f64);
 }
 
 /* Get the dump function for basic dict_avp_basetype */
-static int (*get_default_dump_val_cb(enum dict_avp_basetype datatype))(union avp_value *, char **, size_t *, size_t *)
+static DECLARE_FD_DUMP_PROTOTYPE((*get_default_dump_val_cb(enum dict_avp_basetype datatype)), union avp_value *)
 {
 	switch (datatype) {
 		case AVP_TYPE_OCTETSTRING:
@@ -1425,63 +1434,63 @@
 #define INOBJHDR 	"%*s   "
 #define INOBJHDRVAL 	indent<0 ? 1 : indent, indent<0 ? "-" : "|"
 
+typedef DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb_t), union avp_value *);
+
 /* Formatter for the AVP value dump line */
-static int dump_avp_val(union avp_value *avp_value, 
-			int (*def_dump_val_cb)(union avp_value *, char **, size_t *, size_t *), 
-			char * (*dump_val_cb)(union avp_value *), 
+static DECLARE_FD_DUMP_PROTOTYPE(dump_avp_val, union avp_value *avp_value, 
+			dump_val_cb_t def_dump_val_cb, 
+			dump_val_cb_t dump_val_cb, 
 			enum dict_avp_basetype datatype, 
 			char * type_name, 
 			char * const_name, 
 			int indent, 
-			char **outstr, 
-			size_t *offset, 
-			size_t *outlen,
 		        int header)
 {
 	if (header) {
 		/* Header for all AVP values dumps: */
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, INOBJHDR "value ", INOBJHDRVAL) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, INOBJHDR "value ", INOBJHDRVAL), return NULL);
 	
 		/* If the type is provided, write it */
 		if (type_name) {
-			CHECK_FCT( dump_add_str(outstr, offset, outlen, "t: '%s' ", type_name) );
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "t: '%s' ", type_name), return NULL);
 		}
 	
 		/* Always give the base datatype anyway */
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "(%s) ", type_base_name[datatype]) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(%s) ", type_base_name[datatype]), return NULL);
 
 		/* Now, the value */
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "v: ") );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "v: "), return NULL);
 	}
 	if (const_name) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "'%s' (", const_name) );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s' (", const_name), return NULL);
 	}
 	if (dump_val_cb) {
-		char * str;
-		CHECK_MALLOC_DO( str = (*dump_val_cb)(avp_value), dump_add_str(outstr, offset, outlen, "(dump failed)") );
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, "%s", str) );
-		free(str);
+		CHECK_MALLOC_DO( (*dump_val_cb)( FD_DUMP_STD_PARAMS, avp_value), fd_dump_extend( FD_DUMP_STD_PARAMS, "(dump failed)"));
 	} else {
-		CHECK_FCT( (*def_dump_val_cb)(avp_value, outstr, offset, outlen) );
+		CHECK_MALLOC_DO( (*def_dump_val_cb)( FD_DUMP_STD_PARAMS, avp_value), return NULL);
 	}
 	if (const_name) {
-		CHECK_FCT( dump_add_str(outstr, offset, outlen, ")") );
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, ")"), return NULL);
 	}
 	
 	/* Done! */
-	return 0;
+	return *buf;
 }
 
 /* Dump the value of an AVP of known type into the returned str */
-int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen, int header)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_avp_value, union avp_value *avp_value, struct dict_object * model, int indent, int header)
 {
-	char * (*dump_val_cb)(union avp_value *avp_value) = NULL;
+	DECLARE_FD_DUMP_PROTOTYPE((*dump_val_cb), union avp_value *avp_value) = NULL;
 	struct dict_object * type = NULL;
 	char * type_name = NULL;
 	char * const_name = NULL;
+	size_t o = 0;
+	
+	if (!offset)
+		offset = &o;
 	
 	/* Check the parameters are correct */
-	CHECK_PARAMS( avp_value && verify_object(model) && (model->type == DICT_AVP) );
+	CHECK_PARAMS_DO( avp_value && verify_object(model) && (model->type == DICT_AVP), return NULL );
 	
 	/* Get the type definition of this AVP */
 	type = model->parent;
@@ -1501,14 +1510,14 @@
 		memcpy(&request.search.enum_value, avp_value, sizeof(union avp_value));
 		/* bypass checks */
 		if ((search_enumval( type->dico, ENUMVAL_BY_STRUCT, &request, &enumval ) == 0) && (enumval)) {
-			/* We found a cosntant, get its name */
+			/* We found a constant, get its name */
 			const_name = enumval->data.enumval.enum_name;
 		}
 	}
 	
 	/* And finally, dump the value */
-	CHECK_FCT( dump_avp_val(avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, outstr, offset, outlen, header) );
-	return 0;
+	CHECK_MALLOC_DO( dump_avp_val(FD_DUMP_STD_PARAMS, avp_value, get_default_dump_val_cb(model->data.avp.avp_basetype), dump_val_cb, model->data.avp.avp_basetype, type_name, const_name, indent, header), return NULL );
+	return *buf;
 }
 
 /*******************************************************************************************************/
@@ -1573,51 +1582,51 @@
 	/* Check the "parent" parameter */
 	switch (dict_obj_info[type].parent) {
 		case 0:	/* parent is forbidden */
-			CHECK_PARAMS( parent == NULL );
+			CHECK_PARAMS_DO( parent == NULL, goto error_param );
 		
 		case 1:	/* parent is optional */
 			if (parent == NULL)
 				break;
 		
 		case 2: /* parent is mandatory */
-			CHECK_PARAMS(  verify_object(parent)  );
+			CHECK_PARAMS_DO(  verify_object(parent), goto error_param  );
 			
 			if (type == DICT_RULE ) { /* Special case : grouped AVP or Command parents are allowed */
-				CHECK_PARAMS( (parent->type == DICT_COMMAND ) 
-						|| ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ) );
+				CHECK_PARAMS_DO( (parent->type == DICT_COMMAND ) 
+						|| ( (parent->type == DICT_AVP) && (parent->data.avp.avp_basetype == AVP_TYPE_GROUPED ) ), goto error_param );
 			} else {
-				CHECK_PARAMS( parent->type == dict_obj_info[type].parenttype );
+				CHECK_PARAMS_DO( parent->type == dict_obj_info[type].parenttype, goto error_param );
 			}
 	}
 	
 	/* For AVP object, we must also check that the "vendor" referenced exists */
 	if (type == DICT_AVP) {
 		CHECK_FCT_DO(  fd_dict_search( dict, DICT_VENDOR, VENDOR_BY_ID, &(((struct dict_avp_data *)data)->avp_vendor), (void*)&vendor, ENOENT ),
-			{ TRACE_DEBUG(INFO, "Unable to find vendor '%d' referenced in the AVP data", ((struct dict_avp_data *)data)->avp_vendor); return EINVAL; }  );
+			{ TRACE_DEBUG(INFO, "Unable to find vendor '%d' referenced in the AVP data", ((struct dict_avp_data *)data)->avp_vendor); goto error_param; }  );
 		
 		/* Also check if a parent is provided, that the type are the same */
 		if (parent) {
-			CHECK_PARAMS(  parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype  );
+			CHECK_PARAMS_DO(  parent->data.type.type_base == ((struct dict_avp_data *)data)->avp_basetype, goto error_param  );
 		}
 	}
 	
 	/* For RULE object, we must also check that the "avp" referenced exists */
 	if (type == DICT_RULE) {
-		CHECK_PARAMS(  verify_object(((struct dict_rule_data *)data)->rule_avp)  );
-		CHECK_PARAMS(  ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP  );
+		CHECK_PARAMS_DO(  verify_object(((struct dict_rule_data *)data)->rule_avp), goto error_param  );
+		CHECK_PARAMS_DO(  ((struct dict_rule_data *)data)->rule_avp->type == DICT_AVP, goto error_param  );
 	}
 	
 	/* For COMMAND object, check that the 'R' flag is fixed */
 	if (type == DICT_COMMAND) {
-		CHECK_PARAMS( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST   );
+		CHECK_PARAMS_DO( ((struct dict_cmd_data *)data)->cmd_flag_mask & CMD_FLAG_REQUEST, goto error_param   );
 	}
 	
 	/* We have to check that the new values are not equal to the sentinels */
 	if (type == DICT_VENDOR) {
-		CHECK_PARAMS( ((struct dict_vendor_data *)data)->vendor_id != 0   );
+		CHECK_PARAMS_DO( ((struct dict_vendor_data *)data)->vendor_id != 0, goto error_param   );
 	}
 	if (type == DICT_APPLICATION) {
-		CHECK_PARAMS( ((struct dict_application_data *)data)->application_id != 0   );
+		CHECK_PARAMS_DO( ((struct dict_application_data *)data)->application_id != 0, goto error_param   );
 	}
 	
 	/* Parameters are valid, create the new object */
@@ -1717,6 +1726,10 @@
 	
 	return 0;
 	
+error_param:
+	ret = EINVAL;
+	goto all_errors;
+
 error_unlock:
 	CHECK_POSIX_DO(  pthread_rwlock_unlock(&dict->dict_lock),  /* continue */  );
 	if (ret == EEXIST) {
@@ -1727,7 +1740,7 @@
 				/* if we are here, it means the two vendors id are identical */
 				if (fd_os_cmp(locref->data.vendor.vendor_name, locref->datastr_len, 
 						new->data.vendor.vendor_name, new->datastr_len)) {
-					TRACE_DEBUG(FULL, "Conflicting vendor name");
+					TRACE_DEBUG(INFO, "Conflicting vendor name: %s", new->data.vendor.vendor_name);
 					break;
 				}
 				/* Otherwise (same name), we consider the function succeeded, since the (same) object is in the dictionary */
@@ -1865,23 +1878,26 @@
 				ret = 0;
 				break;
 		}
-		if (ret) {
-			TRACE_DEBUG(INFO, "An existing object with different non-key data was found: EEXIST");
-			if (TRACE_BOOL(INFO)) {
-				fd_log_debug("New object to insert:");
-				dump_object(new, 0, 0, 3);
-				fd_log_debug("Object already in dictionary:");			
-				dump_object(locref, 0, 0 , 3);
-			}
-		} else {
+		if (!ret) {
 			TRACE_DEBUG(FULL, "An existing object with the same data was found, ignoring the error...");
 		}
 		if (ref)
 			*ref = locref;
-	} else {
-		CHECK_FCT_DO( ret, ); /* log the error */ 
 	}
-
+all_errors:
+	if (ret != 0) {
+		char * buf = NULL;
+		size_t len = 0;
+		
+		CHECK_MALLOC( dict_obj_info[CHECK_TYPE(type) ? type : 0].dump_data(&buf, &len, NULL, data) );
+		TRACE_DEBUG(INFO, "An error occurred while adding the following data in the dictionary: %s", buf);
+		
+		if (ret == EEXIST) {
+			CHECK_MALLOC( dump_object(&buf, &len, NULL, locref, 0, 0, 0) );
+			TRACE_DEBUG(INFO, "Conflicting entry in the dictionary: %s", buf);
+		}
+		free(buf);
+	}
 error_free:
 	free(new);
 	return ret;
--- a/libfdproto/dictionary_functions.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/dictionary_functions.c	Fri May 03 19:20:56 2013 +0800
@@ -152,10 +152,8 @@
 }
 
 /* Dump the content of an Address AVP */
-char * fd_dictfct_Address_dump(union avp_value * avp_value)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Address_dump, union avp_value * avp_value)
 {
-	char * ret;
-	#define STR_LEN	1024
 	union {
 		sSA	sa;
 		sSS	ss;
@@ -163,15 +161,17 @@
 		sSA6	sin6;
 	} s;
 	uint16_t fam;
+	size_t o = 0;
+	
+	if (!offset)
+		offset = &o;
 	
 	memset(&s, 0, sizeof(s));
 	
-	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
-	
 	/* The first two octets represent the address family, http://www.iana.org/assignments/address-family-numbers/ */
 	if (avp_value->os.len < 2) {
-		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
-		return ret;
+		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
+		return *buf;
 	}
 	
 	/* Following octets are the address in network byte order already */
@@ -181,8 +181,8 @@
 			/* IP */
 			s.sa.sa_family = AF_INET;
 			if (avp_value->os.len != 6) {
-				snprintf(ret, STR_LEN, "[invalid IP length: %zd]", avp_value->os.len);
-				return ret;
+				CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid IP length: %zd]", avp_value->os.len), return NULL);
+				return *buf;
 			}
 			memcpy(&s.sin.sin_addr.s_addr, avp_value->os.data + 2, 4);
 			break;
@@ -190,23 +190,17 @@
 			/* IP6 */
 			s.sa.sa_family = AF_INET6;
 			if (avp_value->os.len != 18) {
-				snprintf(ret, STR_LEN, "[invalid IP6 length: %zd]", avp_value->os.len);
-				return ret;
+				CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid IP6 length: %zd]", avp_value->os.len), return NULL);
+				return *buf;
 			}
 			memcpy(&s.sin6.sin6_addr.s6_addr, avp_value->os.data + 2, 16);
 			break;
 		default:
-			snprintf(ret, STR_LEN, "[unsupported family: 0x%hx]", fam);
-			return ret;
+			CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[unsupported family: 0x%hx]", fam), return NULL);
+			return *buf;
 	}
 	
-	{
-		int rc = getnameinfo(&s.sa, sSAlen(&s.sa), ret, STR_LEN, NULL, 0, NI_NUMERICHOST);
-		if (rc)
-			snprintf(ret, STR_LEN, "%s", (char *)gai_strerror(rc));
-	}
-	
-	return ret;
+	return fd_sa_dump_node(FD_DUMP_STD_PARAMS, &s.sa, NI_NUMERICHOST);
 }
 
 
@@ -215,42 +209,25 @@
 /*    UTF8String  AVP  type    */
 /*******************************/
 
-/* Dump the AVP in a natural human-readable format */
-char * fd_dictfct_UTF8String_dump(union avp_value * avp_value)
+/* 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)
 {
-#define TRUNC_LEN	1024 /* avoid very long strings */
-	char * ret;
-	CHECK_MALLOC_DO( ret = malloc(TRUNC_LEN+2+3+1), return NULL );
-	*ret = '"';
-	strncpy(ret+1, (char *)avp_value->os.data, TRUNC_LEN);
-	/* be sure to have a nul-terminated string */
-	ret[TRUNC_LEN+1] = '\0';
-	if (ret[1] != '\0') {
-		/* We sanitize the returned string to avoid UTF8 boundary problem.
-		We do this whether the string is trucated at TRUNC_LEN or not, to avoid potential problem
-		with malformed AVP */
-
-		char * end = strchr(ret, '\0');
-		while (end > ret) {
-			end--;
-			char b = *end;
-			/* after the position pointed by end, we have only \0s */
-			if ((b & 0x80) == 0) {
-				break; /* this is a single byte char, no problem */
-			} else {
-				/* this byte is start or cont. of multibyte sequence, as we do not know the next byte we need to delete it. */
-				*end = '\0';
-				if (b & 0x40)
-					break; /* This was a start byte, we can stop the loop */
-			}
-		}
-		if (strlen((char *)avp_value->os.data) > strlen(ret+1))
-			strcat(end, "...");
-		strcat(end, "\"");
-	} else {
-		*ret = '\0';
+	size_t o = 0, l;
+	if (!offset)
+		offset = &o;
+	
+	l = avp_value->os.len;
+	/* Just in case the string ends in invalid UTF-8 chars, we shorten it */
+	while ((l > 0) && (avp_value->os.data[l - 1] & 0x80)) {
+		/* this byte is start or cont. of multibyte sequence, as we do not know the next byte we need to delete it. */
+		l--;
+		if (avp_value->os.data[l] & 0x40)
+			break; /* This was a start byte, we can stop the loop */
 	}
-	return ret;
+	
+	CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "\"%.*s\"", (int)l, (char *)avp_value->os.data), return NULL);
+	
+	return *buf;
 }
 
 
@@ -325,22 +302,26 @@
 	return diameter_string_to_time_t((const char *)avp_value->os.data, avp_value->os.len, interpreted);
 }
 
-char * fd_dictfct_Time_dump(union avp_value * avp_value)
+DECLARE_FD_DUMP_PROTOTYPE(fd_dictfct_Time_dump, union avp_value * avp_value)
 {
-	char * ret;
+	size_t o = 0;
 	time_t val;
 	struct tm conv;
-	CHECK_MALLOC_DO( ret = malloc(STR_LEN), return NULL );
+		
+	if (!offset)
+		offset = &o;
+	
 	if (avp_value->os.len != 4) {
-		snprintf(ret, STR_LEN, "[invalid length: %zd]", avp_value->os.len);
-		return ret;
+		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[invalid length: %zd]", avp_value->os.len), return NULL);
+		return *buf;
 	}
+
 	if (diameter_string_to_time_t((char *)avp_value->os.data, avp_value->os.len, &val) != 0) {
-		snprintf(ret, STR_LEN, "[time conversion error]");
-		return ret;
+		CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "[time conversion error]"), return NULL);
+		return *buf;
 	}
-	gmtime_r(&val, &conv);
-	snprintf(ret, STR_LEN, "%d%02d%02dT%02d%02d%02d+00", conv.tm_year+1900, conv.tm_mon+1, conv.tm_mday, conv.tm_hour, conv.tm_min, conv.tm_sec);
-	return ret;
+	
+	CHECK_MALLOC_DO( fd_dump_extend(FD_DUMP_STD_PARAMS, "%d%02d%02dT%02d%02d%02d+00", conv.tm_year+1900, conv.tm_mon+1, conv.tm_mday, conv.tm_hour, conv.tm_min, conv.tm_sec), return NULL);
+	return *buf;
 }
 
--- a/libfdproto/fdproto-internal.h	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/fdproto-internal.h	Fri May 03 19:20:56 2013 +0800
@@ -50,16 +50,12 @@
 /* Where debug messages are sent */
 extern FILE * fd_g_debug_fstr;
 
-/* Special message dump function */
-void fd_msg_dump_fstr_one ( struct msg * msg, FILE * fstr );
-void fd_msg_dump_fstr ( struct msg * msg, FILE * fstr );
-
 /* Iterator on the rules of a parent object */
 int fd_dict_iterate_rules ( struct dict_object *parent, void * data, int (*cb)(void *, struct dict_rule_data *) );
 
 /* Dispatch / messages / dictionary API */
 int fd_dict_disp_cb(enum dict_object_type type, struct dict_object *obj, struct fd_list ** cb_list);
-int fd_dict_dump_avp_value(union avp_value *avp_value, struct dict_object * model, int indent, char **outstr, size_t *offset, size_t *outlen, int header);
+DECLARE_FD_DUMP_PROTOTYPE(fd_dict_dump_avp_value, union avp_value *avp_value, struct dict_object * model, int indent, int header);
 int fd_disp_call_cb_int( struct fd_list * cb_list, struct msg ** msg, struct avp *avp, struct session *sess, enum disp_action *action, 
 			struct dict_object * obj_app, struct dict_object * obj_cmd, struct dict_object * obj_avp, struct dict_object * obj_enu);
 extern pthread_rwlock_t fd_disp_lock;
@@ -68,40 +64,4 @@
 int fd_sess_reclaim_msg ( struct session ** session );
 
 
-/* For dump routines into string buffers */
-#include <stdarg.h>
-static __inline__ int dump_init_str(char **outstr, size_t *offset, size_t *outlen) 
-{
-	*outlen = 1<<12;
-	CHECK_MALLOC( *outstr = malloc(*outlen) );
-	*offset = 0;
-	(*outstr)[0] = 0;
-	return 0;
-}
-static __inline__ int dump_add_str(char **outstr, size_t *offset, size_t *outlen, char * fmt, ...) 
-{
-	va_list argp;
-	int len;
-	va_start(argp, fmt);
-	len = vsnprintf(*outstr + *offset, *outlen - *offset, fmt, argp);
-	va_end(argp);
-	if ((len + *offset) >= *outlen) {
-		char * newstr;
-		/* buffer was too short, extend */
-		size_t newsize = ((len + *offset) + (1<<12)) & ~((1<<12) - 1); /* next multiple of 4k */
-		CHECK_MALLOC( newstr = realloc(*outstr, newsize) );
-		
-		/* redo */
-		*outstr = newstr;
-		*outlen = newsize;
-		va_start(argp, fmt);
-		len = vsnprintf(*outstr + *offset, *outlen - *offset, fmt, argp);
-		va_end(argp);
-	}
-	*offset += len;
-	return 0;
-}
-
-
-
 #endif /* _LIBFDPROTO_INTERNAL_H */
--- a/libfdproto/fifo.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/fifo.c	Fri May 03 19:20:56 2013 +0800
@@ -118,46 +118,46 @@
 }
 
 /* Dump the content of a queue */
-void fd_fifo_dump(int level, char * name, struct fifo * queue, void (*dump_item)(int level, void * item))
+DECLARE_FD_DUMP_PROTOTYPE(fd_fifo_dump, char * name, struct fifo * queue, fd_fifo_dump_item_cb dump_item)
 {
-	TRACE_ENTRY("%i %p %p %p", level, name, queue, dump_item);
-	
-	if (!TRACE_BOOL(level))
-		return;
+	size_t o = 0;
+	if (!offset)
+		offset = &o;
 	
-	fd_log_debug("Dumping queue '%s' (%p):", name ?: "?", queue);
+	if (name) {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "'%s'(@%p): ", name, queue), return NULL);	
+	} else {
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{fifo}(@%p): ", queue), return NULL);
+	}
+	
 	if (!CHECK_FIFO( queue )) {
-		fd_log_debug("  Queue invalid!");
-		if (queue)
-			fd_log_debug("  (%x != %x)", queue->eyec, FIFO_EYEC);
-		return;
+		return fd_dump_extend(FD_DUMP_STD_PARAMS, "INVALID/NULL\n");
 	}
 	
 	CHECK_POSIX_DO(  pthread_mutex_lock( &queue->mtx ), /* continue */  );
-	fd_log_debug("   %d elements in queue / %d threads waiting", queue->count, queue->thrs);
-	fd_log_debug("   %d elements max / %d threads waiting to push", queue->max, queue->thrs_push);
-	fd_log_debug("   thresholds: %d / %d (h:%d), cb: %p,%p (%p), highest: %d",
-			queue->high, queue->low, queue->highest, 
-			queue->h_cb, queue->l_cb, queue->data,
-			queue->highest_ever);
-	fd_log_debug("   stats: total:%lld in %ld.%06ld, blocking:%ld.%06ld, last:%ld.%06ld",
-			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) );
+	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", 
+						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),
+						queue->high, queue->low, queue->highest, queue->h_cb, queue->l_cb, queue->data), 
+			 goto error);
 	
 	if (dump_item) {
 		struct fd_list * li;
 		int i = 0;
 		for (li = queue->list.next; li != &queue->list; li = li->next) {
 			struct fifo_item * fi = (struct fifo_item *)li;
-			fd_log_debug("  [%i] item %p in fifo %p, posted:%ld.%06ld", 
-				i++, fi->item.o, queue, (long)fi->posted_on.tv_sec,(long)(fi->posted_on.tv_nsec/1000));
-			(*dump_item)(level, fi->item.o);
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, " [#%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 */  );
+	return NULL;
 }
 
 /* Delete a queue. It must be empty. */ 
--- a/libfdproto/log.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/log.c	Fri May 03 19:20:56 2013 +0800
@@ -142,14 +142,16 @@
 	(void)pthread_mutex_unlock(&fd_log_lock);
 }
 
-/* Log debug message to file. */
-void fd_log_debug_fstr( FILE * fstr, const char * format, ... )
+/* Log a debug message */
+void fd_log_va ( int loglevel, const char * format, va_list args )
 {
-	va_list ap;
+	(void)pthread_mutex_lock(&fd_log_lock);
 	
-	va_start(ap, format);
-	vfprintf(fstr, format, ap);
-	va_end(ap);
+	pthread_cleanup_push(fd_cleanup_mutex_silent, &fd_log_lock);
+	fd_logger(loglevel, format, args);
+	pthread_cleanup_pop(0);
+	
+	(void)pthread_mutex_unlock(&fd_log_lock);
 }
 
 /* Function to set the thread's friendly name */
@@ -207,3 +209,51 @@
 
 	return buf;
 }
+
+
+/* Helper function for fd_*_dump. Prints the format string from 'offset' into '*buf', extends if needed. The location of buf can be updated by this function. */
+char * fd_dump_extend(char ** buf, size_t *len, size_t *offset, const char * format, ... )
+{
+	va_list ap;
+	int to_write;
+	size_t o = 0;
+	static size_t mempagesz = 0;
+	
+	if (!mempagesz) {
+		mempagesz = sysconf(_SC_PAGESIZE); /* We alloc buffer by memory pages for efficiency */
+		if (mempagesz <= 0)
+			mempagesz = 1024; /* default size if above call failed */
+	}
+	
+	/* we do not TRACE_ENTRY this one on purpose */
+	
+	CHECK_PARAMS_DO(buf && len, return NULL);
+	
+	if (*buf == NULL) {
+		CHECK_MALLOC_DO(*buf = malloc(mempagesz), return NULL);
+		*len = mempagesz;
+	}
+	
+	if (offset)
+		o = *offset;
+	
+	va_start(ap, format);
+	to_write = vsnprintf(*buf + o, *len - o, format, ap);
+	va_end(ap);
+	
+	if (to_write + o >= *len) {
+		/* There was no room in the buffer, we extend and redo */
+		size_t new_len = (((to_write + o) / mempagesz) + 1) * mempagesz;
+		CHECK_MALLOC_DO(*buf = realloc(*buf, new_len), return NULL);
+		*len = new_len;
+		
+		va_start(ap, format);
+		to_write = vsnprintf(*buf + o, *len - o, format, ap);
+		va_end(ap);
+	}
+	
+	if (offset)
+		*offset += to_write;
+	
+	return *buf;
+}
--- a/libfdproto/messages.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/messages.c	Fri May 03 19:20:56 2013 +0800
@@ -710,6 +710,34 @@
 /***************************************************************************************************************/
 /* 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 )
+{
+	return NULL;
+}
+/* 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 )
+{
+	return NULL;
+}
+
+#ifndef OLD_CODE_TO_BE_REPLACED
+void fd_msg_dump_walk ( int level, msg_or_avp *obj )
+{
+	LOG_D("fd_msg_dump_walk %d, %p is deprecated", level, obj);
+}
+void fd_msg_dump_one ( int level, msg_or_avp * obj )
+{
+	LOG_D("fd_msg_dump_one %d, %p is deprecated", level, obj);
+}
+#else  /* OLD_CODE_TO_BE_REPLACED */
+
+
 /* indent inside an object */
 #define INOBJHDR 	"%*s   "
 #define INOBJHDRVAL 	indent<0 ? 1 : indent, indent<0 ? "-" : "|"
@@ -1075,7 +1103,7 @@
 	free(outstr);
 }
 
-
+#endif /*  OLD_CODE_TO_BE_REPLACED */
 /***************************************************************************************************************/
 /* Simple meta-data management */
 
--- a/libfdproto/sessions.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/sessions.c	Fri May 03 19:20:56 2013 +0800
@@ -69,6 +69,7 @@
 	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 *, os0_t, void *); /* The cleanup function to be called for cleaning a state */
+	session_state_dump *state_dump; /* dumper function */
 	void             *opaque; /* a value that is passed as is to the cleanup callback */
 };
 
@@ -272,7 +273,7 @@
 }
 
 /* Create a new handler */
-int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state *, os0_t, void *), void * opaque )
+int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(session_state *, os0_t, void *), session_state_dump dumper, void * opaque )
 {
 	struct session_handler *new;
 	
@@ -289,6 +290,7 @@
 	
 	new->eyec = SH_EYEC;
 	new->cleanup = cleanup;
+	new->state_dump = dumper;
 	new->opaque = opaque;
 	
 	*handler = new;
@@ -872,49 +874,63 @@
 
 
 /* Dump functions */
-void fd_sess_dump(int level, struct session * session)
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump, struct session * session, int with_states)
 {
-	struct fd_list * li;
-	char buf[30];
-	struct tm tm;
+	size_t o = 0;
+	if (!offset)
+		offset = &o;
+	
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{session}(@%p): ", session), return NULL);
 	
-	if (!TRACE_BOOL(level))
-		return;
-	
-	fd_log_debug("\t  %*s -- Session @%p --", level, "", session);
 	if (!VALIDATE_SI(session)) {
-		fd_log_debug("\t  %*s  Invalid session object", level, "");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), 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",
+							session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed,
+							timebuf, session->timeout.tv_nsec/1000), 
+				 return NULL);
 		
-		fd_log_debug("\t  %*s  sid '%s'(%zd), hash %x, msg %d, destroyed %d", level, "", session->sid, session->sidlen, session->hash, session->msg_cnt, session->is_destroyed);
-
-		strftime(buf, sizeof(buf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
-		fd_log_debug("\t  %*s  timeout %s.%09ld", level, "", buf, session->timeout.tv_nsec);
-
-		CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
-		pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
-		for (li = session->states.next; li != &session->states; li = li->next) {
-			struct state * st = (struct state *)(li->o);
-			fd_log_debug("\t  %*s    handler %d registered data %p", level, "", st->hdl->id, st->state);
+		if (with_states) {
+			struct fd_list * li;
+			CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
+			pthread_cleanup_push( fd_cleanup_mutex, &session->stlock );
+			
+			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);
+				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"));
+				} else {
+					CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "<%p>\n", st->state), return NULL);
+				}
+			}
+			
+			pthread_cleanup_pop(0);
+			CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
 		}
-		pthread_cleanup_pop(0);
-		CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
 	}
-	fd_log_debug("\t  %*s -- end of session @%p --", level, "", session);
+	return *buf;
 }
 
-void fd_sess_dump_hdl(int level, struct session_handler * handler)
+DECLARE_FD_DUMP_PROTOTYPE(fd_sess_dump_hdl, struct session_handler * handler)
 {
-	if (!TRACE_BOOL(level))
-		return;
+	size_t o = 0;
+	if (!offset)
+		offset = &o;
 	
-	fd_log_debug("\t  %*s -- Handler @%p --", level, "", handler);
+	CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "{sesshdl}(@%p): ", handler), return NULL);
+	
 	if (!VALIDATE_SH(handler)) {
-		fd_log_debug("\t  %*s  Invalid session handler object", level, "");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "INVALID/NULL\n"), return NULL);
 	} else {
-		fd_log_debug("\t  %*s  id %d, cleanup %p, opaque %p", level, "", handler->id, handler->cleanup, handler->opaque);
+		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);
 	}
-	fd_log_debug("\t  %*s -- end of handler @%p --", level, "", handler);
+	return *buf;
 }	
 
 int fd_sess_getcount(uint32_t *cnt)
--- a/libfdproto/utils.c	Fri May 03 15:33:57 2013 +0800
+++ b/libfdproto/utils.c	Fri May 03 19:20:56 2013 +0800
@@ -35,33 +35,44 @@
 
 #include "fdproto-internal.h"
 
-char * fd_sa_dump_node(char * buf, size_t bufsize, sSA * sa, int flags) 
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node, sSA * sa, int flags)
 {
 	char addrbuf[INET6_ADDRSTRLEN];
+	size_t o = 0;
+	if (!offset)
+		offset = &o;
+	
 	if (sa) {
 		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), NULL, 0, flags);
-		if (rc)
-			snprintf(buf, bufsize, "%s", gai_strerror(rc));
-		else
-			snprintf(buf, bufsize, "%s", &addrbuf[0]);
+		if (rc) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", gai_strerror(rc)), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", &addrbuf[0]), return NULL);
+		}
 	} else {
-		snprintf(buf, bufsize, "(NULL / ANY)");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(NULL / ANY)"), return NULL);
 	}
-	return buf;
+	
+	return *buf;
 }
 
-char * fd_sa_dump_node_serv(char * buf, size_t bufsize, sSA * sa, int flags) 
+DECLARE_FD_DUMP_PROTOTYPE(fd_sa_dump_node_serv, sSA * sa, int flags) 
 {
 	char addrbuf[INET6_ADDRSTRLEN];
 	char servbuf[32];
+	size_t o = 0;
+	if (!offset)
+		offset = &o;
+	
 	if (sa) {
 		int rc = getnameinfo(sa, sSAlen( sa ), addrbuf, sizeof(addrbuf), servbuf, sizeof(servbuf), flags);
-		if (rc)
-			snprintf(buf, bufsize, "%s", gai_strerror(rc));
-		else
-			snprintf(buf, bufsize, "%s", &addrbuf[0]);
+		if (rc) {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", gai_strerror(rc)), return NULL);
+		} else {
+			CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "%s", &addrbuf[0]), return NULL);
+		}
 	} else {
-		snprintf(buf, bufsize, "(NULL / ANY)");
+		CHECK_MALLOC_DO( fd_dump_extend( FD_DUMP_STD_PARAMS, "(NULL / ANY)"), return NULL);
 	}
-	return buf;
+	return *buf;
 }
"Welcome to our mercurial repository"