Index: include/freeDiameter/libfdproto.h
===================================================================
--- include/freeDiameter/libfdproto.h	(revision 769)
+++ include/freeDiameter/libfdproto.h	(revision 778)
@@ -851,4 +851,8 @@
 int fd_dict_getlistof(int criteria, void * parent, struct fd_list ** sentinel);
 
+/* Function to remove an entry from the dictionary.
+  This cannot be used if the object has children (for example a vendor with vendor-specific AVPs).
+  In such case, the children must be removed first. */
+int fd_dict_delete(struct dict_object * obj);
 
 /*
@@ -1860,4 +1864,7 @@
 void fd_sess_dump_hdl(int level, struct session_handler * handler);
 
+/* For statistics / monitoring: get the number of struct session in memory */
+int fd_sess_getcount(uint32_t *cnt);
+
 /*============================================================*/
 /*                         ROUTING                            */
Index: libfdproto/dictionary.c
===================================================================
--- libfdproto/dictionary.c	(revision 770)
+++ libfdproto/dictionary.c	(revision 778)
@@ -1812,4 +1812,42 @@
 }
 
+
+int fd_dict_delete(struct dict_object * obj)
+{
+	int i;
+	struct dictionary * dict;
+	int ret=0;
+	
+	/* check params */
+	CHECK_PARAMS( verify_object(obj) && obj->dico);
+	dict = obj->dico;
+
+	/* Lock the dictionary for change */
+	CHECK_POSIX(  pthread_rwlock_wrlock(&dict->dict_lock)  );
+	
+	/* check the object is not sentinel for another list */
+	for (i=0; i<NB_LISTS_PER_OBJ; i++) {
+		if (!_OBINFO(obj).haslist[i] && !(FD_IS_LIST_EMPTY(&obj->list[i]))) {
+			/* There are children, this is not good */
+			ret = EINVAL;
+			TRACE_DEBUG (FULL, "Cannot delete object, list %d not empty:", i);
+			#if 0
+			dump_list(&obj->list[i], 0,0,0);
+			#endif
+			break;
+		}
+	}
+	
+	/* ok, now destroy the object */
+	if (!ret)
+		destroy_object(obj);
+	
+	/* Unlock */
+	CHECK_POSIX(  pthread_rwlock_unlock(&dict->dict_lock)  );
+	
+	return ret;
+}
+
+
 int fd_dict_search ( struct dictionary * dict, enum dict_object_type type, int criteria, void * what, struct dict_object **result, int retval )
 {
Index: libfdproto/sessions.c
===================================================================
--- libfdproto/sessions.c	(revision 740)
+++ libfdproto/sessions.c	(revision 778)
@@ -115,4 +115,6 @@
 #define H_LOCK( _hash ) (&(sess_hash[H_MASK(_hash)].lock    ))
 
+static uint32_t		sess_cnt = 0; /* counts all active session (that are in the expiry list) */
+
 /* The following are used to generate sid values that are eternaly unique */
 static uint32_t   	sid_h;	/* initialized to the current time in fd_sess_init */
@@ -485,4 +487,5 @@
 	}
 	fd_list_insert_after( li, &sess->expire );
+	sess_cnt++;
 
 	/* We added a new expiring element, we must signal */
@@ -612,5 +615,8 @@
 	/* Unlink from the expiry list */
 	CHECK_POSIX_DO( pthread_mutex_lock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
-	fd_list_unlink( &sess->expire ); /* no need to signal the condition here */
+	if (!FD_IS_LIST_EMPTY(&sess->expire)) {
+		sess_cnt--;
+		fd_list_unlink( &sess->expire ); /* no need to signal the condition here */
+	}
 	CHECK_POSIX_DO( pthread_mutex_unlock( &exp_lock ), { ASSERT(0); /* otherwise cleanup handler is not pop'd */ } );
 	
@@ -890,2 +896,11 @@
 	fd_log_debug("\t  %*s -- end of handler @%p --\n", level, "", handler);
 }	
+
+int fd_sess_getcount(uint32_t *cnt)
+{
+	CHECK_PARAMS(cnt);
+	CHECK_POSIX( pthread_mutex_lock( &exp_lock ) );
+	*cnt = sess_cnt;
+	CHECK_POSIX( pthread_mutex_unlock( &exp_lock ) );
+	return 0;
+}
Index: tests/testdict.c
===================================================================
--- tests/testdict.c	(revision 770)
+++ tests/testdict.c	(revision 778)
@@ -166,4 +166,42 @@
 	}
 
+	/* Test delete function */
+	{
+		struct fd_list * li = NULL;
+		struct fd_list * sentinel = NULL;
+		struct dict_object * obj=NULL;
+		vendor_id_t vid = 0;
+		int count = 0, cntbkp;
+		
+		CHECK( 0, fd_dict_search(fd_g_config->cnf_dict, DICT_VENDOR, VENDOR_BY_ID, &vid, &obj, ENOENT) );
+		
+		CHECK( EINVAL, fd_dict_delete(obj) );
+			
+		
+		CHECK( 0, fd_dict_getlistof(AVP_BY_NAME, obj, &sentinel));
+		obj = NULL;
+		
+		for (li = sentinel->next; li != sentinel; li = li->next) {
+			struct dict_avp_data data;
+			CHECK( 0, fd_dict_getval(li->o, &data) );
+			count++;
+			if (data.avp_basetype != AVP_TYPE_GROUPED)
+				obj = li->o;
+		}
+		
+		CHECK(1, obj ? 1 : 0 );
+#if 1
+		fd_dict_dump_object(obj);
+#endif
+		CHECK( 0, fd_dict_delete(obj) );
+		cntbkp = count;
+		count = 0;
+		for (li = sentinel->next; li != sentinel; li = li->next) {
+			count++;
+		}
+		CHECK( 1, cntbkp - count );
+		
+	}
+	
 	/* That's all for the tests yet */
 	PASSTEST();
Index: tests/testsess.c
===================================================================
--- tests/testsess.c	(revision 740)
+++ tests/testsess.c	(revision 778)
@@ -174,4 +174,20 @@
 		CHECK( 0, fd_sess_destroy( &sess1 ) );
 	}
+	
+	/* Test fd_sess_getcount */
+	{
+		uint32_t cnt;
+		CHECK( 0, fd_sess_new( &sess1, TEST_DIAM_ID, CONSTSTRLEN(TEST_DIAM_ID), NULL, 0 ) );
+		CHECK( 0, fd_sess_new( &sess2, TEST_DIAM_ID, CONSTSTRLEN(TEST_DIAM_ID), NULL, 0 ) );
+		CHECK( 0, fd_sess_getcount(&cnt));
+		CHECK( 2, cnt);
+		CHECK( 0, fd_sess_destroy( &sess2 ) );
+		CHECK( 0, fd_sess_getcount(&cnt));
+		CHECK( 1, cnt);
+		CHECK( 0, fd_sess_destroy( &sess1 ) );
+		CHECK( 0, fd_sess_getcount(&cnt));
+		CHECK( 0, cnt);
+		
+	}
 		
 	/* Test fd_sess_fromsid */
