changeset 20:277ec00d793e

Backup before typhoon... Progress on server side
author Sebastien Decugis <sdecugis@nict.go.jp>
date Wed, 07 Oct 2009 19:31:39 +0900
parents 9f28243f5d53
children bef197f6826f
files INSTALL doc/freediameter.conf.sample freeDiameter/CMakeLists.txt freeDiameter/cnxctx.c freeDiameter/config.c freeDiameter/fD.h freeDiameter/fdd.y freeDiameter/main.c freeDiameter/p_psm.c freeDiameter/peers.c freeDiameter/sctp.c freeDiameter/server.c include/freeDiameter/freeDiameter.h include/freeDiameter/libfreeDiameter.h
diffstat 14 files changed, 575 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/INSTALL	Mon Oct 05 17:51:06 2009 +0900
+++ b/INSTALL	Wed Oct 07 19:31:39 2009 +0900
@@ -8,7 +8,7 @@
 make
 
 You can enable the unary tests by doing:
-cmake -DNO_TESTS:BOOL=OFF ../
+cmake -DSKIP_TESTS:BOOL=OFF ../
 make
 make tests
 
@@ -37,3 +37,5 @@
 You can change the default configuration file pathname:
 DEFAULT_CONF_FILE:STRING=/path/to/some/freeDiameter.conf
 
+Build binary with symbols, for debug:
+CMAKE_BUILD_TYPE:STRING=Debug
--- a/doc/freediameter.conf.sample	Mon Oct 05 17:51:06 2009 +0900
+++ b/doc/freediameter.conf.sample	Wed Oct 07 19:31:39 2009 +0900
@@ -1,5 +1,7 @@
 # This is a sample configuration file for freeDiameter daemon.
 
+# Only the "TLS_Cred" directive is really mandatory in this file.
+
 ##############################################################
 ##  Peer identity and realm 
 
@@ -30,11 +32,11 @@
 # Default: use RFC3588bis method with separate port for TLS.
 #TLS_old_method;
 
-# Disable use of TCP protocol (only SCTP)
+# Disable use of TCP protocol (only listen and connect in SCTP)
 # Default : TCP enabled
 #No_TCP;
 
-# Disable use of SCTP protocol (only TCP)
+# Disable use of SCTP protocol (only listen and connect in TCP)
 # Default : SCTP enabled
 #No_SCTP;
 # This option has no effect if freeDiameter is compiled with DISABLE_SCTP option,
@@ -92,6 +94,7 @@
 # The information about revoked certificates.
 # The file contains a list of trusted CRLs in PEM format. They should have been verified before. 
 # (This parameter is passed to gnutls_certificate_set_x509_crl_file function)
+# Note: currently, openssl CRL seems not supported...
 # Default : GNUTLS default behavior
 #TLS_CRL = "<file.PEM>";
 
@@ -210,3 +213,7 @@
 LoadExtension = "extensions/dict_eap.fdx";
 ConnectPeer = "jules.nautilus6.org" ;
 ConnectPeer = "aaa.nautilus6.org" { No_TLS; No_IP; No_TCP; SCTP_streams = 60; } ;
+TLS_Cred = "/etc/openssl-ca/clients/certs/fdtest.cert" , "/etc/openssl-ca/clients/privkeys/fdtest.key.pem";
+TLS_CA = "/etc/openssl-ca/public-www/cacert.pem";
+# TLS_CRL = "/etc/openssl-ca/public-www/crl.pem";
+
--- a/freeDiameter/CMakeLists.txt	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/CMakeLists.txt	Wed Oct 07 19:31:39 2009 +0900
@@ -10,6 +10,7 @@
 SET(FD_COMMON_SRC
 	fD.h
 	config.c
+	cnxctx.c
 	dispatch.c
 	extensions.c
 	dict_base_proto.c
@@ -18,8 +19,13 @@
 	peers.c
 	p_expiry.c
 	p_psm.c
+	server.c
 	)
 
+IF(NOT DISABLE_SCTP)
+	SET(FD_COMMON_SRC ${FD_COMMON_SRC} sctp.c)
+ENDIF(NOT DISABLE_SCTP)
+
 SET(FD_COMMON_GEN_SRC
 		lex.fdd.c
 		fdd.tab.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freeDiameter/cnxctx.c	Wed Oct 07 19:31:39 2009 +0900
@@ -0,0 +1,143 @@
+/*********************************************************************************************************
+* 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 a connection context */
+struct cnxctx * fd_cnx_init(int sock, int proto)
+{
+	struct cnxctx * conn = NULL;
+	
+	TRACE_ENTRY("%d %d", sock, proto);
+	CHECK_PARAMS_DO( (proto == IPPROTO_TCP) || (proto == IPPROTO_SCTP), return NULL);
+	
+	CHECK_MALLOC_DO( conn = malloc(sizeof(struct cnxctx)), return NULL );
+	memset(conn, 0, sizeof(struct cnxctx));
+	
+	conn->cc_socket = sock;
+	conn->cc_proto  = proto;
+	
+	fd_list_init(&conn->cc_ep_remote, conn);
+	fd_list_init(&conn->cc_ep_local, conn);
+	
+	if (proto == IPPROTO_SCTP) {
+#ifndef DISABLE_SCTP
+		CHECK_FCT_DO( fd_sctp_get_str_info( sock, &conn->cc_sctp_para.str_in, &conn->cc_sctp_para.str_out ),
+				{ free(conn); return NULL; } );
+		conn->cc_sctp_para.pairs = (conn->cc_sctp_para.str_out < conn->cc_sctp_para.str_in) ? conn->cc_sctp_para.str_out : conn->cc_sctp_para.str_in;
+#else /* DISABLE_SCTP */
+		ASSERT(0);
+#endif /* DISABLE_SCTP */
+	}
+	
+	return conn;
+}
+
+/* TLS handshake the connection */
+int fd_cnx_handshake(struct cnxctx * conn, int mode)
+{
+	TRACE_ENTRY( "%p %d", conn, mode);
+	CHECK_PARAMS( conn && ( (mode == GNUTLS_CLIENT) || (mode == GNUTLS_SERVER) ) );
+	
+	/* Save the mode */
+	conn->cc_tls_para.mode = mode;
+	
+	/* Create the master session context */
+	CHECK_GNUTLS_DO( gnutls_init (&conn->cc_tls_para.session, mode), return ENOMEM );
+	
+	/* Set the algorithm suite */
+	CHECK_GNUTLS_DO( gnutls_priority_set( conn->cc_tls_para.session, fd_g_config->cnf_sec_data.prio_cache ), return EINVAL );
+	
+	/* Set the credentials of this side of the connection */
+	CHECK_GNUTLS_DO( gnutls_credentials_set (conn->cc_tls_para.session, GNUTLS_CRD_CERTIFICATE, fd_g_config->cnf_sec_data.credentials), return EINVAL );
+	
+	/* Request the remote credentials as well */
+	if (mode == GNUTLS_SERVER) {
+		gnutls_certificate_server_set_request (conn->cc_tls_para.session, GNUTLS_CERT_REQUIRE);
+	}
+
+	/* Set the socket info in the session */
+	gnutls_transport_set_ptr (conn->cc_tls_para.session, (gnutls_transport_ptr_t) conn->cc_socket);
+
+	/* Special case: multi-stream TLS is not natively managed in GNU TLS, we use a wrapper library */
+	if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
+#ifndef DISABLE_SCTP
+		TODO("Initialize the SCTP TLS wrapper");
+		TODO("Set the lowat, push and pull functions");
+#else /* DISABLE_SCTP */
+		ASSERT(0);
+#endif /* DISABLE_SCTP */
+	}
+	
+	/* Handshake master session */
+	{
+		int ret;
+		CHECK_GNUTLS_DO( ret = gnutls_handshake(conn->cc_tls_para.session),
+			{
+				if (TRACE_BOOL(INFO)) {
+					fd_log_debug("TLS Handshake failed on socket %d : %s\n", conn->cc_socket, gnutls_strerror(ret));
+				}
+				return EINVAL;
+			} );
+		
+		/* Now verify the remote credentials are valid -- only simple test here */
+		CHECK_GNUTLS_DO( gnutls_certificate_verify_peers2 (conn->cc_tls_para.session, &ret), return EINVAL );
+		if (ret) {
+			if (TRACE_BOOL(INFO)) {
+				fd_log_debug("TLS: Remote certificate invalid on socket %d :\n", conn->cc_socket);
+				if (ret & GNUTLS_CERT_INVALID)
+					fd_log_debug(" - The certificate is not trusted (unknown CA?)\n");
+				if (ret & GNUTLS_CERT_REVOKED)
+					fd_log_debug(" - The certificate has been revoked.\n");
+				if (ret & GNUTLS_CERT_SIGNER_NOT_FOUND)
+					fd_log_debug(" - The certificate hasn't got a known issuer.\n");
+				if (ret & GNUTLS_CERT_SIGNER_NOT_CA)
+					fd_log_debug(" - The certificate signer is not a CA, or uses version 1, or 3 without basic constraints.\n");
+				if (ret & GNUTLS_CERT_INSECURE_ALGORITHM)
+					fd_log_debug(" - The certificate signature uses a weak algorithm.\n");
+			}
+			return EINVAL;
+		}
+	}
+	
+	/* Other sessions in case of multi-stream SCTP are resumed from the master */
+	if ((conn->cc_proto == IPPROTO_SCTP) && (conn->cc_sctp_para.pairs > 0)) {
+#ifndef DISABLE_SCTP
+		TODO("Init and resume all additional sessions from the master one.");
+#endif /* DISABLE_SCTP */
+	}
+	
+	return 0;
+}
--- a/freeDiameter/config.c	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/config.c	Wed Oct 07 19:31:39 2009 +0900
@@ -238,10 +238,12 @@
 				 { TRACE_DEBUG(INFO, "Error in priority string at position : %s", err_pos); return EINVAL; } );
 	}
 	if (! fd_g_config->cnf_sec_data.dh_bits) {
+		TRACE_DEBUG(FULL, "Generating DH parameters...");
 		CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
 					fd_g_config->cnf_sec_data.dh_cache,
 					GNUTLS_DEFAULT_DHBITS),
 				 { TRACE_DEBUG(INFO, "Error in DH bits value : %d", GNUTLS_DEFAULT_DHBITS); return EINVAL; } );
