Mercurial > hg > freeDiameter
changeset 6:b0d377c79d80
Progress on dispatch API spec; added fd_sess_reclaim function and test
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Thu, 03 Sep 2009 16:03:25 +0900 |
parents | c2d2729e3603 |
children | e5af94b04946 |
files | freeDiameter/tests/testsess.c include/freeDiameter/libfreeDiameter.h libfreeDiameter/sessions.c |
diffstat | 3 files changed, 172 insertions(+), 29 deletions(-) [+] |
line wrap: on
line diff
--- a/freeDiameter/tests/testsess.c Thu Sep 03 14:33:45 2009 +0900 +++ b/freeDiameter/tests/testsess.c Thu Sep 03 16:03:25 2009 +0900 @@ -171,6 +171,36 @@ CHECK( 0, fd_sess_destroy( &sess1 ) ); } + /* Test fd_sess_reclaim */ + { + struct mystate *tms; + + CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) ); + CHECK( 1, new ? 1 : 0 ); + + CHECK( 0, fd_sess_reclaim( &sess1 ) ); + CHECK( NULL, sess1 ); + + CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) ); + CHECK( 1, new ? 1 : 0 ); + + tms = new_state(TEST_SID, NULL); + CHECK( 0, fd_sess_state_store ( hdl1, sess1, &tms ) ); + + CHECK( 0, fd_sess_reclaim( &sess1 ) ); + CHECK( NULL, sess1 ); + + CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) ); + CHECK( 0, new ); + + CHECK( 0, fd_sess_destroy( &sess1 ) ); + + CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) ); + CHECK( 1, new ? 1 : 0 ); + + CHECK( 0, fd_sess_destroy( &sess1 ) ); + } + /* Test timeout function */ { struct timespec timeout;
--- a/include/freeDiameter/libfreeDiameter.h Thu Sep 03 14:33:45 2009 +0900 +++ b/include/freeDiameter/libfreeDiameter.h Thu Sep 03 16:03:25 2009 +0900 @@ -1308,10 +1308,10 @@ * EINVAL : A parameter is invalid. * ENOMEM : Not enough memory to complete the operation */ -int fd_sess_handler_create_int ( struct session_handler ** handler, void (*cleanup)(char * sid, session_state * state) ); +int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(char * sid, session_state * state) ); /* Macro to avoid casting everywhere */ #define fd_sess_handler_create( _handler, _cleanup ) \ - fd_sess_handler_create_int( (_handler), (void (*)(char *, session_state *))(_cleanup) ) + fd_sess_handler_create_internal( (_handler), (void (*)(char *, session_state *))(_cleanup) ) /* * FUNCTION: fd_sess_handler_destroy @@ -1437,6 +1437,22 @@ */ int fd_sess_destroy ( struct session ** session ); +/* + * FUNCTION: fd_sess_reclaim + * + * PARAMETERS: + * session : Pointer to a session object. + * + * DESCRIPTION: + * Destroys the resources of a session, only if no session_state is associated with it. + * + * RETURN VALUE: + * 0 : The session no longer exists. + * EINVAL : A parameter is invalid. + */ +int fd_sess_reclaim ( struct session ** session ); + + /* @@ -1458,9 +1474,9 @@ * EALREADY : Data was already associated with this session and client. * ENOMEM : Not enough memory to complete the operation */ -int fd_sess_state_store_int ( struct session_handler * handler, struct session * session, session_state ** state ); +int fd_sess_state_store_internal ( struct session_handler * handler, struct session * session, session_state ** state ); #define fd_sess_state_store( _handler, _session, _state ) \ - fd_sess_state_store_int( (_handler), (_session), (void *)(_state) ) + fd_sess_state_store_internal( (_handler), (_session), (void *)(_state) ) /* * FUNCTION: fd_sess_state_retrieve @@ -1480,9 +1496,9 @@ * 0 : *state is updated (NULL or points to the state if it was found). * EINVAL : A parameter is invalid. */ -int fd_sess_state_retrieve_int ( struct session_handler * handler, struct session * session, session_state ** state ); +int fd_sess_state_retrieve_internal ( struct session_handler * handler, struct session * session, session_state ** state ); #define fd_sess_state_retrieve( _handler, _session, _state ) \ - fd_sess_state_retrieve_int( (_handler), (_session), (void *)(_state) ) + fd_sess_state_retrieve_internal( (_handler), (_session), (void *)(_state) ) /* For debug */ @@ -1494,47 +1510,118 @@ /* DISPATCH */ /*============================================================*/ -/* The dispatch process consists in passing a message to some handlers - (typically provided by extensions) based on its content (app id, cmd code...) */ - -/* The dispatch module has two main roles: +/* Dispatch module (passing incoming messages to extensions registered callbacks) + * is split between the library and the daemon. + * + * The library provides the support for associating dispatch callbacks with + * dictionary objects. + * + * The daemon is responsible for calling the callbacks for a message when appropriate. + * + * + * The dispatch module has two main roles: * - help determine if a message can be handled locally (during the routing step) + * This decision involves only the application-id of the message. * - pass the message to the callback(s) that will handle it (during the dispatch step) * - * These are the possibilities for registering a callback: + * These are the possibilities for registering a so-called dispatch callback: * * -> For All messages. * This callback is called for all messages that are handled locally. This should be used only - * internally by the daemon, or for debug purpose. + * for debug purpose. * - * -> by AVP value (constants). - * This callback will be called when a message is received and contains a certain AVP with a specified value. + * -> by AVP value (constants only). + * This callback will be called when a message is received and contains an AVP with a specified enumerated value. * * -> by AVP. * This callback will be called when the received message contains a certain AVP. * * -> by command-code. - * This callback will be called when the message is a specific command. + * This callback will be called when the message is a specific command (and 'R' flag). * * -> by application. * This callback will be called when the message has a specific application-id. * * ( by vendor: would this be useful? it may be added later) - * - * Note that several criteria may be selected at the same time, for example command-code AND application id. - * - * When a callback is called, it receives the message as parameter, and eventually a pointer to - * the AVP in the message when this is appropriate. + */ +enum disp_how { + DISP_HOW_ANY = 1, /* Any message. This should be only used for debug. */ + DISP_HOW_APPID, /* Any message with the specified application-id */ + DISP_HOW_CC, /* Messages of the specified command-code (request or answer). App id may be specified. */ + DISP_HOW_AVP, /* Messages containing a specific AVP. Command-code and App id may be specified. */ + DISP_HOW_AVP_ENUMVAL /* Messages containing a specific AVP with a specific enumerated value. Command-code and App id may be specified. */ +}; +/* + * Several criteria may be selected at the same time, for example command-code AND application id. * - * The callback must process the message, and eventually create an answer to it. See the definition - * bellow for more information. - * - * If no callback has handled the message, a default handler will be called with the effect of - * requeuing the message for forwarding on the network to another peer (for requests, if possible), or - * discarding the message (for answers). + * If several callbacks are registered for the same object, their order is unspecified. + * The order in which the callbacks are called is: + * DISP_HOW_ANY + * DISP_HOW_AVP_ENUMVAL & DISP_HOW_AVP + * DISP_HOW_CC + * DISP_HOW_APPID */ +/* When a callback is registered, a "when" argument is passed in addition to the disp_how value, + * to specify which values the criteria must match. */ +struct disp_when { + struct dict_object * app_id; + struct dict_object * command; + struct dict_object * avp; + struct dict_object * value; +}; +/* Here is the details on this "when" argument, depending on the disp_how value. + * + * DISP_HOW_ANY. + * In this case, "when" must be NULL. + * + * DISP_HOW_APPID. + * Only the "app_id" field must be set, other fields are ignored. It points to a dictionary object of type DICT_APPLICATION. + * + * DISP_HOW_CC. + * The "command" field must be defined and point to a dictionary object of type DICT_COMMAND. + * The "app_id" may be also set. In the case it is set, it restricts the callback to be called only with this command-code and app id. + * The other fields are ignored. + * + * DISP_HOW_AVP. + * The "avp" field of the structure must be set and point to a dictionary object of type DICT_AVP. + * The "app_id" field may be set to restrict the messages matching to a specific app id. + * The "command" field may also be set to a valid DICT_COMMAND object. + * The content of the "value" field is ignored. + * + * DISP_HOW_AVP_ENUMVAL. + * All fields have the same constraints and meaning as in DISP_REG_AVP. In addition, the "value" field must be set + * and points to a valid DICT_ENUMVAL object. + * + * Here is a sumary of the fields: ( M : must be set; m : may be set; 0 : ignored ) + * field: app_id command avp value + * APPID : M 0 0 0 + * CC : m M 0 0 + * AVP : m m M 0 + * ENUMVA: m m M M + */ + +/* The callbacks that are registered have the following prototype: + * + * int dispatch_callback( struct msg ** msg, struct avp * avp, struct session * session, int * is_answer ); + * + * FUNCTION: dispatch_callback + * + * PARAMETERS: + * msg : the received message on function entry. may be updated to answer on return (see description) + * avp : for callbacks registered with DISP_HOW_AVP or DISP_HOW_AVP_ENUMVAL, direct link to the triggering AVP. + * session : if the message contains a Session-Id AVP, the corresponding session object. + * + * 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.) + */ /*============================================================*/
--- a/libfreeDiameter/sessions.c Thu Sep 03 14:33:45 2009 +0900 +++ b/libfreeDiameter/sessions.c Thu Sep 03 16:03:25 2009 +0900 @@ -241,7 +241,7 @@ } /* Create a new handler */ -int fd_sess_handler_create_int ( struct session_handler ** handler, void (*cleanup)(char * sid, session_state * state) ) +int fd_sess_handler_create_internal ( struct session_handler ** handler, void (*cleanup)(char * sid, session_state * state) ) { struct session_handler *new; @@ -564,10 +564,36 @@ return 0; } +/* Destroy a session if it is not used */ +int fd_sess_reclaim ( struct session ** session ) +{ + struct session * sess; + + TRACE_ENTRY("%p", session); + CHECK_PARAMS( session && VALIDATE_SI(*session) ); + + sess = *session; + *session = NULL; + + CHECK_FCT( pthread_mutex_lock( H_LOCK(sess->hash) ) ); + CHECK_FCT( pthread_mutex_lock( &exp_lock ) ); + if (FD_IS_LIST_EMPTY(&sess->states)) { + fd_list_unlink( &sess->chain_h ); + fd_list_unlink( &sess->expire ); + sess->eyec = 0xdead; + free(sess->sid); + free(sess); + } + CHECK_FCT( pthread_mutex_unlock( &exp_lock ) ); + CHECK_FCT( pthread_mutex_unlock( H_LOCK(sess->hash) ) ); + + return 0; +} + /* Save a state information with a session */ -int fd_sess_state_store_int ( struct session_handler * handler, struct session * session, session_state ** state ) +int fd_sess_state_store_internal ( struct session_handler * handler, struct session * session, session_state ** state ) { struct state *new; struct fd_list * li; @@ -616,7 +642,7 @@ } /* Get the data back */ -int fd_sess_state_retrieve_int ( struct session_handler * handler, struct session * session, session_state ** state ) +int fd_sess_state_retrieve_internal ( struct session_handler * handler, struct session * session, session_state ** state ) { struct fd_list * li; struct state * st = NULL;