فهرست منبع

core: rewrite add_interfaces() with getifaddrs() based implementation

To make IPV6 work with Solaris, add_interfaces() had to be modified.
I decided to reimplement it with a getifaddrs() based implementation,
which is available from Solaris 11 upwards, and also on FreeBSD and
Linux. By default, the latter continues to use the netlink based
variant.
Christian Kuehnke 9 سال پیش
والد
کامیت
424ac4dba7
2فایلهای تغییر یافته به همراه33 افزوده شده و 111 حذف شده
  1. 1 1
      Makefile.defs
  2. 32 110
      socket_info.c

+ 1 - 1
Makefile.defs

@@ -1785,7 +1785,7 @@ ifeq ($(CC_NAME), suncc)
 endif
 	OLD_SOLARIS= $(shell echo "$(OSREL)" | \
 				sed -e 's/^5\.[0-6][^0-9]*$$/yes/' )
-	LIBS+= -L$(LOCALBASE)/lib -lxnet -lnsl 
+	LIBS+= -L$(LOCALBASE)/lib -lxnet -lsocket -lnsl 
 ifeq	($(OLD_SOLARIS), yes)
 		LIBS+=-lposix4
 else

+ 32 - 110
socket_info.c

@@ -41,6 +41,7 @@
 
 #include <sys/ioctl.h>
 #include <net/if.h>
+#include <ifaddrs.h>
 #ifdef HAVE_SYS_SOCKIO_H
 #include <sys/sockio.h>
 #endif
@@ -1129,7 +1130,8 @@ error:
 	return -1;
 
 }
-/* add all family type addresses of interface if_to the socket_info array
+/* add all family type addresses of interface if_name to the socket_info array
+ * if family ==0, uses all families
  * if if_name==0, adds all addresses on all interfaces
  * uses RTNETLINK sockets to get addresses on the present interface on LINUX
  * return: -1 on error, 0 on success
@@ -1160,7 +1162,7 @@ int add_interfaces_via_netlink(char* if_name, int family, unsigned short port,
 				LM_DBG("in add_iface_via_netlink Name %s Address %s\n",
 							ifaces[i].name, tmp->addr);
 					/* match family */
