changeset 378:41e3c2a3721c

Replaced old mechanism to discover local addresses by a call to getifaddrs, lot cleaner! Should close #4
author Sebastien Decugis <sdecugis@nict.go.jp>
date Mon, 05 Jul 2010 16:21:22 +0900
parents 7c0ddec9ab42
children 7337305ee51e
files freeDiameter/cnxctx.c freeDiameter/cnxctx.h freeDiameter/fD.h freeDiameter/p_ce.c freeDiameter/p_psm.c freeDiameter/sctp.c freeDiameter/server.c freeDiameter/tcp.c include/freeDiameter/CMakeLists.txt
diffstat 9 files changed, 76 insertions(+), 128 deletions(-) [+]
line wrap: on
line diff
--- a/freeDiameter/cnxctx.c	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/cnxctx.c	Mon Jul 05 16:21:22 2010 +0900
@@ -36,11 +36,15 @@
 #include "fD.h"
 #include "cnxctx.h"
 
+#include <net/if.h>
+#include <ifaddrs.h> /* for getifaddrs */
+
 /* The maximum size of Diameter message we accept to receive (<= 2^24) to avoid too big mallocs in case of trashed headers */
 #ifndef DIAMETER_MSG_SIZE_MAX
 #define DIAMETER_MSG_SIZE_MAX	65535	/* in bytes */
 #endif /* DIAMETER_MSG_SIZE_MAX */
 
+
 /* Connections contexts (cnxctx) in freeDiameter are wrappers around the sockets and TLS operations .
  * They are used to hide the details of the processing to the higher layers of the daemon.
  * They are always oriented on connections (TCP or SCTP), connectionless modes (UDP or SCTP) are not supported.
@@ -73,7 +77,6 @@
  *    - fd_cnx_destroy
  */
 
-
 /*******************************************/
 /*     Creation of a connection object     */
 /*******************************************/
@@ -467,64 +470,38 @@
 }
 
 /* Get the list of endpoints (IP addresses) of the local and remote peers on this connection */
-int fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote)
+int fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps)
 {
-	TRACE_ENTRY("%p %p %p", conn, local, remote);
-	CHECK_PARAMS(conn);
+	TRACE_ENTRY("%p %p %p", conn, eps);
+	CHECK_PARAMS(conn && eps);
 	
-	if (local) {
-		/* Retrieve the local endpoint(s) of the connection */
-		switch (conn->cc_proto) {
-			case IPPROTO_TCP: {
-				sSS ss;
-				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, EP_FL_LL | EP_FL_PRIMARY));
-			}
-			break;
+	/* Check we have a full connection object, not a listening socket (with no remote) */
+	CHECK_PARAMS( conn->cc_incoming );
 
-			#ifndef DISABLE_SCTP
-			case IPPROTO_SCTP: {
-				CHECK_FCT(fd_sctp_get_local_ep(conn->cc_socket, local));
-			}
-			break;
-			#endif /* DISABLE_SCTP */
-
-			default:
-				CHECK_PARAMS(0);
+	/* Retrieve the peer endpoint(s) of the connection */
+	switch (conn->cc_proto) {
+		case IPPROTO_TCP: {
+			sSS ss;
+			socklen_t sl;
+			CHECK_FCT(fd_tcp_get_remote_ep(conn->cc_socket, &ss, &sl));
+			CHECK_FCT(fd_ep_add_merge( eps, (sSA *)&ss, sl, EP_FL_LL | EP_FL_PRIMARY ));
 		}
-	}
-	
-	if (remote) {
-		/* Check we have a full connection object, not a listening socket (with no remote) */
-		CHECK_PARAMS( conn->cc_incoming );
-		
-		/* Retrieve the peer endpoint(s) of the connection */
-		switch (conn->cc_proto) {
-			case IPPROTO_TCP: {
-				sSS ss;
-				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, EP_FL_LL | EP_FL_PRIMARY ));
-			}
-			break;
+		break;
 
-			#ifndef DISABLE_SCTP
-			case IPPROTO_SCTP: {
-				CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, remote));
-			}
-			break;
-			#endif /* DISABLE_SCTP */
+		#ifndef DISABLE_SCTP
+		case IPPROTO_SCTP: {
+			CHECK_FCT(fd_sctp_get_remote_ep(conn->cc_socket, eps));
+		}
+		break;
+		#endif /* DISABLE_SCTP */
 
-			default:
-				CHECK_PARAMS(0);
-		}
+		default:
+			CHECK_PARAMS(0);
 	}
 
 	return 0;
 }
 
-
 /* Get a string describing the remote peer address (ip address or fqdn) */
 char * fd_cnx_getremoteid(struct cnxctx * conn)
 {
@@ -532,6 +509,30 @@
 	return conn->cc_remid;
 }
 
