changeset 123:d1cef88ac5f2

Added new directives in conf, improved peer internal dsecription, replaces sockaddr with aliases
author Sebastien Decugis <sdecugis@nict.go.jp>
date Fri, 08 Aug 2008 18:04:38 +0900
parents 9a341105760a
children b4d229d647b7
files doc/waaad.conf.sample include/waaad/conf-api.h include/waaad/security-api.h waaad/conf-gram.y waaad/conf-token.l waaad/conf.c waaad/dict-base.c waaad/peer-internal.h waaad/security.c waaad/security.h waaad/waaad-internal.h
diffstat 11 files changed, 395 insertions(+), 72 deletions(-) [+]
line wrap: on
line diff
--- a/doc/waaad.conf.sample	Thu Aug 07 11:25:59 2008 +0900
+++ b/doc/waaad.conf.sample	Fri Aug 08 18:04:38 2008 +0900
@@ -9,12 +9,32 @@
 # The Diameter-Id of this peer.
 # This must be a valid FQDN that resolves to the local host.
 # Default: no default
-diameter-id = "test.local";
+diameter-id = "aaa.koganei.wide.ad.jp";
 
 # The port this peer is listening on for incoming connections (TCP and SCTP).
 # Default: 3868
 # LocalPort = 3868;
 
+# Directives for the addresses that the local peer will use.
+# The following directives are defined:
+#  'no_tcp;' : do not listen for TCP traffic, or attempt TCP connections. -- SCTP cannot be disabled.
+#  'no_ip4;' : do not use local IP addresses.
+#  'no_ip6;' : do not use local IPv6 addresses.
+#  'primary = "xxx.xxx.xxx.xxx";'       : Listen TCP and SCTP connections on this address.
+#  'primary = "aaaa:bbbb::dddd:eeee";'  : Listen TCP and SCTP connections on this address.
+#  'secondary = "xxx.xxx.xxx.xxx";'     : also use this IP for SCTP multihoming, but not as TCP server.
+#  'secondary = "aaaa:bbbb::dddd:eeee";': also use this IPv6 for SCTP multihoming, but not as TCP server.
+#
+# Note that:
+#  If no_ip4 is specified, no_ip6, primary4 and secondary4 are forbidden.
+#  If no_ip6 is specified, no_ip4, primary6 and secondary6 are forbidden.
+#  primary* directives use more resources than secondary* (one thread per primary sockets).
+#  The first "primary" directive that appears will be used as primary for SCTP and as
+#  value for Host-IP-Address for CER/CEA exchanged over TCP.
+#  
+# The default is to use both IP and IPv6, allow TCP, and let the system select the addresses.
+# In that case, the address used in CER/CEA will be the first value returned by DNS for the diameter-id resolution.
+
 # Where the messages are sent?
 # Valid values: console, syslog.
 # Multiple values are allowed. Separator is ','. Example:
--- a/include/waaad/conf-api.h	Thu Aug 07 11:25:59 2008 +0900
+++ b/include/waaad/conf-api.h	Fri Aug 08 18:04:38 2008 +0900
@@ -40,23 +40,39 @@
 #define _CONF_API_H
 
 #include <stddef.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
 
 /* The version of this API, to check binary compatibility -- increment each time a change is made in api_conf_t */
 #define WAAAD_API_CONF_VER	1
 
+#ifndef sSA_ALIASES
+#define sSS	struct sockaddr_storage
+#define sSA	struct sockaddr
+#define sSA4	struct sockaddr_in
+#define sSA6	struct sockaddr_in6
+#define sSA_ALIASES
+#endif /* sSA_ALIASES */
+
 /* This type contains all the parts of the global configuration of the daemon that can be accessed by the extensions */
 typedef struct {
 
 	char		*diameter_identity;	/* The Diameter Identity of the local peer */
+	uint16_t	 local_port;		/* The port on which to listen for incoming connexions. */
 	
-	uint16_t	 local_port;		/* The port on which to listen for incoming connexions. */
+	sSS		 local_addr_diamid[2];	/* The first address resolved from the Diameter Id (IP and IPv6),
+						   to use in Host-IP-Address if following list is empty. */
+	sSS		*local_addr_pri_sa;	/* points to a 0-terminated array of sSS containing the primary addresses from conf file. */
+	sSS		*local_addr_sec_sa;	/* points to a 0-terminated array of sSS containing the secondary addresses from conf file. */
+	
+	int		 disable_inet4;		/* if != 0, the local host does not use the IP protocol */
+	int		 disable_inet6;		/* if != 0, the local host does not use the IPv6 protocol */
+	int		 disable_tcp;		/* if != 0, the local host does not use the TCP protocol */
+	int		 disable_relay;		/* if != 0, the local host does not relay Diameter messages */
 	
 	int		 tctimer;		/* The value in seconds of the Tc timer */
-	
 	int		 twtimer;		/* The value in seconds of the Tw timer */
 	
-	int		 disable_relay;		/* if != 0, the local host do not relay Diameter messages */
-	
 } ext_conf_t; /* One should use the always-defined "g_pconf" pointer to access these fields */
 
 /* Now define the type of the structure that contains the callback to pass to extensions */
