changeset 13:ef9ef3bf4752

Progress on peer state machine
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 30 Sep 2009 18:25:46 +0900
parents 418d2ce80dc8
children 14cf6daf716d
files doc/freediameter.conf.sample freeDiameter/CMakeLists.txt freeDiameter/fD.h freeDiameter/fdd.y freeDiameter/main.c freeDiameter/p_expiry.c freeDiameter/p_psm.c freeDiameter/peers.c freeDiameter/queues.c include/freeDiameter/CMakeLists.txt include/freeDiameter/freeDiameter-host.h.in include/freeDiameter/freeDiameter.h include/freeDiameter/libfreeDiameter.h
diffstat 13 files changed, 510 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/doc/freediameter.conf.sample	Mon Sep 28 17:29:25 2009 +0900
+++ b/doc/freediameter.conf.sample	Wed Sep 30 18:25:46 2009 +0900
@@ -162,3 +162,4 @@
 LoadExtension = "extensions/dict_nasreq.fdx";
 LoadExtension = "extensions/dict_eap.fdx";
 ConnectPeer = "jules.nautilus6.org" ;
+ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ;
--- a/freeDiameter/CMakeLists.txt	Mon Sep 28 17:29:25 2009 +0900
+++ b/freeDiameter/CMakeLists.txt	Wed Sep 30 18:25:46 2009 +0900
@@ -14,8 +14,10 @@
 	extensions.c
 	dict_base_proto.c
 	messages.c
+	queues.c
 	peers.c
-	queues.c
+	p_expiry.c
+	p_psm.c
 	)
 
 SET(FD_COMMON_GEN_SRC
--- a/freeDiameter/fD.h	Mon Sep 28 17:29:25 2009 +0900
+++ b/freeDiameter/fD.h	Wed Sep 30 18:25:46 2009 +0900
@@ -126,6 +126,10 @@
 	/* connection context: socket & other metadata */
 	struct cnxctx	*p_cnxctx;
 	
+	/* Callback on initial connection success / failure */
+	void 		(*p_cb)(struct peer_info *, void *);
+	void 		*p_cb_data;
+	
 };
 #define CHECK_PEER( _p ) \
 	(((_p) != NULL) && (((struct fd_peer *)(_p))->p_eyec == EYEC_PEER))
@@ -150,10 +154,21 @@
 
 /* Functions */
 int fd_peer_init();
+int fd_peer_fini();
 void fd_peer_dump_list(int details);
-int fd_peer_start();
-int fd_peer_waitstart();
+/* fd_peer_add declared in freeDiameter.h */
+int fd_peer_rc_decr(struct fd_peer **ptr, int locked);
 
+/* Peer expiry */
+int fd_p_expi_init(void);
+int fd_p_expi_fini(void);
+int fd_p_expi_update(struct fd_peer * peer, int locked );
+int fd_p_expi_unlink(struct fd_peer * peer, int locked );
 
+/* Peer state machine */
+int fd_psm_start();
+int fd_psm_begin(struct fd_peer * peer );
+int fd_psm_terminate(struct fd_peer * peer );
+void fd_psm_abord(struct fd_peer * peer );
 
 #endif /* _FD_H */
--- a/freeDiameter/fdd.y	Mon Sep 28 17:29:25 2009 +0900
+++ b/freeDiameter/fdd.y	Wed Sep 30 18:25:46 2009 +0900
@@ -209,12 +209,13 @@
 					{ yyerror (&yylloc, conf, "Out of memory"); YYERROR; } );
 				memset(ep, 0, sizeof(struct fd_endpoint));
 				fd_list_init(&ep->chain, NULL);
+				ep->meta.conf = 1;
 				
 				memset(&hints, 0, sizeof(hints));
 				hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
 				ret = getaddrinfo($3, NULL, &hints, &ai);
-				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
-				
+				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; }
+				ASSERT( ai->ai_addrlen <= sizeof(sSS) );
 				memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
 				free($3);
 				freeaddrinfo(ai);
@@ -425,11 +426,17 @@
 					{ yyerror (&yylloc, conf, "Out of memory"); YYERROR; } );
 				memset(ep, 0, sizeof(struct fd_endpoint));
 				fd_list_init(&ep->chain, NULL);
