changeset 67:98aee9a4d101

some functions added in the message module, not complete yet
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 08 Jul 2008 17:29:18 +0900
parents 1bdc97dbb28e
children 19632505658f
files include/waaad/message-api.h waaad/message.c
diffstat 2 files changed, 475 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/include/waaad/message-api.h	Tue Jul 08 17:27:52 2008 +0900
+++ b/include/waaad/message-api.h	Tue Jul 08 17:29:18 2008 +0900
@@ -60,13 +60,16 @@
 typedef void	msg_t;		/* Pointer to a message object */
 typedef void	msg_avp_t;	/* Pointer to an AVP object */
 
+/* The protocol version */
+#define MSG_VERSION	1
+
 /* In the two following types, some fields are marked (READONLY). 
  * This means that the content of these fields will be overwritten by the daemon so modifying it is useless.
  */
 
 /* The following structure represents the header of a message. */
 typedef struct {
-	uint8_t		 msg_version;		/* (READONLY) Version of Diameter: must be 1. */
+	uint8_t		 msg_version;		/* (READONLY) Version of Diameter: must be MSG_VERSION (1). */
 	uint32_t	 msg_length;		/* (READONLY)(3 bytes) indicates the length of the message */
 	uint8_t		 msg_flags;		/* Message flags: CMD_FLAG_* */
 	command_code_t	 msg_code;		/* (3 bytes) the command-code. See dictionary-api.h for more detail */
@@ -95,12 +98,9 @@
 	MSG_BRW_WALK		/* This is equivalent to FIRST_CHILD or NEXT or PARENT->next, first that is not NULL. Use this to walk inside all AVPs. */
 } msg_dir_t;
 
-/* Flags for the msg_new function */
-#define MSG_NEW_FROM_TEMPLATE	0x01		/* When creating a message, also create AVPs from dictionary template. The values are not set */
-
-/* Flags for the msg_avp_new function */
-#define MSG_AVP_NEW_SETVAL	0x01		/* When creating an AVP, set its avp_data member to a valid storage area. Use this if you will set the value of the AVP. */
-
+/* Flags for the msg_new and msg_avp_new functions */
+#define MSGFL_FROM_TEMPLATE	0x01	/* When creating an object, if it can contain children, also create the children using the "template" values in the dictionary */
+#define MSGFL_MAX		MSGFL_FROM_TEMPLATE	/* The biggest valid flag value */
 
 
 #ifndef IN_EXTENSION
@@ -118,7 +118,7 @@
  *  found       : pointer to the element that has been found, if any, or NULL if no element was found / an error occurred.
  *
  * DESCRIPTION: 
- *   Retrieve location of modifiable data of a message.
+ *   Explore the content of a message object.
  *
  * RETURN VALUE:
  *  0      	: The location has been written.
@@ -186,7 +186,7 @@
  *
  * PARAMETERS:
  *  model 	: Pointer to a DICT_COMMAND dictionary object describing the message to create.
- *  flags	: combination of MSG_NEW_* flags.
+ *  flags	: combination of MSGFL_* flags.
  *  msg 	: Upon success, pointer to the new message is stored here.
  *
  * DESCRIPTION: 
@@ -205,7 +205,7 @@
  *
  * PARAMETERS:
  *  model 	: Pointer to a DICT_AVP dictionary object describing the avp to create.
- *  flags	: combination of MSG_AVP_NEW_* flags.
+ *  flags	: combination of MSGFL_* flags.
  *  avp 	: Upon success, pointer to the new avp is stored here.
  *
  * DESCRIPTION: 
@@ -225,7 +225,7 @@
  * PARAMETERS:
  *  avp 	: Pointer to a valid avp object with a NULL avp_data.
  *  value 	: pointer to a avp_value_t structure. The content will be COPIED into the internal storage area. 
- *		 If data type is an octet string, the string is not copied!
+ *		 If data type is an octetstring, the data is also copied.
  *
  * DESCRIPTION: 
  *   Initialize the avp_data field of an AVP object.
--- a/waaad/message.c	Tue Jul 08 17:27:52 2008 +0900
+++ b/waaad/message.c	Tue Jul 08 17:29:18 2008 +0900
@@ -40,89 +40,473 @@
  */
 
 #include <errno.h>
+#include <string.h>
+#include <assert.h>
 
 #include "waaad-internal.h"
 
 /* These types are internal to this module. It represents the "real" content of msg_t and msg_avp_t objects. */
 
