Index: doc/freediameter.conf.sample
===================================================================
--- doc/freediameter.conf.sample	(revision 23)
+++ doc/freediameter.conf.sample	(revision 24)
@@ -205,6 +205,6 @@
 TcTimer = 60;
 TwTimer = 6;
-ListenOn = "133.243.146.201";
-ListenOn = "fe80::21d:9ff:fe89:7d68%eth0";
+#ListenOn = "133.243.146.201";
+#ListenOn = "fe80::21d:9ff:fe89:7d68%eth0";
 NoRelay;
 LoadExtension = "extensions/dbg_monitor.fdx";
Index: freeDiameter/CMakeLists.txt
===================================================================
--- freeDiameter/CMakeLists.txt	(revision 22)
+++ freeDiameter/CMakeLists.txt	(revision 24)
@@ -13,4 +13,5 @@
 	cnxctx.c
 	dispatch.c
+	endpoints.c
 	extensions.c
 	dict_base_proto.c
Index: freeDiameter/cnxctx.c
===================================================================
--- freeDiameter/cnxctx.c	(revision 23)
+++ freeDiameter/cnxctx.c	(revision 24)
@@ -174,7 +174,13 @@
 	return NULL;
 }
-#ifndef DISABLE_SCTP
+
+/* Same function for SCTP, with a list of local endpoints to bind to */
 struct cnxctx * fd_cnx_serv_sctp(uint16_t port, struct fd_list * ep_list)
 {
+#ifdef DISABLE_SCTP
+	TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
+	ASSERT(0);
+	CHECK_FCT_DO( ENOTSUP, return NULL);
+#else /* DISABLE_SCTP */
 	struct cnxctx * cnx = NULL;
 	sSS dummy;
@@ -201,6 +207,6 @@
 	fd_cnx_destroy(cnx);
 	return NULL;
-}
 #endif /* DISABLE_SCTP */
+}
 
 /* Allow clients to connect on the server socket */
@@ -239,10 +245,11 @@
 	CHECK_PARAMS_DO(serv, return NULL);
 	
+	/* Accept the new connection -- this is blocking until new client enters or cancellation */
 	CHECK_SYS_DO( cli_sock = accept(serv->cc_socket, (sSA *)&ss, &ss_len), return NULL );
 	
 	if (TRACE_BOOL(INFO)) {
-		fd_log_debug("%s - new client [", fd_cnx_getid(serv));
-		sSA_DUMP_NODE( &ss, AI_NUMERICHOST );
-		fd_log_debug("] connected.\n");
+		fd_log_debug("%s : accepted new client [", fd_cnx_getid(serv));
+		sSA_DUMP_NODE( &ss, NI_NUMERICHOST );
+		fd_log_debug("].\n");
 	}
 	
@@ -259,23 +266,25 @@
 		/* Numeric values for debug */
 		rc = getnameinfo((sSA *)&ss, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
-		if (rc)
+		if (rc) {
 			snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
-		
-		snprintf(cli->cc_id, sizeof(cli->cc_id), "Client %s [%s]:%s (%d) / serv (%d)", 
+			portbuf[0] = '\0';
+		}
+		
+		snprintf(cli->cc_id, sizeof(cli->cc_id), "Incoming %s [%s]:%s (%d) @ serv (%d)", 
 				IPPROTO_NAME(cli->cc_proto), 
 				addrbuf, portbuf, 
 				cli->cc_socket, serv->cc_socket);
 		
-		/* Textual value for log messages */
-		rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, NI_NUMERICHOST);
+		/* Name for log messages */
+		rc = getnameinfo((sSA *)&ss, sizeof(sSS), cli->cc_remid, sizeof(cli->cc_remid), NULL, 0, 0);
 		if (rc)
 			snprintf(cli->cc_remid, sizeof(cli->cc_remid), "[err:%s]", gai_strerror(rc));
 	}
 
+#ifndef DISABLE_SCTP
 	/* SCTP-specific handlings */
-#ifndef DISABLE_SCTP
 	if (cli->cc_proto == IPPROTO_SCTP) {
 		/* Retrieve the number of streams */
-		CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out ), goto error );
+		CHECK_FCT_DO( fd_sctp_get_str_info( cli->cc_socket, &cli->cc_sctp_para.str_in, &cli->cc_sctp_para.str_out, NULL ), goto error );
 		if (cli->cc_sctp_para.str_out > cli->cc_sctp_para.str_in)
 			cli->cc_sctp_para.pairs = cli->cc_sctp_para.str_out;
@@ -291,10 +300,119 @@
 }
 
