Commit fdafd9fe authored by Sebastien Decugis's avatar Sebastien Decugis
Browse files

Progress on dispatch API spec; added fd_sess_reclaim function and test

parent e3bfb711
......@@ -171,6 +171,36 @@ int main(int argc, char *argv[])
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;
......
......@@ -1308,10 +1308,10 @@ typedef void session_state;
* 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_settimeout( struct session * session, const struct timespec * timeou
*/
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 @@ int fd_sess_destroy ( struct session ** session );
* 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 @@ int fd_sess_state_store_int ( struct session_handler * handler, struct session *
* 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 @@ void fd_sess_dump_hdl(int level, struct session_handler * handler);
/* 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)
*/
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.
*
* 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.
*
* Note that several criteria may be selected at the same time, for example command-code AND application id.
* 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.
*
* 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.
* 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.
*
* The callback must process the message, and eventually create an answer to it. See the definition
* bellow for more information.
* 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.
*
* 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).
* 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.)
*/
/*============================================================*/
......
......@@ -241,7 +241,7 @@ int fd_sess_init(void)
}
/* 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 @@ int fd_sess_destroy ( struct session ** session )
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 @@ int fd_sess_state_store_int ( struct session_handler * handler, struct session *
}
/* 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;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment