changeset 5:c2d2729e3603

Completed new session module tests; some bugs fixed
author Sebastien Decugis <sdecugis@nict.go.jp>
date Thu, 03 Sep 2009 14:33:45 +0900
parents 883311bf7df3
children b0d377c79d80
files freeDiameter/tests/testsess.c include/freeDiameter/libfreeDiameter.h libfreeDiameter/sessions.c
diffstat 3 files changed, 247 insertions(+), 46 deletions(-) [+]
line wrap: on
line diff
--- a/freeDiameter/tests/testsess.c	Wed Sep 02 18:28:27 2009 +0900
+++ b/freeDiameter/tests/testsess.c	Thu Sep 03 14:33:45 2009 +0900
@@ -46,7 +46,7 @@
 	int  *  freed;	/* location where to write the freed status */
 };
 
-void mycleanup( char * sid, struct mystate * data )
+static void mycleanup( char * sid, struct mystate * data )
 {
 	/* sanity */
 	CHECK( 1, sid ? 1 : 0 );
@@ -60,6 +60,20 @@
 	free(data);
 }
 
+static __inline__ struct mystate * new_state(char * sid, int *freed) 
+{
+	struct mystate *new;
+	new = malloc(sizeof(struct mystate));
+	CHECK( 1, new ? 1 : 0 );
+	memset(new, 0, sizeof(struct mystate));
+	new->eyec = TEST_EYEC;
+	new->sid = strdup(sid);
+	CHECK( 1, new->sid ? 1 : 0 );
+	new->freed = freed;
+	return new;
+}
+	
+
 /* Main test routine */
 int main(int argc, char *argv[])
 {
@@ -77,7 +91,7 @@
 		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup ) );
 		CHECK( 0, fd_sess_handler_destroy( &hdl2 ) );
 		CHECK( 0, fd_sess_handler_create ( &hdl2, mycleanup ) );
-		#if 1
+		#if 0
 		fd_sess_dump_hdl(0, hdl1);
 		fd_sess_dump_hdl(0, hdl2);
 		#endif
@@ -88,7 +102,7 @@
 		/* DiamId is provided, not opt */
 		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, NULL, 0 ) );
 		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, NULL, 0 ) );
-		#if 1
+		#if 0
 		fd_sess_dump(0, sess1);
 		fd_sess_dump(0, sess2);
 		#endif
@@ -105,7 +119,7 @@
 		/* diamId and opt */
 		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, TEST_OPT, 0 ) );
 		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, TEST_OPT, strlen(TEST_OPT) - 1 ) );
-		#if 1
+		#if 0
 		fd_sess_dump(0, sess1);
 		fd_sess_dump(0, sess2);
 		#endif
@@ -129,7 +143,7 @@
 		CHECK( EALREADY, fd_sess_new( &sess3, NULL, TEST_SID, strlen(TEST_SID) ) );
 		CHECK( sess3, sess1 );
 		CHECK( 0, fd_sess_new( &sess2, NULL, TEST_SID, strlen(TEST_SID) - 1 ) );
-		#if 1
+		#if 0
 		fd_sess_dump(0, sess1);
 		fd_sess_dump(0, sess2);
 		#endif
@@ -139,18 +153,176 @@
 		CHECK( 0, strcmp( str1, TEST_SID ) );
 		
 		CHECK( 0, fd_sess_destroy( &sess2 ) );
+		CHECK( 0, fd_sess_destroy( &sess1 ) );
 	}
 		
+	/* Test fd_sess_fromsid */
+	{
+		CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) );
+		CHECK( 1, new ? 1 : 0 );
 		
+		CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess2, &new ) );
+		CHECK( 0, new );
+		CHECK( sess1, sess2 );
+		
+		CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess3, NULL ) );
+		CHECK( sess1, sess3 );
+		
+		CHECK( 0, fd_sess_destroy( &sess1 ) );
+	}
+	
+	/* Test timeout function */
+	{
+		struct timespec timeout;
+		
+		CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) );
+		CHECK( 1, new ? 1 : 0 );
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &timeout) );
+		CHECK( 0, fd_sess_settimeout( sess1, &timeout) );
+		timeout.tv_sec = 0;
+		timeout.tv_nsec= 50000000; /* 50 ms */
+		CHECK( 0, clock_nanosleep(CLOCK_REALTIME, 0, &timeout, NULL) );
+		
+		CHECK( 0, fd_sess_fromsid( TEST_SID, strlen(TEST_SID), &sess1, &new ) );
+		CHECK( 1, new ? 1 : 0 );
+		
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &timeout) );
+		timeout.tv_sec += 2678500; /* longer that SESS_DEFAULT_LIFETIME */
+		CHECK( 0, fd_sess_settimeout( sess1, &timeout) );
+		
+		/* Create a second session */
+		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, NULL, 0 ) );
+		
+		/* We don't really have away to verify the expiry list is in proper order automatically here... */
+		
+		CHECK( 0, fd_sess_destroy( &sess2 ) );
+		CHECK( 0, fd_sess_destroy( &sess1 ) );
+	}
+	
 	
-/*	
-int fd_sess_new ( struct session ** session, char * diamId, char * opt, size_t optlen );
-int fd_sess_fromsid ( char * sid, size_t len, struct session ** session, int * new);
-int fd_sess_getsid ( struct session * session, char ** sid );
-int fd_sess_settimeout( struct session * session, const struct timespec * timeout );
-int fd_sess_destroy ( struct session ** session );
-*/
+	/* Test states operations */
+	{
+		struct mystate * ms[6], *tms;
+		int freed[6];
+		int i;
+		struct timespec timeout;
+		
+		/* Create three sessions */
+		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, NULL, 0 ) );
+		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, NULL, 0 ) );
+		CHECK( 0, fd_sess_new( &sess3, TEST_DIAM_ID, NULL, 0 ) );
+		
+		/* Create 2 states */
+		CHECK( 0, fd_sess_getsid(sess1, &str1) );
+		freed[0] = 0;
+		ms[0] = new_state(str1, &freed[0]);
+		ms[1] = new_state(str1, NULL);
 