-/* Client side: connect to a remote server */
-struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa,  socklen_t addrlen)
-{
-
-	TODO("...");
+/* Client side: connect to a remote server -- cancelable */
+struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa /* contains the port already */, socklen_t addrlen)
+{
+	int sock;
+	struct cnxctx * cnx = NULL;
+	
+	TRACE_ENTRY("%p %d", sa, addrlen);
+	CHECK_PARAMS_DO( sa && addrlen, return NULL );
+	
+	/* Create the socket and connect, which can take some time and/or fail */
+	CHECK_FCT_DO( fd_tcp_client( &sock, sa, addrlen ), return NULL );
+	
+	if (TRACE_BOOL(INFO)) {
+		fd_log_debug("Connection established to server '");
+		sSA_DUMP_NODE_SERV( sa, NI_NUMERICSERV);
+		fd_log_debug("' (TCP:%d).\n", sock);
+	}
+	
+	/* Once the socket is created successfuly, prepare the remaining of the cnx */
+	CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } );
+	
+	cnx->cc_socket = sock;
+	cnx->cc_proto  = IPPROTO_TCP;
+	
+	/* Generate the names for the object */
+	{
+		char addrbuf[INET6_ADDRSTRLEN];
+		char portbuf[10];
+		int  rc;
+		
+		/* Numeric values for debug */
+		rc = getnameinfo(sa, addrlen, addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+		if (rc) {
+			snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
+			portbuf[0] = '\0';
+		}
+		
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of TCP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
+		
+		/* Name for log messages */
+		rc = getnameinfo(sa, addrlen, cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
+		if (rc)
+			snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
+	}
+	
+	return cnx;
+
+error:
+	fd_cnx_destroy(cnx);
 	return NULL;
+}
+
+/* Same for SCTP, accepts a list of remote addresses to connect to (see sctp_connectx) */
+struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list)
+{
+#ifdef DISABLE_SCTP
+	TRACE_DEBUG(INFO, "This function should never been called when SCTP is disabled...");
+	ASSERT(0);
+	CHECK_FCT_DO( ENOTSUP, return NULL);
+#else /* DISABLE_SCTP */
+	int sock;
+	struct cnxctx * cnx = NULL;
+	sSS primary;
+	
+	TRACE_ENTRY("%p", list);
+	CHECK_PARAMS_DO( list && !FD_IS_LIST_EMPTY(list), return NULL );
+	
+	CHECK_FCT_DO( fd_sctp_client( &sock, no_ip6, port, list ), return NULL );
+	
+	/* Once the socket is created successfuly, prepare the remaining of the cnx */
+	CHECK_MALLOC_DO( cnx = fd_cnx_init(1), { shutdown(sock, SHUT_RDWR); return NULL; } );
+	
+	cnx->cc_socket = sock;
+	cnx->cc_proto  = IPPROTO_SCTP;
+	
+	/* Retrieve the number of streams and primary address */
+	CHECK_FCT_DO( fd_sctp_get_str_info( sock, &cnx->cc_sctp_para.str_in, &cnx->cc_sctp_para.str_out, &primary ), goto error );
+	if (cnx->cc_sctp_para.str_out > cnx->cc_sctp_para.str_in)
+		cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_out;
+	else
+		cnx->cc_sctp_para.pairs = cnx->cc_sctp_para.str_in;
+	
+	/* Generate the names for the object */
+	{
+		char addrbuf[INET6_ADDRSTRLEN];
+		char portbuf[10];
+		int  rc;
+		
+		/* Numeric values for debug */
+		rc = getnameinfo((sSA *)&primary, sizeof(sSS), addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf), NI_NUMERICHOST | NI_NUMERICSERV);
+		if (rc) {
+			snprintf(addrbuf, sizeof(addrbuf), "[err:%s]", gai_strerror(rc));
+			portbuf[0] = '\0';
+		}
+		
+		snprintf(cnx->cc_id, sizeof(cnx->cc_id), "Client of SCTP server [%s]:%s (%d)", addrbuf, portbuf, cnx->cc_socket);
+		
+		/* Name for log messages */
+		rc = getnameinfo((sSA *)&primary, sizeof(sSS), cnx->cc_remid, sizeof(cnx->cc_remid), NULL, 0, 0);
+		if (rc)
+			snprintf(cnx->cc_remid, sizeof(cnx->cc_remid), "[err:%s]", gai_strerror(rc));
+	}
+	
+	if (TRACE_BOOL(INFO)) {
+		fd_log_debug("Connection established to server '");
+		sSA_DUMP_NODE_SERV( &primary, NI_NUMERICSERV);
+		fd_log_debug("' (SCTP:%d).\n", sock);
+	}
+	
+	return cnx;
+
+error:
+	fd_cnx_destroy(cnx);
+	return NULL;
+#endif /* DISABLE_SCTP */
 }
 
@@ -415,5 +533,5 @@
 				socklen_t sl;
 				CHECK_FCT(fd_tcp_get_local_ep(conn->cc_socket, &ss, &sl));
-				CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, 0, 0, 0, 1 ));
+				CHECK_FCT(fd_ep_add_merge( local, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY));
 			}
 			break;
@@ -441,5 +559,5 @@
 				socklen_t sl;
 				CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
-				CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, 0, 0, 0, 1 ));
+				CHECK_FCT(fd_ep_add_merge( remote, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
 			}
 			break;
@@ -528,6 +646,2 @@
 	return;
 }
-
-
-
-
Index: freeDiameter/config.c
===================================================================
--- freeDiameter/config.c	(revision 23)
+++ freeDiameter/config.c	(revision 24)
@@ -272,42 +272,2 @@
 	return 0;
 }
-
-/* Add an endpoint information in a list */
-int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, int conf, int disc, int adv, int ll )
-{
-	struct fd_endpoint * ep;
-	struct fd_list * li;
-	int cmp = -1;
-	
-	TRACE_ENTRY("%p %p %u %i %i %i %i", list, sa, sl, conf, disc, adv, ll);
-	CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) && (conf || disc || adv || ll) );
-	
-	/* Search place in the list */
-	for (li = list->next; li != list; li = li->next) {
-		ep = (struct fd_endpoint *)li;
-		
-		cmp = memcmp(&ep->ss, sa, sl);
-		if (cmp >= 0)
-			break;
-	}
-	
-	if (cmp) {
-		/* new item to be added */
-		CHECK_MALLOC( ep = malloc(sizeof(struct fd_endpoint)) );
-		memset(ep, 0, sizeof(struct fd_endpoint));
-		fd_list_init(&ep->chain, NULL);
-		memcpy(&ep->ss, sa, sl);
-		
-		/* Insert in the list */
-		fd_list_insert_before(li, &ep->chain);
-	}
-	
-	/* Merge the flags */
-	ep->meta.conf = conf || ep->meta.conf;
-	ep->meta.disc = disc || ep->meta.disc;
-	ep->meta.adv  =  adv || ep->meta.adv;
-	ep->meta.ll   =   ll || ep->meta.ll;
-	
-	return 0;
-}
-
Index: freeDiameter/endpoints.c
===================================================================
--- freeDiameter/endpoints.c	(revision 24)
+++ freeDiameter/endpoints.c	(revision 24)
@@ -0,0 +1,110 @@
+/*********************************************************************************************************
+* 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"
+
+
+/* Add an endpoint information in a list */
+int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags )
+{
+	struct fd_endpoint * ep;
+	struct fd_list * li;
+	int cmp = -1;
+	
+	TRACE_ENTRY("%p %p %u %x", list, sa, sl, flags);
+	CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) );
+	
+	/* Search place in the list */
+	for (li = list->next; li != list; li = li->next) {
+		ep = (struct fd_endpoint *)li;
+		
+		cmp = memcmp(&ep->ss, sa, sl);
+		if (cmp >= 0)
+			break;
+	}
+	
+	if (cmp) {
+		/* new item to be added */
+		CHECK_MALLOC( ep = malloc(sizeof(struct fd_endpoint)) );
+		memset(ep, 0, sizeof(struct fd_endpoint));
+		fd_list_init(&ep->chain, NULL);
+		memcpy(&ep->ss, sa, sl);
+		
+		/* Insert in the list */
+		fd_list_insert_before(li, &ep->chain);
+	}
+	
+	/* Merge the flags */
+	ep->flags |= flags;
+	
+	return 0;
+}
+
+/* Delete endpoints that do not have a matching flag from a list (0: delete all endpoints) */
+int fd_ep_filter( struct fd_list * list, uint32_t flags )
+{
+	struct fd_list * li;
+	
+	TRACE_ENTRY("%p %x", list, flags);
+	CHECK_PARAMS(list);
+	
+	for (li = list->next; li != list; li = li->next) {
+		struct fd_endpoint * ep = (struct fd_endpoint *)li;
+		
+		if (! (ep->flags & flags)) {
+			li = li->prev;
+			fd_list_unlink(&ep->chain);
+			free(ep);
+		}
+	}
+	
+	return 0;
+}
+
+/* Reset the given flag(s) from all items in the list */
+int fd_ep_clearflags( struct fd_list * list, uint32_t flags )
+{
+	struct fd_list * li;
+	
+	TRACE_ENTRY("%p %x", list, flags);
+	CHECK_PARAMS(list);
+	
+	for (li = list->next; li != list; li = li->next) {
+		struct fd_endpoint * ep = (struct fd_endpoint *)li;
+		ep->flags &= ~flags;
+	}
+	
+	return 0;
+}
Index: freeDiameter/fD.h
===================================================================
--- freeDiameter/fD.h	(revision 23)
+++ freeDiameter/fD.h	(revision 24)
@@ -207,5 +207,6 @@
 int fd_cnx_serv_listen(struct cnxctx * conn);
 struct cnxctx * fd_cnx_serv_accept(struct cnxctx * serv);