-					if (family == tmp->family){
+					if (family && family == tmp->family){
 					/* check if loopback */
 					if (ifaces[i].flags & IFF_LOOPBACK){
 						LM_DBG("INTERFACE %s is loopback", ifaces[i].name);
@@ -1182,129 +1184,49 @@ error:
 #endif /* __OS_linux */
 
 /* add all family type addresses of interface if_name to the socket_info array
+ * if family ==0, uses all families
  * if if_name==0, adds all addresses on all interfaces
- * WARNING: it only works with ipv6 addresses on FreeBSD
  * return: -1 on error, 0 on success
  */
 int add_interfaces(char* if_name, int family, unsigned short port,
 					unsigned short proto,
 					struct addr_info** ai_l)
 {
-	struct ifconf ifc;
-	struct ifreq ifr;
-	struct ifreq ifrcopy;
-	char*  last;
-	char* p;
-	int size;
-	int lastlen;
-	int s;
 	char* tmp;
 	struct ip_addr addr;
-	int ret;
+	int ret = -1;
 	enum si_flags flags;
+	struct ifaddrs *ifap, *ifa;
 
-#ifdef HAVE_SOCKADDR_SA_LEN
-	#ifndef MAX
-		#define MAX(a,b) ( ((a)>(b))?(a):(b))
-	#endif
-#endif
-	/* ipv4 or ipv6 only*/
-	flags=SI_NONE;
-	s=socket(family, SOCK_DGRAM, 0);
-	ret=-1;
-	lastlen=0;
-	ifc.ifc_req=0;
-	for (size=100; ; size*=2){
-		ifc.ifc_len=size*sizeof(struct ifreq);
-		ifc.ifc_req=(struct ifreq*) pkg_malloc(size*sizeof(struct ifreq));
-		if (ifc.ifc_req==0){
-			LM_ERR("memory allocation failure\n");
-			goto error;
-		}
-		if (ioctl(s, SIOCGIFCONF, &ifc)==-1){
-			if(errno==EBADF) return 0; /* invalid descriptor => no such ifs*/
-			LM_ERR("ioctl failed: %s\n", strerror(errno));
-			goto error;
-		}
-		if  ((lastlen) && (ifc.ifc_len==lastlen)) break; /*success,
-														   len not changed*/
-		lastlen=ifc.ifc_len;
-		/* try a bigger array*/
-		pkg_free(ifc.ifc_req);
-	}
-	
-	last=(char*)ifc.ifc_req+ifc.ifc_len;
-	for(p=(char*)ifc.ifc_req; p<last;
-			p+=
-			#ifdef __OS_linux
-				sizeof(ifr) /* works on x86_64 too */
-			#else
-				(sizeof(ifr.ifr_name)+
-				#ifdef  HAVE_SOCKADDR_SA_LEN
-					MAX(ifr.ifr_addr.sa_len, sizeof(struct sockaddr))
-				#else
-					( (ifr.ifr_addr.sa_family==AF_INET)?
-						sizeof(struct sockaddr_in):
-						((ifr.ifr_addr.sa_family==AF_INET6)?
-						sizeof(struct sockaddr_in6):sizeof(struct sockaddr)) )
-				#endif
-				)
-			#endif
-		)
+	if (getifaddrs (&ifap) != 0) {
+		LM_ERR("getifaddrs failed\n");
+		return -1;
+        }
+
+	for (ifa = ifap; ifa; ifa = ifa->ifa_next)
 	{
-		/* copy contents into ifr structure
-		 * warning: it might be longer (e.g. ipv6 address) */
-		memcpy(&ifr, p, sizeof(ifr));
-		if (ifr.ifr_addr.sa_family!=family){
-			/*printf("strange family %d skipping...\n",
-					ifr->ifr_addr.sa_family);*/
+		if (if_name && strcmp(if_name, ifa->ifa_name))
 			continue;
+		if (family && family != ifa->ifa_addr->sa_family)
+			continue;
+		sockaddr2ip_addr(&addr, (struct sockaddr*)ifa->ifa_addr);
+		tmp=ip_addr2a(&addr);
+		if (ifa->ifa_flags & IFF_LOOPBACK) 
+			flags = SI_IS_LO;
+		else
+			flags = SI_NONE;
+		if (new_addr_info2list(tmp, flags, ai_l)!=0)
+		{
+			LM_ERR("new_addr_info2list failed\n");
+			ret = -1;
+			break;
 		}
-		
-		/*get flags*/
-		ifrcopy=ifr;
-		if (ioctl(s, SIOCGIFFLAGS,  &ifrcopy)!=-1){ /* ignore errors */
-			/* ignore down ifs only if listening on all of them*/
-			if (if_name==0){ 
-				/* if if not up, skip it*/
-				if (!(ifrcopy.ifr_flags & IFF_UP)) continue;
-			}
-		}
-		
-		
-		
-		if ((if_name==0)||
-			(strncmp(if_name, ifr.ifr_name, sizeof(ifr.ifr_name))==0)){
-			
-			/*add address*/
-			sockaddr2ip_addr(&addr, 
-					(struct sockaddr*)(p+(long)&((struct ifreq*)0)->ifr_addr));
-			if ((tmp=ip_addr2a(&addr))==0) goto error;
-			/* check if loopback */
-			if (ifrcopy.ifr_flags & IFF_LOOPBACK) 
-				flags|=SI_IS_LO;
-			/* save the info */
-			if (new_addr_info2list(tmp, flags, ai_l)!=0){
-				LM_ERR("new_addr_info2list failed\n");
-				goto error;
-			}
-			ret=0;
-		}
-			/*
-			printf("%s:\n", ifr->ifr_name);
-			printf("        ");
-			print_sockaddr(&(ifr->ifr_addr));
-			printf("        ");
-			ls_ifflags(ifr->ifr_name, family, options);
-			printf("\n");*/
+		LM_DBG("If: %8s Fam: %8x Flg: %16lx Adr: %s\n", ifa->ifa_name, ifa->ifa_addr->sa_family, ifa->ifa_flags, tmp);
+
+		ret = 0;
 	}
-	pkg_free(ifc.ifc_req); /*clean up*/
-	close(s);
+	freeifaddrs(ifap);
 	return  ret;
-error:
-	if (ifc.ifc_req) pkg_free(ifc.ifc_req);
-	close(s);
-	return -1;
 }
 
 
@@ -1474,7 +1396,7 @@ static int fix_socket_list(struct socket_info **list, int* type_flags)
 	for (si=*list;si;){
 		next=si->next;
 		ai_lst=0;
-		if (add_interfaces(si->name.s, AF_INET, si->port_no,
+		if (add_interfaces(si->name.s, 0, si->port_no,
 							si->proto, &ai_lst)!=-1){
 			if (si->flags & SI_IS_MHOMED){
 				if((new_si=new_sock2list_after(ai_lst->name.s, 0, si->port_no,