-				
+				ep->meta.conf = 1;
 				memset(&hints, 0, sizeof(hints));
-				hints.ai_flags = AI_ADDRCONFIG;
+				hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICHOST;
 				ret = getaddrinfo($4, NULL, &hints, &ai);
-				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
+				if (ret == EAI_NONAME) {
+					/* The name was maybe not numeric, try again */
+					ep->meta.disc = 1;
+					hints.ai_flags &= ~ AI_NUMERICHOST;
+					ret = getaddrinfo($4, NULL, &hints, &ai);
+				}
+				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); free(ep); YYERROR; }
 				
 				memcpy(&ep->ss, ai->ai_addr, ai->ai_addrlen);
 				free($4);
--- a/freeDiameter/main.c	Mon Sep 28 17:29:25 2009 +0900
+++ b/freeDiameter/main.c	Wed Sep 30 18:25:46 2009 +0900
@@ -88,7 +88,7 @@
 	CHECK_FCT(  fd_ext_load()  );
 	
 	/* Start the peer state machines */
-	CHECK_FCT( fd_peer_start() );
+	CHECK_FCT( fd_psm_start() );
 	
 	/* Now, just wait for events */
 	TRACE_DEBUG(INFO, FD_PROJECT_BINARY " daemon initialized.");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freeDiameter/p_expiry.c	Wed Sep 30 18:25:46 2009 +0900
@@ -0,0 +1,78 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, 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 "fD.h"
+
+
+
+
+/* Initialize peers expiry mechanism */
+int fd_p_expi_init(void)
+{
+	TODO("");
+	return ENOTSUP;
+}
+
+/* Finish peers expiry mechanism */
+int fd_p_expi_fini(void)
+{
+	TODO("");
+	return ENOTSUP;
+}
+
+/* Add a peer in the expiry list if needed */
+int fd_p_expi_update(struct fd_peer * peer, int locked )
+{
+	TODO("");
+	
+	/* if peer expires */
+		/* add to the expiry list in appropriate position */
+		/* increment peer refcount */
+		/* signal the expiry thread if we added in first position */
+	
+	return ENOTSUP;
+}
+
+/* Remove a peer from expiry list if needed */
+int fd_p_expi_unlink(struct fd_peer * peer, int locked )
+{
+	TODO("");
+	/* if peer is in expiry list */
+		/* remove from the list */
+		/* decrement peer refcount */
+		/* no need to signal the expiry thread ... */
+	
+	return ENOTSUP;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freeDiameter/p_psm.c	Wed Sep 30 18:25:46 2009 +0900
@@ -0,0 +1,92 @@
+/*********************************************************************************************************
+* Software License Agreement (BSD License)                                                               *
+* Author: Sebastien Decugis <sdecugis@nict.go.jp>							 *
+*													 *
+* Copyright (c) 2009, 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 "fD.h"
+
+static int started = 0;
+static pthread_mutex_t  started_mtx = PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t   started_cnd = PTHREAD_COND_INITIALIZER;
+
+/* Wait for start signal */
+static int fd_psm_waitstart()
+{
+	TRACE_ENTRY("");
+	CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
+awake:	
+	if (! started) {
+		pthread_cleanup_push( fd_cleanup_mutex, &started_mtx );
+		CHECK_POSIX( pthread_cond_wait(&started_cnd, &started_mtx) );
+		pthread_cleanup_pop( 0 );
+		goto awake;
+	}
+	CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
+	return 0;
+}
+
+/* Allow the state machines to start */
+int fd_psm_start()
+{
+	TRACE_ENTRY("");
+	CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
+	started = 1;
+	CHECK_POSIX( pthread_cond_broadcast(&started_cnd) );
+	CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
+	return 0;
+}
+
+/* Create the PSM thread of one peer structure */
+int fd_psm_begin(struct fd_peer * peer )
+{
+	TRACE_ENTRY("%p", peer);
+	TODO("");
+	return ENOTSUP;
+}
+
+/* End the PSM (clean ending) */
+int fd_psm_terminate(struct fd_peer * peer )
+{
+	TRACE_ENTRY("%p", peer);
+	TODO("");
+	return ENOTSUP;
+}
+
+/* End the PSM violently */
+void fd_psm_abord(struct fd_peer * peer )
+{
+	TRACE_ENTRY("%p", peer);
+	TODO("");
+	return;
+}
+
--- a/freeDiameter/peers.c	Mon Sep 28 17:29:25 2009 +0900
+++ b/freeDiameter/peers.c	Wed Sep 30 18:25:46 2009 +0900
@@ -50,35 +50,6 @@
 struct fd_list   fd_g_peers;
 pthread_rwlock_t fd_g_peers_rw;
 
-static int started = 0;
-static pthread_mutex_t  started_mtx = PTHREAD_MUTEX_INITIALIZER;
-static pthread_cond_t   started_cnd = PTHREAD_COND_INITIALIZER;
-
-/* Wait for start signal */
-int fd_peer_waitstart()
-{
-	CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
-awake:	
-	if (! started) {
-		pthread_cleanup_push( fd_cleanup_mutex, &started_mtx );
-		CHECK_POSIX( pthread_cond_wait(&started_cnd, &started_mtx) );
-		pthread_cleanup_pop( 0 );
-		goto awake;
-	}
-	CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
-	return 0;
-}
-
-/* Allow the state machines to start */
-int fd_peer_start()
-{
-	CHECK_POSIX( pthread_mutex_lock(&started_mtx) );
-	started = 1;
-	CHECK_POSIX( pthread_cond_broadcast(&started_cnd) );
-	CHECK_POSIX( pthread_mutex_unlock(&started_mtx) );
-	return 0;
-}
-
 /* Initialize the peers list */
 int fd_peer_init()
 {
@@ -87,6 +58,20 @@
 	fd_list_init(&fd_g_peers, NULL);
 	CHECK_POSIX( pthread_rwlock_init(&fd_g_peers_rw, NULL) );
 	
+	CHECK_FCT(fd_p_expi_init());
+	
+	return 0;
+}
+
+/* Terminate peer module (destroy all peers) */
+int fd_peer_fini()
+{
+	TRACE_ENTRY();
+	
+	CHECK_FCT_DO(fd_p_expi_fini(), /* continue */);
+	
+	TODO("Complete this function")
+	
 	return 0;
 }
 
@@ -118,8 +103,235 @@
 	CHECK_FCT_DO( pthread_rwlock_unlock(&fd_g_peers_rw), /* continue */ );
 }
 
