Index: include/freeDiameter/freeDiameter-host.h.in
===================================================================
--- include/freeDiameter/freeDiameter-host.h.in	(revision 1098)
+++ include/freeDiameter/freeDiameter-host.h.in	(revision 935)
@@ -95,7 +95,4 @@
 #endif /* FD_DEFAULT_CONF_FILENAME */
 
-/* Maximum number of hooks handlers that can be registered. Make this compilation option if needed */
-#define FD_HOOK_HANDLE_LIMIT	5
-
 #ifdef __cplusplus
 }
Index: include/freeDiameter/libfdcore.h
===================================================================
--- include/freeDiameter/libfdcore.h	(revision 1098)
+++ include/freeDiameter/libfdcore.h	(revision 1099)
@@ -879,5 +879,5 @@
 /* These functions allow an extension to collect state information about the
  * framework, as well as being hooked at some key checkpoints in the processing
- * for logging or statistics purpose.
+ * for logging / statistics purpose.
  */
  
@@ -887,9 +887,9 @@
  * PARAMETERS:
  *  type	: The type of hook that triggered this call, in case same cb is registered for several hooks.
- *  msg 	: If relevant, the pointer to the message triggering the call. NULL otherwise.
+ *  msg 	: If relevant, the pointer to the message trigging the call. NULL otherwise.
  *  peer        : If relevant, the pointer to the peer associated with the call. NULL otherwise.
  *  other	: For some callbacks, the remaining information is passed in this parameter. See each hook detail.
  *  permsgdata  : Structure associated with a given message, across several hooks. 
- *                 A different structure is associated with requests and corresponding answers. 
+ *                 Same structure is associated with requests and corresponding answers. 
  *                 See fd_hook_data_hdl below for details.
  *                 If no fd_hook_data_hdl is registered with this callback, this parameter is always NULL
@@ -916,6 +916,8 @@
 		 - {msg} is NULL.
 		 - {peer} is NULL.
-		 - {other} is a pointer to a structure { size_t len; uint8_t * buf; } containing the received buffer.
-		 - {permsgdata} points to either a new empty structure allocated for this message (cf. fd_hook_data_hdl), or NULL if no hdl is registered.
+		 - {*other} is NULL, {other} points to a valid location where you can store a pointer. 
+		    This same pointer will then passed to the next hook, once message is processed.
+		    IMPORTANT: free() will be called on this pointer if any problem, so this pointer must be malloc'd.
+		 - {permsgdata} is NULL.
 		 */
 		 
@@ -926,6 +928,6 @@
 		 - {peer} is set if the message is received from a peer's connection, and NULL if the message is from a new client
 		   connected and not yet identified
-		 - {other} is NULL.
-		 - {permsgdata} points to either a new empty structure allocated for this message or the one passed to HOOK_DATA_RECEIVED if used.
+		 - {*other} contains the pointer stored with the HOOK_DATA_RECEIVED hook if any, NULL otherwise. After this hook returns, free(*other) is called if not NULL.
+		 - {permsgdata} points to either a new empty structure allocated for this request (cf. fd_hook_data_hdl), or the request's existing structure if the message is an answer.
 		 */
 	
@@ -944,11 +946,12 @@
 		   try to call fd_msg_parse_dict, it will slow down the operation of a relay agent.
 		 - {peer} is set if the message is sent to a peer's connection, and NULL if the message is sent to a new client
-		   connected and not yet identified, or being rejected
+		   connected and not yet identified / being rejected
 		 - {other} is NULL.
 		 - {permsgdata} points to existing structure if any, or a new structure otherwise. 
+		    If the message is an answer, the structure is shared with the corresponding request.
 		 */
 	
 	HOOK_MESSAGE_FAILOVER,
-		/* Hook called when a message that was sent to a peer is being requeued, because e.g. the connection was teared down.
+		/* Hook called when a message that was sent to a peer is being requeued, because e.g. the connection was torn down.
 		   In that case the message will go again through the routing process.
 		 - {msg} points to the corresponding request message (the answer is discarded). Again, the objects may not have been dictionary resolved. If you
@@ -956,5 +959,5 @@
 		 - {peer} is the peer this message was previously sent to.
 		 - {other} is NULL.
-		 - {permsgdata} points to existing structure if any, or a new structure otherwise. 
+		 - {permsgdata} points to existing structure associated with this request. 
 		 */
 	
