From c4ef7b16092d370ede7420a1c468a4271526edc5 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 12 Jan 2013 20:39:47 +0800 Subject: [PATCH] introduce getifaddrs for toolchains without it David found that uclibc did not provide this slightly esoteric api and provided one from BSD that can be built by the library internally. AG: Made contingent on configure option --enable-builtin-getifaddrs Signed-off-by: David Signed-off-by: Andy Green --- README-test-server | 7 ++ configure.ac | 14 +++ lib/Makefile.am | 3 + lib/getifaddrs.c | 271 ++++++++++++++++++++++++++++++++++++++++++++ lib/getifaddrs.h | 76 +++++++++++++ lib/libwebsockets.c | 4 + 6 files changed, 375 insertions(+) create mode 100644 lib/getifaddrs.c create mode 100644 lib/getifaddrs.h diff --git a/README-test-server b/README-test-server index a8d9999a..a2ce2103 100644 --- a/README-test-server +++ b/README-test-server @@ -24,6 +24,8 @@ disabled when building this way 3) ./configure --prefix=/usr --enable-mingw --host=x86_64-w64-mingw32 4) make +For uClibc, you will likely need --enable-builtin-getifaddrs + otherwise if /usr/local/... and /usr/local/lib are OK then... $ ./configure @@ -63,6 +65,11 @@ There are a couple of other possible configure options --enable-x-google-mux Enable experimental x-google-mux support in the build (see notes later in document) +--enable-builtin-getifaddrs if your libc lacks getifaddrs, you can build an + implementation into the library. By default your libc + one is used. + + Testing server with a browser ----------------------------- diff --git a/configure.ac b/configure.ac index 8afdd4dc..fce03117 100644 --- a/configure.ac +++ b/configure.ac @@ -123,6 +123,20 @@ fi AM_CONDITIONAL(DISABLE_DEBUG, test x$disable_debug = xyes) +# +# +# +AC_ARG_ENABLE(builtin-getifaddrs, + [ --enable-builtin-getifaddrs Use BSD getifaddrs implementation from libwebsockets... default is your libc provides it], + [ builtin_getifaddrs=yes + ]) +if test "x$x_google_mux" = "xyes" ; then +CFLAGS="$CFLAGS -DLWS_BUILTIN_GETIFADDRS" +fi +AM_CONDITIONAL(USE_BUILTIN_GETIFADDRS, test x$builtin_getifaddrs = xyes) + + + # Checks for header files. AC_CHECK_HEADERS([zlib.h fcntl.h netinet/in.h stdlib.h string.h sys/socket.h unistd.h sys/prctl.h]) diff --git a/lib/Makefile.am b/lib/Makefile.am index 6fb8d05f..b1eb4344 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -11,6 +11,9 @@ dist_libwebsockets_la_SOURCES=libwebsockets.c \ extension-deflate-frame.c extension-deflate-frame.h\ private-libwebsockets.h +if USE_BUILTIN_GETIFADDRS +dist_libwebsockets_la_SOURCES += getifaddrs.c +endif if EXT_GOOGLE_MUX dist_libwebsockets_la_SOURCES += extension-x-google-mux.c extension-x-google-mux.h diff --git a/lib/getifaddrs.c b/lib/getifaddrs.c new file mode 100644 index 00000000..1591a431 --- /dev/null +++ b/lib/getifaddrs.c @@ -0,0 +1,271 @@ +/* downloaded from http://ftp.uninett.no/pub/OpenBSD/src/kerberosV/src/lib/roken/getifaddrs.c */ +#if !HAVE_GETIFADDRS +/* + * Copyright (c) 2000 - 2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif + +#ifdef HAVE_NETINET_IN6_VAR_H +#include +#endif + +#ifndef max +#define max(a,b) ((a)>(b)?(a):(b)) +#endif + +#include "getifaddrs.h" + +static int +getifaddrs2(struct ifaddrs **ifap, + int af, int siocgifconf, int siocgifflags, + size_t ifreq_sz) +{ + int ret; + int fd; + size_t buf_size; + char *buf; + struct ifconf ifconf; + char *p; + size_t sz; + struct sockaddr sa_zero; + struct ifreq *ifr; + + struct ifaddrs *start, **end = &start; + + buf = NULL; + + memset (&sa_zero, 0, sizeof(sa_zero)); + fd = socket(af, SOCK_DGRAM, 0); + if (fd < 0) + return -1; + + buf_size = 8192; + for (;;) { + buf = calloc(1, buf_size); + if (buf == NULL) { + ret = ENOMEM; + goto error_out; + } + ifconf.ifc_len = buf_size; + ifconf.ifc_buf = buf; + + /* + * Solaris returns EINVAL when the buffer is too small. + */ + if (ioctl (fd, siocgifconf, &ifconf) < 0 && errno != EINVAL) { + ret = errno; + goto error_out; + } + /* + * Can the difference between a full and a overfull buf + * be determined? + */ + + if (ifconf.ifc_len < (int)buf_size) + break; + free (buf); + buf_size *= 2; + } + + for (p = ifconf.ifc_buf; + p < ifconf.ifc_buf + ifconf.ifc_len; + p += sz) { + struct ifreq ifreq; + struct sockaddr *sa; + size_t salen; + + ifr = (struct ifreq *)p; + sa = &ifr->ifr_addr; + + sz = ifreq_sz; + salen = sizeof(struct sockaddr); +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + salen = sa->sa_len; + sz = max(sz, sizeof(ifr->ifr_name) + sa->sa_len); +#endif +#ifdef SA_LEN + salen = SA_LEN(sa); + sz = max(sz, sizeof(ifr->ifr_name) + SA_LEN(sa)); +#endif + memset (&ifreq, 0, sizeof(ifreq)); + memcpy (ifreq.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); + + if (ioctl(fd, siocgifflags, &ifreq) < 0) { + ret = errno; + goto error_out; + } + + *end = malloc(sizeof(**end)); + + (*end)->ifa_next = NULL; + (*end)->ifa_name = strdup(ifr->ifr_name); + (*end)->ifa_flags = ifreq.ifr_flags; + (*end)->ifa_addr = malloc(salen); + memcpy((*end)->ifa_addr, sa, salen); + (*end)->ifa_netmask = NULL; + +#if 0 + /* fix these when we actually need them */ + if(ifreq.ifr_flags & IFF_BROADCAST) { + (*end)->ifa_broadaddr = malloc(sizeof(ifr->ifr_broadaddr)); + memcpy((*end)->ifa_broadaddr, &ifr->ifr_broadaddr, + sizeof(ifr->ifr_broadaddr)); + } else if(ifreq.ifr_flags & IFF_POINTOPOINT) { + (*end)->ifa_dstaddr = malloc(sizeof(ifr->ifr_dstaddr)); + memcpy((*end)->ifa_dstaddr, &ifr->ifr_dstaddr, + sizeof(ifr->ifr_dstaddr)); + } else + (*end)->ifa_dstaddr = NULL; +#else + (*end)->ifa_dstaddr = NULL; +#endif + + (*end)->ifa_data = NULL; + + end = &(*end)->ifa_next; + + } + *ifap = start; + close(fd); + free(buf); + return 0; + error_out: + close(fd); + free(buf); + errno = ret; + return -1; +} + +int +getifaddrs(struct ifaddrs **ifap) +{ + int ret = -1; + errno = ENXIO; +#if defined(AF_INET6) && defined(SIOCGIF6CONF) && defined(SIOCGIF6FLAGS) + if (ret) + ret = getifaddrs2 (ifap, AF_INET6, SIOCGIF6CONF, SIOCGIF6FLAGS, + sizeof(struct in6_ifreq)); +#endif +#if defined(HAVE_IPV6) && defined(SIOCGIFCONF) + if (ret) + ret = getifaddrs2 (ifap, AF_INET6, SIOCGIFCONF, SIOCGIFFLAGS, + sizeof(struct ifreq)); +#endif +#if defined(AF_INET) && defined(SIOCGIFCONF) && defined(SIOCGIFFLAGS) + if (ret) + ret = getifaddrs2 (ifap, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, + sizeof(struct ifreq)); +#endif + return ret; +} + +void +freeifaddrs(struct ifaddrs *ifp) +{ + struct ifaddrs *p, *q; + + for(p = ifp; p; ) { + free(p->ifa_name); + if(p->ifa_addr) + free(p->ifa_addr); + if(p->ifa_dstaddr) + free(p->ifa_dstaddr); + if(p->ifa_netmask) + free(p->ifa_netmask); + if(p->ifa_data) + free(p->ifa_data); + q = p; + p = p->ifa_next; + free(q); + } +} + +#ifdef TEST + +void +print_addr(const char *s, struct sockaddr *sa) +{ + int i; + printf(" %s=%d/", s, sa->sa_family); +#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN + for(i = 0; i < sa->sa_len - ((long)sa->sa_data - (long)&sa->sa_family); i++) + printf("%02x", ((unsigned char*)sa->sa_data)[i]); +#else + for(i = 0; i < sizeof(sa->sa_data); i++) + printf("%02x", ((unsigned char*)sa->sa_data)[i]); +#endif + printf("\n"); +} + +void +print_ifaddrs(struct ifaddrs *x) +{ + struct ifaddrs *p; + + for(p = x; p; p = p->ifa_next) { + printf("%s\n", p->ifa_name); + printf(" flags=%x\n", p->ifa_flags); + if(p->ifa_addr) + print_addr("addr", p->ifa_addr); + if(p->ifa_dstaddr) + print_addr("dstaddr", p->ifa_dstaddr); + if(p->ifa_netmask) + print_addr("netmask", p->ifa_netmask); + printf(" %p\n", p->ifa_data); + } +} + +int +main() +{ + struct ifaddrs *a = NULL, *b; + getifaddrs2(&a, AF_INET, SIOCGIFCONF, SIOCGIFFLAGS, sizeof(struct ifreq)); + print_ifaddrs(a); + printf("---\n"); + getifaddrs(&b); + print_ifaddrs(b); + return 0; +} +#endif +#endif diff --git a/lib/getifaddrs.h b/lib/getifaddrs.h new file mode 100644 index 00000000..56864657 --- /dev/null +++ b/lib/getifaddrs.h @@ -0,0 +1,76 @@ +#if HAVE_GETIFADDRS +#include +#include +#else +#ifdef __cplusplus +extern "C" { +#endif +/* + * Copyright (c) 2000 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* $KTH: ifaddrs.hin,v 1.3 2000/12/11 00:01:13 assar Exp $ */ + +#ifndef __ifaddrs_h__ +#define __ifaddrs_h__ + +/* + * the interface is defined in terms of the fields below, and this is + * sometimes #define'd, so there seems to be no simple way of solving + * this and this seemed the best. */ + +#undef ifa_dstaddr + +struct ifaddrs { + struct ifaddrs *ifa_next; + char *ifa_name; + unsigned int ifa_flags; + struct sockaddr *ifa_addr; + struct sockaddr *ifa_netmask; + struct sockaddr *ifa_dstaddr; + void *ifa_data; +}; + +#ifndef ifa_broadaddr +#define ifa_broadaddr ifa_dstaddr +#endif + +int getifaddrs(struct ifaddrs**); + +void freeifaddrs(struct ifaddrs*); + +#endif /* __ifaddrs_h__ */ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c index b36a9b28..dd6e8d7c 100644 --- a/lib/libwebsockets.c +++ b/lib/libwebsockets.c @@ -25,7 +25,11 @@ #include #include #else +#ifdef LWS_BUILTIN_GETIFADDRS +#include +#else #include +#endif #include #include #include