+/* Forward declaration */
+struct _msg_avp_chain;
+
+/* List structure */
+typedef struct _msg_list {
+	struct _msg_list      *next;  /* Next element in the list */
+	struct _msg_list      *prev;  /* Previous element in the list */
+	struct _msg_list      *head;  /* Pointer to the sentinel of this list */
+	struct _msg_avp_chain *top;   /* the head of the current object */
+	rule_position_t	       pos;   /* The position rule of this object, if any, otherwise 0. */
+} _msg_list_t;
+
+typedef enum {
+	_MSG_MSG = 1, 
+	_MSG_AVP
+} _msg_objtype_t;
+
 /* The following structure is used to represent the chaining of AVPs in a message or a grouped AVP. */
 typedef struct _msg_avp_chain {
-	struct _msg_avp_chain	*mac_parent;	/* The parent object of this list, or NULL if this is the message header */
-	struct _msg_avp_chain	*mac_prev;	/* The previous AVP at this level, or NULL if this is first element. */
-	struct _msg_avp_chain	*mac_next;	/* The following AVP at this level, or NULL if this is last element. */
-	struct _msg_avp_chain	*mac_fch;	/* The first child element under this object, or NULL if no child. */
-	struct _msg_avp_chain	*mac_lch;	/* The last child element under this object, or NULL if no child. */
+	_msg_list_t		chaining;	/* Chaining information at this level. */
+	_msg_list_t		children;	/* sentinel for the children of this object */
+	_msg_objtype_t		type;		/* Type of this object, _MSG_MSG or _MSG_AVP */
 } _msg_avp_chain_t;
 
-/* The following structure represents an AVP in a message. */
+/* Some details about chaining:
+ *
+ *  A message is made of a header ( _msg_t ) and 0 or more AVPs (_msg_avp_t ).
+ * The structure is a kind of tree, where AVPs can contain other AVPs (grouped AVPs).
+ * Exemple:
+ * msg
+ *  |-avp
+ *  |-gavp
+ *  |   |-avp
+ *  |   |-avp
+ *  |   \-avp
+ *  |-avp
+ *  \-avp
+ *
+ * Each "component" (msg or avp) structure begins with a _msg_avp_chain_t component.
+ * The element at the top of the hierarchy (msg in our example) has all the fields of its "chaining" equal to the same value.
+ *
+ * All elements at the same level are linked by their "chaining" list.
+ * The "children" list is the sentinel for the lists of children of this element.
+ */
+
+/* The following definitions are used to avoid programming errors. */
+#define _MSG_MSG_EYEC	(0x11355463)
+#define _MSG_AVP_EYEC	(0x11355467)
+
+/* The following structure represents an AVP instance. */
 typedef struct {
-	_msg_avp_chain_t avp_chain;		/* Chaining information of this AVP in the message */
+	_msg_avp_chain_t avp_chain;		/* Chaining information of this AVP */
+	int		 avp_eyec;		/* Must be equal to _MSG_AVP_EYEC */
 	dict_object_t 	*avp_model;		/* If not NULL, pointer to the dictionary object of this avp */
+	msg_avp_data_t	 avp_public;		/* AVP data that can be managed by extensions */
+	
 	char		*avp_source;		/* If the message was parsed from a buffer, pointer to the AVP start in the buffer. */
-	msg_avp_data_t	 avp_public;		/* AVP data that can be managed by extensions */
 	avp_value_t	 avp_storage;		/* To avoid many alloc/free, store the integer values here and set avp_public.avp_data to &storage */
+	int		 avp_mustfreeos;	/* 1 if an octetstring is malloc'd in avp_storage and must be freed. */
 } _msg_avp_t;
 
-/* The following structure represents the header of a message, and contains pointer to the whole message. */
+/* Macro to cast a msg_avp_t */
+#define _A(_x) ((_msg_avp_t *)(_x))
+/* Check the type and eyecatcher */
+#define CHECK_AVP(_x) ((_A(_x)->avp_chain.type == _MSG_AVP) && (_A(_x)->avp_eyec == _MSG_AVP_EYEC))
+
+/* The following structure represents an instance of a message (command and children AVPs). */
 typedef struct {
-	_msg_avp_chain_t msg_avps;		/* List of the AVPs in the message */
+	_msg_avp_chain_t msg_chain;		/* List of the AVPs in the message */
+	int		 msg_eyec;		/* Must be equal to _MSG_MSG_EYEC */
 	dict_object_t 	*msg_model;		/* If not NULL, pointer to the dictionary object of this message */
 	msg_data_t	 msg_public;		/* Message data that can be managed by extensions. */
 	
-	/* Meta-data */
 	char		*msg_source;		/* If the message was parsed from a buffer, pointer to the message start in the buffer. */
-	int		 msg_routable;		/* Is this a routable message? */
-	
+	int		 msg_routable;		/* Is this a routable message? (0: undef, 1: routable, 2: non routable) */
 } _msg_t;
 