--- a/include/waaad/security-api.h	Thu Aug 07 11:25:59 2008 +0900
+++ b/include/waaad/security-api.h	Fri Aug 08 18:04:38 2008 +0900
@@ -87,7 +87,13 @@
 #include <sys/types.h>
 #include <sys/socket.h>
 
-
+#ifndef sSA_ALIASES
+#define sSS	struct sockaddr_storage
+#define sSA	struct sockaddr
+#define sSA4	struct sockaddr_in
+#define sSA6	struct sockaddr_in6
+#define sSA_ALIASES
+#endif /* sSA_ALIASES */
 
 /* The following type represents a "connection" object (for example, a socket) */
 typedef void sec_conn_t;
@@ -231,7 +237,7 @@
  *  0      	: Operation complete.
  *  !0 		: An error occurred. The module will not be used for this peer.
  */
-typedef int (*sec_is_supported_peer_cb_t) (char * diamid, struct sockaddr * sa, int * priority);
+typedef int (*sec_is_supported_peer_cb_t) (char * diamid, sSA * sa, int * priority);
 
 
 /* The following type contains all the information needed to register a security module. */
--- a/waaad/conf-gram.y	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/conf-gram.y	Fri Aug 08 18:04:38 2008 +0900
@@ -59,6 +59,7 @@
 #include "conf-gram.h"	/* bison is not smart enough to define the YYLTYPE before including this code, so... */
 
 #include <string.h>
+#include <stdlib.h>
 #include <sys/stat.h>
 #include <errno.h>
 #include <sys/socket.h>
@@ -113,6 +114,98 @@
 	return 1;
 }
 
+/* Global variable to store a sockaddr checked by is_valid_addr */
+static sSS _ss;
+
+static int have_ip4 = 0; /* have some ip4 been added already? */
+static int have_ip6 = 0; /* have some ip6 been added already? */
+
+/* This function converts a string into an IP or IPv6 address */
+static int is_valid_addr( char * candidate, waaad_conf_t * pconfig) 
+{
+	int ret=0;
+	
+	/* Clean the storage area */
+	memset(&_ss, 0, sizeof(_ss));
+	
+	/* Search for a ":" in the string */
+	if (!strchr(candidate, ':')) {
+		sSA4 * sin = (sSA4 *) &_ss;
+		/* Assume this is IPv4 */
+		ret = inet_pton(AF_INET, candidate, &sin->sin_addr.s_addr);
+		if (ret == 1) {
+			if (pconfig->pub.disable_inet4) {
+				log_error("Cannot use the address '%s' since NO_IP4 was defined\n", candidate);
+				return 0;
+			}
+			have_ip4++;
+			sin->sin_family = AF_INET;
+			sin->sin_port = htons(pconfig->pub.local_port);
+			return 1; /* the IP is valid */
+		}
+		if (ret == 0) {
+			log_error("Error on IP address '%s': unrecognized.\n", candidate);
+		} else {
+			log_error("Error on IP address '%s': %s.\n", candidate, strerror(errno));
+		}
+	} else {
+		sSA6 * sin6 = (sSA6 *)&_ss;
+		/* Assume this is IPv6 */
+		ret = inet_pton(AF_INET6, candidate, &sin6->sin6_addr.s6_addr);
+		if (ret == 1) {
+			if (pconfig->pub.disable_inet6) {
+				log_error("Cannot use the address '%s' since NO_IP6 was defined\n", candidate);
+				return 0;
+			}
+			have_ip6++;
+			sin6->sin6_family = AF_INET6;
+			sin6->sin6_port = htons(pconfig->pub.local_port);
+			return 1; /* the IPv6 is valid */
+		}
+		if (ret == 0) {
+			log_error("Error on IPv6 address '%s': unrecognized.\n", candidate);
+		} else {
+			log_error("Error on IPv6 address '%s': %s.\n", candidate, strerror(errno));
+		}
+	}
+
+	/* This candidate is not valid */
+	return 0;
+}
+
+/* This function extends the list of addresses and stores the new value of _ss inside */
+static int queue_ss( sSS ** plist )
+{
+	sSS * new;
+	
+	if (*plist == NULL) {
+		/* If the array has not been alloc'd yet */
+		*plist = malloc( sizeof (sSS) * 2 );
+		if (! *plist) {
+			log_error("Memory allocation failed.");
+			return ENOMEM;
+		}
+		new = *plist;
+	} else {
+		/* otherwise, we need to resize the array to add the new element */
+		int cnt = 0;
+		new = *plist;
+		while (new->ss_family != 0)
+			cnt++, new++;
+		*plist = realloc(*plist, sizeof(sSS) * (cnt + 2));
+		if (! *plist) {
+			log_error("Memory allocation failed.");
+			return ENOMEM;
+		}
+		new = (*plist) + cnt;
+	}
+	
+	/* Now, new points to the beginning of the location where the _ss must be stored */
+	memcpy(new, &_ss, sizeof(sSS));
+	memset(new+1, 0,  sizeof(sSS));
+	return 0;
+}
+
 /* Function to report the errors */
 void yyerror (YYLTYPE *ploc, waaad_conf_t * pconfig, char const *s)
 {
@@ -131,12 +224,12 @@
 } ext_detail={NULL, NULL};
 
 /* Global variable to store temporarily peer information */