+		TRACE_DEBUG(FULL, "DH parameters generated.");
 	}
 	
 	
--- a/freeDiameter/fD.h	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/fD.h	Wed Oct 07 19:31:39 2009 +0900
@@ -172,6 +172,40 @@
 	struct msg	*req;	/* A request that was sent and not yet answered. */
 };
 
+/* The connection context structure */
+struct cnxctx {
+	int 		cc_socket;	/* The socket object of the connection -- <=0 if no socket is created */
+	
+	struct fifo   **cc_events;	/* Location of the events list to send connection events */
+	
+	int 		cc_proto;	/* IPPROTO_TCP or IPPROTO_SCTP */
+	int		cc_tls;		/* Is TLS already started ? */
+	
+	uint16_t	cc_port;	/* Remote port of the connection, when we are client */
+	struct fd_list	cc_ep_remote;	/* The remote address(es) of the connection */
+	struct fd_list	cc_ep_local;	/* The local address(es) of the connection */
+	
+	/* If cc_proto == SCTP */
+	struct	{
+		int		str_out;/* Out streams */
+		int		str_in;	/* In streams */
+		int		pairs;	/* max number of pairs ( = min(in, out)) */
+		int		next;	/* # of stream the next message will be sent to */
+	} 		cc_sctp_para;
+	
+	/* If cc_tls == true */
+	struct {
+		int				 mode; 		/* GNUTLS_CLIENT / GNUTLS_SERVER */
+		gnutls_session_t 		 session;	/* Session object (stream #0 in case of SCTP) */
+	}		cc_tls_para;
+	
+	/* If both conditions */
+	struct {
+		gnutls_session_t 		*res_sessions;	/* Sessions of other pairs of streams, resumed from the first */
+		/* Buffers, threads, ... */
+	}		cc_sctp_tls_para;
+};
+
 /* Functions */
 int fd_peer_fini();
 void fd_peer_dump_list(int details);
@@ -191,4 +225,22 @@
 int fd_psm_terminate(struct fd_peer * peer );
 void fd_psm_abord(struct fd_peer * peer );
 
+/* Server sockets */
+void fd_servers_dump();
+int fd_servers_start();
+void fd_servers_stop();
+
+/* Connection contexts */
+struct cnxctx * fd_cnx_init(int sock, int proto);
+int fd_cnx_handshake(struct cnxctx * conn, int mode);
+
+/* SCTP */
+#ifndef DISABLE_SCTP
+int fd_sctp_create_bind_server( int * socket, uint16_t port );
+int fd_sctp_get_str_info( int socket, int *in, int *out );
+
+#endif /* DISABLE_SCTP */
+
+
+
 #endif /* _FD_H */
--- a/freeDiameter/fdd.y	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/fdd.y	Wed Oct 07 19:31:39 2009 +0900
@@ -510,10 +510,12 @@
 tls_dh:			TLS_DH_BITS '=' INTEGER ';'
 			{
 				conf->cnf_sec_data.dh_bits = $3;
+				TRACE_DEBUG(FULL, "Generating DH parameters...");
 				CHECK_GNUTLS_DO( gnutls_dh_params_generate2( 
 							conf->cnf_sec_data.dh_cache,
 							conf->cnf_sec_data.dh_bits),
 						{ yyerror (&yylloc, conf, "Error setting DH Bits parameters."); 
 						 YYERROR; } );
+				TRACE_DEBUG(FULL, "DH parameters generated.");
 			}
 			;
--- a/freeDiameter/main.c	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/main.c	Wed Oct 07 19:31:39 2009 +0900
@@ -122,6 +122,10 @@
 				fd_ext_dump();
 				break;
 			
+			case FDEV_DUMP_SERV:
+				fd_servers_dump();
+				break;
+			
 			case FDEV_DUMP_QUEUES:
 				fd_fifo_dump(0, "Incoming messages", fd_g_incoming, fd_msg_dump_walk);
 				fd_fifo_dump(0, "Outgoing messages", fd_g_outgoing, fd_msg_dump_walk);
@@ -170,6 +174,7 @@
 		case_str(FDEV_TERMINATE);
 		case_str(FDEV_DUMP_DICT);
 		case_str(FDEV_DUMP_EXT);
+		case_str(FDEV_DUMP_SERV);
 		case_str(FDEV_DUMP_QUEUES);
 		case_str(FDEV_DUMP_CONFIG);
 		case_str(FDEV_DUMP_PEERS);
--- a/freeDiameter/p_psm.c	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/p_psm.c	Wed Oct 07 19:31:39 2009 +0900
@@ -43,6 +43,7 @@
 	, "STATE_WAITCNXACK"
 	, "STATE_WAITCNXACK_ELEC"
 	, "STATE_WAITCEA"
+	, "STATE_OPEN_HANDSHAKE"
 	, "STATE_SUSPECT"
 	, "STATE_REOPEN"
 	, "STATE_ZOMBIE"
--- a/freeDiameter/peers.c	Mon Oct 05 17:51:06 2009 +0900
+++ b/freeDiameter/peers.c	Wed Oct 07 19:31:39 2009 +0900
@@ -343,8 +343,8 @@
 				peer->p_hdr.info.pi_flags.sec == PI_SEC_DEFAULT ? "" :
 					(peer->p_hdr.info.pi_flags.sec == PI_SEC_NONE ? "IPSec." : "InbandTLS."),
 				peer->p_hdr.info.pi_flags.exp ? "Expire." : "",
