diff include/freeDiameter/libfdproto.h @ 1085:7d7266115a34

Cleaning of the traces in progress
author Sebastien Decugis <sdecugis@freediameter.net>
date Fri, 03 May 2013 19:20:56 +0800
parents b380c9f3be1e
children 1c5d410788cc
line wrap: on
line diff
--- 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
 }
"Welcome to our mercurial repository"