+/* Alloc / reinit a peer structure. if *ptr is not NULL, it must already point to a valid struct fd_peer. */
+static int fd_sp_reinit(struct fd_peer ** ptr)
+{
+	struct fd_peer *p;
+	
+	TRACE_ENTRY("%p", ptr);
+	CHECK_PARAMS(ptr);
+	
+	if (*ptr) {
+		p = *ptr;
+	} else {
+		CHECK_MALLOC( p = malloc(sizeof(struct fd_peer)) );
+		*ptr = p;
+	}
+	
+	/* Now initialize the content */
+	memset(p, 0, sizeof(struct fd_peer));
+	
+	fd_list_init(&p->p_hdr.chain, p);
+	
+	fd_list_init(&p->p_hdr.info.pi_endpoints, NULL);
+	p->p_hdr.info.pi_state = STATE_DISABLED;
+	fd_list_init(&p->p_hdr.info.pi_apps, NULL);
+	
+	p->p_eyec = EYEC_PEER;
+	CHECK_POSIX( pthread_mutex_init(&p->p_mtx, NULL) );
+	fd_list_init(&p->p_expiry, p);
+	fd_list_init(&p->p_actives, p);
+	p->p_hbh = lrand48();
+	CHECK_FCT( fd_fifo_new(&p->p_events) );
+	CHECK_FCT( fd_fifo_new(&p->p_recv) );
+	CHECK_FCT( fd_fifo_new(&p->p_tosend) );
+	fd_list_init(&p->p_sentreq, p);
+	
+	return 0;
+}
+
+#define free_null( _v ) 	\
+	if (_v) {		\
+		free(_v);	\
+		(_v) = NULL;	\
+	}
+	
+#define free_list( _l ) 						\
+	while (!FD_IS_LIST_EMPTY(_l)) {					\
+		struct fd_list * __li = ((struct fd_list *)(_l))->next;	\
+		fd_list_unlink(__li);					\
+		free(__li);						\
+	}
+
+/* Destroy a structure once all cleanups have been performed */
+static int fd_sp_destroy(struct fd_peer ** ptr)
+{
+	struct fd_peer *p;
+	void * t;
+	
+	TRACE_ENTRY("%p", ptr);
+	CHECK_PARAMS(ptr);
+	p = *ptr;
+	*ptr = NULL;
+	CHECK_PARAMS(p);
+	
+	CHECK_PARAMS( (p->p_refcount == 0) && FD_IS_LIST_EMPTY(&p->p_hdr.chain) );
+	
+	free_null(p->p_hdr.info.pi_diamid); 
+	free_null(p->p_hdr.info.pi_realm); 
+	free_list( &p->p_hdr.info.pi_endpoints );
+	/* Assume the security data is already freed */
+	free_null(p->p_hdr.info.pi_prodname);
+	free_list( &p->p_hdr.info.pi_apps );
+	
+	free_null(p->p_dbgorig);
+	CHECK_POSIX( pthread_mutex_destroy(&p->p_mtx) );
+	ASSERT(FD_IS_LIST_EMPTY(&p->p_expiry));
+	ASSERT(FD_IS_LIST_EMPTY(&p->p_actives));
+	
+	CHECK_FCT( fd_thr_term(&p->p_psm) );
+	while ( fd_fifo_tryget(p->p_events, &t) == 0 ) {
+		struct fd_event * ev = t;
+		TRACE_DEBUG(FULL, "Found event %d(%p) in queue of peer %p being destroyed", ev->code, ev->data, p);
+		free(ev);
+	}
+	CHECK_FCT( fd_fifo_del(&p->p_events) );
+	
+	CHECK_FCT( fd_thr_term(&p->p_inthr) );
+	while ( fd_fifo_tryget(p->p_recv, &t) == 0 ) {
+		struct msg * m = t;
+		TRACE_DEBUG(FULL, "Found message %p in incoming queue of peer %p being destroyed", m, p);
+		/* We simply destroy, the remote peer will re-send to someone else...*/
+		CHECK_FCT(fd_msg_free(m));
+	}
+	CHECK_FCT( fd_fifo_del(&p->p_recv) );
+	
+	CHECK_FCT( fd_thr_term(&p->p_outthr) );
+	while ( fd_fifo_tryget(p->p_tosend, &t) == 0 ) {
+		struct msg * m = t;
+		TRACE_DEBUG(FULL, "Found message %p in outgoing queue of peer %p being destroyed, requeue", m, p);
+		/* We simply requeue in global, the routing thread will re-handle it. */
+		
+	}
+	CHECK_FCT( fd_fifo_del(&p->p_tosend) );
+	
+	while (!FD_IS_LIST_EMPTY(&p->p_sentreq)) {
+		struct sentreq * sr = (struct sentreq *)(p->p_sentreq.next);
+		fd_list_unlink(&sr->chain);
+		TRACE_DEBUG(FULL, "Found message %p in list of sent requests to peer %p being destroyed, requeue (fallback)", sr->req, p);
+		CHECK_FCT(fd_fifo_post(fd_g_outgoing, &sr->req));
+		free(sr);
+	}
+	
+	TRACE_DEBUG(NONE, "TODO: destroy p->p_cnxctx here");
+	
+	if (p->p_cb)
+		(*p->p_cb)(NULL, p->p_cb_data);
+	
+	free(p);
+	
+	return 0;
+}
+
+/* Decrement refcount, delete if 0 */
+int fd_peer_rc_decr(struct fd_peer **ptr, int locked)
+{
+	int count;
+	struct fd_peer *p;
+	TRACE_ENTRY("%p %d", p, locked);
+	
+	CHECK_PARAMS(ptr && CHECK_PEER( *ptr ));
+	p = *ptr;
+	
+	if (!locked) {
+		CHECK_POSIX( pthread_rwlock_rdlock(&fd_g_peers_rw) );
+		CHECK_POSIX( pthread_mutex_lock( &p->p_mtx ) );
+		CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
+	}
+	
+	count = --(p->p_refcount);
+	
+	if (!locked) {
+		CHECK_POSIX( pthread_mutex_unlock( &p->p_mtx ) );
+	}
+	
+	if (count <= 0) {
+		/* All links have already been removed, we can destroy */
+		CHECK_FCT( fd_sp_destroy(ptr) );
+	}
+	return 0;
+}
+
 /* Add a new peer entry */
 int fd_peer_add ( struct peer_info * info, char * orig_dbg, void (*cb)(struct peer_info *, void *), void * cb_data )
 {
-	return ENOTSUP;
+	struct fd_peer *p = NULL;
+	struct fd_list * li;
+	int ret = 0;
+	TRACE_ENTRY("%p %p %p %p", info, orig_dbg, cb, cb_data);
+	CHECK_PARAMS(info && info->pi_diamid);
+	
+	/* Create a structure to contain the new peer information */
+	CHECK_FCT( fd_sp_reinit(&p) );
+	
+	/* Copy the informations from the parameters received */
+	CHECK_MALLOC( p->p_hdr.info.pi_diamid = strdup(info->pi_diamid) );
+	if (info->pi_realm) {
+		CHECK_MALLOC( p->p_hdr.info.pi_realm = strdup(info->pi_realm) );
+	}
+	
+	p->p_hdr.info.pi_flags.pro3 = info->pi_flags.pro3;
+	p->p_hdr.info.pi_flags.pro4 = info->pi_flags.pro4;
+	p->p_hdr.info.pi_flags.alg  = info->pi_flags.alg;
+	p->p_hdr.info.pi_flags.sec  = info->pi_flags.sec;
+	p->p_hdr.info.pi_flags.exp  = info->pi_flags.exp;
+	
+	p->p_hdr.info.pi_lft     = info->pi_lft;
+	p->p_hdr.info.pi_streams = info->pi_streams;
+	p->p_hdr.info.pi_port    = info->pi_port;
+	p->p_hdr.info.pi_tctimer = info->pi_tctimer;
+	p->p_hdr.info.pi_twtimer = info->pi_twtimer;
+	
+	/* Move the items from one list to the other */
+	while (!FD_IS_LIST_EMPTY( &info->pi_endpoints ) ) {
+		li = info->pi_endpoints.next;
+		fd_list_unlink(li);
+		fd_list_insert_before(&p->p_hdr.info.pi_endpoints, li);
+	}
+	
+	p->p_hdr.info.pi_sec_module = info->pi_sec_module;
+	memcpy(&p->p_hdr.info.pi_sec_data, &info->pi_sec_data, sizeof(info->pi_sec_data));
+	
+	/* The internal data */
+	if (orig_dbg) {
+		CHECK_MALLOC( p->p_dbgorig = strdup(orig_dbg) );
+	} else {
+		CHECK_MALLOC( p->p_dbgorig = strdup("unknown") );
+	}
+	p->p_cb = cb;
+	p->p_cb_data = cb_data;
+	
+	/* Ok, now check if we don't already have an entry with the same Diameter Id, and insert this one */
+	CHECK_POSIX( pthread_rwlock_wrlock(&fd_g_peers_rw) );
+	CHECK_POSIX( pthread_mutex_lock( &p->p_mtx ) );
+	
+	for (li = fd_g_peers.next; li != &fd_g_peers; li = li->next) {
+		struct fd_peer * prev = (struct fd_peer *)li;
+		int cmp = strcasecmp( p->p_hdr.info.pi_diamid, prev->p_hdr.info.pi_diamid );
+		if (cmp < 0)
+			continue;
+		if (cmp == 0)
+			ret = EEXIST;
+		break;
+	}
+	
+	/* We can insert the new peer object */
+	if (! ret) {
+		/* Update expiry list */
+		CHECK_FCT_DO( ret = fd_p_expi_update( p, 1 ), goto out );
+		
+		/* Insert the new element in the list */
+		fd_list_insert_before( li, &p->p_hdr.chain );
+		p->p_refcount++;
+	}
+
+out:	
+	CHECK_POSIX( pthread_mutex_unlock( &p->p_mtx ) );
+	CHECK_POSIX( pthread_rwlock_unlock(&fd_g_peers_rw) );
+	if (ret) {
+		CHECK_FCT( fd_sp_destroy(&p) );
+	} else {
+		CHECK_FCT( fd_psm_start(p) );
+	}
+	return ret;
 }
