Rewrite the interface detection code.

Turns out SIOCGIFCONF is rather painful to get working cross-platform. This
should work better, and can be used even with ipv6 :)
This commit is contained in:
Bill Currie 2011-08-11 18:32:39 +09:00
parent c1a60551ae
commit 4cec4b9f96
3 changed files with 67 additions and 41 deletions

View file

@ -10,10 +10,10 @@ AC_CHECK_HEADERS(
alloca.h arpa/inet.h asm/io.h assert.h conio.h \
ctype.h ddraw.h dinput.h direct.h dirent.h dlfcn.h dmedia/audio.h \
dmedia/cdaudio.h dpmi.h dsound.h errno.h execinfo.h fcntl.h io.h \
libc.h limits.h linux/cdrom.h linux/joystick.h linux/soundcard.h \
machine/soundcard.h malloc.h math.h mgraph.h _mingw.h netdb.h \
netinet/in.h process.h pthread.h pwd.h rpc/types.h setjmp.h signal.h \
stdarg.h stdio.h stdlib.h string.h strings.h sys/asoundlib.h \
ifaddrs.h libc.h limits.h linux/cdrom.h linux/joystick.h \
linux/soundcard.h machine/soundcard.h malloc.h math.h mgraph.h _mingw.h \
netdb.h netinet/in.h process.h pthread.h pwd.h rpc/types.h setjmp.h \
signal.h stdarg.h stdio.h stdlib.h string.h strings.h sys/asoundlib.h \
sys/audioio.h sys/filio.h sys/ioctl.h sys/io.h sys/ipc.h sys/mman.h \
sys/param.h sys/poll.h sys/shm.h sys/signal.h sys/socket.h \
sys/soundcard.h sys/stat.h sys/time.h sys/types.h sys/uio.h termios.h \

View file

@ -79,3 +79,16 @@ connect (0, NULL, 42);
LIBS="$SAVELIBS"
fi
AC_SUBST(NET_LIBS)
AC_MSG_CHECKING([for getifaddrs])
SAVELIBS="$LIBS"
LIBS="$LIBS $NET_LIBS"
AC_TRY_LINK([],
[
getifaddrs (0);
],
AC_DEFINE(HAVE_GETIFADDRS, 1, [Define this if you have getifaddrs()])
AC_MSG_RESULT(yes),
AC_MSG_RESULT(no)
)
LIBS="$SAVELIBS"

View file

@ -52,6 +52,9 @@ static __attribute__ ((used)) const char rcsid[] =
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif
#ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
@ -114,7 +117,7 @@ static int net_controlsocket;
static int net_broadcastsocket = 0;
static struct qsockaddr broadcastaddr;
static unsigned myAddr;
static uint32_t myAddr;
#include "net_udp.h"
@ -126,43 +129,53 @@ uint32_t *last_iface;
static int
get_iface_list (int sock)
{
int ret;
int buflen;
struct ifconf ifconf;
#ifdef HAVE_GETIFADDRS
struct ifaddrs *ifa_head;
struct ifaddrs *ifa;
struct ifreq ifreq;
buflen = sizeof (*ifconf.ifc_req) * 4;
ifconf.ifc_req = 0;
do {
buflen *= 2;
ifconf.ifc_len = buflen;
ifconf.ifc_req = realloc (ifconf.ifc_req, ifconf.ifc_len);
if ((ret = ioctl (sock, SIOCGIFCONF, &ifconf)) < 0) {
Sys_MaskPrintf (SYS_NET, "ioctl: %s", strerror (errno));
break;
}
} while (ifconf.ifc_len == buflen);
if (ret >= 0) {
int i;
num_ifaces = ifconf.ifc_len / sizeof (*ifconf.ifc_req);
ifaces = malloc (num_ifaces * sizeof (int32_t));
Sys_MaskPrintf (SYS_NET, "Interfaces (count = %d)\n", num_ifaces);
for (i = 0; i < num_ifaces; i++) {
struct sockaddr_in *sa;
sa = (struct sockaddr_in *) &ifconf.ifc_req[i].ifr_ifru.ifru_addr;
Sys_MaskPrintf (SYS_NET, " %-10s %s\n",
ifconf.ifc_req[i].ifr_name,
inet_ntoa (sa->sin_addr));
memcpy (&ifaces[i], &sa->sin_addr, sizeof (uint32_t));
if (!default_iface && ifaces[i] != htonl (0x7f000001))
default_iface = &ifaces[i];
}
if (getifaddrs (&ifa_head) < 0)
goto no_ifaddrs;
for (ifa = ifa_head; ifa; ifa = ifa->ifa_next) {
if (!ifa->ifa_flags & IFF_UP)
continue;
if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
continue;
strncpy (ifreq.ifr_name, ifa->ifa_name, IFNAMSIZ);
ifreq.ifr_name[IFNAMSIZ - 1] = 0;
ioctl (sock, SIOCGIFINDEX, (char*) &ifreq);
if (ifreq.ifr_ifindex > num_ifaces)
num_ifaces = ifreq.ifr_ifindex;
}
if (default_iface)
myAddr = *default_iface;
free (ifconf.ifc_req);
return ret;
ifaces = malloc (num_ifaces * sizeof (uint32_t));
Sys_MaskPrintf (SYS_NET, "%d interfaces\n", num_ifaces);
for (ifa = ifa_head; ifa; ifa = ifa->ifa_next) {
int index;
struct sockaddr_in *sa;
if (!ifa->ifa_flags & IFF_UP)
continue;
if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != AF_INET)
continue;
strncpy (ifreq.ifr_name, ifa->ifa_name, IFNAMSIZ);
ifreq.ifr_name[IFNAMSIZ - 1] = 0;
ioctl (sock, SIOCGIFINDEX, (char*) &ifreq);
index = ifreq.ifr_ifindex - 1;
sa = (struct sockaddr_in *) ifa->ifa_addr;
memcpy (&ifaces[index], &sa->sin_addr, sizeof (uint32_t));
Sys_MaskPrintf (SYS_NET, " %-10s %s\n", ifa->ifa_name,
inet_ntoa (sa->sin_addr));
if (!default_iface && ifaces[index] != htonl (0x7f000001))
default_iface = &ifaces[index];
}
freeifaddrs (ifa_head);
return 0;
#endif
no_ifaddrs:
ifaces = &myAddr;
default_iface = &ifaces[0];
num_ifaces = 1;
return 0;
}
int
@ -187,7 +200,7 @@ UDP_Init (void)
gethostname (buff, MAXHOSTNAMELEN);
local = gethostbyname (buff);
if (local)
myAddr = *(int *) local->h_addr_list[0];
myAddr = *(uint32_t *) local->h_addr_list[0];
else
myAddr = 0;