-				peer->p_hdr.info.pi_flags.inband & PI_INB_NONE ? "InbandIPsecOK." : "",
-				peer->p_hdr.info.pi_flags.inband & PI_INB_TLS ?  "InbandTLSOK." : "",
+				peer->p_hdr.info.pi_flags.inband_none ? "InbandIPsec." : "",
+				peer->p_hdr.info.pi_flags.inband_tls ?  "InbandTLS." : "",
 				peer->p_hdr.info.pi_flags.relay ? "Relay (0xffffff)" : "No relay"
 				);
 		fd_log_debug("\tLifetime : %d sec\n", peer->p_hdr.info.pi_lft);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freeDiameter/sctp.c	Wed Oct 07 19:31:39 2009 +0900
@@ -0,0 +1,50 @@
+/*********************************************************************************************************
+* 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"
+
+int fd_sctp_create_bind_server( int * socket, uint16_t port )
+{
+	TODO("Create sctp server, using fd_g_config: cnf_endpoints, no_ip4, no_ip6, cnf_sctp_str");
+	
+	return ENOTSUP;
+}
+
+int fd_sctp_get_str_info( int socket, int *in, int *out )
+{
+	TODO("Retrieve streams info from the socket");
+	
+	return ENOTSUP;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/freeDiameter/server.c	Wed Oct 07 19:31:39 2009 +0900
@@ -0,0 +1,273 @@
+/*********************************************************************************************************
+* 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"
+
+/* This file contains the server (listening) part of the daemon */
+
+struct fd_list		FD_SERVERS = FD_LIST_INITIALIZER(FD_SERVERS);	/* The list of all server sockets */
+/* We don't need to protect this list, it is only accessed from the main thread. */
+
+/* Server (listening socket) information */
+struct server {
+	struct fd_list	chain;		/* link in the FD_SERVERS list */
+
+	int 		socket;		/* server socket, or <= 0 */
+	
+	int 		proto;		/* IPPROTO_TCP or IPPROTO_SCTP */
+	int 		secur;		/* TLS is started immediatly after connection ? */
+	
+	pthread_t	serv_thr;	/* The thread listening for new connections */
+	int		serv_status;	/* 0 : not created; 1 : running; 2 : terminated */
+	
+	pthread_mutex_t	clients_mtx;	/* Mutex to protect the list of clients connected to the thread */
+	struct fd_list	clients;	/* The list of clients connecting to this server, which information is not yet known */
+	
+	char *		serv_name;	/* A string to identify this server */
+};
+
+/* Client (connected remote endpoint, not received CER yet) information */
+struct client {
+	struct fd_list	 chain;	/* link in the server's list of clients */
+	
+	struct cnxctx	*conn;	/* Parameters of the connection; sends its events to the ev fifo bellow */
+	
+	struct timespec	 ts;	/* Delay for receiving CER: INCNX_TIMEOUT */
+	struct fifo	*ev;	/* Events of the connection -- allowed: TIMEOUT, ERROR (cnx, tls), MSG_RCV (CER, other=>error) */
+	
+	pthread_t	 cli_thr; /* connection state machine (simplified PSM) */
+};
+
+/* Parameter for the thread handling the new connected client, to avoid bloking the server thread */
+struct cli_fast {
+	struct server * serv;
+	int		sock;
+	sSS		ss;
+	socklen_t	sslen;
+};
+
+
+/* This thread is called when a new client had just connected */
+static void * handle_client_fast(void * arg)
+{
+	struct cli_fast * cf = arg;
+	struct client * c = NULL;
+	
+	/* Name the current thread */
+	ASSERT(arg);
+	{
+		char addr[128];
+		int offset = snprintf(addr, sizeof(addr), "Srv %d/Cli %d : ", cf->serv->socket, cf->sock);
+		int rc = getnameinfo((sSA *)&cf->ss, sizeof(sSS), addr + offset, sizeof(addr) - offset, NULL, 0, 0);
+		if (rc)
+			memcpy(addr + offset, gai_strerror(rc), sizeof(addr) - offset);
+		
+		if (TRACE_BOOL(INFO)) {
+			fd_log_debug( "New connection %s, sock %d, from '%s'\n", cf->serv->serv_name, cf->sock, addr + offset);
+		}
+	
+		fd_log_threadname ( addr );
+	}
+	
+	/* Create a client structure */
+	CHECK_MALLOC_DO( c = malloc(sizeof(struct client)), goto early_error );
+	memset(c, 0, sizeof(struct client));
+	fd_list_init(&c->chain, c);
+	c->cli_thr = pthread_self();
+	
+	/* Create the connection context */
+	CHECK_MALLOC_DO( c->conn = fd_cnx_init(cf->sock, cf->serv->proto), goto early_error );
+	
+	/* In case we are a secure server, handshake now */
+	if (cf->serv->secur) {
+		
+		TODO("Continue");
+	}
+	
+	/* Save the client in the list */
+	CHECK_POSIX_DO( pthread_mutex_lock( &cf->serv->clients_mtx ), goto early_error );
+	fd_list_insert_before(&cf->serv->clients, &c->chain);
+	CHECK_POSIX_DO( pthread_mutex_unlock( &cf->serv->clients_mtx ), goto error );
+	
+	
+	
+	
+early_error:
+	TRACE_DEBUG(INFO, "Thread is detaching to die");
+	pthread_detach(pthread_self());
+	shutdown(cf->sock, SHUT_RDWR);
+	free(cf);
+	free(c);
+error:	
+	TRACE_DEBUG(INFO, "Thread is terminating");
+	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
+	return NULL;
+}
+
+/* The thread for the server */
+static void * serv_th(void * arg)
+{
+	struct server *sv = (struct server *)arg;
+	struct cli_fast cf;
+	
+	CHECK_PARAMS_DO(sv, goto error);
+	fd_log_threadname ( sv->serv_name );
+	sv->serv_status = 1;
+	
+	memset(&cf, 0, sizeof(struct cli_fast));
+	cf.serv = sv;
+	
+	
+	/* Accept incoming connections */
+	CHECK_SYS_DO(  listen(sv->socket, 5), goto error );
+	
+	do {
+		struct cli_fast * ncf;
+		pthread_t	  thr;
+		
+		/* Re-init socket size */
+		cf.sslen = sizeof(sSS);
+		
+		/* Wait for a new client */
+		CHECK_SYS_DO( cf.sock = accept(sv->socket, (sSA *)&cf.ss, &cf.sslen), goto error );
+		
+		TRACE_DEBUG(FULL, "New connection accepted");
+		
+		/* Create the copy for the client thread */
+		CHECK_MALLOC_DO( ncf = malloc(sizeof(struct cli_fast)), goto error );
+		memcpy(ncf, &cf, sizeof(struct cli_fast));
+		
+		/* Create the thread to handle the new incoming connection */
+		CHECK_POSIX_DO( pthread_create( &thr /* we don't use it, but NULL is not standard */, NULL, handle_client_fast, ncf), goto error );
+		
+	} while (1);
+	
+error:	
+	if (sv)
+		sv->serv_status = 2;
+	/* Send error signal to the daemon */
+	TRACE_DEBUG(INFO, "An error occurred in server module! Thread is terminating...");
+	CHECK_FCT_DO(fd_event_send(fd_g_config->cnf_main_ev, FDEV_TERMINATE, NULL), );
+
+	return NULL;
+}
+
+
+/* Create a new server structure */
+static struct server * new_serv( int proto, int secur, int socket )
+{
+	char buf[32];
+	char * sn = NULL;
+	struct server * new;
+	
+	/* Create the server debug name */
+	buf[sizeof(buf) - 1] = '\0';
+	snprintf(buf, sizeof(buf) - 1, "Serv %d (%s%s)", socket, IPPROTO_NAME( proto ),	secur ? "s" : "");
+	CHECK_MALLOC_DO( sn = strdup(buf), return NULL );
+	
+	/* New server structure */
+	CHECK_MALLOC_DO( new = malloc(sizeof(struct server)), return NULL );
+	
+	memset(new, 0, sizeof(struct server));
+	fd_list_init(&new->chain, new);
+	new->socket = socket;
+	new->proto = proto;
+	new->secur = secur;
+	CHECK_POSIX_DO( pthread_mutex_init(&new->clients_mtx, NULL), return NULL );
+	fd_list_init(&new->clients, new);
+	
+	new->serv_name = sn;
+	
+	return new;
+}
+
+/* Dump all servers information */
+void fd_servers_dump()
+{
+	struct fd_list * li;
+	
+	fd_log_debug("Dumping servers list :\n");
+	for (li = FD_SERVERS.next; li != &FD_SERVERS; li = li->next) {
+		struct server * sv = (struct server *)li;
+		fd_log_debug("  Serv '%s': %s(%d), %s, %s, %s\n", 
+				sv->serv_name, 
+				(sv->socket > 0) ? "Open" : "Closed", sv->socket,
+				IPPROTO_NAME( sv->proto ),
+				sv->secur ? "Secur" : "NotSecur",
+				(sv->serv_status == 0) ? "Thread not created" :
+				((sv->serv_status == 1) ? "Thread running" :
+				((sv->serv_status == 2) ? "Thread terminated" :
+							  "Thread status unknown")));
+		/* Dump the endpoints ? */
+		/* Dump the client list ? */
+	}
+}
+
+/* Start all the servers */
+int fd_servers_start()
+{
+	int  socket;
+	struct server * sv;
+	
+	/* SCTP */
+	if (!fd_g_config->cnf_flags.no_sctp) {
+#ifdef DISABLE_SCTP
+		ASSERT(0);
+#else /* DISABLE_SCTP */
+		
+		/* Create the server on default port */
+		CHECK_FCT( fd_sctp_create_bind_server( &socket, fd_g_config->cnf_port ) );
+		CHECK_MALLOC( sv = new_serv(IPPROTO_SCTP, 0, socket) );
+		
+		
+		
+		
+#endif /* DISABLE_SCTP */
+	}
+	
+	/* TCP */
+	if (!fd_g_config->cnf_flags.no_tcp) {
+		
+		
+	}
+	
+	return 0;
+}
+
+/* Terminate all the servers */
+void fd_servers_stop()
+{
+	
+}
--- a/include/freeDiameter/freeDiameter.h	Mon Oct 05 17:51:06 2009 +0900
+++ b/include/freeDiameter/freeDiameter.h	Wed Oct 07 19:31:39 2009 +0900
@@ -117,7 +117,7 @@
 /* Endpoints */
 struct fd_endpoint {
 	struct fd_list  chain;	/* link in cnf_endpoints list */
-	sSS		ss;	/* the socket information. */
+	sSS		ss;	/* the socket information. List is always ordered by ss value (memcmp) */
 	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 */
@@ -174,11 +174,12 @@
 	 FDEV_TERMINATE = 1000	/* request to terminate */
 	,FDEV_DUMP_DICT		/* Dump the content of the dictionary */
 	,FDEV_DUMP_EXT		/* Dump state of extensions */
+	,FDEV_DUMP_SERV		/* Dump the server socket status */
 	,FDEV_DUMP_QUEUES	/* Dump the message queues */
 	,FDEV_DUMP_CONFIG	/* Dump the configuration */
 	,FDEV_DUMP_PEERS	/* Dump the list of peers */
 };