--- a/freeDiameter/queues.c	Mon Sep 28 17:29:25 2009 +0900
+++ b/freeDiameter/queues.c	Wed Sep 30 18:25:46 2009 +0900
@@ -56,10 +56,15 @@
 	TRACE_ENTRY();
 	
 	/* Stop the providing threads */
+	TODO("Stop the providing threads");
+	
 	/* Empty all contents */
+	TODO("Empty all contents (dump to log file ?)");
+	
 	/* Now, delete the queues */
 	CHECK_FCT( fd_fifo_del ( &fd_g_incoming ) );
 	CHECK_FCT( fd_fifo_del ( &fd_g_outgoing ) );
 	CHECK_FCT( fd_fifo_del ( &fd_g_local ) );
+	
 	return 0;
 }
--- a/include/freeDiameter/CMakeLists.txt	Mon Sep 28 17:29:25 2009 +0900
+++ b/include/freeDiameter/CMakeLists.txt	Wed Sep 30 18:25:46 2009 +0900
@@ -11,6 +11,9 @@
 # Disable SCTP support completly ?
 OPTION(DISABLE_SCTP "Disable SCTP support?")
 
+# Disable SCTP support completly ?
+OPTION(ERRORS_ON_TODO "(development) Generate compilation errors on TODO items ?" OFF)
+
 
 ########################
 # System checks 
