Mercurial > hg > waaad
changeset 98:7d3d175c3b8d
Completed the session module and test
author | Sebastien Decugis <sdecugis@nict.go.jp> |
---|---|
date | Tue, 22 Jul 2008 18:32:12 +0900 |
parents | 55d9e3443e59 |
children | d5fcb2af8c5a |
files | include/waaad/session-api.h waaad/session.c waaad/session.h waaad/tests/Makefile.am waaad/tests/testsess.c |
diffstat | 5 files changed, 725 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/include/waaad/session-api.h Thu Jul 17 18:23:09 2008 +0900 +++ b/include/waaad/session-api.h Tue Jul 22 18:32:12 2008 +0900 @@ -133,6 +133,7 @@ * RETURN VALUE: * 0 : The session is created. * EINVAL : A parameter is invalid. + * EALREADY : A session with the same name already exists (only for SESSION_NEW_SEQUENCE and SESSION_NEW_FULL) * ENOMEM : Not enough memory to complete the operation */ int sess_new ( sess_id_t ** session, sess_flags_t flags, char * opt ); @@ -275,6 +276,7 @@ * RETURN VALUE: * 0 : The data has been retrieved. * EINVAL : A parameter is invalid. + * ENOENT : No data was associated with this session and client */ int sess_data_get ( sess_id_t * session, sess_reg_t * client, void ** data ); @@ -284,15 +286,17 @@ * PARAMETERS: * session : the session with which the data is associated. * client : the client that registered the data. - * data : The pointer to the data is written here before being unregistered. + * data : if !NULL, the pointer to the data is written here before being unregistered. * * DESCRIPTION: - * Remove data from the session module. The data is stored in the "data" parameter so - * that the caller can clean it up properly. This makes an implicit call to sess_unlink. + * Remove data from the session module. If data is not NULL, the data is stored in the "data" parameter so + * that the caller can clean it up properly. Otherwise, if data is NULL, the cleanup function is called if any. + * This function makes an implicit call to sess_unlink. * * RETURN VALUE: * 0 : The data is not registered anymore. * EINVAL : A parameter is invalid. + * ENOENT : No data was associated with this session and client */ int sess_data_dereg ( sess_id_t * session, sess_reg_t * client, void ** data );
--- a/waaad/session.c Thu Jul 17 18:23:09 2008 +0900 +++ b/waaad/session.c Tue Jul 22 18:32:12 2008 +0900 @@ -62,8 +62,9 @@ /* Types and globals definitions */ /* The following two integers are used to generate values which are eternaly unique */ -static uint32_t g_sid_h; /* initialized to the current time at module initialization */ -static uint32_t g_sid_l; /* incremented each time a session id is created. There is no lock yet... hum :s */ +static uint32_t g_sid_h; /* initialized to the current time at module initialization */ +static uint32_t g_sid_l; /* incremented each time a session id is created. */ +static pthread_mutex_t g_sid_lock = PTHREAD_MUTEX_INITIALIZER; /************ sess_id_t ***********/ @@ -124,10 +125,12 @@ static struct { _sli_t sentinel; /* sentinel element for this sublist */ pthread_mutex_t lock; /* the mutex for this sublist */ + int count; /* Number of items in this list */ } sess_hash [ 1 << SESS_HASH_SIZE ] ; #define H_MASK( __hash ) ((__hash) & (( 1 << SESS_HASH_SIZE ) - 1)) #define H_LIST( _hash ) (&(sess_hash[H_MASK(_hash)].sentinel)) #define H_LOCK( _hash ) (&(sess_hash[H_MASK(_hash)].lock )) +#define H_COUNT(_hash ) ( sess_hash[H_MASK(_hash)].count ) /************ sess_reg_t and data ***********/ @@ -210,7 +213,7 @@ } /********************************************************************************************************/ -/* Function to compare a (hash, sid) with a sess_id_element. */ +/* Function to compare a (hash, sid, len) with a sess_id_element. */ static __inline__ int cmp_si(uint32_t hash1, char * sid1, size_t sid1len, _sess_id_t * si2) { if (hash1 < si2->hash) @@ -257,6 +260,95 @@ /********************************************************************************************************/ +/* Remove a piece of data linked from a _sess_reg_t. The _sess_reg_t lock must be held */ +static int _destroy_sr_data(_sd_data_t * sd, void ** data) +{ + int ret = 0; + + /* Call the destroy function for this element */ + if (data) + *data = sd->data; + else + if (sd->clncb) + sd->clncb(sd->data); + + /* Unlink the session */ + ret = sess_unlink((sess_id_t **)&sd->si); + if (ret != 0) { + TRACE_DEBUG(INFO, "sess_unlink failed: %s", strerror(ret)); + return ret; + } + + /* Unchain this element */ + SLI_remove( sd ); + + /* And free it */ + free(sd); + + return 0; +} + +/* Remove any data linked from a _sess_reg_t. The _sess_reg_t lock must be held */ +static int _destroy_sr_alldata(_sli_t * sentinel) +{ + int ret = 0; + while (!SLI_isempty( sentinel )) { + ret = _destroy_sr_data(_SD(sentinel->next), NULL); + if (ret != 0) { + TRACE_DEBUG(INFO, "_destroy_sr_data failed: %s", strerror(ret)); + return ret; + } + } + return 0; +} + +/* Remove a _sess_reg_t and any data linked from it. The _str_lock lock must be held */ +static int _destroy_sr(_sess_reg_t * item) +{ + int ret = 0; + + /* Lock the object */ + ret = pthread_mutex_lock( &item->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Invalidate */ + item->eyec = 0xdead; + + /* Destroy any data contained in this object */ + ret = _destroy_sr_alldata(&item->sentinel); + if (ret != 0) { + TRACE_DEBUG(INFO, "_destroy_sr_alldata failed: %s", strerror(ret)); + (void)pthread_mutex_unlock( &item->lock ); + return ret; + } + + /* Unlink */ + SLI_remove(item); + + /* Destroy the mutex */ + ret = pthread_mutex_unlock( &item->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + ret = pthread_mutex_destroy( &item->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_destroy failed: %s", strerror(ret)); + return ret; + } + + /* Free the object */ + free(item); + + return 0; +} + + +/********************************************************************************************************/ + /* Initialize the module */ int sess_init ( void ) { @@ -272,6 +364,7 @@ return ret; } SLI_init( &sess_hash[i].sentinel ); + sess_hash[i].count = 0; } /* Initialize the sentinel for registered clients */ @@ -331,9 +424,6 @@ _sess_id_t * newsi; /* The element did not exist already, li points to the previous element */ - if (new) - *new = 0; - /* Create a new element -- how to do this outside the mutex section, and efficiently? */ newsi = malloc(sizeof(_sess_id_t)); if (newsi == NULL) { @@ -370,8 +460,14 @@ /* Store this element in the list */ SLI_addafter(li, newsi); + /* Increment the counter */ + H_COUNT(hash) += 1; + /* Save the reference to it */ *session = (sess_id_t *)newsi; + + if (new) + *new = 1; } end: /* Finish, unlock the line */ @@ -426,13 +522,24 @@ memset(str, 0, len+1); /* Increment the value of the low32 */ + ret = pthread_mutex_lock(&g_sid_lock); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + goto end; + } ++g_sid_l; /* Now write the new value */ if (opt) - strsz = snprintf(str, len + 1, "%s;%ju;%ju;%s", g_pconf->diameter_identity, g_sid_h, g_sid_l, opt); + strsz = snprintf(str, len + 1, "%s;%u;%u;%s", g_pconf->diameter_identity, g_sid_h, g_sid_l, opt); else - strsz = snprintf(str, len + 1, "%s;%ju;%ju", g_pconf->diameter_identity, g_sid_h, g_sid_l); + strsz = snprintf(str, len + 1, "%s;%u;%u", g_pconf->diameter_identity, g_sid_h, g_sid_l); + + ret = pthread_mutex_unlock(&g_sid_lock); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + goto end; + } } break; @@ -477,6 +584,7 @@ } /* Now str points to the new session string. Create the new session */ + TRACE_DEBUG(FULL, "Creating session object for sid: '%s'", str); ret = sess_fromsid( str, strsz, session, &new ); if (ret != 0) { @@ -495,7 +603,7 @@ goto end; } - ret = EINVAL; + ret = EALREADY; } end: @@ -509,71 +617,459 @@ int sess_getsid ( sess_id_t * session, char ** sid ) { TRACE_ENTRY( "%p %p", session, sid ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check the parameter */ + if ( (! VALIDATE_SI(session)) || (sid == NULL)) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + /* Write the location and exit */ + *sid = _SI(session)->sid; + return 0; } /* Increase refcount of a session */ int sess_link ( sess_id_t * session ) { + int ret = 0; + TRACE_ENTRY( "%p", session ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check the parameter */ + if (! VALIDATE_SI(session)) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + /* Lock the list entry */ + ret = pthread_mutex_lock(H_LOCK(_SI(session)->hash)); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Increment the refcount */ + _SI(session)->rc++; + + /* Unlock the list entry */ + ret = pthread_mutex_unlock(H_LOCK(_SI(session)->hash)); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + return 0; } /* Decrease refcount of a session, eventually free it. */ int sess_unlink ( sess_id_t ** session ) { + int ret = 0; + uint32_t hash; + TRACE_ENTRY( "%p", session ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check the parameter */ + if ((session == NULL) || (! VALIDATE_SI(*session))) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + /* Copy the hash value */ + hash = _SI(*session)->hash; + + /* Lock the list entry */ + ret = pthread_mutex_lock(H_LOCK(hash)); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Decrement the refcount */ + _SI(*session)->rc--; + + /* If the count is now 0, we destroy the object */ + if (_SI(*session)->rc == 0) { + _SI(*session)->eyec = 0xdead; + + /* Unlink the element from the chain */ + SLI_remove(*session); /* actually &(*session)->chain, which is the same */ + + /* Update the count */ + H_COUNT(hash) -= 1; + + /* Now free the element */ + if (_SI(*session)->sid) + free(_SI(*session)->sid); + free(*session); + } + + /* Unlock the list entry */ + ret = pthread_mutex_unlock(H_LOCK(hash)); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + /* Update the location for the calling function */ + *session = NULL; + + return 0; } /* Create a new client of the module. */ int sess_regext ( sess_reg_t ** client ) { + int ret = 0; + _sess_reg_t * new = NULL; + TRACE_ENTRY( "%p", client ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check the parameter */ + if (client == NULL) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + /* Create a new object */ + new = (_sess_reg_t *) malloc(sizeof(_sess_reg_t)); + if (new == NULL) { + log_error("Memory allocation failed: %s\n", strerror(errno)); + TRACE_DEBUG(INFO, "malloc failed"); + return ENOMEM; + } + + /* Initialize the object */ + memset(new, 0, sizeof(_sess_reg_t)); + SLI_init(&new->list); + new->eyec = _SR_EYEC; + ret = pthread_mutex_init(&new->lock, NULL); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_init failed: %s", strerror(ret)); + free(new); + return ret; + } + SLI_init(&new->sentinel); + + /* Save the new object in the list */ + ret = pthread_mutex_lock(&_str_lock); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + free(new); + return ret; + } + + SLI_addafter( &_srt_sentinel, &new->list); + + ret = pthread_mutex_unlock(&_str_lock); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + /* Copy the reference to the calling process */ + *client = (sess_reg_t *)new; + + return 0; } /* Destroy a client of the module. */ int sess_deregext ( sess_reg_t * client ) { + int ret = 0; + TRACE_ENTRY( "%p", client ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + if (!VALIDATE_SR(client)) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + /* Lock the list of clients */ + ret = pthread_mutex_lock( &_str_lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Now destroy the client handler */ + ret = _destroy_sr(_SR(client)); + if (ret != 0) { + TRACE_DEBUG(INFO, "_destroy_sr failed: %s", strerror(ret)); + (void)pthread_mutex_unlock( &_str_lock ); + return ret; + } + + /* Unlock the list of clients */ + ret = pthread_mutex_unlock( &_str_lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + return 0; } /* Register data in a session. */ int sess_data_reg ( sess_id_t * session, sess_reg_t * client, void * data, void (*cleanup)(void *) ) { + int ret = 0; + _sd_data_t * new = NULL; + _sli_t *prev = NULL; + TRACE_ENTRY( "%p %p %p %p", session, client, data, cleanup ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check parameters */ + if ( (!VALIDATE_SI(session)) || (!VALIDATE_SR(client)) || (data == NULL)) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + /* Create a new object to hold the data */ + new = (_sd_data_t *) malloc(sizeof(_sd_data_t)); + if (new == NULL) { + log_error("Memory allocation failed: %s\n", strerror(errno)); + TRACE_DEBUG(INFO, "malloc failed"); + return ENOMEM; + } + memset(new, 0, sizeof(_sd_data_t)); + SLI_init(&new->list); + new->si = _SI(session); + new->clncb = cleanup; + new->data = data; + + /* Link the session */ + ret = sess_link((sess_id_t *)new->si); + if (ret != 0) { + TRACE_DEBUG(INFO, "sess_link failed: %s", strerror(ret)); + free(new); + return ret; + } + + /* Lock the client object */ + ret = pthread_mutex_lock( &_SR(client)->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + (void)sess_unlink((sess_id_t **)&new->si); + free(new); + return ret; + } + + /* Find the place in the list */ + ret = find_sd(new->si, &_SR(client)->sentinel, &prev); + if (ret == 0) { + /* There is already data associated with this session and client */ + TRACE_DEBUG(INFO, "Data already associated with session/client."); + (void)sess_unlink((sess_id_t **)&new->si); + free(new); + (void)pthread_mutex_unlock( &_SR(client)->lock ); + return EALREADY; + } + + /* Now "prev" is the previous element where the new element must be put */ + SLI_addafter(prev, new); + + /* Unlock, we're done */ + ret = pthread_mutex_unlock( &_SR(client)->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + return 0; } /* Retrieve registered data. */ int sess_data_get ( sess_id_t * session, sess_reg_t * client, void ** data ) { + int ret = 0; + _sli_t *item = NULL; + TRACE_ENTRY( "%p %p %p", session, client, data ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check parameters */ + if ( (!VALIDATE_SI(session)) || (!VALIDATE_SR(client)) || (data == NULL)) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + *data = NULL; + + /* Lock the client object */ + ret = pthread_mutex_lock( &_SR(client)->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Find the data */ + ret = find_sd(_SI(session), &_SR(client)->sentinel, &item); + if (ret == 0) { + *data = _SD(item)->data; + } + + /* Unlock, we're done */ + ret = pthread_mutex_unlock( &_SR(client)->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + return (*data == NULL) ? ENOENT : 0; } /* Remove registered data from a session. */ int sess_data_dereg ( sess_id_t * session, sess_reg_t * client, void ** data ) { + int ret = 0; + int noent = 0; + _sli_t *item = NULL; + TRACE_ENTRY( "%p %p %p", session, client, data ); - TRACE_DEBUG (INFO, "@@@ %s: not implemented yet.", __FUNCTION__ ); - return ENOTSUP; + + /* Check parameters */ + if ( (!VALIDATE_SI(session)) || (!VALIDATE_SR(client)) ) { + TRACE_DEBUG(INFO, "Invalid parameter"); + return EINVAL; + } + + if (data) + *data = NULL; + + /* Lock the client object */ + ret = pthread_mutex_lock( &_SR(client)->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Find the data */ + ret = find_sd(_SI(session), &_SR(client)->sentinel, &item); + if (ret == 0) { + ret = _destroy_sr_data(_SD(item), data); + if (ret != 0) { + TRACE_DEBUG(INFO, "_destroy_sr_data failed: %s", strerror(ret)); + (void)pthread_mutex_unlock( &_SR(client)->lock ); + return ret; + } + } else { + TRACE_DEBUG(INFO, "data not found."); + noent = 1; + } + + /* Unlock, we're done */ + ret = pthread_mutex_unlock( &_SR(client)->lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + return noent ? ENOENT : 0; } /* End of the module */ int sess_fini ( void ) { + int ret = 0; + int i; + TRACE_ENTRY( "" ); - TRACE_DEBUG (INFO, "@@@ Not implemented yet." ); + + /* Lock the list of clients */ + ret = pthread_mutex_lock( &_str_lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_lock failed: %s", strerror(ret)); + return ret; + } + + /* Destroy all the registered clients */ + while (!SLI_isempty( &_srt_sentinel )) { + TRACE_DEBUG(FULL, "Destroying module %p...", _srt_sentinel.next); + ret = _destroy_sr( _SR(_srt_sentinel.next) ); + if (ret != 0) { + TRACE_DEBUG(INFO, "_destroy_sr failed: %s", strerror(ret)); + (void)pthread_mutex_unlock( &_str_lock ); + return ret; + } + } + + /* Unlock the list of clients */ + ret = pthread_mutex_unlock( &_str_lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_unlock failed: %s", strerror(ret)); + return ret; + } + + /* Destroy the lock */ + ret = pthread_mutex_destroy( &_str_lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_destroy failed: %s", strerror(ret)); + return ret; + } + + /* Check that there is no more session registered */ + for (i = 0; i < sizeof(sess_hash) / sizeof(sess_hash[0]); i++) { + if (!SLI_isempty(&sess_hash[i].sentinel)) { + TRACE_DEBUG(INFO, "List of session (%d) is not empty. Maybe messages are still refering sessions? EBUSY", i); + return EBUSY; + } + ret = pthread_mutex_destroy( &sess_hash[i].lock ); + if (ret != 0) { + TRACE_DEBUG(INFO, "pthread_mutex_destroy failed: %s", strerror(ret)); + return ret; + } + } + + /* Done! */ return 0; } +/********************************************************************************************************/ +/* debug functions */ + +static void _dump_si ( _sess_id_t * si, int indent ) +{ + TRACE_DEBUG(FULL, "%*ssession @%p: h:%8x rc:%d ts:%d sid:'%s'", indent, "", si, si->hash, si->rc, si->ts.tv_sec, si->sid); +} + +static void _dump_hash (void) +{ + int i; + + TRACE_DEBUG(FULL, " ======= Dumping the session hash table ======= "); + for (i=0; i < sizeof(sess_hash) / sizeof(sess_hash[0]); i++) { + _sli_t * item; + TRACE_DEBUG(FULL, " l:%02d cnt:%d", i, sess_hash[i].count); + for (item = &sess_hash[i].sentinel; item->next != &sess_hash[i].sentinel; item = item->next) + _dump_si(_SI(item->next), 3); + } + TRACE_DEBUG(FULL, " =======/end of session hash table dump/======= "); +} + +static void _dump_sd ( _sd_data_t * sd, int indent ) +{ + TRACE_DEBUG(FULL, "%*sdata @%p: data:%p clncb:%p sid:'%s'", indent, "", sd, sd->data, sd->clncb, sd->si->sid); +} + +static void _dump_regs (void) +{ + _sli_t * client; + _sli_t * data; + + TRACE_DEBUG(FULL, " ======= Dumping the registered clients list ======= "); + for (client = &_srt_sentinel; client->next != &_srt_sentinel; client = client->next) { + TRACE_DEBUG(FULL, "client @%p:", client->next); + for (data = &_SR(client->next)->sentinel; data->next != &_SR(client->next)->sentinel; data = data->next) { + _dump_sd(_SD(data->next), 3); + } + } + TRACE_DEBUG(FULL, " =======/end of registered clients list dump/======= "); +} + +void sess_dump(void) +{ + _dump_hash(); + _dump_regs(); +} +
--- a/waaad/session.h Thu Jul 17 18:23:09 2008 +0900 +++ b/waaad/session.h Tue Jul 22 18:32:12 2008 +0900 @@ -79,4 +79,7 @@ int sess_fini ( void ); +/* For debug only */ +void sess_dump( void ); + #endif /* _SESSION_H */
--- a/waaad/tests/Makefile.am Thu Jul 17 18:23:09 2008 +0900 +++ b/waaad/tests/Makefile.am Tue Jul 22 18:32:12 2008 +0900 @@ -36,6 +36,9 @@ # Testing the queues: testmeq_SOURCES = testmeq.c tests.h $(WAAADSOURCES) -check_PROGRAMS = testdict testmesg testmeq +# Testing the sessions: +testsess_SOURCES = testsess.c tests.h $(WAAADSOURCES) + +check_PROGRAMS = testdict testmesg testmeq testsess TESTS = $(check_PROGRAMS)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/waaad/tests/testsess.c Tue Jul 22 18:32:12 2008 +0900 @@ -0,0 +1,189 @@ +/********************************************************************************************************* +* 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. * +*********************************************************************************************************/ + +#include "tests.h" + +/* Test for the sessions module */ + +/* Structure that is passed to the module */ +typedef struct { + int hasbeenfreed; + int id; +} td_t; + +/* Function that "cleanup" the data */ +void cleanup(void * data) { + td_t * d = (td_t *)data; + d->hasbeenfreed += 1; +} + +#define TEST_DIAM_ID "testsess.myid" + +/* Main test routine */ +int main(int argc, char *argv[]) +{ + sess_reg_t * client1 = NULL; + sess_reg_t * client2 = NULL; + + sess_id_t * session1 = NULL; + sess_id_t * session2 = NULL; + sess_id_t * session3 = NULL; + + td_t td[4] = { {0,1}, {0,2}, {0,3}, {0,4}}; + td_t *ptd; + + char * str = NULL; + int new; + + /* First, initialize the daemon modules */ + INIT_WAAAD(); + g_pconf->diameter_identity = TEST_DIAM_ID; + + /* Tests creation and destruction of sessions */ + { + sess_id_t * session = NULL; + + /* Create one session */ + CHECK( 0, sess_new ( &session1, SESSION_NEW_DEFAULT, NULL ) ); + + /* Check it begins as expected */ + CHECK( 0, sess_getsid ( session1, &str) ); + CHECK( 0, strncmp( TEST_DIAM_ID, str, strlen(TEST_DIAM_ID)) ); + + /* Check we can not create another session with the same name */ + CHECK( EALREADY, sess_new ( &session, SESSION_NEW_FULL, str ) ); + CHECK( EALREADY, sess_new ( &session, SESSION_NEW_SEQUENCE, str + strlen(TEST_DIAM_ID) + 1 ) ); + + /* Now create a session using the opt part */ + CHECK( 0, sess_new ( &session2, SESSION_NEW_DEFAULT, "user@testsess" ) ); + CHECK( 0, sess_getsid ( session2, &str) ); + CHECK( 0, strcmp( ";user@testsess", str + strlen(str) - strlen(";user@testsess")) ); /* verify the end of the string */ + + /* Test the link and unlink */ + CHECK( 0, sess_link ( session2 ) ); + session = session2; + CHECK( 0, sess_unlink ( &session ) ); + session = session2; + CHECK( 0, sess_unlink ( &session ) ); + CHECK( EINVAL, sess_unlink ( &session2 ) ); + CHECK( 0, sess_new ( &session2, SESSION_NEW_DEFAULT, "user@testsess" ) ); + + /* Create a third session */ + CHECK( 0, sess_new ( &session3, SESSION_NEW_SEQUENCE, "1;1;another_test_session" ) ); + + /* Check we find it again */ + CHECK( 0, sess_fromsid ( TEST_DIAM_ID ";" "1;1;another_test_session" "and some trash data follow", strlen(TEST_DIAM_ID ";" "1;1;another_test_session"), &session, &new) ); + CHECK( 0, new); + CHECK( 0, sess_unlink( &session ) ); + + #if 0 + sess_dump(); + #endif + } + + /* Tests the registration of client functions */ + { + /* Create the two module clients */ + CHECK( 0, sess_regext ( &client1 ) ); + CHECK( 0, sess_regext ( &client2 ) ); + + /* Test that we can delete the clients */ + CHECK( 0, sess_deregext ( client1 ) ); + CHECK( 0, sess_deregext ( client2 ) ); + + /* Register it again */ + CHECK( 0, sess_regext ( &client1 ) ); + CHECK( 0, sess_regext ( &client2 ) ); + } + + /* Now associate data with the sessions */ + { + /* Associate data with all sessions */ + CHECK( 0, sess_data_reg( session1, client1, &td[0], cleanup) ); + CHECK( 0, sess_data_reg( session2, client1, &td[1], cleanup) ); + CHECK( 0, sess_data_reg( session3, client1, &td[2], cleanup) ); + + /* Destroy the client, the cleanup function must be called */ + CHECK( 0, sess_deregext ( client1 ) ); + CHECK( 1, td[0].hasbeenfreed ); + td[0].hasbeenfreed = 0; + CHECK( 1, td[1].hasbeenfreed ); + td[1].hasbeenfreed = 0; + CHECK( 1, td[2].hasbeenfreed ); + td[2].hasbeenfreed = 0; + + /* Recreate the client */ + CHECK( 0, sess_regext ( &client1 ) ); + + /* Associate data */ + CHECK( 0, sess_data_reg( session1, client1, &td[0], cleanup) ); + CHECK( 0, sess_data_reg( session2, client1, &td[1], cleanup) ); + CHECK( 0, sess_data_reg( session2, client2, &td[2], cleanup) ); + CHECK( 0, sess_data_reg( session3, client2, &td[3], cleanup) ); + + /* Check we cannot associate more data with the same tuplet */ + CHECK( EALREADY, sess_data_reg( session2, client1, &td[3], cleanup) ); + + /* Get the data */ + CHECK( 0, sess_data_get( session2, client1, (void **)&ptd ) ); + CHECK( 2, ptd->id ); + CHECK( 0, sess_data_get( session2, client2, (void **)&ptd ) ); + CHECK( 3, ptd->id ); + + /* Check case where there is no data */ + CHECK( ENOENT, sess_data_get( session1, client2, (void **)&ptd ) ); + + /* Now remove the data */ + CHECK( 0, sess_data_dereg( session3, client2, (void **)&ptd ) ); + CHECK( 4, ptd->id ); + CHECK( 0, ptd->hasbeenfreed ); + + CHECK( 0, sess_data_dereg( session2, client2, NULL ) ); + CHECK( 1, td[2].hasbeenfreed ); + + #if 0 + sess_dump(); + #endif + } + + CHECK( 0, sess_unlink( &session1 ) ); + CHECK( 0, sess_unlink( &session2 ) ); + CHECK( 0, sess_unlink( &session3 ) ); + CHECK( 0, sess_fini() ); + + /* That's all for the tests yet */ + PASSTEST(); +} +