changeset 210:2b5027949f85

Fix issue where the same address can be added several times in a list
author Sebastien Decugis <sdecugis@nict.go.jp>
date Tue, 16 Feb 2010 16:33:03 +0900
parents b9f48f2f2a22
children 929513df9024
files freeDiameter/endpoints.c
diffstat 1 files changed, 57 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/freeDiameter/endpoints.c	Tue Feb 16 15:29:55 2010 +0900
+++ b/freeDiameter/endpoints.c	Tue Feb 16 16:33:03 2010 +0900
@@ -46,16 +46,18 @@
 		sSA4 *sin;
 		sSA6 *sin6;
 	} ptr;
+	in_port_t * port;
 	int cmp = -1;
 	
 	TRACE_ENTRY("%p %p %u %x", list, sa, sl, flags);
 	CHECK_PARAMS( list && sa && (sl <= sizeof(sSS)) );
 	
+	ptr.sa = sa;
+	
 	/* Filter out a bunch of invalid addresses */
-	if (! (flags & EP_ACCEPTALL)) {
-		ptr.sa = sa;
-		switch (sa->sa_family) {
-			case AF_INET:
+	switch (sa->sa_family) {
+		case AF_INET:
+			if (! (flags & EP_ACCEPTALL)) {
 				if (IN_IS_ADDR_UNSPECIFIED(&ptr.sin->sin_addr) 
 				 || IN_IS_ADDR_LOOPBACK(&ptr.sin->sin_addr)
 				 || IN_MULTICAST(ptr.sin->sin_addr.s_addr)
@@ -63,32 +65,72 @@
 				 || IN_BADCLASS(ptr.sin->sin_addr.s_addr)
 				 || (ptr.sin->sin_addr.s_addr == INADDR_BROADCAST))
 					return 0;
-				break;
+			}
+			port = &ptr.sin->sin_port;
+			break;
 
-			case AF_INET6:
+		case AF_INET6:
+			if (! (flags & EP_ACCEPTALL)) {
 				if (IN6_IS_ADDR_UNSPECIFIED(&ptr.sin6->sin6_addr) 
 				 || IN6_IS_ADDR_LOOPBACK(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_MULTICAST(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_LINKLOCAL(&ptr.sin6->sin6_addr)
 				 || IN6_IS_ADDR_SITELOCAL(&ptr.sin6->sin6_addr))
 					return 0;
-				break;
+			}
+			port = &ptr.sin6->sin6_port;
+			break;
 
-			default:
-				return 0;
-		}
-	} else {
-		/* remove it */
-		flags &= ~EP_ACCEPTALL;
+		default:
+			return 0;
 	}
+
+	/* remove the ACCEPTALL flag */
+	flags &= ~EP_ACCEPTALL;
 	
 	/* Search place in the list */
 	for (li = list->next; li != list; li = li->next) {
 		ep = (struct fd_endpoint *)li;
+		in_port_t * ep_port;
 		
-		cmp = memcmp(&ep->ss, sa, sl);
-		if (cmp >= 0)
+		/* First, compare the address family */
+		if (ep->sa.sa_family < sa->sa_family)
+			continue;
+		if (ep->sa.sa_family > sa->sa_family)
 			break;
+		
+		/* Then compare the address field */
+		switch (sa->sa_family) {
+			case AF_INET:
+				cmp = memcmp(&ep->sin.sin_addr, &ptr.sin->sin_addr, sizeof(struct in_addr));
+				ep_port = &ep->sin.sin_port;
+				break;
+			case AF_INET6:
+				cmp = memcmp(&ep->sin6.sin6_addr, &ptr.sin6->sin6_addr, sizeof(struct in6_addr));
+				ep_port = &ep->sin6.sin6_port;
+				break;
+			default:
+				/* Filter this out */
+				return 0;
+		}
+		if (cmp < 0)
+			continue;
+		if (cmp > 0)
+			break;
+		
+		/* Finally compare the port, only if not 0 */
+		if (*port == 0)
+			break;
+		if (*ep_port == 0) {
+			/* save the port information in the list, and break */
+			*ep_port = *port;
+			break;
+		}
+		if (*ep_port < *port)
+			continue;
+		if (*ep_port > *port)
+			cmp = 1;
+		break;
 	}
 	
 	if (cmp) {
"Welcome to our mercurial repository"