-struct cnxctx * fd_cnx_cli_connect(int proto, const sSA * sa,  socklen_t addrlen);
+struct cnxctx * fd_cnx_cli_connect_tcp(sSA * sa, socklen_t addrlen);
+struct cnxctx * fd_cnx_cli_connect_sctp(int no_ip6, uint16_t port, struct fd_list * list);
 char * fd_cnx_getid(struct cnxctx * conn);
 int fd_cnx_start_clear(struct cnxctx * conn);
@@ -222,4 +223,5 @@
 int fd_tcp_create_bind_server( int * sock, sSA * sa, socklen_t salen );
 int fd_tcp_listen( int sock );
+int fd_tcp_client( int *sock, sSA * sa, socklen_t salen );
 int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl);
 int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl);
@@ -229,7 +231,8 @@
 int fd_sctp_create_bind_server( int * sock, struct fd_list * list, uint16_t port );
 int fd_sctp_listen( int sock );
+int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list );
 int fd_sctp_get_local_ep(int sock, struct fd_list * list);
 int fd_sctp_get_remote_ep(int sock, struct fd_list * list);
-int fd_sctp_get_str_info( int socket, int *in, int *out );
+int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary );
 
 #endif /* DISABLE_SCTP */
Index: freeDiameter/fdd.y
===================================================================
--- freeDiameter/fdd.y	(revision 23)
+++ freeDiameter/fdd.y	(revision 24)
@@ -219,5 +219,5 @@
 				ret = getaddrinfo($3, NULL, &hints, &ai);
 				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
-				CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, 1, 0, 0, 0 ), YYERROR );
+				CHECK_FCT_DO( fd_ep_add_merge( &conf->cnf_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF ), YYERROR );
 				freeaddrinfo(ai);
 				free($3);
@@ -430,5 +430,5 @@
 				if (ret == EAI_NONAME) {
 					/* The name was maybe not numeric, try again */
-					disc = 1;
+					disc = EP_FL_DISC;
 					hints.ai_flags &= ~ AI_NUMERICHOST;
 					ret = getaddrinfo($4, NULL, &hints, &ai);
@@ -436,5 +436,5 @@
 				if (ret) { yyerror (&yylloc, conf, gai_strerror(ret)); YYERROR; }
 				
-				CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, 1, disc, 0, 0 ), YYERROR );
+				CHECK_FCT_DO( fd_ep_add_merge( &fddpi.pi_endpoints, ai->ai_addr, ai->ai_addrlen, EP_FL_CONF | disc ), YYERROR );
 				free($4);
 				freeaddrinfo(ai);
Index: freeDiameter/sctp.c
===================================================================
--- freeDiameter/sctp.c	(revision 23)
+++ freeDiameter/sctp.c	(revision 24)
@@ -76,13 +76,13 @@
 		}
 		
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_data_io_event          : %hhu", event.sctp_data_io_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_association_event      : %hhu", event.sctp_association_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_address_event          : %hhu", event.sctp_address_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_send_failure_event     : %hhu", event.sctp_send_failure_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_peer_error_event       : %hhu", event.sctp_peer_error_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_shutdown_event         : %hhu", event.sctp_shutdown_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event);
-		TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event);
-		// TRACE_DEBUG(FULL, "SCTP_EVENTS sctp_authentication_event   : %hhu", event.sctp_authentication_event);
+		TRACE_DEBUG(FULL, "SCTP_EVENTS : sctp_data_io_event          : %hhu", event.sctp_data_io_event);
+		TRACE_DEBUG(FULL, "       	 sctp_association_event      : %hhu", event.sctp_association_event);
+		TRACE_DEBUG(FULL, "       	 sctp_address_event	     : %hhu", event.sctp_address_event);
+		TRACE_DEBUG(FULL, "       	 sctp_send_failure_event     : %hhu", event.sctp_send_failure_event);
+		TRACE_DEBUG(FULL, "       	 sctp_peer_error_event       : %hhu", event.sctp_peer_error_event);
+		TRACE_DEBUG(FULL, "       	 sctp_shutdown_event	     : %hhu", event.sctp_shutdown_event);
+		TRACE_DEBUG(FULL, "       	 sctp_partial_delivery_event : %hhu", event.sctp_partial_delivery_event);
+		TRACE_DEBUG(FULL, "       	 sctp_adaptation_layer_event : %hhu", event.sctp_adaptation_layer_event);
+		// TRACE_DEBUG(FULL, "             sctp_authentication_event    : %hhu", event.sctp_authentication_event);
 		#endif /* DEBUG_SCTP */
 		
