Mercurial > hg > waaad
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; +} + +