@@ -991,6 +994,6 @@
 	
 	HOOK_MESSAGE_DROPPED,
-		/* Hook called when a message is being discarded by the framework because of some error condition (normal or abnormal).
-		   It is probably a good idea to log this for analysis / backup.
+		/* Hook called when a message is being discarded by the framework because of some error.
+		   It is probably a good idea to log this for analysis.
 		 - {msg} points to the message, which will be freed as soon as the hook returns.
 		 - {peer} is NULL.
@@ -1019,5 +1022,5 @@
 
 
-/* Type if the {permsgdata}. It is up to each extension to define its own structure. This is opaque for the framework. */
+/* Type of the {permsgdata} pointer. It is up to each extension to define its own structure. This is opaque for the framework. */
 struct fd_hook_permsgdata;
 
@@ -1032,15 +1035,12 @@
  *
  * PARAMETERS:
- *  permsgdata_size     : the size of the fd_hook_permsgdata structure. 
- *  permsgdata_init_cb  : function called to initialize a new fd_hook_permsgdata structure, when a hook will be called for a message that does not have such structure yet. 
- *                           The memory is already allocated and blanked, so you can pass NULL if no further handling is required.
- *  permsgdata_fini_cb  : function called when a message is being disposed. It should free the resources associated with the fd_hook_permsgdata. 
- *                           You can pass NULL if no special handling is required. The memory of the permsgdata structure itself will be freed by the framework.
- *  new_handle          : On success, a handler to the registered callback is stored here. 
+ *  permsgdata_new_cb     : function called to initialize a new empty fd_hook_permsgdata structure, when a hook will be called for a message with no structure yet. If the function returns NULL, it will be called again for the next hook.
+ *  permsgdata_destroy_cb : function called when a message is being disposed. It should free the resources associated with the fd_hook_permsgdata.
+ *  new_handle            : On success, a handler to the registered callback is stored here. 
  *		             This handler will be used to unregister the cb.
  *
  * DESCRIPTION: 
  *   Register a new fd_hook_data_hdl. This handle is used during hooks registration (see below) in order to associate data with the messages, to allow keeping tracking of the message easily.
- *  Note that these handlers are statically allocated and cannot be unregistered. FD_HOOK_HANDLE_LIMIT handlers can be registered at maximum (recompile libfdproto if you change this value)
+ *  Note that these handlers are statically allocated and cannot be unregistered.
  *
  * RETURN VALUE:
@@ -1050,9 +1050,9 @@
  */
 int fd_hook_data_register(
-	size_t permsgdata_size,
-	void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
-        void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
-        struct fd_hook_data_hdl **new_handle
+	struct fd_hook_permsgdata * (*permsgdata_new_cb)     (void),
+        void (*permsgdata_destroy_cb) (struct fd_hook_permsgdata *),
+        struct fd_hook_data_hdl **    new_handle
 );
+
 
 /* A handler associated with a registered hook callback (for cleanup) */
@@ -1063,5 +1063,5 @@
  *
  * PARAMETERS:
- *  type_mask	  : A bitmask of fd_hook_type bits for which this cb is registered, e.g. ((1 << HOOK_MESSAGE_RECEIVED) || (1 << HOOK_MESSAGE_SENT))
+ *  type	  : The fd_hook_type for which this cb is registered. Call several times if you want to register for several hooks.
  *  fd_hook_cb	  : The callback function to register (see prototype above).
  *  regdata	  : Pointer to pass to the callback when it is called. The data is opaque to the daemon.
@@ -1079,7 +1079,7 @@
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_hook_register (  uint32_t type_mask, 
-			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata), 
-			void  *regdata, 
+int fd_hook_register (  enum fd_hook_type type, 
+			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, void * regdata), 
+			void * regdata, 
 			struct fd_hook_data_hdl *data_hdl,
 			struct fd_hook_hdl ** handler );