+/* Macro to cast a msg_avp_t */
+#define _M(_x) ((_msg_t *)(_x))
+/* Check the type and eyecatcher */
+#define CHECK_MSG(_x) ((_M(_x)->msg_chain.type == _MSG_MSG) && (_M(_x)->msg_eyec == _MSG_MSG_EYEC))
 
-/* Initialize the module */
-int msg_init ( void )
+#define VALIDATE_OBJ(_x) ( (CHECK_MSG(_x)) || (CHECK_AVP(_x)) )
+
+
+/* Macro to validate a MSGFL_ value */
+#define CHECK_MSGFL(_fl) ( ((_fl) & (- (MSGFL_MAX << 1) )) == 0 )
+
+/* initial sizes of AVP from their types, in bytes. -1 for unknown sizes */
+int avp_sizes[] = { 
+	-1,	/* AVP_TYPE_GROUPED: size is dynamic */
+	-1,	/* AVP_TYPE_OCTETSTRING: size is dynamic */
+	 4,	/* AVP_TYPE_INTEGER32: size is dynamic */
+	 8,	/* AVP_TYPE_INTEGER64: size is dynamic */
+	 4,	/* AVP_TYPE_UNSIGNED32: size is dynamic */
+	 8,	/* AVP_TYPE_UNSIGNED64: size is dynamic */
+	 4,	/* AVP_TYPE_FLOAT32: size is dynamic */
+	 8	/* AVP_TYPE_FLOAT64: size is dynamic */
+};
+#define CHECK_BASETYPE( _type ) ( (_type <= AVP_TYPE_MAX) && (_type >= 0) )
+#define GETINITIALSIZE( _type ) (avp_sizes[ CHECK_BASETYPE(_type) ? _type : 0])
+
+/***************************************************************************************************************/
+
+static void item_unlink(_msg_list_t * item);
+
+/* Initialize a _msg_list_t structure */
+static void init_list(_msg_list_t * list, _msg_avp_chain_t * top)
+{
+	list->next = list;
+	list->prev = list;
+	list->head = list;
+	list->top  = top;
+}
+
+/* Initialize a _msg_avp_chain_t structure */
+static void init_chain(_msg_avp_chain_t * chain, int type)
 {
-	TRACE_DEBUG (INFO, "Message module initialized");
-	TRACE_DEBUG (FULL, "@@@ Not implemented yet." );
+	init_list( &chain->chaining, chain);
+	init_list( &chain->children, chain);
+	chain->type = type;
+}
+
+/* Initialize a new AVP object */
+static void init_avp ( _msg_avp_t * avp )
+{
+	memset(avp, 0, sizeof(_msg_avp_t));
+	init_chain( &avp->avp_chain, _MSG_AVP);
+	avp->avp_eyec = _MSG_AVP_EYEC;
+}
+	
+/* Initialize a new MSG object */
+static void init_msg ( _msg_t * msg )
+{
+	memset(msg, 0, sizeof(_msg_t));
+	init_chain( &msg->msg_chain, _MSG_MSG);
+	msg->msg_eyec = _MSG_MSG_EYEC;
+}
+
+/* Destroy and free an AVP or message */
+static int destroy_obj (_msg_avp_chain_t * obj )
+{
+	/* Check the parameter is a valid object */
+	if (!VALIDATE_OBJ(obj)) {
+		TRACE_DEBUG(FULL, "Received an invalid msg or avp. EINVAL");
+		return EINVAL;
+	}
+
+	/* Only accept objects with no linked children */
+	if (obj->children.next != &obj->children) {
+		TRACE_DEBUG(FULL, "Received an AVP or command with children. EINVAL");
+		return EINVAL;
+	}
+	
+	/* Unlink this object if needed */
+	item_unlink( &obj->chaining );
+	
+	/* Free the octetstring if needed */
+	if ((obj->type == _MSG_AVP) && (_A(obj)->avp_mustfreeos == 1)) {
+		free(_A(obj)->avp_storage.os.data);
+	}
+	
+	/* free the object */
+	free(obj);
+	
 	return 0;
 }
 