@@ -104,8 +104,8 @@
 			return ENOTSUP;
 		}
-		TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_num_ostreams   : %hu", init.sinit_num_ostreams);
-		TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_max_instreams  : %hu", init.sinit_max_instreams);
-		TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_max_attempts   : %hu", init.sinit_max_attempts);
-		TRACE_DEBUG(FULL, "Def SCTP_INITMSG sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
+		TRACE_DEBUG(FULL, "Def SCTP_INITMSG : sinit_num_ostreams   : %hu", init.sinit_num_ostreams);
+		TRACE_DEBUG(FULL, "                   sinit_max_instreams  : %hu", init.sinit_max_instreams);
+		TRACE_DEBUG(FULL, "                   sinit_max_attempts   : %hu", init.sinit_max_attempts);
+		TRACE_DEBUG(FULL, "                   sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
 		#endif /* DEBUG_SCTP */
 
@@ -120,8 +120,8 @@
 		/* Check new values */
 		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_INITMSG, &init, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_num_ostreams   : %hu", init.sinit_num_ostreams);
-		TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_max_instreams  : %hu", init.sinit_max_instreams);
-		TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_max_attempts   : %hu", init.sinit_max_attempts);
-		TRACE_DEBUG(FULL, "New SCTP_INITMSG sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
+		TRACE_DEBUG(FULL, "New SCTP_INITMSG : sinit_num_ostreams   : %hu", init.sinit_num_ostreams);
+		TRACE_DEBUG(FULL, "                   sinit_max_instreams  : %hu", init.sinit_max_instreams);
+		TRACE_DEBUG(FULL, "                   sinit_max_attempts   : %hu", init.sinit_max_attempts);
+		TRACE_DEBUG(FULL, "                   sinit_max_init_timeo : %hu", init.sinit_max_init_timeo);
 		#endif /* DEBUG_SCTP */
 	}
@@ -175,7 +175,7 @@
 			return ENOTSUP;
 		}
-		TRACE_DEBUG(FULL, "Def SCTP_RTOINFO srto_initial : %u", rtoinfo.srto_initial);
-		TRACE_DEBUG(FULL, "Def SCTP_RTOINFO srto_max     : %u", rtoinfo.srto_max);
-		TRACE_DEBUG(FULL, "Def SCTP_RTOINFO srto_min     : %u", rtoinfo.srto_min);
+		TRACE_DEBUG(FULL, "Def SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial);
+		TRACE_DEBUG(FULL, "                   srto_max     : %u", rtoinfo.srto_max);
+		TRACE_DEBUG(FULL, "                   srto_min     : %u", rtoinfo.srto_min);
 		#endif /* DEBUG_SCTP */
 
@@ -188,7 +188,7 @@
 		/* Check new values */
 		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_RTOINFO, &rtoinfo, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_RTOINFO srto_initial : %u", rtoinfo.srto_initial);
-		TRACE_DEBUG(FULL, "New SCTP_RTOINFO srto_max     : %u", rtoinfo.srto_max);
-		TRACE_DEBUG(FULL, "New SCTP_RTOINFO srto_min     : %u", rtoinfo.srto_min);
+		TRACE_DEBUG(FULL, "New SCTP_RTOINFO : srto_initial : %u", rtoinfo.srto_initial);
+		TRACE_DEBUG(FULL, "                   srto_max     : %u", rtoinfo.srto_max);
+		TRACE_DEBUG(FULL, "                   srto_min     : %u", rtoinfo.srto_min);
 		#endif /* DEBUG_SCTP */
 	}
@@ -214,9 +214,9 @@
 			return ENOTSUP;
 		}
-		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_asocmaxrxt               : %hu", assoc.sasoc_asocmaxrxt);
-		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
-		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_peer_rwnd                : %u" , assoc.sasoc_peer_rwnd);
-		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_local_rwnd               : %u" , assoc.sasoc_local_rwnd);
-		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO sasoc_cookie_life              : %u" , assoc.sasoc_cookie_life);
+		TRACE_DEBUG(FULL, "Def SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu", assoc.sasoc_asocmaxrxt);
+		TRACE_DEBUG(FULL, "                     sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
+		TRACE_DEBUG(FULL, "                     sasoc_peer_rwnd                : %u" , assoc.sasoc_peer_rwnd);
+		TRACE_DEBUG(FULL, "                     sasoc_local_rwnd               : %u" , assoc.sasoc_local_rwnd);
+		TRACE_DEBUG(FULL, "                     sasoc_cookie_life              : %u" , assoc.sasoc_cookie_life);
 		#endif /* DEBUG_SCTP */
 
@@ -229,9 +229,9 @@
 		/* Check new values */
 		CHECK_SYS(  getsockopt(sk, IPPROTO_SCTP, SCTP_ASSOCINFO, &assoc, &sz)  );
-		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_asocmaxrxt               : %hu", assoc.sasoc_asocmaxrxt);
-		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
-		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_peer_rwnd                : %u" , assoc.sasoc_peer_rwnd);
-		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_local_rwnd               : %u" , assoc.sasoc_local_rwnd);
-		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO sasoc_cookie_life              : %u" , assoc.sasoc_cookie_life);
+		TRACE_DEBUG(FULL, "New SCTP_ASSOCINFO : sasoc_asocmaxrxt               : %hu", assoc.sasoc_asocmaxrxt);
+		TRACE_DEBUG(FULL, "                     sasoc_number_peer_destinations : %hu", assoc.sasoc_number_peer_destinations);
+		TRACE_DEBUG(FULL, "                     sasoc_peer_rwnd                : %u" , assoc.sasoc_peer_rwnd);
+		TRACE_DEBUG(FULL, "                     sasoc_local_rwnd               : %u" , assoc.sasoc_local_rwnd);
+		TRACE_DEBUG(FULL, "                     sasoc_cookie_life              : %u" , assoc.sasoc_cookie_life);
 		#endif /* DEBUG_SCTP */
 	}
@@ -258,6 +258,6 @@
 			return ENOTSUP;
 		}