Index: include/freeDiameter/libfdproto.h
===================================================================
--- include/freeDiameter/libfdproto.h	(revision 1098)
+++ include/freeDiameter/libfdproto.h	(revision 1097)
@@ -2550,12 +2550,4 @@
 
 
-/* Helper for the hooks mechanism, for use from libfdcore */
-struct fd_msg_pmdl {
-	struct fd_list sentinel; /* if the sentinel.o field is NULL, the structure is not initialized. Otherwise it points to the cleanup function in libfdcore. */
-	pthread_mutex_t lock;
-};
-#define FD_MSG_PMDL_INITIALIZER(pmdl_ptr)        { FD_LIST_INITIALIZER(  (pmdl_ptr)->sentinel       ), PTHREAD_MUTEX_INITIALIZER }
-struct fd_msg_pmdl * fd_msg_pmdl_get(struct msg * msg);
-
 /***************************************/
 /*   Manage AVP values                 */
Index: libfdcore/cnxctx.c
===================================================================
--- libfdcore/cnxctx.c	(revision 1098)
+++ libfdcore/cnxctx.c	(revision 1099)
@@ -736,6 +736,4 @@
 		}
 		
-		// fd_msg_log(....)
-		
 		/* We have received a complete message, pass it to the daemon */
 		CHECK_FCT_DO( fd_event_send( fd_cnx_target_queue(conn), FDEVP_CNX_MSG_RECV, length, newmsg), /* continue or destroy everything? */);
@@ -1758,5 +1756,5 @@
 	
 		default:
-			TRACE_DEBUG(INFO, "Unknwon protocol: %d", conn->cc_proto);
+			TRACE_DEBUG(INFO, "Unknown protocol: %d", conn->cc_proto);
 			ASSERT(0);
 			return ENOTSUP;	/* or EINVAL... */
Index: libfdcore/core.c
===================================================================
--- libfdcore/core.c	(revision 1098)
+++ libfdcore/core.c	(revision 1085)
@@ -187,5 +187,4 @@
 	
 	/* Initialize some modules */
-	CHECK_FCT( fd_hooks_init()  );
 	CHECK_FCT( fd_queues_init() );
 	CHECK_FCT( fd_msg_init()    );
Index: libfdcore/fdcore-internal.h
===================================================================
--- libfdcore/fdcore-internal.h	(revision 1098)
+++ libfdcore/fdcore-internal.h	(revision 1085)
@@ -363,7 +363,3 @@
 #define FD_CNX_ORDERED		(1 << 0)	/* All messages sent with this flag set will be delivered in the same order. No guarantee on other messages */
 
-/* Internal calls of the hook mechanism */
-void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl);
-void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl);
-int    fd_hooks_init(void);
 #endif /* _FDCORE_INTERNAL_H */
Index: libfdcore/hooks.c
===================================================================
--- libfdcore/hooks.c	(revision 1098)
+++ libfdcore/hooks.c	(revision 1077)
@@ -36,224 +36,29 @@
 #include "fdcore-internal.h"
 
-/* Structures for the fd_hook_data_hdl management */
-static struct fd_hook_data_hdl {
-	size_t	pmd_size;
-	void  (*pmd_init_cb)(struct fd_hook_permsgdata *);
-	void  (*pmd_fini_cb)(struct fd_hook_permsgdata *);
-} HDH_array[FD_HOOK_HANDLE_LIMIT];
-static int max_index = 0;
-static pthread_mutex_t HDH_lock = PTHREAD_MUTEX_INITIALIZER;
+struct fd_hook_hdl; 
+struct fd_hook_data_hdl;
 
