view include/waaad/message-api.h @ 381:3591d0486a2c

Allow NULL model in msg_new
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 26 May 2009 17:17:05 +0900
parents bad2424e6d0f
children 860f41038ea2
line wrap: on
line source

/*********************************************************************************************************
* Software License Agreement (BSD License)                                                               *
* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
*													 *
* Copyright (c) 2008, WIDE Project and NICT								 *
* All rights reserved.											 *
* 													 *
* Redistribution and use of this software in source and binary forms, with or without modification, are  *
* permitted provided that the following conditions are met:						 *
* 													 *
* * Redistributions of source code must retain the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer.										 *
*    													 *
* * Redistributions in binary form must reproduce the above 						 *
*   copyright notice, this list of conditions and the 							 *
*   following disclaimer in the documentation and/or other						 *
*   materials provided with the distribution.								 *
* 													 *
* * Neither the name of the WIDE Project or NICT nor the 						 *
*   names of its contributors may be used to endorse or 						 *
*   promote products derived from this software without 						 *
*   specific prior written permission of WIDE Project and 						 *
*   NICT.												 *
* 													 *
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 	 *
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 	 *
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.								 *
*********************************************************************************************************/

/* This file contains the definitions of types and functions to manipulate Diameter messages,
 and that can be called by extensions. */
 
/* Note that the message structure is not protected against concurrent accesses. Therefore, no more than one 
 thread must modify a message at the same time. In the case where parallel processing is required, the protection
 of the data must be implemented externally to the msg_* structures.
 */
 
#ifndef _MESSAGE_API_H
#define _MESSAGE_API_H

#include <stddef.h>
#include <waaad/dictionary-api.h>

/*
 ***************************************************************************
 *
 * Message API functions and types
 *
 *
 ***************************************************************************
 */

/* The following types are opaque to extensions */
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 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 */
	application_id_t msg_appl;		/* The application issuing this message */
	uint32_t	 msg_hbhid;		/* The Hop-by-Hop identifier of the message */
	uint32_t	 msg_eteid;		/* The End-to-End identifier of the message */
} msg_data_t;

/* The following structure represents the header of an AVP in a message. */
typedef struct {
	avp_code_t	 avp_code;		/* the AVP Code */
	uint8_t		 avp_flags;		/* AVP_FLAG_* flags */
	uint32_t	 avp_len;		/* (READONLY)(Only 3 bytes are used) the length of the AVP as described in the RFC */
	vendor_id_t	 avp_vendor;		/* Only used if AVP_FLAG_VENDOR is present */
	avp_value_t	*avp_data;		/* pointer to the data of the AVP. NULL means that the value is not set / not understood.
						   One should not directly change this value. See the msg_avp_setvalue function instead.
						   The content of the pointed structure can be changed directly, with this restriction:
						     if the AVP is an OctetString, and you change the value of the pointer avp_data->os.data, then
						     you must call free() on the old value, and the new one must be free()-able.
						 */
} msg_avp_data_t;