+/* Retrieve a list of all IP addresses of the local system from the kernel, using  */
+int fd_cnx_get_local_eps(struct fd_list * list)
+{
+	struct ifaddrs *iflist, *cur;
+	CHECK_SYS(getifaddrs(&iflist));
+	
+	for (cur = iflist; cur != NULL; cur = cur->ifa_next) {
+		if (cur->ifa_flags & IFF_LOOPBACK)
+			continue;
+		
+		if (fd_g_config->cnf_flags.no_ip4 && (cur->ifa_addr->sa_family == AF_INET))
+			continue;
+		
+		if (fd_g_config->cnf_flags.no_ip6 && (cur->ifa_addr->sa_family == AF_INET6))
+			continue;
+		
+		CHECK_FCT(fd_ep_add_merge( list, cur->ifa_addr, sSAlen(cur->ifa_addr), EP_FL_LL ));
+	}
+	
+	freeifaddrs(iflist);
+	
+	return 0;
+}
+
 
 /**************************************/
 /*     Use of a connection object     */
--- a/freeDiameter/cnxctx.h	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/cnxctx.h	Mon Jul 05 16:21:22 2010 +0900
@@ -136,5 +136,8 @@
 
 #endif /* DISABLE_SCTP */
 
+/* UDP */
+int fd_cnx_get_local_eps(struct fd_list * list);
+
 #endif /* _CNXCTX_H */
 
--- a/freeDiameter/fD.h	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/fD.h	Mon Jul 05 16:21:22 2010 +0900
@@ -326,7 +326,7 @@
 int		fd_cnx_getproto(struct cnxctx * conn);
 int		fd_cnx_getTLS(struct cnxctx * conn);
 int             fd_cnx_getcred(struct cnxctx * conn, const gnutls_datum_t **cert_list, unsigned int *cert_list_size);
-int             fd_cnx_getendpoints(struct cnxctx * conn, struct fd_list * local, struct fd_list * remote);
+int             fd_cnx_getremoteeps(struct cnxctx * conn, struct fd_list * eps);
 char *          fd_cnx_getremoteid(struct cnxctx * conn);
 int             fd_cnx_receive(struct cnxctx * conn, struct timespec * timeout, unsigned char **buf, size_t * len);
 int             fd_cnx_recv_setaltfifo(struct cnxctx * conn, struct fifo * alt_fifo); /* send FDEVP_CNX_MSG_RECV event to the fifo list */
--- a/freeDiameter/p_ce.c	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/p_ce.c	Mon Jul 05 16:21:22 2010 +0900
@@ -62,7 +62,7 @@
 	}
 	
 	/* Read the endpoints, maybe used to reconnect to the peer later */
-	CHECK_FCT( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints) );
+	CHECK_FCT( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints) );
 	
 	/* Read the protocol */
 	peer->p_hdr.info.runtime.pir_proto = fd_cnx_getproto(peer->p_cnxctx);
@@ -105,7 +105,7 @@
 	struct dict_object * dictobj = NULL;
 	struct avp * avp = NULL;
 	union avp_value val;
-	struct fd_list *li, local_ep = FD_LIST_INITIALIZER(local_ep);
+	struct fd_list *li;
 	
 	/* Add the Origin-* AVPs */
 	CHECK_FCT( fd_msg_add_origin ( msg, 1 ) );