+		tms = ms[0]; /* save a copy */
+		CHECK( 0, fd_sess_state_store ( hdl1, sess1, &ms[0] ) );
+		CHECK( NULL, ms[0] );
+		CHECK( EINVAL, fd_sess_state_store ( hdl1, sess1, NULL ) );
+		CHECK( EALREADY, fd_sess_state_store ( hdl1, sess1, &ms[1] ) );
+		CHECK( 1, ms[1] ? 1 : 0 );
+		
+		#if 0
+		fd_sess_dump(0, sess1);
+		#endif
+		
+		CHECK( 0, fd_sess_state_retrieve( hdl1, sess1, &ms[0] ) );
+		CHECK( tms, ms[0] );
+		CHECK( 0, freed[0] );
+		
+		CHECK( 0, fd_sess_state_retrieve( hdl1, sess2, &tms ) );
+		CHECK( NULL, tms );
+		
+		mycleanup(str1, ms[0]);
+		mycleanup(str1, ms[1]);
+		
+		/* Now create 6 states */
+		memset(&freed[0], 0, sizeof(freed));
+		CHECK( 0, fd_sess_getsid(sess1, &str1) );
+		ms[0] = new_state(str1, &freed[0]);
+		ms[1] = new_state(str1, &freed[1]);
+		CHECK( 0, fd_sess_getsid(sess2, &str1) );
+		ms[2] = new_state(str1, &freed[2]);
+		ms[3] = new_state(str1, &freed[3]);
+		CHECK( 0, fd_sess_getsid(sess3, &str1) );
+		ms[4] = new_state(str1, &freed[4]);
+		ms[5] = new_state(str1, &freed[5]);
+		str2 = strdup(str1);
+		CHECK( 1, str2 ? 1 : 0 );
+		
+		/* Store the six states */
+		CHECK( 0, fd_sess_state_store ( hdl1, sess1, &ms[0] ) );
+		CHECK( 0, fd_sess_state_store ( hdl2, sess1, &ms[1] ) );
+		CHECK( 0, fd_sess_state_store ( hdl1, sess2, &ms[2] ) );
+		CHECK( 0, fd_sess_state_store ( hdl2, sess2, &ms[3] ) );
+		CHECK( 0, fd_sess_state_store ( hdl1, sess3, &ms[4] ) );
+		CHECK( 0, fd_sess_state_store ( hdl2, sess3, &ms[5] ) );
+		
+		#if 0
+		fd_sess_dump(0, sess1);
+		fd_sess_dump(0, sess2);
+		fd_sess_dump(0, sess3);
+		#endif
+		
+		/* Destroy session 3 */
+		CHECK( 0, fd_sess_destroy( &sess3 ) );
+		CHECK( 0, freed[0] );
+		CHECK( 0, freed[1] );
+		CHECK( 0, freed[2] );
+		CHECK( 0, freed[3] );
+		CHECK( 1, freed[4] );
+		CHECK( 1, freed[5] );
+		
+		/* Destroy handler 2 */
+		CHECK( 0, fd_sess_handler_destroy( &hdl2 ) );
+		CHECK( 0, freed[0] );
+		CHECK( 1, freed[1] );
+		CHECK( 0, freed[2] );
+		CHECK( 1, freed[3] );
+		CHECK( 1, freed[4] );
+		CHECK( 1, freed[5] );
+		
+		#if 1
+		fd_sess_dump(0, sess1);
+		fd_sess_dump(0, sess2);
+		#endif
+		
+		/* Create again session 3, check that no data is associated to it */
+		CHECK( 0, fd_sess_fromsid( str2, strlen(str2), &sess3, &new ) );
+		CHECK( 1, new ? 1 : 0 );
+		CHECK( 0, fd_sess_state_retrieve( hdl1, sess3, &tms ) );
+		CHECK( NULL, tms );
+		CHECK( 0, fd_sess_destroy( &sess3 ) );
+		free(str2);
+		
+		/* Timeout does call cleanups */
+		CHECK( 0, clock_gettime(CLOCK_REALTIME, &timeout) );
+		CHECK( 0, fd_sess_settimeout( sess2, &timeout) );
+		#if 1
+		fd_sess_dump(0, sess1);
+		fd_sess_dump(0, sess2);
+		#endif
+		timeout.tv_sec = 0;
+		timeout.tv_nsec= 50000000; /* 50 ms */
+		CHECK( 0, clock_nanosleep(CLOCK_REALTIME, 0, &timeout, NULL) );
+		CHECK( 0, freed[0] );
+		CHECK( 1, freed[1] );
+		CHECK( 1, freed[2] );
+		CHECK( 1, freed[3] );
+		CHECK( 1, freed[4] );
+		CHECK( 1, freed[5] );
+		
+		/* Check the last data can still be retrieved */
+		CHECK( 0, fd_sess_state_retrieve( hdl1, sess1, &tms ) );
+		CHECK( 0, fd_sess_getsid(sess1, &str1) );
+		mycleanup(str1, tms);
+	}
+	
+	
 	/* That's all for the tests yet */
 	PASSTEST();
 } 
--- a/include/freeDiameter/libfreeDiameter.h	Wed Sep 02 18:28:27 2009 +0900
+++ b/include/freeDiameter/libfreeDiameter.h	Thu Sep 03 14:33:45 2009 +0900
@@ -364,7 +364,7 @@
 /* Compare timespec structures */
 #define TS_IS_INFERIOR( ts1, ts2 ) 		\
 	(    ((ts1)->tv_sec  < (ts2)->tv_sec ) 	\
-	  || ((ts1)->tv_nsec < (ts2)->tv_nsec) )
+	  || (((ts1)->tv_sec  == (ts2)->tv_sec ) && ((ts1)->tv_nsec < (ts2)->tv_nsec) ))
 
 
 /*============================================================*/