-/* The structure linked from the msg structure list */
-struct pmd_list_item {
-	struct fd_list	chain;		/* this list is ordered by hdl */
-	struct fd_hook_data_hdl * hdl; 
-	struct fd_hook_permsgdata { } pmd; /* this data belongs to the extension; we only know the size of it */
-};
-
-#define sizeof_pmd(hdl)	(((size_t)&((struct pmd_list_item *)0)->pmd) + hdl->pmd_size)
-
-/* Now a hook registered by an extension */
-struct fd_hook_hdl {
-	struct fd_list chain[HOOK_PEER_LAST+1];
-	void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata);
-	void  *regdata;
-	struct fd_hook_data_hdl *data_hdl;
-};
-
-/* Array of those hooks */
-struct {
-	struct fd_list sentinel;
-	pthread_rwlock_t rwlock;
-} HS_array[HOOK_PEER_LAST+1];
-
-/* Initialize the array of sentinels for the hooks */
-int fd_hooks_init(void)
+int fd_hook_data_register(
+	struct fd_hook_permsgdata * (*permsgdata_new_cb)     (void),
+        void (*permsgdata_destroy_cb) (struct fd_hook_permsgdata *),
+        struct fd_hook_data_hdl **    new_handle
+)
 {
-	int i;
-	for (i=0; i <= HOOK_PEER_LAST; i++) {
-		fd_list_init(&HS_array[i].sentinel, NULL);
-		CHECK_POSIX( pthread_rwlock_init(&HS_array[i].rwlock, NULL) );
-	}
-	return 0;
+	return ENOTSUP;
 }
 