@@ -113,11 +113,8 @@
 	/* Find the model for Host-IP-Address AVP */
 	CHECK_FCT(  fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Host-IP-Address", &dictobj, ENOENT )  );
 		
-	/* Get the list of endpoints */
-	CHECK_FCT(  fd_cnx_getendpoints(cnx, &local_ep, NULL) );
-	
 	/* Add the AVP(s) -- not sure what is the purpose... We could probably only add the primary one ? */
-	for (li = local_ep.next; li != &local_ep; li = li->next) {
+	for (li = fd_g_config->cnf_endpoints.next; li != &fd_g_config->cnf_endpoints; li = li->next) {
 		struct fd_endpoint * ep = (struct fd_endpoint *)li;
 		
 		CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
@@ -125,7 +122,6 @@
 		CHECK_FCT( fd_msg_avp_add( msg, MSG_BRW_LAST_CHILD, avp ) );
 	}
 	
-	
 	/* Vendor-Id, Product-Name, and Firmware-Revision AVPs */
 	CHECK_FCT( fd_dict_search( fd_g_config->cnf_dict, DICT_AVP, AVP_BY_NAME, "Vendor-Id", &dictobj, ENOENT )  );
 	CHECK_FCT( fd_msg_avp_new ( dictobj, 0, &avp ) );
--- a/freeDiameter/p_psm.c	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/p_psm.c	Mon Jul 05 16:21:22 2010 +0900
@@ -570,9 +570,9 @@
 		CHECK_FCT_DO( fd_ep_clearflags( &peer->p_hdr.info.pi_endpoints, EP_FL_PRIMARY ), /* ignore the error */);
 		
 		/* Get the new ones */
-		CHECK_FCT_DO( fd_cnx_getendpoints(peer->p_cnxctx, NULL, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
+		CHECK_FCT_DO( fd_cnx_getremoteeps(peer->p_cnxctx, &peer->p_hdr.info.pi_endpoints), /* ignore the error */);
 		
-		/* We do not support local endpoints change currently, but it could be added here if needed */
+		/* We do not support local endpoints change currently, but it could be added here if needed (refresh fd_g_config->cnf_endpoints)*/
 		
 		if (TRACE_BOOL(ANNOYING)) {
 			TRACE_DEBUG(ANNOYING, "New remote endpoint(s):" );
--- a/freeDiameter/sctp.c	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/sctp.c	Mon Jul 05 16:21:22 2010 +0900
@@ -932,54 +932,6 @@
 	return 0;
 }
 
-/* Get the list of local endpoints of the socket */
-int fd_sctp_get_local_ep(int sock, struct fd_list * list)
-{
-	union {
-		sSA	*sa;
-		uint8_t	*buf;
-	} ptr;
-	
-	sSA * data = NULL;
-	int count;
-	
-	TRACE_ENTRY("%d %p", sock, list);
-	CHECK_PARAMS(list);
-	
-	/* Read the list on the socket */
-	CHECK_SYS( count = sctp_getladdrs(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, "Unknown address family returned in sctp_getladdrs: %d", ptr.sa->sa_family);
-				goto stop;
-		}
-				
-		CHECK_FCT( fd_ep_add_merge( list, ptr.sa, sl, EP_FL_LL ) );
-		ptr.buf += sl;
-		count --;
-	}
-stop:
-	/* Free the list */
-	sctp_freeladdrs(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(getsockname(sock, (sSA *)&ss, &sl));
-		CHECK_FCT( fd_ep_add_merge( list, (sSA *)&ss, sl, EP_FL_PRIMARY ) );
-	}
-	
-	return 0;
-}
-
 /* Get the list of remote endpoints of the socket */
 int fd_sctp_get_remote_ep(int sock, struct fd_list * list)
 {
--- a/freeDiameter/server.c	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/server.c	Mon Jul 05 16:21:22 2010 +0900
@@ -269,15 +269,6 @@
 		fd_list_insert_before( &FD_SERVERS, &s->chain );
 		CHECK_POSIX( pthread_create( &s->thr, NULL, serv_th, s ) );
 		
-		/* Retrieve the list of endpoints if it was empty */
-		if (empty_conf_ep) {
-			(void) fd_cnx_getendpoints(s->conn, &fd_g_config->cnf_endpoints, NULL);
-			if (TRACE_BOOL(FULL)){
-				fd_log_debug("  Local server address(es) :\n");
-				fd_ep_dump( 5, &fd_g_config->cnf_endpoints );
-			}
-		}
-		
 		/* Create the server on secure port */
 		CHECK_MALLOC( s = new_serv(IPPROTO_SCTP, 1) );
 		CHECK_MALLOC( s->conn = fd_cnx_serv_sctp(fd_g_config->cnf_port_tls, FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints) ? NULL : &fd_g_config->cnf_endpoints) );
@@ -343,6 +334,18 @@
 		}
 	}
 	
+	/* Now, if we still have not got the list of local adresses, try to read it from the kernel directly */
+	if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
+		CHECK_FCT(fd_cnx_get_local_eps(&fd_g_config->cnf_endpoints));
+		if (FD_IS_LIST_EMPTY(&fd_g_config->cnf_endpoints)) {
+			TRACE_DEBUG(INFO, "Unable to find the addresses of the local system. Please use \"ListenOn\" parameter in the configuration.");
+			return EINVAL;
+		}
+	}
+	if (TRACE_BOOL(FULL)){
+		fd_log_debug("  Local server address(es) :\n");
+		fd_ep_dump( 5, &fd_g_config->cnf_endpoints );
+	}
 	return 0;
 }
 
--- a/freeDiameter/tcp.c	Mon Jul 05 14:36:50 2010 +0900
+++ b/freeDiameter/tcp.c	Mon Jul 05 16:21:22 2010 +0900
@@ -169,19 +169,6 @@
 	return ret;
 }
 
-
-/* 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)
-{
-	TRACE_ENTRY("%d %p %p", sock, ss, sl);
-	CHECK_PARAMS( ss && sl );
-	
-	*sl = sizeof(sSS);
-	CHECK_SYS(getsockname(sock, (sSA *)ss, sl));
-	
-	return 0;
-}
-
 /* Get the remote name of a TCP socket */
 int fd_tcp_get_remote_ep(int sock, sSS * ss, socklen_t *sl)
 {
@@ -193,3 +180,4 @@
 	
 	return 0;
 }
+
--- a/include/freeDiameter/CMakeLists.txt	Mon Jul 05 14:36:50 2010 +0900
+++ b/include/freeDiameter/CMakeLists.txt	Mon Jul 05 16:21:22 2010 +0900
@@ -42,6 +42,11 @@
 # malloc.h ?
 CHECK_INCLUDE_FILES (malloc.h HAVE_MALLOC_H)
 
+# getifaddrs ?
+CHECK_FUNCTION_EXISTS (getifaddrs HAVE_GETIFADDRS)
+IF (NOT HAVE_GETIFADDRS)
+   MESSAGE(SEND_ERROR "The getifaddrs function is currently required by freeDiameter.")
+ENDIF (NOT HAVE_GETIFADDRS)
 
 # pthreads
 INCLUDE(FindThreads)
"Welcome to our mercurial repository"