--- a/include/freeDiameter/freeDiameter-host.h.in	Mon Sep 28 17:29:25 2009 +0900
+++ b/include/freeDiameter/freeDiameter-host.h.in	Wed Sep 30 18:25:46 2009 +0900
@@ -44,7 +44,7 @@
 #cmakedefine HOST_BIG_ENDIAN @HOST_BIG_ENDIAN@
 
 #cmakedefine DISABLE_SCTP
-
+#cmakedefine ERRORS_ON_TODO
 #cmakedefine DEBUG
 
 #cmakedefine FD_PROJECT_BINARY "@FD_PROJECT_BINARY@"
--- a/include/freeDiameter/freeDiameter.h	Mon Sep 28 17:29:25 2009 +0900
+++ b/include/freeDiameter/freeDiameter.h	Wed Sep 30 18:25:46 2009 +0900
@@ -80,6 +80,15 @@
 struct fd_endpoint {
 	struct fd_list  chain;	/* link in cnf_endpoints list */
 	sSS		ss;	/* the socket information. */
+	struct {
+		unsigned conf : 1; /* This endpoint is statically configured in a configuration file */
+		unsigned disc : 1; /* This endpoint was resolved from the Diameter Identity or other DNS query */
+		unsigned adv  : 1; /* This endpoint was advertized in Diameter CER/CEA exchange */
+		unsigned ll   : 1; /* Lower layer mechanism provided this endpoint */
+		
+		/* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
+
+	}		meta;	/* Additional information about the endpoint */
 };
 
 /* Applications */
@@ -163,11 +172,11 @@
 #define STATE_STR(state) \
 	peer_state_str[ ((unsigned)(state)) <= STATE_REOPEN ? ((unsigned)(state)) : 0 ]
 
-/* Information about a remote peer, used both for query and for creating a new entry */
+/* Information about a remote peer. Same structure is used for creating a new entry, but not all fields are meaningful in that case */
 struct peer_info {
 	
-	char * pi_diamid;	/* UTF-8, \0 terminated. The Diameter Identity of the remote peer */
-	char * pi_realm;	/* idem, its realm. */
+	char * 		pi_diamid;	/* UTF-8, \0 terminated. The Diameter Identity of the remote peer */
+	char * 		pi_realm;	/* Its realm, as received in CER/CEA exchange. */
 	
 	struct {
 		#define PI_P3_DEFAULT	0	/* Use the default L3 protocol configured for the host */
@@ -190,7 +199,7 @@
 		unsigned	sec :2;
 		
 		#define PI_EXP_NONE	0	/* the peer entry does not expire */
-		#define PI_EXP_INACTIVE	1	/* the peer entry expires after pi_lft seconds without activity */
+		#define PI_EXP_INACTIVE	1	/* the peer entry expires (i.e. is deleted) after pi_lft seconds without activity */
 		unsigned	exp :1;
 		
 		/* Following flags are read-only and received from remote peer */
@@ -198,17 +207,35 @@
 		#define PI_INB_TLS	2	/* Remote peer advertised inband-sec-id 1 (TLS) */
 		unsigned	inband :2;	/* This is only meaningful with pi_flags.sec == 3 */
 		
-		unsigned	relay :1;	/* The remote peer advertized the relay application */		
-	} pi_flags;
+		unsigned	relay :1;	/* The remote peer advertized the relay application */
+
+	} 		pi_flags;	/* Some flags */
 	
 	/* Additional parameters */
-	uint32_t 	pi_lft;		/* lifetime of entry without activity (except watchdogs) (see pi_flags.exp definition) */
+	uint32_t 	pi_lft;		/* lifetime of this peer when inactive (see pi_flags.exp definition) */
 	uint16_t	pi_streams; 	/* number of streams for SCTP. 0 = default */
 	uint16_t	pi_port; 	/* port to connect to. 0: default. */
 	int		pi_tctimer; 	/* use this value for TcTimer instead of global, if != 0 */
 	int		pi_twtimer; 	/* use this value for TwTimer instead of global, if != 0 */
 	
-	struct fd_list	pi_endpoints;	/* Endpoint(s) of the remote peer (discovered or advertized). list of struct fd_endpoint. DNS resolved if empty. */
+	struct fd_list	pi_endpoints;	/* Endpoint(s) of the remote peer (configured, discovered, or advertized). list of struct fd_endpoint. DNS resolved if empty. */
+	
+	/* TLS specific data -- the exact data pointed here depends on the security module in use (ex: gnutls, ...) */
+	enum {
+		PI_SEC_GNUTLS = 0,	/* The security module is GNUTLS, this is the default */
+		PI_SEC_OTHER		/* Another security module (TBD) */
+	}		pi_sec_module;
+	union {
+		/* Security data when pi_sec_module == PI_SEC_GNUTLS */
+		struct {
+			void *	CA;	/* Authority to use to validate this peer credentials (a CA or root certificate) -- use default if NULL */
+			void *	cred;	/* The (valid) credentials that the peer has presented */
+		} 	gnutls;
+		/* Security data when pi_sec_module == PI_SEC_OTHER */
+		struct {
+			void * dummy;	/* Something meaningful for the other security module */
+		} 	other;
+	} 		pi_sec_data;
 	
 	/* The remaining information is read-only, not used for peer creation */
 	enum peer_state	pi_state;
@@ -243,9 +270,18 @@
  *
  * DESCRIPTION: 
  *  Add a peer to the list of peers to which the daemon must maintain a connexion.
- * If cb is not null, the callback is called when the connection is in OPEN state or
+ *
+ *  The content of info parameter is copied, except for the list of endpoints if 
+ * not empty, which is simply moved into the created object. It means that the list
+ * items must have been malloc'd, so that they can be freed.
+ *
+ *  If cb is not null, the callback is called when the connection is in OPEN state or
  * when an error has occurred. The callback should use the pi_state information to 
- * determine which one it is.
+ * determine which one it is. If the first parameter of the called callback is NULL, it 
+ * means that the peer is being destroyed before attempt success / failure. 
+ * cb is called to allow freeing cb_data in  * this case.
+ *
+ *  The orig_dbg string is only useful for easing debug, and can be left to NULL.
  *
  * RETURN VALUE:
  *  0      	: The peer is added.
--- a/include/freeDiameter/libfreeDiameter.h	Mon Sep 28 17:29:25 2009 +0900
+++ b/include/freeDiameter/libfreeDiameter.h	Wed Sep 30 18:25:46 2009 +0900
@@ -189,6 +189,15 @@
 #define TRACE_DEBUG_ALL( str ) 	\
 	TRACE_DEBUG(CALL, str );
 
+/* For development only, to keep track of TODO locations in the code */
+#ifndef ERRORS_ON_TODO
+#define TODO( _msg, _args... ) \
+	TRACE_DEBUG(NONE, _msg , ##_args);
+#else /* ERRORS_ON_TODO */
+#define TODO( _msg, _args... ) \
+	"TODO" = _msg ## _args; /* just a stupid compilation error to spot the todo */
+#endif /* ERRORS_ON_TODO */
+
 
 /* Macros to check a return value and branch out in case of error.
  * These macro must be used only when errors are highly improbable, not for expected errors.
"Welcome to our mercurial repository"