-		TRACE_DEBUG(FULL, "Def SO_LINGER l_onoff  : %d", linger.l_onoff);
-		TRACE_DEBUG(FULL, "Def SO_LINGER l_linger : %d", linger.l_linger);
+		TRACE_DEBUG(FULL, "Def SO_LINGER : l_onoff  : %d", linger.l_onoff);
+		TRACE_DEBUG(FULL, "                l_linger : %d", linger.l_linger);
 		#endif /* DEBUG_SCTP */
 		
@@ -271,6 +271,6 @@
 		/* Check new values */
 		CHECK_SYS(  getsockopt(sk, SOL_SOCKET, SO_LINGER, &linger, &sz)  );
-		TRACE_DEBUG(FULL, "New SO_LINGER l_onoff  : %d", linger.l_onoff);
-		TRACE_DEBUG(FULL, "New SO_LINGER l_linger : %d", linger.l_linger);
+		TRACE_DEBUG(FULL, "New SO_LINGER : l_onoff  : %d", linger.l_onoff);
+		TRACE_DEBUG(FULL, "                l_linger : %d", linger.l_linger);
 		#endif /* DEBUG_SCTP */
 	}
@@ -370,6 +370,9 @@
 		#endif /* DEBUG_SCTP */
 
+#ifndef SCTP_USE_MAPPED_ADDRESSES
 		v4mapped = 0;	/* We don't want v4 mapped addresses */
-		v4mapped = 1;	/* but we have to, otherwise the bind fails in linux currently ... (Ok, It'd be better with a cmake test, any volunteer?) */
+#else /* SCTP_USE_MAPPED_ADDRESSES */
+		v4mapped = 1;	/* but we may have to, otherwise the bind fails in some environments */
+#endif /* SCTP_USE_MAPPED_ADDRESSES */
 		
 		/* Set the option to the socket */
@@ -422,5 +425,5 @@
 	*/
 	
-	/* In case of no_ip4, force the v6only option */
+	/* In case of no_ip4, force the v6only option -- is it a valid option for SCTP ? */
 	#ifdef IPV6_V6ONLY
 	if (fd_g_config->cnf_flags.no_ip4) {
@@ -526,38 +529,59 @@
 	} else {
 		/* Explicit endpoints to bind to from config */
+		
 		union {
-			sSA  	*sa;
-			sSA4 	*sin;
-			sSA6 	*sin6;
-		} sar; /* build the list of endpoints to bind to */
+			sSA     * sa;
+			sSA4	*sin;
+			sSA6	*sin6;
+			uint8_t *buf;
+		} ptr;
+		union {
+			sSA     * sa;
+			uint8_t * buf;
+		} sar;
 		int count = 0; /* number of sock addr in sar array */
+		size_t offset = 0;
 		struct fd_list * li;
 		