-
 static struct _peer_detail {
 	char   * locator;
 	uint16_t port;
 	char     flags;
 } peer_detail={NULL, 0, 0};
+
 /* Flags values; 0 is default behavior */
 #define PEER_NO_SEC	0x1
 #define PEER_TCP	0x2
@@ -158,6 +251,7 @@
 /* Strings subtypes */
 %type <string>	FQDN		/* This is a fqdn. We check that the syntax is correct. */
 %type <string>	FILENAME	/* This is a filename. existence of the file is checked. */
+%type <string>  IPADDRESS	/* This is an IP. the numerical value is stored in _ss. */
 
 /* An integer value */
 %token <integer> INTEGER
@@ -174,6 +268,11 @@
 %token		GEN_TCTIMER
 %token		GEN_TWTIMER
 %token		GEN_DISABLERELAY
+%token		GEN_DISABLETCP
+%token		GEN_DISABLEIP4
+%token		GEN_DISABLEIP6
+%token		GEN_PRIMARY
+%token		GEN_SECONDARY
 
 /* In the "extension" section */
 %token 		SECTION_EXTENSION
@@ -191,21 +290,12 @@
 %token 		PEER_TRANS_SCTP
 %token 		PEER_TRANS_TCP
 
-/* In the "routing" section */
-%token 		SECTION_ROUTING
-
 /* -------------------------------------- */
 %%
 
-	/* The grammar definition - Sections blocs. General and Extension are mandatory (but may be empty) */
-conffile:		  other_sections general_section other_sections extensions_section other_sections
-			| other_sections extensions_section other_sections general_section other_sections
-			;
-
-	/* Other sections are not mandatory and may appear in any order */
-other_sections:		/* empty */
-			| other_sections peers_section	
-			| other_sections routing_section
+	/* The grammar definition - Sections blocs. */
+conffile:		  general_section extensions_section peers_section
+			| general_section peers_section extensions_section
 			;
 
 	/* These types are used several times: */
@@ -231,6 +321,19 @@
 			}
 			;
 				
+IPADDRESS:		QSTRING
+			{
+				/* Verify this is a valid IP */
+				if (!is_valid_addr($1, pconfig)) {
+					yyerror (&yylloc, pconfig, "An error was detected on an IP address, aborting...");
+					YYERROR;
+				}
+				/* _ss is set with the IP numerical value during the check */
+				/* Return the string anyway, to be freed */
+				$$ = $1;
+			}
+			;
+				
 
 	/* Define the [general] section grammar */
 general_section:	SECTION_GENERAL general_content
@@ -243,6 +346,11 @@
 			| general_content gen_tctimer
 			| general_content gen_twtimer
 			| general_content gen_disablerelay