@@ -1458,7 +1458,9 @@
  *  EALREADY	: Data was already associated with this session and client.
  *  ENOMEM	: Not enough memory to complete the operation
  */
-int fd_sess_state_store ( struct session_handler * handler, struct session * session, session_state ** state ); 
+int fd_sess_state_store_int ( 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) )
 
 /*
  * FUNCTION:	fd_sess_state_retrieve
@@ -1478,7 +1480,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 ( struct session_handler * handler, struct session * session, session_state ** state ); 
+int fd_sess_state_retrieve_int ( 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) )
 
 
 /* For debug */
--- a/libfreeDiameter/sessions.c	Wed Sep 02 18:28:27 2009 +0900
+++ b/libfreeDiameter/sessions.c	Thu Sep 03 14:33:45 2009 +0900
@@ -295,12 +295,13 @@
 				/* The list is ordered */
 				if (st->hdl->id < del->id)
 					continue;
-				if (st->hdl->id > del->id)
-					break;
-				/* This state belongs to the handler we are deleting, move the item to the deleted_states list */
-				fd_list_unlink(&st->chain);
-				CHECK_MALLOC( st->sid = strdup(sess->sid) );
-				fd_list_insert_before(&deleted_states, &st->chain);
+				if (st->hdl->id == del->id) {
+					/* This state belongs to the handler we are deleting, move the item to the deleted_states list */
+					fd_list_unlink(&st->chain);
+					CHECK_MALLOC( st->sid = strdup(sess->sid) );
+					fd_list_insert_before(&deleted_states, &st->chain);
+				}
+				break;
 			}
 			CHECK_POSIX(  pthread_mutex_unlock(&sess->stlock)  );
 		}
@@ -399,9 +400,9 @@
 		break;
 	}
 	