-		sar.sa = NULL;
+		sar.buf = NULL;
 		
 		/* Create a flat array from the list of configured addresses */
 		for (li = list->next; li != list; li = li->next) {
 			struct fd_endpoint * ep = (struct fd_endpoint *)li;
+			size_t sz = 0;
 			
-			if ( ! ep->meta.conf )
+			if (! (ep->flags & EP_FL_CONF))
 				continue;
 			
 			count++;
-			if (fd_g_config->cnf_flags.no_ip6) {
-				ASSERT(ep->sa.sa_family == AF_INET);
-				CHECK_MALLOC( sar.sa = realloc(sar.sa, count * sizeof(sSA4))  );
-				memcpy(&sar.sin[count - 1], &ep->sin, sizeof(sSA4));
-				sar.sin[count - 1].sin_port = htons(port);
+			
+			/* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */
+#ifndef SCTP_USE_MAPPED_ADDRESSES
+			if (ep->sa.sa_family == AF_INET6)
+#else /* SCTP_USE_MAPPED_ADDRESSES */
+			if (family == AF_INET6)
+#endif /* SCTP_USE_MAPPED_ADDRESSES */
+				sz = sizeof(sSA6);
+			else
+				sz = sizeof(sSA4);
+			
+			/* augment sar to contain the additional info */
+			CHECK_MALLOC( sar.buf = realloc(sar.buf, offset + sz)  );
+			
+			ptr.buf = sar.buf + offset; /* place of the new SA */
+			offset += sz; /* update to end of sar */
+			
+			if (sz == sizeof(sSA4)) {
+				memcpy(ptr.buf, &ep->sin, sz);
+				ptr.sin->sin_port = htons(port);
 			} else {
-				/* Pass all addresses as IPv6, eventually mapped -- we already filtered out IPv4 addresses if no_ip4 flag is set */
-				CHECK_MALLOC( sar.sa = realloc(sar.sa, count * sizeof(sSA6))  );
-				if (ep->sa.sa_family == AF_INET) {
-					memset(&sar.sin6[count - 1], 0, sizeof(sSA6));
-					sar.sin6[count - 1].sin6_family = AF_INET6;
-					IN6_ADDR_V4MAP( &sar.sin6[count - 1].sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
+				if (ep->sa.sa_family == AF_INET) { /* We must map the address */ 
+					memset(ptr.buf, 0, sz);
+					ptr.sin6->sin6_family = AF_INET6;
+					IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
 				} else {
-					memcpy(&sar.sin6[count - 1], &ep->sin6, sizeof(sSA6));
+					memcpy(ptr.sin6, &ep->sin6, sz);
 				}
-				sar.sin6[count - 1].sin6_port = htons(port);
+				ptr.sin6->sin6_port = htons(port);
 			}
 		}
@@ -572,15 +596,18 @@
 		if (TRACE_BOOL(FULL)) {
 			int i;
-			fd_log_debug("Calling sctp_bindx with the following array:\n");
+			ptr.buf = sar.buf;
+			fd_log_debug("Calling sctp_bindx with the following address array:\n");
 			for (i = 0; i < count; i++) {
-				fd_log_debug("    - ");
-				sSA_DUMP_NODE_SERV( (sar.sa[0].sa_family == AF_INET) ? (sSA *)(&sar.sin[i]) : (sSA *)(&sar.sin6[i]), NI_NUMERICHOST | NI_NUMERICSERV );
-				fd_log_debug("\n");
+				TRACE_DEBUG_sSA(FULL, "    - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
+				ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6) ;
 			}
 		}
 		#endif /* DEBUG_SCTP */
 		
+		/* Bind to this array */
 		CHECK_SYS(  sctp_bindx(*sock, sar.sa, count, SCTP_BINDX_ADD_ADDR)  );
 		
+		/* We don't need sar anymore */
+		free(sar.buf);
 	}
 	
@@ -591,5 +618,9 @@
 	/* Debug: show all local listening addresses */
 	if (TRACE_BOOL(FULL)) {
-		sSA *sa, *sar;
+		sSA *sar;
+		union {
+			sSA	*sa;
+			uint8_t *buf;
+		} ptr;
 		int sz;
 		
@@ -597,8 +628,6 @@
 		
 		fd_log_debug("SCTP server bound on :\n");
-		for (sa = sar; sz-- > 0; sa = (sSA *)(((uint8_t *)sa) + ((sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)))) {
-			fd_log_debug("    - ");
-			sSA_DUMP_NODE_SERV( sa, NI_NUMERICHOST | NI_NUMERICSERV );
-			fd_log_debug("\n");
+		for (ptr.sa = sar; sz-- > 0; ptr.buf += (ptr.sa->sa_family == AF_INET) ? sizeof(sSA4) : sizeof(sSA6)) {
+			TRACE_DEBUG_sSA(FULL, "    - ", ptr.sa, NI_NUMERICHOST | NI_NUMERICSERV, "" );
 		}
 		sctp_freeladdrs(sar);
@@ -617,10 +646,141 @@
 }
 
-/* Retrieve streams information from a connected association */
-int fd_sctp_get_str_info( int socket, int *in, int *out )
+/* Create a client socket and connect to remote server */
+int fd_sctp_client( int *sock, int no_ip6, uint16_t port, struct fd_list * list )
 {
-	TODO("Retrieve streams info from the socket");
-	
-	return ENOTSUP;
+	int family;
+	int count = 0;
+	size_t offset = 0, sz;
+	union {
+		uint8_t *buf;
+		sSA	*sa;
+	} sar;
+	union {
+		uint8_t *buf;
+		sSA	*sa;
+		sSA4	*sin;
+		sSA6	*sin6;
+	} ptr;
+	struct fd_list * li;
+	int ret;
+	
+	sar.buf = NULL;
+	
+	TRACE_ENTRY("%p %i %hu %p", sock, no_ip6, port, list);
+	CHECK_PARAMS( sock && list && (!FD_IS_LIST_EMPTY(list)) );
+	
+	if (no_ip6) {
+		family = AF_INET;
+	} else {
+		family = AF_INET6;
+	}
+	
+	/* Create the socket */
+	CHECK_SYS( *sock = socket(family, SOCK_STREAM, IPPROTO_SCTP) );
+	
+	/* Cleanup if we are cancelled */
+	pthread_cleanup_push(fd_cleanup_socket, sock);
+	
+	/* Set the socket options */
+	CHECK_FCT_DO( ret = fd_setsockopt_prebind(*sock), goto fail );
+	
+	/* Create the array of addresses for sctp_connectx */
+	for (li = list->next; li != list; li = li->next) {
+		struct fd_endpoint * ep = (struct fd_endpoint *) li;
+		
+		count++;
+		
+		/* Size of the new SA we are adding (sar may contain a mix of sockaddr_in and sockaddr_in6) */
+#ifndef SCTP_USE_MAPPED_ADDRESSES
+		if (ep->sa.sa_family == AF_INET6)
+#else /* SCTP_USE_MAPPED_ADDRESSES */
+		if (family == AF_INET6)
+#endif /* SCTP_USE_MAPPED_ADDRESSES */
+			sz = sizeof(sSA6);
+		else
+			sz = sizeof(sSA4);
+		
+		/* augment sar to contain the additional info */
+		CHECK_MALLOC_DO( sar.buf = realloc(sar.buf, offset + sz), { ret = ENOMEM; goto fail; }  );
+
+		ptr.buf = sar.buf + offset; /* place of the new SA */
+		offset += sz; /* update to end of sar */
+			
+		if (sz == sizeof(sSA4)) {
+			memcpy(ptr.buf, &ep->sin, sz);
+			ptr.sin->sin_port = htons(port);
+		} else {
+			if (ep->sa.sa_family == AF_INET) { /* We must map the address */ 
+				memset(ptr.buf, 0, sz);
+				ptr.sin6->sin6_family = AF_INET6;
+				IN6_ADDR_V4MAP( &ptr.sin6->sin6_addr.s6_addr, ep->sin.sin_addr.s_addr );
+			} else {
+				memcpy(ptr.sin6, &ep->sin6, sz);
+			}
+			ptr.sin6->sin6_port = htons(port);
+		}
+	}
+	
+	/* Try connecting */
+	TRACE_DEBUG(FULL, "Attempting SCTP connection (%d addresses attempted)...", count);
+	CHECK_SYS_DO( sctp_connectx(*sock, sar.sa, count), { ret = errno; goto fail; } );
+	free(sar.buf); sar.buf = NULL;
+	
+	/* Set the remaining sockopts */
+	CHECK_FCT_DO( ret = fd_setsockopt_postbind(*sock, 1), goto fail );
+	
+	/* Done! */
+	pthread_cleanup_pop(0);
+	return 0;
+	
+fail:
+	if (*sock > 0) {
+		shutdown(*sock, SHUT_RDWR);
+		*sock = -1;
+	}
+	free(sar.buf);
+	return ret;
+}
+
+/* Retrieve streams information from a connected association -- optionaly provide the primary address */
+int fd_sctp_get_str_info( int sock, int *in, int *out, sSS *primary )
+{
+	struct sctp_status status;
+	socklen_t sz = sizeof(status);
+	
+	TRACE_ENTRY("%d %p %p %p", sock, in, out, primary);
+	CHECK_PARAMS( (sock > 0) && in && out );
+	
+	/* Read the association parameters */
+	memset(&status, 0, sizeof(status));
+	CHECK_SYS(  getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz) );
+	if (sz != sizeof(status))
+	{
+		TRACE_DEBUG(INFO, "Invalid size of socket option: %d / %g", sz, sizeof(status));
+		return ENOTSUP;
+	}
+	#ifdef DEBUG_SCTP
+	TRACE_DEBUG(FULL, "SCTP_STATUS : sstat_state                  : %i" , status.sstat_state);
+	TRACE_DEBUG(FULL, "              sstat_rwnd  	              : %u" , status.sstat_rwnd);
+	TRACE_DEBUG(FULL, "		 sstat_unackdata	      : %hu", status.sstat_unackdata);
+	TRACE_DEBUG(FULL, "		 sstat_penddata 	      : %hu", status.sstat_penddata);
+	TRACE_DEBUG(FULL, "		 sstat_instrms  	      : %hu", status.sstat_instrms);
+	TRACE_DEBUG(FULL, "		 sstat_outstrms 	      : %hu", status.sstat_outstrms);
+	TRACE_DEBUG(FULL, "		 sstat_fragmentation_point    : %u" , status.sstat_fragmentation_point);
+	TRACE_DEBUG_sSA(FULL, "		 sstat_primary.spinfo_address : ", &status.sstat_primary.spinfo_address, NI_NUMERICHOST | NI_NUMERICSERV, "" );
+	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_state   : %d" , status.sstat_primary.spinfo_state);
+	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_cwnd    : %u" , status.sstat_primary.spinfo_cwnd);
+	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_srtt    : %u" , status.sstat_primary.spinfo_srtt);
+	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_rto     : %u" , status.sstat_primary.spinfo_rto);
+	TRACE_DEBUG(FULL, "		 sstat_primary.spinfo_mtu     : %u" , status.sstat_primary.spinfo_mtu);
+	#endif /* DEBUG_SCTP */
+	
+	*in = (int)status.sstat_instrms;
+	*out = (int)status.sstat_outstrms;
+	
+	if (primary)
+		memcpy(primary, &status.sstat_primary.spinfo_address, sizeof(sSS));
+	
+	return 0;
 }
 
@@ -630,6 +790,4 @@
 	union {
 		sSA	*sa;
-		sSA4	*sin;
-		sSA6	*sin6;
 		uint8_t	*buf;
 	} ptr;
@@ -646,14 +804,43 @@
 	
 	while (count) {
-		TODO("get the data from ptr");
-		TODO("Increment ptr to the next sa in data");
-		
+		socklen_t sl;
+		switch (ptr.sa->sa_family) {
+			case AF_INET:	sl = sizeof(sSA4); break;
+			case AF_INET6:	sl = sizeof(sSA6); break;
+			default:
+				TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family);
+		}
+				
+		CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
+		ptr.buf += sl;
 		count --;
 	}
 	
-	/* And now, free the list and return */
+	/* Free the list */
 	sctp_freeladdrs(data);
 	
-	return ENOTSUP;
+	/* Now get the primary address, the add function will take care of merging with existing entry */
+	{
+		 
+		struct sctp_status status;
+		socklen_t sz = sizeof(status);
+		int ret;
+		
+		memset(&status, 0, sizeof(status));
+		/* Attempt to use SCTP_STATUS message to retrieve the primary address */
+		ret = getsockopt(sock, IPPROTO_SCTP, SCTP_STATUS, &status, &sz);
+		if (sz != sizeof(status))
+			ret = -1;
+		sz = sizeof(sSS);
+		if (ret < 0)
+		{
+			/* Fallback to getsockname -- not recommended by draft-ietf-tsvwg-sctpsocket-19#section-7.4 */
+			CHECK_SYS(getsockname(sock, (sSA *)&status.sstat_primary.spinfo_address, &sz));
+		}
+			
+		CHECK_FCT( fd_ep_add_merge( list, (sSA *)&status.sstat_primary.spinfo_address, sz, EP_FL_PRIMARY ) );
+	}
+	
+	return 0;
 }
 