-/* Get a slot in the array */
-int fd_hook_data_register(
-	size_t permsgdata_size,
-	void (*permsgdata_init_cb) (struct fd_hook_permsgdata *),
-        void (*permsgdata_fini_cb) (struct fd_hook_permsgdata *),
-        struct fd_hook_data_hdl **new_handle)
-{
-	int ret = ENOSPC, idx;
-	TRACE_ENTRY("%zd %p %p %p", permsgdata_size, permsgdata_init_cb, permsgdata_fini_cb, new_handle);
-	
-	CHECK_PARAMS( permsgdata_size && new_handle );
-	
-	CHECK_POSIX( pthread_mutex_lock(&HDH_lock) );
-	if (max_index < FD_HOOK_HANDLE_LIMIT) {
-		idx = max_index++;
-		ret = 0;
-	}
-	CHECK_POSIX( pthread_mutex_unlock(&HDH_lock) );
-	
-	if (ret == 0) {
-		HDH_array[idx].pmd_size = permsgdata_size;
-		HDH_array[idx].pmd_init_cb = permsgdata_init_cb;
-		HDH_array[idx].pmd_fini_cb = permsgdata_fini_cb;
-		*new_handle = &HDH_array[idx];
-	}
-	
-	return ret;
-}
-
-/* Register a new hook callback */
-int fd_hook_register (  uint32_t type_mask, 
-			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, struct fd_hook_permsgdata *pmd, void * regdata), 
-			void  *regdata, 
+int fd_hook_register (  enum fd_hook_type type, 
+			void (*fd_hook_cb)(enum fd_hook_type type, struct msg * msg, struct peer_hdr * peer, void * other, void * regdata), 
+			void * regdata, 
 			struct fd_hook_data_hdl *data_hdl,
 			struct fd_hook_hdl ** handler )
 {
-	struct fd_hook_hdl * newhdl = NULL;
-	int i;
-	
-	TRACE_ENTRY("%x %p %p %p %p", type_mask, fd_hook_cb, regdata, data_hdl, handler);
-	
-	CHECK_PARAMS( fd_hook_cb && handler );
-	
-	CHECK_MALLOC( newhdl = malloc(sizeof(struct fd_hook_hdl)) );
-	memset(newhdl, 0, sizeof(struct fd_hook_hdl));
-	
-	newhdl->fd_hook_cb = fd_hook_cb;
-	newhdl->regdata = regdata;
-	newhdl->data_hdl = data_hdl;
-	
-	for (i=0; i <= HOOK_PEER_LAST; i++) {
-		fd_list_init(&newhdl->chain[i], newhdl);
-		if (type_mask & (1<<i)) {
-			CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
-			fd_list_insert_before( &HS_array[i].sentinel, &newhdl->chain[i]);
-			CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
-		}
-	}
-	
-	*handler = newhdl;
-	return 0;
-}
-
-/* free this hook callback */
-int fd_hook_unregister( struct fd_hook_hdl * handler )
-{
-	int i;
-	TRACE_ENTRY("%p", handler);
-	CHECK_PARAMS( handler );
-	
-	for (i=0; i <= HOOK_PEER_LAST; i++) {
-		if ( ! FD_IS_LIST_EMPTY(&handler->chain[i])) {
-			CHECK_POSIX( pthread_rwlock_wrlock(&HS_array[i].rwlock) );
-			fd_list_unlink(&handler->chain[i]);
-			CHECK_POSIX( pthread_rwlock_unlock(&HS_array[i].rwlock) );
-		}
-	}
-	
-	free(handler);
-	
-	return 0;
-}
-
-/* callback for the libfdproto to free the data associated with a message */
-static void pmdl_free(struct fd_msg_pmdl *pmdl)
-{
-	/* destroy all the items in the list */
-	while (!FD_IS_LIST_EMPTY(&pmdl->sentinel)) {
-		struct pmd_list_item * li = (struct pmd_list_item *)(pmdl->sentinel.next);
-		if (li->hdl->pmd_fini_cb) {
-			(*li->hdl->pmd_fini_cb)(&li->pmd);
-		}
-		fd_list_unlink(&li->chain);
-		free(li);
-	}
-	CHECK_POSIX_DO( pthread_mutex_destroy(&pmdl->lock), );
-	pmdl->sentinel.o = NULL;
-}
-
-/* Save the list of pmd into the message structure, as well as the callback to free this list */
-void   fd_hook_associate(struct msg * msg, struct fd_msg_pmdl * pmdl)
-{
-	struct fd_msg_pmdl * in_msg;
-	
-	CHECK_PARAMS_DO( msg && pmdl, return );
-	in_msg = fd_msg_pmdl_get(msg);
-	ASSERT(in_msg && (in_msg->sentinel.o == NULL)); /* error / already initialized ??? */
-	fd_list_init(&in_msg->sentinel, pmdl_free);
-	CHECK_POSIX_DO( pthread_mutex_init(&in_msg->lock, NULL), );
-	/* Now move all items from the pmdl pointer into the initialized list */
-	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
-	fd_list_move_end(&in_msg->sentinel, &pmdl->sentinel);
-	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
-	pmdl_free(pmdl);
-	/* We're done */
-}
-
-/* Return the location of the permsgdata area corresponding to this handle, after eventually having created it. Return NULL in case of failure */
-static struct fd_hook_permsgdata * get_or_create_pmd(struct fd_msg_pmdl *pmdl, struct fd_hook_hdl * h) 
-{
-	struct fd_hook_permsgdata * ret = NULL;
-	struct fd_list * li;
-	CHECK_POSIX_DO( pthread_mutex_lock(&pmdl->lock), );
-	
-	/* Search in the list for an item with the same handle. The list is ordered by this handle */
-	for (li=pmdl->sentinel.next; li != &pmdl->sentinel; li = li->next) {
-		struct pmd_list_item * pli = (struct pmd_list_item *) li;
-		if (pli->hdl == h->data_hdl)
-			ret = &pli->pmd;
-		if (pli->hdl >= h->data_hdl)
-			break;
-	}
-	if (!ret) {
-		/* we need to create a new one and insert before li */
-		struct pmd_list_item * pli;
-		CHECK_MALLOC_DO( pli = malloc(sizeof_pmd(h->data_hdl)), );
-		if (pli) {
-			memset(pli, 0, sizeof_pmd(h->data_hdl));
-			fd_list_init(&pli->chain, pli);
-			pli->hdl = h->data_hdl;
-			ret = &pli->pmd;
-			if (h->data_hdl->pmd_init_cb) {
-				(*h->data_hdl->pmd_init_cb)(ret);
-			}
-			fd_list_insert_before(li, &pli->chain);
-		}
-	}
-	
-	CHECK_POSIX_DO( pthread_mutex_unlock(&pmdl->lock), );
-	return ret;
+	return ENOTSUP;
 }
 
 