-	/* If the session did not exist, we can add it into the hash table */
+	/* If the session did not exist, we can link it in global tables */
 	if (!found) {
-		fd_list_insert_before(li, &sess->chain_h);
+		fd_list_insert_before(li, &sess->chain_h); /* hash table */
 		
 		/* We must also insert in the expiry list */
 		CHECK_POSIX( pthread_mutex_lock( &exp_lock ) );
@@ -409,13 +410,21 @@
 		/* Find the position in that list. We take it in reverse order */
 		for (li = exp_sentinel.prev; li != &exp_sentinel; li = li->prev) {
 			struct session * s = (struct session *)(li->o);
-			
 			if (TS_IS_INFERIOR( &s->timeout, &sess->timeout ) )
 				break;
-			
-			continue;
 		}
 		fd_list_insert_after( li, &sess->expire );
+
+		#if 0
+		if (TRACE_BOOL(ANNOYING)) {	
+			TRACE_DEBUG(FULL, "-- Updated session expiry list --");
+			for (li = exp_sentinel.next; li != &exp_sentinel; li = li->next) {
+				struct session * s = (struct session *)(li->o);
+				fd_sess_dump(FULL, s);
+			}
+			TRACE_DEBUG(FULL, "-- end of expiry list --");
+		}
+		#endif
 		
 		/* We added a new expiring element, we must signal */
 		CHECK_POSIX( pthread_cond_signal(&exp_cond) );
@@ -502,6 +511,17 @@
 	/* We added a new expiring element, we must signal */
 	CHECK_POSIX( pthread_cond_signal(&exp_cond) );
 
+	#if 0
+	if (TRACE_BOOL(ANNOYING)) {	
+		TRACE_DEBUG(FULL, "-- Updated session expiry list --");
+		for (li = exp_sentinel.next; li != &exp_sentinel; li = li->next) {
+			struct session * s = (struct session *)(li->o);
+			fd_sess_dump(FULL, s);
+		}
+		TRACE_DEBUG(FULL, "-- end of expiry list --");
+	}
+	#endif
+
 	/* We're done */
 	CHECK_POSIX( pthread_mutex_unlock( &exp_lock ) );
 	
@@ -547,7 +567,7 @@
 
 
 /* Save a state information with a session */
-int fd_sess_state_store ( struct session_handler * handler, struct session * session, session_state ** state )
+int fd_sess_state_store_int ( struct session_handler * handler, struct session * session, session_state ** state )
 {
 	struct state *new;
 	struct fd_list * li;
@@ -596,7 +616,7 @@
 }
 
 /* Get the data back */
-int fd_sess_state_retrieve ( struct session_handler * handler, struct session * session, session_state ** state )
+int fd_sess_state_retrieve_int ( struct session_handler * handler, struct session * session, session_state ** state )
 {
 	struct fd_list * li;
 	struct state * st = NULL;
@@ -631,29 +651,34 @@
 }
 
 
-
 /* Dump functions */
 void fd_sess_dump(int level, struct session * session)
 {
 	struct fd_list * li;
+	char buf[30];
+	struct tm tm;
+	
 	if (!TRACE_BOOL(level))
 		return;
 	
-	fd_log_debug("Session @%p:\n", session);
+	fd_log_debug("\t  %*s -- Session @%p --\n", level, "", session);
 	if (!VALIDATE_SI(session)) {
-		fd_log_debug("  Invalid session object\n");
-		return;
-	}
+		fd_log_debug("\t  %*s  Invalid session object\n", level, "");
+	} else {
 		
-	fd_log_debug("  sid '%s', hash %x\n", session->sid, session->hash);
-	fd_log_debug("  timeout %d.%09d\n", session->timeout.tv_sec, session->timeout.tv_nsec);
-	
-	CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
-	for (li = session->states.next; li != &session->states; li = li->next) {
-		struct state * st = (struct state *)(li->o);
-		fd_log_debug("    handler %d registered data %p\n", st->hdl->id, st->state);
+		fd_log_debug("\t  %*s  sid '%s', hash %x\n", level, "", session->sid, session->hash);
+
+		strftime(buf, sizeof(buf), "%D,%T", localtime_r( &session->timeout.tv_sec , &tm ));
+		fd_log_debug("\t  %*s  timeout %s.%09ld\n", level, "", buf, session->timeout.tv_nsec);
+
+		CHECK_POSIX_DO( pthread_mutex_lock(&session->stlock), /* ignore */ );
+		for (li = session->states.next; li != &session->states; li = li->next) {
+			struct state * st = (struct state *)(li->o);
+			fd_log_debug("\t  %*s    handler %d registered data %p\n", level, "", st->hdl->id, st->state);
+		}
+		CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
 	}
-	CHECK_POSIX_DO( pthread_mutex_unlock(&session->stlock), /* ignore */ );
+	fd_log_debug("\t  %*s -- end of session @%p --\n", level, "", session);
 }
 
 void fd_sess_dump_hdl(int level, struct session_handler * handler)
@@ -661,11 +686,11 @@
 	if (!TRACE_BOOL(level))
 		return;
 	
-	fd_log_debug("Handler @%p:\n", handler);
+	fd_log_debug("\t  %*s -- Handler @%p --\n", level, "", handler);
 	if (!VALIDATE_SH(handler)) {
-		fd_log_debug("  Invalid session handler object\n");
-		return;
+		fd_log_debug("\t  %*s  Invalid session handler object\n", level, "");
+	} else {
+		fd_log_debug("\t  %*s  id %d, cleanup %p\n", level, "", handler->id, handler->cleanup);
 	}
-		
-	fd_log_debug("  id %d, cleanup %p\n", handler->id, handler->cleanup);
+	fd_log_debug("\t  %*s -- end of handler @%p --\n", level, "", handler);
 }	
"Welcome to our mercurial repository"