+			| general_content gen_disabletcp
+			| general_content gen_disableip4
+			| general_content gen_disableip6
+			| general_content gen_primary
+			| general_content gen_secondary
 			;
 
 gen_log:		GEN_LOG '=' gen_log_type ';'
@@ -331,6 +439,68 @@
 			}
 			;
 
+gen_disabletcp:		GEN_DISABLETCP ';'
+			{
+				pconfig->pub.disable_tcp = 1;
+			}
+			;
+
+gen_disableip4:		GEN_DISABLEIP4 ';'
+			{
+				if (pconfig->pub.disable_inet6) {
+					yyerror (&yylloc, pconfig, "NO_IP6 and NO_IP4 can not be used together.");
+					YYERROR;
+				}
+				if (have_ip4) {
+					yyerror (&yylloc, pconfig, "A primary or secondary IP address was defined, but NO_IP4 appears.");
+					YYERROR;
+				}
+				pconfig->pub.disable_inet4 = 1;
+			}
+			;
+
+gen_disableip6:		GEN_DISABLEIP6 ';'
+			{
+				if (pconfig->pub.disable_inet4) {
+					yyerror (&yylloc, pconfig, "NO_IP4 and NO_IP6 can not be used together.");
+					YYERROR;
+				}
+				if (have_ip6) {
+					yyerror (&yylloc, pconfig, "A primary or secondary IPv6 address was defined, but NO_IP6 appears.");
+					YYERROR;
+				}
+				pconfig->pub.disable_inet6 = 1;
+			}
+			;
+			
+gen_primary:		GEN_PRIMARY '=' IPADDRESS ';'
+			{
+				/* queue the sa in _ss into pconfig->pub.local_addr_pri_sa */
+				if (queue_ss(&pconfig->pub.local_addr_pri_sa) != 0) {
+					yyerror (&yylloc, pconfig, "An error occurred while saving an address, aborting...");
+					YYERROR;
+				}
+				
+				
+				/* we don't need the string anymore */
+				free($3);
+			}
+			;
+
+gen_secondary:		GEN_SECONDARY '=' IPADDRESS ';'
+			{
+				/* queue the sa in _ss into pconfig->pub.local_addr_sec_sa */
+				if (queue_ss(&pconfig->pub.local_addr_sec_sa) != 0) {
+					yyerror (&yylloc, pconfig, "An error occurred while saving an address, aborting...");
+					YYERROR;
+				}
+				
+				/* we don't need the string anymore */
+				free($3);
+			}
+			;
+
+
 	/* Define the [extensions] section grammar */
 extensions_section:	SECTION_EXTENSION extensions_content
 			;
@@ -472,11 +642,3 @@
 				peer_detail.flags |= PEER_TCP;
 			}
 			;
-
-	/* Define the [routing] section grammar */
-routing_section:	SECTION_ROUTING routing_content
-			;
-
-routing_content:	/* empty is allowed */
-			;
-
--- a/waaad/conf-token.l	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/conf-token.l	Fri Aug 08 18:04:38 2008 +0900
@@ -119,15 +119,17 @@
 (?i:"console")		{ return GEN_LOG_CONSOLE; 			} /* Log messages to console */
 (?i:"syslog")		{ return GEN_LOG_SYSLOG; 			} /* Log messages to syslog */
 
-(?i:"Diameter-Id")	{ return GEN_DIAMID;				} /* How to specify the Diameter Identity of the local peer */
-
-(?i:"LocalPort")	{ return GEN_PORT;				} /* The port the local peer is listening on */
+(?i:"TcTimer")		{ return GEN_TCTIMER;				} /* Specify the Tc timer value */
+(?i:"TwTimer")		{ return GEN_TWTIMER;				} /* Specify the Tw timer value */
+(?i:"DisableRelay")	{ return GEN_DISABLERELAY;			} /* Is relaying disabled? */
 