@@ -661,8 +848,47 @@
 int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
 {
-	TODO("SCTP: sctp_getpaddrs");
-		
-	
-	return ENOTSUP;
+	union {
+		sSA	*sa;
+		uint8_t	*buf;
+	} ptr;
+	
+	sSA * data;
+	int count;
+	
+	TRACE_ENTRY("%d %p", sock, list);
+	CHECK_PARAMS(list);
+	
+	/* Read the list on the socket */
+	CHECK_SYS( count = sctp_getpaddrs(sock, 0, &data)  );
+	ptr.sa = data;
+	
+	while (count) {
+		socklen_t sl;
+		switch (ptr.sa->sa_family) {
+			case AF_INET:	sl = sizeof(sSA4); break;
+			case AF_INET6:	sl = sizeof(sSA6); break;
+			default:
+				TRACE_DEBUG(INFO, "Unkown address family returned in sctp_getpaddrs: %d", ptr.sa->sa_family);
+		}
+				
+		CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
+		ptr.buf += sl;
+		count --;
+	}
+	
+	/* Free the list */
+	sctp_freepaddrs(data);
+	
+	/* Now get the primary address, the add function will take care of merging with existing entry */
+	{
+		sSS ss;
+		socklen_t sl = sizeof(sSS);
+	
+		CHECK_SYS(getpeername(sock, (sSA *)&ss, &sl));
+		CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) );
+	}
+	
+	/* Done! */
+	return 0;
 }
 
Index: freeDiameter/server.c
===================================================================
--- freeDiameter/server.c	(revision 22)
+++ freeDiameter/server.c	(revision 24)
@@ -291,5 +291,5 @@
 				struct fd_endpoint * ep = (struct fd_endpoint *)li;
 				sSA * sa = (sSA *) &ep->ss;
-				if (! ep->meta.conf)
+				if (! (ep->flags & EP_FL_CONF))
 					continue;
 				if (fd_g_config->cnf_flags.no_ip4 && (sa->sa_family == AF_INET))
Index: freeDiameter/tcp.c
===================================================================
--- freeDiameter/tcp.c	(revision 23)
+++ freeDiameter/tcp.c	(revision 24)
@@ -113,4 +113,30 @@
 }
 
+/* Create a client socket and connect to remote server */
+int fd_tcp_client( int *sock, sSA * sa, socklen_t salen )
+{
+	TRACE_ENTRY("%p %p %d", sock, sa, salen);
+	CHECK_PARAMS( sock && sa && salen );
+	
+	/* Create the socket */
+	CHECK_SYS(  *sock = socket(sa->sa_family, SOCK_STREAM, IPPROTO_TCP)  );
+	
+	/* Cleanup if we are cancelled */
+	pthread_cleanup_push(fd_cleanup_socket, sock);
+	
+	/* Set the socket options */
+	CHECK_FCT(  fd_tcp_setsockopt(sa->sa_family, *sock)  );
+	
+	TRACE_DEBUG_sSA(FULL, "Attempting TCP connection with peer: ", sa, NI_NUMERICHOST | NI_NUMERICSERV, "..." );
+	
+	/* Try connecting to the remote address */
+	CHECK_SYS( connect(*sock, sa, salen) );
+	
+	/* Done! */
+	pthread_cleanup_pop(0);
+	return 0;
+}
+
+
 /* Get the local name of a TCP socket -- would be nice if it did not return "0.0.0.0"... */
 int fd_tcp_get_local_ep(int sock, sSS * ss, socklen_t *sl)
