Mercurial > hg > waaad
view include/waaad/message-api.h @ 401:860f41038ea2
Updated copyright information
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 02 Jun 2009 15:10:55 +0900 |
parents | 3591d0486a2c |
children | 7b3d4431610a |
line wrap: on
line source
/********************************************************************************************************* * Software License Agreement (BSD License) * * Author: Sebastien Decugis <sdecugis@nict.go.jp> * * * * Copyright (c) 2009, 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 */