-/* End of the module */
-int msg_fini ( void )
+/***************************************************************************************************************/
+
+/* Insert an item in a list, ordered by positions. */
+static void insert_in_list_pos(_msg_list_t * sentinel, _msg_list_t * item)
+{
+	_msg_list_t *li;
+	
+	/* In case the item has no "position", assign the optional placement */
+	if (!item->pos)
+		item->pos = RULE_OPTIONAL;
+	
+	/* Do some sanity checkings */
+	assert(sentinel->head == sentinel); /* the sentinel is really a sentinel */
+	assert(item->head == item); /* the item is not linked already */
+	
+	/* Find the place where the new item should be inserted. */
+	for (li = sentinel; (li->next != sentinel) && (li->next->pos <= item->pos); li = li->next);
+	
+	/* Now insert it here */
+	item->head = sentinel;
+	item->next = li->next;
+	item->prev = li;
+	li->next = item;
+	item->next->prev = item;
+}
+
+#define INSERT_after( __ref, __new ) {	\
+	(__new)->next = (__ref)->next;	\
+	(__new)->prev = (__ref);	\
+	(__ref)->next->prev = (__new);	\
+	(__ref)->next = (__new);	\
+	(__new)->head = (__ref)->head;	\
+}
+#define INSERT_before( __ref, __new ) {	\
+	(__new)->prev = (__ref)->prev;	\
+	(__new)->next = (__ref);	\
+	(__ref)->prev->next = (__new);	\
+	(__ref)->prev = (__new);	\
+	(__new)->head = (__ref)->head;	\
+}
+	
+/* Unlink an item from a list */
+static void item_unlink(_msg_list_t * item)
+{
+	/* Check first that this item is linked */
+	if (item->head == item)
+		return;
+	
+	/* remove from the list */
+	item->next->prev = item->prev;
+	item->prev->next = item->next;
+	
+	/* sanitize the local values */
+	item->next = item;
+	item->prev = item;
+	item->head = item;
+}
+	
+
+/* Destroy an object and all its children */
+static void destroy_tree(_msg_avp_chain_t * obj)
+{
+	_msg_list_t *sub;
+	
+	/* Destroy any subtree */
+	while ( (sub = obj->children.next) != &obj->children)
+		destroy_tree(sub->top);
+	
+	/* Then unlink and destroy the object */
+	destroy_obj(obj);
+}
+
+
+/***************************************************************************************************************/
+
+/* We use this structure to pass arguments to create_child_avp when called in dict_iterate_rules */
+typedef struct {
+	_msg_avp_chain_t * parent;
+	int flags;
+} cb_data_t;
+
+/* For each rule of a parent object, this function is called for creations from templates */
+static int create_child_avp(void *data, dict_rule_data_t *rule)
+{
+	int ret = 0, i;
+	cb_data_t *_data = (cb_data_t *)data;
+
+	TRACE_DEBUG(FULL, "enter (%p, %p)", _data, rule);
+	
+	/* Create as many children as the template says */
+	for (i=0; i<rule->rule_template; i++) {
+		msg_avp_t * child = NULL;
+	
+		/* Create the child AVP -- eventually a tree of AVPs */
+		ret = msg_avp_new(rule->rule_avp, _data->flags, &child);
+		if (ret != 0) {
+			TRACE_DEBUG(FULL, "Creation of child AVP failed: %d (%s)", ret, strerror(ret));
+			return ret;
+		}
+
+		/* If no error occurred, link this child into the parent's hierarchy */
+		_A(child)->avp_chain.chaining.pos = rule->rule_position;
+		insert_in_list_pos(&(_data->parent->children), &(_A(child)->avp_chain.chaining));
+	}
+		
+	/* We're done with this rule entry */
+	return 0;
+}
+/***************************************************************************************************************/
+
+/* Create a new AVP instance */
+int msg_avp_new ( dict_object_t * model, int flags, msg_avp_t ** avp )
 {
-	TRACE_DEBUG (FULL, "Unloading message module...");
-	TRACE_DEBUG (FULL, "@@@ Not implemented yet." );
+	int ret=0;
+	_msg_avp_t *new = NULL;
+	dict_object_type_t dicttype;
+	dict_avp_data_t    dictavpdata;
+	
+	TRACE_DEBUG (FULL, "Creating an AVP instance (%p, %x, %p)", model, flags, avp );
+	
+	/* Check the parameters */
+	if ((!model) || (!avp) || (!CHECK_MSGFL(flags))) {
+		TRACE_DEBUG (FULL, "EINVAL." );
+		return EINVAL;
+	}
+	
+	ret = dict_gettype(model, &dicttype);
+	if (ret || (dicttype != DICT_AVP)) {
+		TRACE_DEBUG (FULL, "(%d, %d) -> EINVAL.", ret, dicttype );
+		return EINVAL;
+	}
+	
+	ret = dict_getval(model, &dictavpdata);
+	if (ret != 0) {
+		TRACE_DEBUG (FULL, "Error occurred in dict_getval: %d (%s).", ret, strerror(ret) );
+		return EINVAL;
+	}
+	
+	/* Create a new object */
+	new = (_msg_avp_t *) malloc (sizeof(_msg_avp_t));
+	if (!new) {
+		log_error("Unable to allocate enough memory: %s\n", strerror(errno));
+		TRACE_DEBUG (FULL, "malloc failed.");
+		return ENOMEM;
+	}
+	
+	/* Initialize the fields */
+	init_avp(new);
+	new->avp_model = model;
+	
+	new->avp_public.avp_code    = dictavpdata.avp_code;
+	new->avp_public.avp_flags   = dictavpdata.avp_flag_val;
+	new->avp_public.avp_datalen = GETINITIALSIZE(dictavpdata.avp_basetype);
+	new->avp_public.avp_vendor  = dictavpdata.avp_vendor;
+	
+	/* Create the children from template if needed */
+	if ((flags & MSGFL_FROM_TEMPLATE) && (dictavpdata.avp_basetype == AVP_TYPE_GROUPED)) {
+		cb_data_t data = { (_msg_avp_chain_t *)new, flags};
+		ret = dict_iterate_rules ( model, &data, create_child_avp );
+		if (ret != 0) {
+			TRACE_DEBUG (FULL, "dict_iterate_rules failed (%s).", strerror(ret) );
+			destroy_tree((_msg_avp_chain_t *)new);
+			return ret;
+		}
+	}
+	
+	/* The new object is ready, return */
+	*avp = new;
+	return 0;
+}
+
+/* Create a new message instance */
+int msg_new ( dict_object_t * model, int flags, msg_t ** msg )
+{
+	int ret=0;
+	_msg_t *new = NULL;
+	dict_object_type_t dicttype;
+	dict_cmd_data_t    dictdata;
+	
+	TRACE_DEBUG (FULL, "Creating a message instance (%p, %x, %p)", model, flags, msg );
+	
+	/* Check the parameters */
+	if ((!model) || (!msg) || (!CHECK_MSGFL(flags))) {
+		TRACE_DEBUG (FULL, "EINVAL." );
+		return EINVAL;
+	}
+	
+	ret = dict_gettype(model, &dicttype);
+	if (ret || (dicttype != DICT_COMMAND)) {
+		TRACE_DEBUG (FULL, "(%d, %d) -> EINVAL.", ret, dicttype );
+		return EINVAL;
+	}
+	
+	ret = dict_getval(model, &dictdata);
+	if (ret != 0) {
+		TRACE_DEBUG (FULL, "Error occurred in dict_getval: %d (%s).", ret, strerror(ret) );
+		return EINVAL;
+	}
+	
+	/* Create a new object */
+	new = (_msg_t *) malloc (sizeof(_msg_t));
+	if (!new) {
+		log_error("Unable to allocate enough memory: %s\n", strerror(errno));
+		TRACE_DEBUG (FULL, "malloc failed.");
+		return ENOMEM;
+	}
+	
+	/* Initialize the fields */
+	init_msg(new);
+	new->msg_model = model;
+	
+	new->msg_public.msg_version	= MSG_VERSION;
+	new->msg_public.msg_length	= 0;	/* This will be updated later */
+	new->msg_public.msg_flags	= dictdata.cmd_flag_val;
+	new->msg_public.msg_code	= dictdata.cmd_code;
+	
+	/* Create the children from template if needed */
+	if (flags & MSGFL_FROM_TEMPLATE) {
+		cb_data_t data = { (_msg_avp_chain_t *)new, flags};
+		ret = dict_iterate_rules ( model, &data, create_child_avp );
+		if (ret != 0) {
+			TRACE_DEBUG (FULL, "dict_iterate_rules failed (%s).", strerror(ret) );
+			destroy_tree((_msg_avp_chain_t *)new);
+			return ret;
+		}
+	}
+	
+	/* The new object is ready, return */
+	*msg = new;
+	return 0;
+}
+
+/* Add an AVP into a tree */
+int msg_avp_add ( void * reference, msg_dir_t dir, msg_avp_t *avp)
+{
+	/* Check the parameters */
+	if (!VALIDATE_OBJ(reference)) {
+		TRACE_DEBUG(FULL, "Received an invalid msg or avp. EINVAL");
+		return EINVAL;
+	}
+	if (!CHECK_AVP(avp)) {
+		TRACE_DEBUG(FULL, "Received an invalid avp. EINVAL");
+		return EINVAL;
+	}
+	if (_A(avp)->avp_chain.chaining.head != &_A(avp)->avp_chain.chaining) {
+		TRACE_DEBUG(FULL, "Received an avp already chained. EINVAL");
+		return EINVAL;
+	}
+	
+	/* Now insert */
+	switch (dir) {
+		case MSG_BRW_NEXT:
+			/* Check the reference is an AVP */
+			if (((_msg_avp_chain_t *) reference)->type != _MSG_AVP) {
+				TRACE_DEBUG(FULL, "Received an invalid reference type. EINVAL");
+				return EINVAL;
+			}
+			/* Insert the new avp after the reference */
+			INSERT_after( &_A(reference)->avp_chain.chaining, &_A(avp)->avp_chain.chaining );
+			break;
+
+		case MSG_BRW_PREV:
+			/* Check the reference is an AVP */
+			if (((_msg_avp_chain_t *) reference)->type != _MSG_AVP) {
+				TRACE_DEBUG(FULL, "Received an invalid reference type. EINVAL");
+				return EINVAL;
+			}
+			/* Insert the new avp before the reference */
+			INSERT_before( &_A(reference)->avp_chain.chaining, &_A(avp)->avp_chain.chaining );
+			break;
+
+		case MSG_BRW_FIRST_CHILD:
+			/* Insert the new avp after the children sentinel */
+			INSERT_after( &_A(reference)->avp_chain.children, &_A(avp)->avp_chain.chaining );
+			break;
+
+		case MSG_BRW_LAST_CHILD:
+			/* Insert the new avp before the children sentinel */
+			INSERT_before( &_A(reference)->avp_chain.children, &_A(avp)->avp_chain.chaining );
+			break;
+
+		default:
+			/* Other directions are invalid */
+			TRACE_DEBUG(FULL, "Received an invalid direction. EINVAL");
+			return EINVAL;
+	}
+			
 	return 0;
 }
 
 