Index: include/freeDiameter/CMakeLists.txt
===================================================================
--- include/freeDiameter/CMakeLists.txt	(revision 23)
+++ include/freeDiameter/CMakeLists.txt	(revision 24)
@@ -13,4 +13,5 @@
 IF (NOT DISABLE_SCTP)
 	OPTION(DEBUG_SCTP "Verbose SCTP (for debug)?" OFF)
+	OPTION(SCTP_USE_MAPPED_ADDRESSES "Use v6-mapped v4 addresses in SCTP (workaround some SCTP limitations)?" OFF)
 ENDIF (NOT DISABLE_SCTP)
 
Index: include/freeDiameter/freeDiameter-host.h.in
===================================================================
--- include/freeDiameter/freeDiameter-host.h.in	(revision 23)
+++ include/freeDiameter/freeDiameter-host.h.in	(revision 24)
@@ -46,4 +46,5 @@
 #cmakedefine DISABLE_SCTP
 #cmakedefine DEBUG_SCTP
+#cmakedefine SCTP_USE_MAPPED_ADDRESSES
 #cmakedefine ERRORS_ON_TODO
 #cmakedefine DEBUG
Index: include/freeDiameter/freeDiameter.h
===================================================================
--- include/freeDiameter/freeDiameter.h	(revision 23)
+++ include/freeDiameter/freeDiameter.h	(revision 24)
@@ -118,23 +118,21 @@
 struct fd_endpoint {
 	struct fd_list  chain;	/* link in cnf_endpoints list */
+	
 	union {
-		sSS		ss;	/* the socket information. List is always ordered by ss value (memcmp) */
+		sSS		ss;	/* the socket information. List is always ordered by ss value (memcmp) -- see fd_ep_add_merge */
 		sSA4		sin;
 		sSA6		sin6;
 		sSA		sa;
 	};
-	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 */
-};
-
-/* Add a new entry in a list of endpoints -- merge if the sockaddr was already there */
-int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, int conf, int disc, int adv, int ll );
+	
+#define	EP_FL_CONF	(1 << 0)	/* This endpoint is statically configured in a configuration file */
+#define	EP_FL_DISC	(1 << 1)	/* This endpoint was resolved from the Diameter Identity or other DNS query */
+#define	EP_FL_ADV	(1 << 2)	/* This endpoint was advertized in Diameter CER/CEA exchange */
+#define	EP_FL_LL	(1 << 3)	/* Lower layer mechanism provided this endpoint */
+#define	EP_FL_PRIMARY	(1 << 4)	/* This endpoint is primary in a multihomed SCTP association */
+	uint32_t	flags;		/* Additional information about the endpoint */
+		
+	/* To add: a validity timestamp for DNS records ? How do we retrieve this lifetime from DNS ? */
+};
 
 /* Applications */
@@ -468,3 +466,13 @@
 
 
+/***************************************/
+/*   Endpoints lists helpers           */
+/***************************************/
+
+int fd_ep_add_merge( struct fd_list * list, sSA * sa, socklen_t sl, uint32_t flags );
+int fd_ep_filter( struct fd_list * list, uint32_t flags );
+int fd_ep_clearflags( struct fd_list * list, uint32_t flags );
+
+
+
 #endif /* _FREEDIAMETER_H */
Index: include/freeDiameter/libfreeDiameter.h
===================================================================
--- include/freeDiameter/libfreeDiameter.h	(revision 23)
+++ include/freeDiameter/libfreeDiameter.h	(revision 24)
@@ -336,25 +336,5 @@
 	}							\
 }
-/* Same, for a service */
-#define sSA_DUMP_SERV( sa, flag ) {				\
-	sSA * __sa = (sSA *)(sa);				\
-	char __servbuf[32];					\
-	if (__sa) {						\
-	  int __rc = getnameinfo(__sa, 				\
-	  		sizeof(sSS),				\
-			NULL,					\
-			0,					\
-			__servbuf,				\
-			sizeof(__servbuf),			\
-			flag);					\
-	  if (__rc)						\
-	  	fd_log_debug("%s", (char *)gai_strerror(__rc));	\
-	  else							\
-	  	fd_log_debug("%s", &__servbuf[0]);		\
-	} else {						\
-		fd_log_debug("(unknown)");			\
-	}							\
-}
-/* Combine both */
+/* Same but with the port (service) also */
 #define sSA_DUMP_NODE_SERV( sa, flag ) {				\
 	sSA * __sa = (sSA *)(sa);					\
@@ -376,4 +356,17 @@
 		fd_log_debug("(NULL / ANY)");				\
 	}								\
+}
+/* Inside a debug trace */
+#define TRACE_DEBUG_sSA(level, prefix, sa, flags, suffix ) {										\
+	if ( TRACE_BOOL(level) ) {												\
+		char __buf[25];													\
+		char * __thn = ((char *)pthread_getspecific(fd_log_thname) ?: "unnamed");					\
+		fd_log_debug("\t | tid:%-20s\t%s\tin %s@%s:%d\n"								\
+			  "\t%s|%*s" prefix ,  											\
+					__thn, fd_log_time(NULL, __buf, sizeof(__buf)), __PRETTY_FUNCTION__, __FILE__, __LINE__,\
+					(level < FULL)?"@":" ",level, ""); 							\
+		sSA_DUMP_NODE_SERV( sa, flags );										\
+		fd_log_debug(suffix "\n");											\
+	}															\
 }
 
@@ -481,4 +474,12 @@
 	free(buffer);
 }
+static __inline__ void fd_cleanup_socket(void * sockptr)
+{
+	if (sockptr) {
+		shutdown(*(int *)sockptr, SHUT_RDWR);
+		*(int *)sockptr = 0;
+	}
+}
+
 
 /*============================================================*/