/* The following enum is used to browse inside message */
typedef enum {
	MSG_BRW_NEXT = 1,	/* Get the next element at the same level, or NULL if this is the last element. */
	MSG_BRW_PREV,		/* Get the previous element at the same level, or NULL if this is the first element. */
	MSG_BRW_FIRST_CHILD,	/* Get the first child AVP of this element, if any. */
	MSG_BRW_LAST_CHILD,	/* Get the last child AVP of this element, if any. */
	MSG_BRW_PARENT,		/* Get the parent element of this element, if any. Only the msg_t object has no parent. */
	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 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_ALLOW_ETEID	0x02	/* When creating a message, a new end-to-end ID is allocated and set in the message */
#define MSGFL_MAX		MSGFL_ALLOW_ETEID	/* The biggest valid flag value */


#ifndef IN_EXTENSION

/***************************************/
/*   Generic message manipulation      */
/***************************************/

/*
 * FUNCTION:	msg_browse
 *
 * PARAMETERS:
 *  reference 	: Pointer to a valid msg_t or msg_avp_t.
 *  dir         : direction for browsing
 *  found       : If not NULL, set to the element that has been found, if any, or NULL if no element was found / an error occurred.
 *  depth	: If not NULL, points to an integer representing the "depth" of this object in the tree. This is a relative value.
 *
 * DESCRIPTION: 
 *   Explore the content of a message object. If "found" is null, only error checking is performed.
 *  If "depth" is provided, it is updated as follow on successful function return:
 *   - not modified for MSG_BRW_NEXT and MSG_BRW_PREV.
 *   - *depth = *depth + 1 for MSG_BRW_FIRST_CHILD and MSG_BRW_LAST_CHILD.
 *   - *depth = *depth - 1 for MSG_BRW_PARENT.
 *   - *depth = *depth - X for MSG_BRW_WALK, with X between -1 (returned the 1st child) and +N (returned the Nth parent's next).
 *
 * RETURN VALUE:
 *  0      	: The location has been written.
 *  EINVAL 	: A parameter is invalid.
 *  ENOENT	: No element has been found where requested, and "found" was NULL. 
 */
int msg_browse ( void * reference, msg_dir_t dir, void ** found, int * depth );

/*
 * FUNCTION:	msg_search_avp
 *
 * PARAMETERS:
 *  msg 	: The message structure in which to search the AVP.
 *  what 	: The dictionary model of the AVP to search.
 *  avp		: location where the AVP reference is stored if found.
 *
 * DESCRIPTION: 
 *   Search the first top-level AVP of a given model inside a message.
 * Note: only the first instance of the AVP is returned by this function.
 * Note: only top-level AVPs are searched, not inside grouped AVPs.
 * Use msg_browse if you need more advanced research features.
 *
 * RETURN VALUE:
 *  0      	: The AVP has been found.
 *  EINVAL 	: A parameter is invalid.
 *  ENOENT	: No AVP has been found, and "avp" was NULL (otherwise, *avp is set to NULL and 0 returned).
 */
int msg_search_avp ( msg_t * msg, dict_object_t * what, msg_avp_t ** avp );

/*
 * FUNCTION:	msg_model
 *
 * PARAMETERS:
 *  reference 	: Pointer to a valid msg_t or msg_avp_t.
 *  model       : on success, pointer to the dictionary model of this command or AVP. NULL otherwise.
 *
 * DESCRIPTION: 
 *   Retrieve the dictionary object describing this message or avp. If the object is unknown or the msg_parse_dict has not been called,
 *  NULL is put in *model.
 *
 * RETURN VALUE:
 *  0      	: The model has been set.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_model ( void * reference, dict_object_t ** model );

/*
 * FUNCTION:	msg_data
 *
 * PARAMETERS:
 *  msg 	: Pointer to a valid message object.
 *  pdata 	: Upon success, pointer to the msg_data_t structure of this message. The fields may be changed. All data is in host byte order.
 *
 * DESCRIPTION: 
 *   Retrieve location of modifiable data of a message. 
 *
 * RETURN VALUE:
 *  0      	: The location has been written.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_data ( msg_t *msg, msg_data_t **pdata );

/*
 * FUNCTION:	msg_avp_data
 *
 * PARAMETERS:
 *  avp 	: Pointer to a valid avp object.
 *  pdata 	: Upon success, pointer to the msg_avp_data_t structure of this avp. The fields may be changed. All data is in host byte order.
 *
 * DESCRIPTION: 
 *   Retrieve location of modifiable data of an avp. 
 *
 * RETURN VALUE:
 *  0      	: The location has been written.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_avp_data ( msg_avp_t *avp, msg_avp_data_t **pdata );



/***************************************/
/*   Sending a message on the network  */
/***************************************/

/*
 * FUNCTION:	msg_send
 *
 * PARAMETERS:
 *  msg 	: Location of the message to be sent on the network (set to NULL on function return).
 *  anscb	: A callback to be called with answer (if msg is a request) (optional)
 *  anscb_data	: opaque data to be passed back to the anscb when it is called.
 *
 * DESCRIPTION: 
 *   Sends a message on the network. For requests, the end-to-end id must be set (see msg_get_eteid).
 * For answers, the message must be created with function msg_new_answ.
 *
 * The routing module will handle sending to the correct peer, usually based on the Destination-Realm AVP.
 *
 * If the msg is a request, there are two ways of receiving the answer:
 *  - either having registered a callback in the dispatch module (disp_register)
 *  - or provide a callback as parameter here. If such callback is provided, it is called before the dispatch callbacks.
 *    The prototype for this callback function is:
 *     void anscb(void * data, msg_t ** answer)
 *	where:
 *		data   : opaque data that was registered along with the callback.
 *		answer : location of the message pointer.
 *      note1: on function return, if *answer is not NULL, the message is passed to the dispatch module for regular callbacks.
 *	       otherwise, the callback must take care of freeing the message.
 *	note2: the opaque data is not freed by the daemon in any case, extension should ensure clean handling.
 * 
 * If no callback is registered to handle an answer, the message is discarded and an error is logged.
 *
 * RETURN VALUE:
 *  0      	: The message has been send.
 *  EINVAL 	: A parameter is invalid (ex: anscb provided but message is not a request).
 *  ...
 */
int msg_send ( msg_t ** msg, void (*anscb)(void *, msg_t **), void * data );


/***************************************/
/*   Message creation and destruction  */
/***************************************/

/*
 * FUNCTION:	msg_new
 *
 * PARAMETERS:
 *  model 	: Pointer to a DICT_COMMAND dictionary object describing the message to create, or NULL.
 *  flags	: combination of MSGFL_* flags.
 *  msg 	: Upon success, pointer to the new message is stored here.
 *
 * DESCRIPTION: 
 *   Create a new Diameter message structure. 
 *
 * RETURN VALUE:
 *  0      	: The message is created.
 *  EINVAL 	: A parameter is invalid.
 *  (other standard errors may be returned, too, with their standard meaning. Example:
 *    ENOMEM 	: Memory allocation for the new message failed.)
 */
int msg_new ( dict_object_t * model, int flags, msg_t ** msg );

/*
 * FUNCTION:	msg_new_answ
 *
 * PARAMETERS:
 *  msg 	: Location of the request message on function entry, and answer upon return.
 *  flags	: combination of MSGFL_* flags.
 *
 * DESCRIPTION: 
 *   Create a new anwer message corresponding to a query.
 *   Note that upon return, the query object is no longer available. It is anyway safe to keep a copy
 *  of a pointer to this query, as long as it is not modified or freed.
 *   Note also that no AVP value is set in the answer. The calling app must create the Session-Id AVP, 
 *  Origin-Host, and so on...
 *
 * RETURN VALUE:
 *  0      	: The answer message is created.
 *  EINVAL 	: A parameter is invalid.
 *  (other standard errors may be returned, too, with their standard meaning. Example:
 *    ENOMEM 	: Memory allocation for the new message failed.)
 */
int msg_new_answ ( msg_t ** msg, int flags );

/*
 * FUNCTION:	msg_avp_new
 *
 * PARAMETERS:
 *  model 	: Pointer to a DICT_AVP dictionary object describing the avp to create.
 *  flags	: combination of MSGFL_* flags.
 *  avp 	: Upon success, pointer to the new avp is stored here.
 *
 * DESCRIPTION: 
 *   Create a new AVP instance.
 *
 * RETURN VALUE:
 *  0      	: The AVP is created.
 *  EINVAL 	: A parameter is invalid.
 *  (other standard errors may be returned, too, with their standard meaning. Example:
 *    ENOMEM 	: Memory allocation for the new avp failed.)
 */
int msg_avp_new ( dict_object_t * model, int flags, msg_avp_t ** avp );

/*
 * FUNCTION:	msg_avp_setvalue
 *
 * PARAMETERS:
 *  avp 	: Pointer to a valid avp object with a NULL avp_data. The model must be known.
 *  value 	: pointer to a avp_value_t structure. The content will be COPIED into the internal storage area. 
 *		 If data type is an octetstring, the data is also copied.
 * 		 If value is a NULL pointer, the previous data is erased and value is unset in the AVP.
 *
 * DESCRIPTION: 
 *   Initialize the avp_data field of an AVP object.
 *
 * RETURN VALUE:
 *  0      	: The avp_data has been set.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_avp_setvalue ( msg_avp_t *avp, avp_value_t *value );

/*
 * FUNCTION:	msg_avp_value_encode
 *
 * PARAMETERS:
 *  avp 	: Pointer to a valid avp object with a NULL avp_data. The model must be known.
 *  data 	: Pointer to the data that must be encoded as AVP value and stored in the AVP.
 *		 This is only valid for AVPs of a derived type and which type_data_encode callback is set.
 *
 * DESCRIPTION: 
 *   Initialize the avp_data field of an AVP object from formatted data, using the AVP's type encode function.
 *
 * RETURN VALUE:
 *  0      	: The avp_data has been set.
 *  EINVAL 	: A parameter is invalid.
 *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
 */
int msg_avp_value_encode ( void *data, msg_avp_t *avp );

/*
 * FUNCTION:	msg_avp_value_interpret
 *
 * PARAMETERS:
 *  avp 	: Pointer to a valid avp object with a non-NULL avp_data value.
 *  data 	: Upon success, formatted interpretation of the AVP value is stored here.
 *
 * DESCRIPTION: 
 *   Interpret the content of an AVP of Derived type and store the result in data pointer. The real type
 * of the data pointer is dependent on the AVP type. This function calls the type_data_interpret callback 
 * of the type.
 *
 * RETURN VALUE:
 *  0      	: The avp_data has been set.
 *  EINVAL 	: A parameter is invalid.
 *  ENOTSUP 	: There is no appropriate callback registered with this AVP's type.
 */
int msg_avp_value_interpret ( msg_avp_t *avp, void *data );

/*
 * FUNCTION:	msg_avp_add
 *
 * PARAMETERS:
 *  reference 	: Pointer to a valid msg_t or msg_avp_t.
 *  dir         : location where the new AVP should be inserted relative to the reference. MSG_BRW_PARENT and MSG_BRW_WALK are not valid.
 *  avp         : pointer to the AVP object that must be inserted.
 *
 * DESCRIPTION: 
 *   Retrieve location of modifiable data of a message.
 *
 * RETURN VALUE:
 *  0      	: The location has been written.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_avp_add ( void * reference, msg_dir_t dir, msg_avp_t *avp);

/*
 * FUNCTION:	msg_free
 *
 * PARAMETERS:
 *  object      : pointer to the message or AVP object that must be unlinked and freed.
 *  subtree	: Indicate if children AVP must also be freed.
 *
 * DESCRIPTION: 
 *   Unlink and free a message or AVP object.
 *  If the object is an AVP linked into a message, the AVP is removed before being freed.
 *  If the subtree parameter is 0, and the object has children AVPs, an error is returned.
 *  If the subtree parameter is not 0, any children AVP is also freed.
 *
 * RETURN VALUE:
 *  0      	: The message has been freed.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_free ( void * object, int subtree );

/*
 * FUNCTION:	msg_update_length
 *
 * PARAMETERS:
 *  ref 	: Pointer to a valid msg_t or msg_avp_t. 
 *
 * DESCRIPTION: 
 *   Update the length field of the object passed as parameter. This can be a message or an AVP.
 *  As a side effect, all children objects are also updated. Therefore, all avp_data fields of
 * the children objects must be set, or an error will occur.
 *
 * RETURN VALUE:
 *  0      	: The location has been written.
 *  EINVAL 	: A parameter is invalid.
 */
int msg_update_length ( void * object );


/***************************************/
/*   Message  reception                */
/***************************************/

/*
 * FUNCTION:	msg_avp_getrawdata
 *
 * PARAMETERS:
 *  avp		: An avp object which model could not be found in the dictionary by msg_parse_dict.
 *  data	: pointer to the data buffer of this AVP. The size of the buffer is in the avp_datalen field of the AVP.
 *
 * DESCRIPTION: 
 *   This function provides an access to the data received in an unknown AVP.
 *  If called on an AVP for which msg_parse_dict was not yet called, or the model was found, the data pointer is set to NULL on return.
 *
 * RETURN VALUE:
 *  0      	: The data parameter now points to the received data.
 *  EINVAL 	: A parameter is invalid for this operation.
 */
int msg_avp_getrawdata ( msg_avp_t *avp, unsigned char **data );


/***************************************/
/*   Message  reception or sending     */
/***************************************/

/*
 * FUNCTION:	msg_parse_rules
 *
 * PARAMETERS:
 *  object	: A msg_t or msg_avp_t object that must be verified.
 *  rule	: if not NULL, the first conflicting rule will be put here if a conflict is found.
 *
 * DESCRIPTION: 
 *   Check that the children of the object do not conflict with the dictionary rules.
 *
 * RETURN VALUE:
 *  0      	: The message has been fully parsed as described.
 *  EBADMSG	: A conflict was detected, or a mandatory AVP is unknown in the dictionary.
 *  EINVAL 	: the msg parameter is invalid for this operation.
 *  ENOMEM	: Unable to allocate enough memory to complete the operation.
 */
int msg_parse_rules ( void * object, dict_object_t ** rule);


/***************************************/
/*   Others                            */
/***************************************/

/*
 * FUNCTION:	msg_get_eteid
 *
 * PARAMETERS:
 *  -
 *
 * DESCRIPTION: 
 *   Get a new unique End-to-end id value for the local peer.
 *
 * RETURN VALUE:
 *  The new assigned value. No error code is defined.
 */
uint32_t msg_get_eteid ( void );


#endif /* ! IN_EXTENSION */

/* The version of this API, to check binary compatibility -- increment each time a change is made in api_msg_t */
#define WAAAD_API_MSG_VER	1

/* Now define the type of the structure that contains the callback to pass to extensions */
typedef struct {
	/* The header is common to all sub-API pieces */
	size_t	length;		/* The size of this structure, may be useful for extensions not using the facility */
	int	version;	/* The version of this API/ABI, must be WAAAD_API_MSG_VER */
	
	/* the remaining is message-specific */
	int (*msg_browse)              ( void * reference, msg_dir_t dir, void ** found, int * depth );
	int (*msg_search_avp)          ( msg_t * msg, dict_object_t * what, msg_avp_t ** avp );
	int (*msg_model)               ( void * reference, dict_object_t ** model );
	int (*msg_data)                ( msg_t *msg, msg_data_t **pdata );
	int (*msg_avp_data)            ( msg_avp_t *avp, msg_avp_data_t **pdata );
	int (*msg_send)                ( msg_t ** msg, void (*anscb)(void *, msg_t **), void * data );
	int (*msg_new)                 ( dict_object_t * model, int flags, msg_t ** msg );
	int (*msg_new_answ)            ( msg_t ** msg, int flags );
	int (*msg_avp_new)             ( dict_object_t * model, int flags, msg_avp_t ** avp );
	int (*msg_avp_setvalue)        ( msg_avp_t *avp, avp_value_t *value );
	int (*msg_avp_value_encode)    ( void *data, msg_avp_t *avp );
	int (*msg_avp_value_interpret) ( msg_avp_t *avp, void *data );
	int (*msg_avp_add)             ( void * reference, msg_dir_t dir, msg_avp_t *avp);
	int (*msg_free)                ( void * object, int subtree );
	int (*msg_update_length)       ( void * object );
	int (*msg_avp_getrawdata)      ( msg_avp_t *avp, unsigned char **data );
	int (*msg_parse_rules)         ( void * object, dict_object_t ** rule);
   uint32_t (*msg_get_eteid)           ( void );

} api_msg_t;

#ifdef IN_EXTENSION

/* From within the extensions, we register callbacks in the following global structure */
#ifdef DECLARE_API_POINTERS
api_msg_t * g_api_msg=NULL;
#else /* DECLARE_API_POINTERS */
extern api_msg_t * g_api_msg;
#endif /* DECLARE_API_POINTERS */

/* These defines allow to call functions from extension in the same way as in waaad */
#define msg_browse	          g_api_msg->msg_browse
#define msg_search_avp	          g_api_msg->msg_search_avp
#define msg_model	          g_api_msg->msg_model
#define msg_data	          g_api_msg->msg_data
#define msg_avp_data	          g_api_msg->msg_avp_data
#define msg_send		  g_api_msg->msg_send
#define msg_new		          g_api_msg->msg_new
#define msg_new_answ		  g_api_msg->msg_new_answ
#define msg_avp_new	          g_api_msg->msg_avp_new
#define msg_avp_setvalue          g_api_msg->msg_avp_setvalue
#define msg_avp_value_encode      g_api_msg->msg_avp_value_encode
#define msg_avp_value_interpret   g_api_msg->msg_avp_value_interpret
#define msg_avp_add	          g_api_msg->msg_avp_add
#define msg_free	          g_api_msg->msg_free
#define msg_update_length         g_api_msg->msg_update_length
#define msg_avp_getrawdata        g_api_msg->msg_avp_getrawdata
#define msg_parse_rules	          g_api_msg->msg_parse_rules
#define msg_get_eteid	          g_api_msg->msg_get_eteid


#else /* IN_EXTENSION */

/* From the daemon, we must initialize the API object, in extension.c */
# define MY_WAAAD_API_MSG_VER 1
# if MY_WAAAD_API_MSG_VER != WAAAD_API_MSG_VER
#  error "You must update API_INIT_MSG also"
# endif

#define API_INIT_MSG( api_msg ) 					\
{									\
	(api_msg).length                    = sizeof(api_msg_t);	\
	(api_msg).version                   = WAAAD_API_MSG_VER;	\
	(api_msg).msg_browse                = msg_browse;		\
	(api_msg).msg_search_avp            = msg_search_avp;		\
	(api_msg).msg_model                 = msg_model;		\
	(api_msg).msg_data                  = msg_data;			\
	(api_msg).msg_avp_data              = msg_avp_data;		\
	(api_msg).msg_send                  = msg_send;			\
	(api_msg).msg_new                   = msg_new;			\
	(api_msg).msg_new_answ              = msg_new_answ;		\
	(api_msg).msg_avp_new               = msg_avp_new;		\
	(api_msg).msg_avp_setvalue          = msg_avp_setvalue;		\
	(api_msg).msg_avp_value_encode      = msg_avp_value_encode;	\
	(api_msg).msg_avp_value_interpret   = msg_avp_value_interpret;	\
	(api_msg).msg_avp_add               = msg_avp_add;		\
	(api_msg).msg_free                  = msg_free;			\
	(api_msg).msg_update_length         = msg_update_length;	\
	(api_msg).msg_avp_getrawdata        = msg_avp_getrawdata;	\
	(api_msg).msg_parse_rules           = msg_parse_rules;		\
	(api_msg).msg_get_eteid             = msg_get_eteid;		\
}							

#endif /* IN_EXTENSION */

#endif /* ! _MESSAGE_API_H */
"Welcome to our mercurial repository"