-(?i:"TcTimer")		{ return GEN_TCTIMER;				} /* Specify the Tc timer value */
-
-(?i:"TwTimer")		{ return GEN_TWTIMER;				} /* Specify the Tw timer value */
-
-(?i:"DisableRelay")	{ return GEN_DISABLERELAY;			} /* Is relaying disabled? */
+(?i:"Diameter-Id")	{ return GEN_DIAMID;				} /* How to specify the Diameter Identity of the local peer */
+(?i:"LocalPort")	{ return GEN_PORT;				} /* The port the local peer is listening on */
+(?i:"no_tcp")		{ return GEN_DISABLETCP;			} /* Is TCP disabled? */
+(?i:"no_ip4")		{ return GEN_DISABLEIP4;			} /* Is IP disabled? */
+(?i:"no_ip6")		{ return GEN_DISABLEIP6;			} /* Is IPv6 disabled? */
+(?i:"primary")		{ return GEN_PRIMARY;				} /* An address to listen to TCP and SCTP connections */
+(?i:"secondary")	{ return GEN_SECONDARY;				} /* An address to use in SCTP multihoming (+ all primaries) */
 
 	/* The EXTENSION section tokens */
 (?i:"[extensions]")	{ return SECTION_EXTENSION; 			} /* enter the Extension section */
--- a/waaad/conf.c	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/conf.c	Fri Aug 08 18:04:38 2008 +0900
@@ -51,6 +51,8 @@
 #include <string.h>
 #include <errno.h>
 #include <stdio.h>
+#include <arpa/inet.h>
+#include <netdb.h>
  
 waaad_conf_t * g_conf=NULL;
 
@@ -78,15 +80,79 @@
 	return 0;
 }
 
+/* dump a list of SA */
+static void conf_dump_addr(char * name, sSS * array)
+{
+	sSS * ptr = array;
+	if (!array) {
+		TRACE_DEBUG( INFO, "  %-11s : -", name);
+	} else {
+		TRACE_DEBUG( INFO, "  %-11s :", name);
+		while (ptr->ss_family != 0) {
+			switch (ptr->ss_family) {
+				case AF_INET:
+					{
+						char buf[INET_ADDRSTRLEN];
+						sSA4 * sin = (sSA4 *)ptr;
+						if (inet_ntop(sin->sin_family, &sin->sin_addr, buf, sizeof(buf)) == NULL) {
+							TRACE_DEBUG( INFO, "                (error in inet_ntop: %s)", strerror(errno));
+						} else {
+							TRACE_DEBUG( INFO, "                %s", &buf);
+						}
+					}
+					break;
+					
+				case AF_INET6:
+					{
+						char buf[INET6_ADDRSTRLEN];
+						sSA6 * sin6 = (sSA6 *)ptr;
+						if (inet_ntop(sin6->sin6_family, &sin6->sin6_addr, buf, sizeof(buf)) == NULL) {
+							TRACE_DEBUG( INFO, "                (error in inet_ntop: %s)", strerror(errno));
+						} else {
+							TRACE_DEBUG( INFO, "                %s", &buf);
+						}
+					}
+					break;
+					
+				default:
+					TRACE_DEBUG( INFO, "                (invalid AF: %d)", ptr->ss_family)
+			}
+			ptr++;
+		}
+	}
+}
+
 /* Output the parsed configuration */
 static void conf_dump(void)
 {
+	char buf4[INET_ADDRSTRLEN];
+	char buf6[INET6_ADDRSTRLEN];
+	char *str4 = "-";
+	char *str6 = "-";
+	if (g_pconf->local_addr_diamid[0].ss_family == AF_INET) {
+		sSA4 * sin = (sSA4 *)&g_pconf->local_addr_diamid[0];
+		if (inet_ntop(sin->sin_family, &sin->sin_addr, buf4, sizeof(buf4))) {
+			str4 = buf4;
+		}
+	}
+	if (g_pconf->local_addr_diamid[1].ss_family == AF_INET6) {
+		sSA6 * sin6 = (sSA6 *)&g_pconf->local_addr_diamid[1];
+		if (inet_ntop(sin6->sin6_family, &sin6->sin6_addr, buf6, sizeof(buf6))) {
+			str6 = buf6;
+		}
+	}
+	
 	TRACE_DEBUG( INFO, "--- Parsed configuration : ---");
-	TRACE_DEBUG( INFO, "  Diameter-Id : %s", g_pconf->diameter_identity);
+	TRACE_DEBUG( INFO, "  Diameter-Id : %s ( %s / %s )", g_pconf->diameter_identity, str4, str6);
 	TRACE_DEBUG( INFO, "  Local port  : %hd",g_pconf->local_port);
 	TRACE_DEBUG( INFO, "  Tc timer    : %d", g_pconf->tctimer);
 	TRACE_DEBUG( INFO, "  Tw timer    : %d", g_pconf->twtimer);
 	TRACE_DEBUG( INFO, "  Relaying    : %s", g_pconf->disable_relay ? "Disabled" : "Enabled");
+	TRACE_DEBUG( INFO, "  TCP         : %s", g_pconf->disable_tcp   ? "Disabled" : "Enabled");
+	TRACE_DEBUG( INFO, "  IP          : %s", g_pconf->disable_inet4 ? "Disabled" : "Enabled");
+	TRACE_DEBUG( INFO, "  IPv6        : %s", g_pconf->disable_inet6 ? "Disabled" : "Enabled");
+	   conf_dump_addr( "Primary",   g_pconf->local_addr_pri_sa );
+	   conf_dump_addr( "Secondary", g_pconf->local_addr_sec_sa );
 	TRACE_DEBUG( INFO, "------------------------------");
 }
 
