Index: libfdcore/cnxctx.c
===================================================================
--- libfdcore/cnxctx.c	(revision 1099)
+++ libfdcore/cnxctx.c	(revision 1101)
@@ -736,4 +736,6 @@
 		}
 		
+		// 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? */);
Index: libfdcore/core.c
===================================================================
--- libfdcore/core.c	(revision 1085)
+++ libfdcore/core.c	(revision 1098)
@@ -187,4 +187,5 @@
 	
 	/* 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 1085)
+++ libfdcore/fdcore-internal.h	(revision 1098)
@@ -363,3 +363,7 @@
 #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 1077)
+++ libfdcore/hooks.c	(revision 1098)
@@ -36,29 +36,224 @@
 #include "fdcore-internal.h"
 
-struct fd_hook_hdl; 
-struct fd_hook_data_hdl;
-
+/* 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;
+
+/* 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 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;
+}
+
+/* Get a slot in the array */
 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
-)
-{
-	return ENOTSUP;
-}
-
-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, 
+	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, 
 			struct fd_hook_data_hdl *data_hdl,
 			struct fd_hook_hdl ** handler )
 {
-	return ENOTSUP;
-}
-
-
+	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 )
 {
-	return ENOTSUP;
-}
-
+	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;
+}
+
+
+/* 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)
+{
+	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), );
+}