-const char * fd_ev_str(int event);
+const char * fd_ev_str(int event); /* defined in freeDiameter/main.c */
 
 
 /***************************************/
@@ -201,6 +202,7 @@
 				   We have sent a CER on our initiated connection, and received a CER from the remote peer on another connection. Election.
 				   If we win the election, we must disconnect the initiated connection and send a CEA on the other => we go to OPEN state.
 				   If we lose, we disconnect the other connection (receiver) and fallback to WAITCEA state. */
+	STATE_OPEN_HANDSHAKE,	/* TLS Handshake and validation are in progress in open state */
 	
 	/* Failover state machine */
 	STATE_SUSPECT,		/* A DWR was sent and not answered within TwTime. Failover in progress. */
@@ -210,7 +212,7 @@
 	STATE_ZOMBIE		/* The PSM thread is not running anymore; it must be re-started or peer should be deleted. */
 #define STATE_MAX STATE_ZOMBIE
 };
-extern const char *peer_state_str[];
+extern const char *peer_state_str[]; /* defined in freeDiameter/p_psm.c */
 #define STATE_STR(state) \
 	(((unsigned)(state)) <= STATE_MAX ? peer_state_str[((unsigned)(state)) ] : "<Invalid>")
 
@@ -244,10 +246,8 @@
 		#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 */