-/* The function that does the work of calling the extension's callbacks and also managing the permessagedata structures */
-void   fd_hook_call(enum fd_hook_type type, struct msg * msg, struct fd_peer * peer, void * other, struct fd_msg_pmdl * pmdl)
+int fd_hook_unregister( struct fd_hook_hdl * handler )
 {
-	struct fd_list * li;
-	ASSERT(type <= HOOK_PEER_LAST);
-	
-	/* lock the list of hooks for this type */
-	CHECK_POSIX_DO( pthread_rwlock_rdlock(&HS_array[type].rwlock), );
-	
-	/* for each registered hook */
-	for (li = HS_array[type].sentinel.next; li != &HS_array[type].sentinel; li = li->next) {
-		struct fd_hook_hdl * h = (struct fd_hook_hdl *)li->o;
-		struct fd_hook_permsgdata * pmd = NULL;
-		
-		/* do we need to handle pmd ? */
-		if (h->data_hdl && pmdl) {
-			pmd = get_or_create_pmd(pmdl, h);
-		}
-		
-		/* Now, call this callback */
-		(*h->fd_hook_cb)(type, msg, &peer->p_hdr, other, pmd, h->regdata);
-	}
-	
-	/* done */
-	CHECK_POSIX_DO( pthread_rwlock_unlock(&HS_array[type].rwlock), );
+	return ENOTSUP;
 }
+
Index: libfdcore/p_sr.c
===================================================================
--- libfdcore/p_sr.c	(revision 1078)
+++ libfdcore/p_sr.c	(revision 1099)
@@ -196,5 +196,5 @@
 	} while (1);
 error:	
-	; /* pthread_cleanup_pop sometimes expands as "} ..." and the label beofre this cause some compilers to complain... */
+	; /* pthread_cleanup_pop sometimes expands as "} ..." and the label before this cause some compilers to complain... */
 	pthread_cleanup_pop( 1 );
 	ASSERT(0); /* we have encountered a problem, maybe time to signal the framework to terminate? */
Index: libfdproto/messages.c
===================================================================
--- libfdproto/messages.c	(revision 1098)
+++ libfdproto/messages.c	(revision 1099)
@@ -137,5 +137,5 @@
 	DiamId_t		 msg_src_id;		/* Diameter Id of the peer this message was received from. This string is malloc'd and must be freed */
 	size_t			 msg_src_id_len;	/* cached length of this string */
-	struct fd_msg_pmdl	 msg_pmdl;		/* list of permessagedata structures. */
+	
 };
 
@@ -674,8 +674,4 @@
 	}
 	
-	if ((obj->type == MSG_MSG) && (_M(obj)->msg_pmdl.sentinel.o != NULL)) {
-		((void (*)(struct fd_msg_pmdl *))_M(obj)->msg_pmdl.sentinel.o)(&_M(obj)->msg_pmdl);
-	}
-	
 	/* free the object */
 	free(obj);
@@ -1255,6 +1251,6 @@
 		return anscb ? EINVAL : 0; /* we associate with requests only */
 	
-	CHECK_PARAMS( (anscb == NULL)    || (msg->msg_cb.anscb == NULL) ); /* We are not overwritting a cb */
-	CHECK_PARAMS( (expirecb == NULL) || (msg->msg_cb.expirecb == NULL) ); /* We are not overwritting a cb */
+	CHECK_PARAMS( (anscb == NULL)    || (msg->msg_cb.anscb == NULL) ); /* We are not overwriting a cb */
+	CHECK_PARAMS( (expirecb == NULL) || (msg->msg_cb.expirecb == NULL) ); /* We are not overwriting a cb */
 	
 	/* Associate callback and data with the message, if any */
@@ -1500,11 +1496,4 @@
 	
 	return 0;
-}
-
-/* Retrieve the location of the pmd list for the message; return NULL if failed */
-struct fd_msg_pmdl * fd_msg_pmdl_get(struct msg * msg)
-{
-	CHECK_PARAMS_DO( CHECK_MSG(msg), return NULL );
-	return &msg->msg_pmdl;
 }
 