-int msg_parse_buffer ( char * buffer, msg_t ** msg )
-{
-	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
-}
 
-int msg_bufferize ( msg_t * msg, char ** buffer, int * is_routable )
-{
-	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
-}
-
-int msg_new ( dict_object_t * model, int flags, msg_t ** msg )
-{
-	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
-}
-
-
-int msg_avp_new ( dict_object_t * model, int flags, msg_avp_t ** avp )
-{
-	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
-}
-
-int msg_avp_add ( void * reference, msg_dir_t dir, msg_avp_t *avp)
-{
-	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
-	return ENOTSUP;
-}
 
 int msg_parse_dict ( msg_t * msg )
 {
@@ -202,5 +586,35 @@
 	return ENOTSUP;
 }
 
+int msg_parse_buffer ( char * buffer, msg_t ** msg )
+{
+	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
+	return ENOTSUP;
+}
+
+int msg_bufferize ( msg_t * msg, char ** buffer, int * is_routable )
+{
+	TRACE_DEBUG (FULL, "@@@ %s: not implemented yet.", __FUNCTION__ );
+	return ENOTSUP;
+}
+
+
 
 
+/* Initialize the module */
+int msg_init ( void )
+{
+	/* There are no globals to initialize in this module... */
+	TRACE_DEBUG (INFO, "Message module initialized");
+	return 0;
+}
+
+/* End of the module */
+int msg_fini ( void )
+{
+	/* Nothing to do here */
+	TRACE_DEBUG (FULL, "Unloading message module...");
+	return 0;
+}
+
+
"Welcome to our mercurial repository"