@@ -105,7 +171,6 @@
 int conf_parse ( void )
 {
 	extern FILE * yyin;
-	
 	int ret;
 	
 	if (!g_conf) {
@@ -132,6 +197,42 @@
 		return EINVAL;
 	}
 	
+	/* We now resolv the diameter-id */
+	{
+		struct addrinfo *ai = NULL, *p, hints;
+		int gotip4 = 0;
+		int gotip6 = 0;
+		
+		memset(&hints, 0, sizeof(hints));
+		hints.ai_flags = AI_ADDRCONFIG;
+
+		ret = getaddrinfo(g_pconf->diameter_identity, NULL, &hints, &ai);
+		if (ret != 0) {
+			log_error("Error resolving Diameter-Id '%s': %s.\n", g_pconf->diameter_identity, gai_strerror(ret));
+			return EINVAL;
+		}
+		for (p = ai; p != NULL; p = p->ai_next) {
+			switch (p->ai_family) {
+				case AF_INET:
+					if (gotip4)
+						break;
+					memcpy(&g_pconf->local_addr_diamid[0], p->ai_addr, sizeof(sSA4));
+					gotip4++;
+					break;
+					
+				case AF_INET6:
+					if (gotip6)
+						break;
+					memcpy(&g_pconf->local_addr_diamid[1], p->ai_addr, sizeof(sSA6));
+					gotip6++;
+					break;
+			}
+			if (gotip4 && gotip6)
+				break;
+		}
+
+		freeaddrinfo(ai);
+	}
 	conf_dump();
 
 	return 0;
--- a/waaad/dict-base.c	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/dict-base.c	Fri Aug 08 18:04:38 2008 +0900
@@ -51,7 +51,7 @@
 /* Address AVP <-> struct sockaddr_storage */
 static int Address_encode(void * data, avp_value_t * avp_value)
 {
-	struct sockaddr_storage * ss = (struct sockaddr_storage *) data;
+	sSS * ss = (sSS *) data;
 	uint16_t AddressType = 0;
 	size_t	size = 0;
 	unsigned char * buf = NULL;
@@ -67,7 +67,7 @@
 		case AF_INET:
 			{
 				/* We are encoding a IP address */
-				struct sockaddr_in * sin = (struct sockaddr_in *)ss;
+				sSA4 * sin = (sSA4 *)ss;
 				
 				AddressType = 1;/* see http://www.iana.org/assignments/address-family-numbers/ */
 				size = 6;	/* 2 for AddressType + 4 for data */
@@ -88,7 +88,7 @@
 		case AF_INET6:
 			{
 				/* We are encoding a IP address */
-				struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *)ss;
+				sSA6 * sin6 = (sSA6 *)ss;
 				
 				AddressType = 2;/* see http://www.iana.org/assignments/address-family-numbers/ */
 				size = 18;	/* 2 for AddressType + 16 for data */
@@ -136,7 +136,7 @@
 	switch (AddressType) {
 		case 1 /* IP */:
 			{
-				struct sockaddr_in * sin = (struct sockaddr_in *)interpreted;
+				sSA4 * sin = (sSA4 *)interpreted;
 				
 				if (avp_value->os.len != 6) {
 					TRACE_DEBUG(INFO, "Received invalid buffer size (%d instead of %d)", avp_value->os.len, 6);
@@ -152,7 +152,7 @@
 				
 		case 2 /* IP6 */:
 			{
-				struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *)interpreted;
+				sSA6 * sin6 = (sSA6 *)interpreted;
 				
 				if (avp_value->os.len != 18) {
 					TRACE_DEBUG(INFO, "Received invalid buffer size (%d instead of %d)", avp_value->os.len, 18);
--- a/waaad/peer-internal.h	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/peer-internal.h	Fri Aug 08 18:04:38 2008 +0900
@@ -66,20 +66,24 @@
 	/* Stable states */
 	STATE_DISABLED = 1,	/* No connexion must be attempted */
 	STATE_OPEN,		/* Connexion established */
-	/* Transitional states */
-	STATE_SUSPECT,		/* Connexion established but maybe broken */
-	STATE_CLOSED,		/* No connexion established, will re-attempt after TcTimer. */
-	STATE_CLOSING,		/* the connexion is being shutdown */
-	STATE_WAIT_CNX,		/* Trying to establish a connexion at transport level, waiting for ACK/NACK or new cnx initiated by remote peer (concurrent attempts) */
-	STATE_WAIT_CEA		/* CER has been sent, waiting for CEA or timeout */
-	/* TBC... */
-
-	/* Other states from the RFC: are they needed? Wait-Conn-Ack/Elect, Wait-Returns */
+	
+	/* Peer state machine */
+	STATE_CLOSED,		/* No connection established, will re-attempt after TcTimer. */
+	STATE_CLOSING,		/* the connection is being shutdown (DPR/DPA in progress) */
+	STATE_WAITCNXACK,	/* Attempting to establish transport-level connection */
+	STATE_WAITCNXACK_ELEC,	/* Received a CER from this same peer on an incoming connection (other peer object), while we were waiting for cnx ack */
+	STATE_WAITCEA,		/* Connection established, CER sent, waiting for CEA */
+	STATE_WAITRETURNS_ELEC,	/* 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. */
+	
+	/* Failover state machine */
+	STATE_SUSPECT,		/* A DWR was sent and not answered within TwTime. Failover in progress. */
+	STATE_REOPEN		/* Connection has been re-established, waiting for 3 DWR/DWA exchanges before putting back to service */
 	
 } peer_state_t;
 
-
-/* List of sent requests, ordered by hop-by-hop id */
+/* List of sent requests to this peer, ordered by hop-by-hop id */
 typedef struct _sent_r {
 	/* Chaining information */
 	struct _sent_r	*next;	/* The next sent request */
@@ -88,13 +92,12 @@
 	/* Pointer to the message */
 	msg_t		*msg;
 
-	/* The following two fields are copied from message for faster processing on message reception */
+	/* The following two fields are copied from message for faster processing on message reception and failover */
 	uint32_t	 hbh;	/* The hop-by-hop value of the message */
-	int	 	 rtb;	/* Is this a routable message? */
+	int	 	 rtb;	/* Is this a routable message? => discarded or requeued on failover */
 	
 } _sent_req_t;
 
-
 struct _peer;
 
 /* A list element for peers lists */
@@ -106,42 +109,46 @@
 } _pi_t;
 
 /* Flags definitions */
-#define	PEERFL_DYNAMIC	( 1 << 0 )	/* The peer is not statically configured and will expire */
-#define	PEERFL_EXPIRETS	( 1 << 1 )	/* The peer expires at the p_expire time. If not set, the peer expires at transport disconnection */
+#define	PEERFL_DYNAMIC		( 1 << 0 )	/* The peer is not statically configured and will expire */
+#define	PEERFL_EXPIRETS		( 1 << 1 )	/* The peer expires at the p_expire time. If not set, the (dynamic) peer expires at transport disconnection */
+#define PEERFL_DW_PENDING	( 1 << 2 )	/* A DWR message was sent and not answered yet */
+#define PEERFL_CNX_PB		( 1 << 3 )	/* The peer was disconnected because of watchdogs; must exchange 3 watchdogs before putting back to normal */
 
 /* Peer internal description */
 typedef struct _peer {
 	/* Chaining of the peer in global lists */
 	_pi_t		 p_global;	/* List of peers this peer belongs to */
-	_pi_t		 p_active;	/* Sublist containing only the active peers */
+	_pi_t		 p_active;	/* Sublist containing only the active peers (in STATE_OPEN) */
 
-	/* For debug  only */
+	/* For debug */
 	uint32_t	 p_eyec;	/* An eyecatcher to verify object is valid. Must be PEER_EYEC. */
 	
 	/* Peer data */
 	char 		*p_diamid;	/* The Diameter-Id of this peer, once known */
 	char 		*p_realm;	/* pointer to the beginning of the realm in the diamid string. */
-	uint32_t	 p_hbh;		/* current Hop-by-hop value */
+	uint32_t	 p_hbh;		/* next Hop-by-hop free value */
 	pthread_mutex_t	 p_lock;	/* Mutex to protect this object */
+	uint32_t	 p_flags;	/* The PEERFL_* flags */
+	struct timespec	 p_expire;	/* Lifetime of the peer, for dynamic peers */
 	
 	/* Peer state */
 	peer_state_t	 p_state;	/* State of the peer */
 	pthread_t	 p_psm;		/* The thread handling this peer state machine. */
-	uint32_t	 p_flags;	/* Some PEERFL_* flags */
-	struct timespec	 p_expire;	/* Lifetime of the peer, for dynamic peers */
+	pthread_cond_t	 p_condvar;	/* The cond var to be waited in the peer state machine (for timeouts and DWR) */
 	struct timespec	 p_ts;		/* multi-purpose timespec (meaning depends on the state) */
 	
 	/* Messages handling */
-	meq_t 		*p_in_q;	/* Incoming message queue */
+	meq_t 		*p_in_q;	/* Incoming (received) message queue */
 	pthread_t	 p_in_th;	/* The thread handling messages reception, created by p_psm */
-	
 	meq_t 		*p_out_q;	/* Outgoing message queue */
 	pthread_t	 p_out_th;	/* The thread handling messages envoy, created by p_psm */
-	
-	_sent_req_t	 p_sent;	/* List of sent requests */
+	_sent_req_t	 p_sent;	/* List of sent requests without answer */
 	
 	/* Connection information */
 	int		 p_sock;	/* We use standard Berkeley sockets for both TCP and SCTP connections */
+	int		 p_sock_tmp;	/* In case of election, store the socket on which the CER was received here, temporarily */
+	size_t		 p_peeraddr_sz;	/* Number of items in the array p_peeraddr bellow */
+	sSS 		*p_peeraddr;	/* Array of the attachment points of the remote peer (received in Host-IP-Address AVPs) */
 	
 	/* Security information */
 	_sec_item_t 	*p_sec_list;	/* Used only before a sucessful CER/CEA exchange */
@@ -150,9 +157,9 @@
 	sec_session_t	 p_sec_session;	/* structure passed back to the security module, for connection information */
 	void		*p_ext_session;	/* opaque data that can be used by the security extension to store internal states */
 	
-	/* Supported applications (result of CER/CEA) */
+	/* Supported applications (result of CER/CEA) -- contains all applications advertized by remote */
 	size_t		 p_app_size;	/* The size of the array pointed by p_app_list */
-	peer_appl_t	*p_app_list;	/* points to a 0-terminated array of supported applications */
+	peer_appl_t	*p_app_list;	/* points to an array of supported applications, of size p_app_size + 1, and the last element is always 0 */
 	
 } _peer_t;
 
--- a/waaad/security.c	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/security.c	Fri Aug 08 18:04:38 2008 +0900
@@ -254,7 +254,7 @@
 }
 	
 /* Create a list of _sec_item_t */
-int sec_getmodules(char * diamid, struct sockaddr * sa, _sec_item_t **modules)
+int sec_getmodules(char * diamid, sSA * sa, _sec_item_t **modules)
 {
 	int ret = 0;
 	int prio;
--- a/waaad/security.h	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/security.h	Fri Aug 08 18:04:38 2008 +0900
@@ -123,7 +123,7 @@
  *   0 : List created properly
  *  !0 : an error occurred
  */
-int sec_getmodules(char * diamid, struct sockaddr * sa, _sec_item_t **modules);
+int sec_getmodules(char * diamid, sSA * sa, _sec_item_t **modules);
 
 /*
  * FUNCTION:	sec_freemodules
--- a/waaad/waaad-internal.h	Thu Aug 07 11:25:59 2008 +0900
+++ b/waaad/waaad-internal.h	Fri Aug 08 18:04:38 2008 +0900
@@ -41,6 +41,15 @@
 #ifndef _WAAAD_INTERNAL_H
 #define _WAAAD_INTERNAL_H
 
+/* Some aliases to socket addresses structures */
+#ifndef sSA_ALIASES
+#define sSS	struct sockaddr_storage
+#define sSA	struct sockaddr
+#define sSA4	struct sockaddr_in
+#define sSA6	struct sockaddr_in6
+#define sSA_ALIASES
+#endif /* sSA_ALIASES */
+
 /* Configuration generated by the configure script. Contains host-specific environment information */
 #include "config.h"
 
"Welcome to our mercurial repository"