-		#define PI_INB_NONE	1	/* Remote peer advertised inband-sec-id 0 (None) */
-		#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	inband_none :1;	/* This is only meaningful with pi_flags.sec == 3 */
+		unsigned	inband_tls  :1;	/* This is only meaningful with pi_flags.sec == 3 */
 		
 		unsigned	relay :1;	/* The remote peer advertized the relay application */
 
@@ -337,17 +337,29 @@
  *  0   : The callback is added.
  * !0	: An error occurred.
  */
-int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */) );
+int fd_peer_validate_register ( int (*peer_validate)(struct peer_info * /* info */, int * /* auth */, int (**cb2)(struct peer_info *)) );
 /*
  * CALLBACK:	peer_validate
  *
  * PARAMETERS:
  *   info     : Structure containing information about the peer attempting the connection.
  *   auth     : Store there the result if the peer is accepted (1), rejected (-1), or unknown (0).
+ *   cb2      : If != NULL and in case of PI_SEC_TLS_OLD, another callback to call after handshake (if auth = 1).
  *
  * DESCRIPTION: 
  *   This callback is called when a new connection is being established from an unknown peer,
- *  after the CER is received. An extension must register such callback with peer_validate_register.
+ * after the CER is received. An extension must register such callback with peer_validate_register.
+ *
+ *   If (info->pi_flags.sec == PI_SEC_TLS_OLD) the extension may instruct the daemon explicitely
+ * to not use TLS by clearing info->pi_flags.inband_tls -- only if inband_none is set.
+ *
+ *   If (info->pi_flags.sec == PI_SEC_TLS_OLD) and info->pi_flags.inband_tls is set,
+ * the extension may also need to check the credentials provided during the TLS
+ * exchange (remote certificate). For this purpose, it may set the address of a new callback
+ * to be called once the handshake is completed. This new callback receives the information
+ * structure as parameter (with pi_sec_data set) and returns 0 if the credentials are correct,
+ * or an error code otherwise. If the error code is received, the connection is closed and the 
+ * peer is destroyed.
  *
  * RETURN VALUE:
  *  0      	: The authorization decision has been written in the location pointed by auth.
--- a/include/freeDiameter/libfreeDiameter.h	Mon Oct 05 17:51:06 2009 +0900
+++ b/include/freeDiameter/libfreeDiameter.h	Wed Oct 07 19:31:39 2009 +0900
@@ -336,6 +336,12 @@
 }
 /* if needed, add sSA_DUMP_SERVICE */
 
+/* A l4 protocol name (TCP / SCTP) */
+#define IPPROTO_NAME( _proto )					\
+	( ((_proto) == IPPROTO_TCP) ? "TCP" :			\
+		(((_proto) == IPPROTO_SCTP) ? "SCTP" :		\
+			"Unknown"))
+
 /* The sockaddr length of a sSS structure */
 #define sSSlen( _ss_ )	\
 	( (socklen_t) ( ((_ss_)->ss_family == AF_INET) ? (sizeof(sSA4)) :		\
"Welcome to our mercurial repository"