From 01bf2fcf57944104f9a774c8716950f397d666ce Mon Sep 17 00:00:00 2001 From: Dmitri Pal Date: Wed, 7 Oct 2009 09:45:39 -0400 Subject: ELAPI Compatibility code for getifaddr() Addreses ticket #94 Actually works pretty well. To try use --enable-compat when build ELAPI. It will use compatibility code instead of getifaddr(). The trick in the elapi_ioctl.h with memory allocation is taken from Stevens book. --- common/elapi/Makefile.am | 4 + common/elapi/conf_macros.m4 | 15 ++++ common/elapi/configure.ac | 3 + common/elapi/elapi_basic.h | 5 +- common/elapi/elapi_defines.h | 27 +++++++ common/elapi/elapi_event.c | 35 +++++---- common/elapi/elapi_ioctl.c | 142 ++++++++++++++++++++++++++++++++++++ common/elapi/elapi_ioctl.h | 39 ++++++++++ common/elapi/elapi_net.h | 103 ++++++++++++++++++++++++++ common/elapi/elapi_test/Makefile.am | 4 + 10 files changed, 357 insertions(+), 20 deletions(-) create mode 100644 common/elapi/elapi_defines.h create mode 100644 common/elapi/elapi_ioctl.c create mode 100644 common/elapi/elapi_ioctl.h create mode 100644 common/elapi/elapi_net.h diff --git a/common/elapi/Makefile.am b/common/elapi/Makefile.am index 53f2c3eff..747a3883b 100644 --- a/common/elapi/Makefile.am +++ b/common/elapi/Makefile.am @@ -55,13 +55,17 @@ libelapi_la_SOURCES = \ elapi_resolve.c \ elapi_async.c \ elapi_subst.c \ + elapi_ioctl.c \ elapi_event.h \ elapi_priv.h \ elapi_sink.h \ elapi_log.h \ elapi_async.h \ + elapi_net.h \ + elapi_ioctl.h \ elapi_fd.h \ elapi_tm.h \ + elapi_defines.h \ elapi.h libelapi_la_LIBADD = libprovider.la libelapibasic.la diff --git a/common/elapi/conf_macros.m4 b/common/elapi/conf_macros.m4 index e20dfdbaf..e3de2b7ff 100644 --- a/common/elapi/conf_macros.m4 +++ b/common/elapi/conf_macros.m4 @@ -54,3 +54,18 @@ AC_DEFUN([WITH_APP_NAME_SIZE], fi AC_SUBST(appnamesize) ]) + +AC_DEFUN([WITH_COMPAT], + [ AC_ARG_ENABLE([compat], + [AC_HELP_STRING([--enable-compat], + [use platform compatibility code]) + ], + , + [AC_CHECK_FUNC([getifaddrs], + AC_DEFINE([HAVE_GETIFADDRS], [1], + [Define if platform has getifaddrs()]) + ) + ] + ) + + ]) diff --git a/common/elapi/configure.ac b/common/elapi/configure.ac index ad2ffceec..82be136df 100644 --- a/common/elapi/configure.ac +++ b/common/elapi/configure.ac @@ -14,6 +14,7 @@ AM_SILENT_RULES AC_CONFIG_HEADERS([config.h]) + # Enable trace build AC_ARG_ENABLE([trace], [AS_HELP_STRING([--enable-trace[=LEVEL]],[build with low level tracing enabled])], @@ -21,12 +22,14 @@ AC_ARG_ENABLE([trace], [trace_level="0"]) AS_IF([test ["$trace_level" -gt "0"] -a ["$trace_level" -lt "8"] ],[AC_SUBST([TRACE_VAR],["-DTRACE_LEVEL=$trace_level"])]) + m4_include(conf_macros.m4) WITH_CONFIG_DIR WITH_CONFIG_APP_DIR WITH_APP_NAME WITH_APP_NAME_SIZE +WITH_COMPAT m4_include(def_macros.m4) diff --git a/common/elapi/elapi_basic.h b/common/elapi/elapi_basic.h index 8d23c7db7..480ef1bf8 100644 --- a/common/elapi/elapi_basic.h +++ b/common/elapi/elapi_basic.h @@ -21,10 +21,7 @@ #define ELAPI_BASIC_H #include - -#ifndef EOK -#define EOK 0 -#endif +#include "elapi_defines.h" /* Generic data structure for the data output */ struct elapi_data_out { diff --git a/common/elapi/elapi_defines.h b/common/elapi/elapi_defines.h new file mode 100644 index 000000000..84030e86f --- /dev/null +++ b/common/elapi/elapi_defines.h @@ -0,0 +1,27 @@ +/* + ELAPI + + Global defines for ELAPI + + Copyright (C) Dmitri Pal 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef ELAPI_DEFINES_H +#define ELAPI_DEFINES_H + +#ifndef EOK +#define EOK 0 +#endif + +#endif diff --git a/common/elapi/elapi_event.c b/common/elapi/elapi_event.c index e7a5d779e..ff7393933 100644 --- a/common/elapi/elapi_event.c +++ b/common/elapi/elapi_event.c @@ -31,10 +31,10 @@ #include /* for isspace() */ #include /* for va_arg() */ #include /* for strndup() */ -#include /* for getifaddrs() */ #include "elapi_priv.h" #include "elapi_event.h" +#include "elapi_net.h" #include "trace.h" #include "config.h" @@ -69,7 +69,9 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) char host[NI_MAXHOST]; char address[NI_MAXHOST]; char *hnm, *haddr; - struct ifaddrs *ifaddr, *ifa; + ELAPI_ADDRLIST ifaddr; + ELAPI_ADDRITEM ifa; + struct sockaddr *addr; int family; int set_hostname = 0; int set_ip = 0; @@ -88,26 +90,27 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) /* If we are not asked for ip then say we already have it */ if (!(base & E_HAVE_HOSTIP)) set_ip = 1; - if (getifaddrs(&ifaddr) == EOK) { + if (ELAPI_GET_ADDRLIST(&ifaddr) == EOK) { TRACE_FLOW_STRING("getifaddrs", "Ok"); /* Walk through linked list, maintaining head pointer so we can free list later */ + ELAPI_GET_FIRST_ADDR_ITEM(ifaddr, ifa); - ifa = ifaddr; while (ifa != NULL) { TRACE_FLOW_STRING("Top of the loop", ""); used_this_ip = 0; - if (!ifa->ifa_addr) { - ifa = ifa->ifa_next; + ELAPI_GET_ADDR(ifa, addr); + if (!addr) { + ELAPI_GET_NEXT_ADDR_ITEM(ifaddr, ifa); continue; } - family = ifa->ifa_addr->sa_family; + family = addr->sa_family; TRACE_FLOW_NUMBER("Family", family); @@ -121,7 +124,7 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) * We will trust it here and not clear memory using memset. */ - gai_ret_host = getnameinfo(ifa->ifa_addr, + gai_ret_host = getnameinfo(addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), host, @@ -130,7 +133,7 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) 0, 0 /* Gets host name */); - gai_ret_addr = getnameinfo(ifa->ifa_addr, + gai_ret_addr = getnameinfo(addr, (family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6), address, @@ -173,7 +176,7 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) error = col_add_str_property(tpl, NULL, E_HOSTNAME, hnm, 0); if (error) { TRACE_ERROR_NUMBER("Failed to add host name. Error", error); - freeifaddrs(ifaddr); + ELAPI_ADDR_LIST_CLEANUP(ifaddr); return error; } /* Done with the name */ @@ -201,7 +204,7 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) error = col_add_str_property(tpl, NULL, E_HOSTIP, haddr, 0); if (error) { TRACE_ERROR_NUMBER("Failed to add host name. Error", error); - freeifaddrs(ifaddr); + ELAPI_ADDR_LIST_CLEANUP(ifaddr); return error; } set_ip = 1; @@ -230,7 +233,7 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) error = col_add_str_property(tpl, NULL, E_HOSTALIAS, hnm, 0); if (error) { TRACE_ERROR_NUMBER("Failed to add host name. Error", error); - freeifaddrs(ifaddr); + ELAPI_ADDR_LIST_CLEANUP(ifaddr); return error; } } @@ -253,18 +256,18 @@ static int add_host_identity(struct collection_item *tpl, unsigned base) error = col_add_str_property(tpl, NULL, E_HOSTIPS, haddr, 0); if (error) { TRACE_ERROR_NUMBER("Failed to add host name. Error", error); - freeifaddrs(ifaddr); + ELAPI_ADDR_LIST_CLEANUP(ifaddr); return error; } } } } - TRACE_INFO_NUMBER("Moving to next", ifa->ifa_next); - ifa = ifa->ifa_next; + TRACE_INFO_STRING("Moved to next", ""); + ELAPI_GET_NEXT_ADDR_ITEM(ifaddr, ifa); TRACE_INFO_NUMBER("Moved to", ifa); } - freeifaddrs(ifaddr); + ELAPI_ADDR_LIST_CLEANUP(ifaddr); } /* Make sure that we really have the name after all */ diff --git a/common/elapi/elapi_ioctl.c b/common/elapi/elapi_ioctl.c new file mode 100644 index 000000000..c2a42a17c --- /dev/null +++ b/common/elapi/elapi_ioctl.c @@ -0,0 +1,142 @@ +/* + ELAPI + + Special platform specific functions related to networking + + Copyright (C) Dmitri Pal 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include "elapi_ioctl.h" +#include "trace.h" +#include "config.h" + +#ifndef HAVE_GETIFADDRS + +/* These functions are taken form Stevens's + * UNIX Network Programming Volume 1 + */ + +int elapi_get_addrlist(struct ifconf *ifc) +{ + int sockfd; + int length, lastlen; + int error; + char *buffer; + + TRACE_FLOW_STRING("elapi_get_addrlist", "Entry"); + + /* Open socket */ + sockfd = socket(AF_INET, SOCK_DGRAM, 0); + + lastlen = 0; + length = INTERFACE_NUM_GUESS * sizeof(struct ifreq); + + /* Allocate right amount of memory */ + /* This is a trick from Stevens book */ + /* Search web for "get_ifi_info" to get original code */ + for ( ; ; ) { + + buffer = malloc(length); + ifc->ifc_len = length; + ifc->ifc_buf = buffer; + + /* Read list */ + if (ioctl(sockfd, SIOCGIFCONF, ifc) < 0) { + error = errno; + TRACE_INFO_NUMBER("Ioctl call failed", error); + if (error != EINVAL || lastlen != 0) { + free(buffer); + TRACE_ERROR_NUMBER("ioctl failed", error); + return error; + } + } else { + TRACE_INFO_NUMBER("Length returned", ifc->ifc_len); + TRACE_INFO_NUMBER("Previous length", lastlen); + /* Break if length is same */ + if (ifc->ifc_len == lastlen) break; + lastlen = ifc->ifc_len; + } + + /* Grow length */ + length += INTERFACE_NUM_INC * sizeof(struct ifreq); + free(buffer); + } + + TRACE_FLOW_STRING("elapi_get_addrlist", "Exit"); + return EOK; +} + +/* Get the variable part of the size of the address */ +static int elapi_get_addrlen(struct ifreq *ifr) +{ + int len; + + TRACE_FLOW_STRING("elapi_get_addrlen", "Entry"); + +#ifdef HAVE_SOCKADDR_SA_LEN + len = max(sizeof(struct sockaddr), ifr->ifr_addr.sa_len); +#else + switch (ifr->ifr_addr.sa_family) { +#ifdef IPV6 + case AF_INET6: + len = sizeof(struct sockaddr_in6); + break; +#endif + case AF_INET: + default: + len = sizeof(struct sockaddr); + break; + } +#endif /* HAVE_SOCKADDR_SA_LEN */ + + TRACE_FLOW_NUMBER("elapi_get_addrlen Returning", len); + return len; +} + +/* Get next address */ +struct ifreq *elapi_get_next_addr(struct ifconf *ifc, struct ifreq *current) +{ + char *ifr; + + TRACE_FLOW_STRING("elapi_get_next_addr", "Entry"); + + TRACE_INFO_NUMBER("Current ifi", current); + TRACE_INFO_NUMBER("Address", ¤t->ifr_addr); + + /* Move to the next item */ + ifr = (char *)current + sizeof(current->ifr_name) + elapi_get_addrlen(current); + + TRACE_INFO_NUMBER("New ifi", ifr); + + /* Check if we are beyond the end of the allocated area */ + /* Have to cast otherwise get warnings */ + if (ifr >= ((char *)ifc->ifc_buf + ifc->ifc_len)) ifr = NULL; + + TRACE_INFO_NUMBER("New ifi adjusted", ifr); + + TRACE_FLOW_STRING("elapi_get_next_addr", "Exit"); + + return (struct ifreq *)ifr; +} + + +#endif /* HAVE_GETIFADDRS */ diff --git a/common/elapi/elapi_ioctl.h b/common/elapi/elapi_ioctl.h new file mode 100644 index 000000000..409cb0047 --- /dev/null +++ b/common/elapi/elapi_ioctl.h @@ -0,0 +1,39 @@ +/* + ELAPI + + Header file for the ELAPI handling of network interfaces. + + Copyright (C) Dmitri Pal 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef ELAPI_IOCTL_H +#define ELAPI_IOCTL_H + +#include "config.h" + +#ifndef HAVE_GETIFADDRS + +#include "elapi_defines.h" +#include + +/* Function prototypes */ +int elapi_get_addrlist(struct ifconf *ifc); +struct ifreq *elapi_get_next_addr(struct ifconf *ifc, struct ifreq *current); + +#define INTERFACE_NUM_GUESS 3 +#define INTERFACE_NUM_INC 1 + +#endif /* HAVE_GETIFADDRS */ + +#endif diff --git a/common/elapi/elapi_net.h b/common/elapi/elapi_net.h new file mode 100644 index 000000000..c9f8af7e7 --- /dev/null +++ b/common/elapi/elapi_net.h @@ -0,0 +1,103 @@ +/* + ELAPI + + Header file for the ELAPI handling of netwok interfaces. + + Copyright (C) Dmitri Pal 2009 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef ELAPI_NET_H +#define ELAPI_NET_H + +#include "config.h" + +#ifdef HAVE_GETIFADDRS +#include /* for getifaddrs() */ + +/* Macros then just wrap the getifaddrs() interface */ + +/* Type of the variable that stores the list */ +#define ELAPI_ADDRLIST struct ifaddrs * + +/* Type of the variable that stores the item */ +#define ELAPI_ADDRITEM struct ifaddrs * + +/* Function to build list of the interfaces */ +#define ELAPI_GET_ADDRLIST getifaddrs + +/* Macro to get first item from the list */ +#define ELAPI_GET_FIRST_ADDR_ITEM(list, item) \ + do { \ + item = list; \ + } while(0) + +/* Macro to get next item from the list */ +#define ELAPI_GET_NEXT_ADDR_ITEM(list, item) \ + do { \ + item = item->ifa_next; \ + } while(0) + + +/* Macro to get address */ +#define ELAPI_GET_ADDR(item, addr) \ + do { \ + addr = item->ifa_addr; \ + } while(0) + +/* Function to free the list */ +#define ELAPI_ADDR_LIST_CLEANUP freeifaddrs + +#else +/* Do everything using ioctl yourself... */ + +#include "elapi_ioctl.h" + +/* Type of the variable that stores the list */ +#define ELAPI_ADDRLIST struct ifconf + +/* Type of valiable that is used as a pointer */ +#define ELAPI_ADDRITEM struct ifreq * + +/* Function to build list of the interfaces */ +#define ELAPI_GET_ADDRLIST elapi_get_addrlist + +/* Macro to get first item from the list */ +#define ELAPI_GET_FIRST_ADDR_ITEM(list, item) \ + do { \ + item = (struct ifreq *)list.ifc_buf; \ + } while(0) + +/* Macro to get next item from the list */ +#define ELAPI_GET_NEXT_ADDR_ITEM(list, item) \ + do { \ + item = elapi_get_next_addr(&list, item); \ + } while(0) + + +/* Macro to get address */ +#define ELAPI_GET_ADDR(item, addr) \ + do { \ + addr = &(item->ifr_addr); \ + } while(0) + +/* Function to free the list */ +#define ELAPI_ADDR_LIST_CLEANUP(list) \ + do { \ + free(list.ifc_buf); \ + } while(0) + + +#endif /* HAVE_GETIFADDRS */ + +#endif diff --git a/common/elapi/elapi_test/Makefile.am b/common/elapi/elapi_test/Makefile.am index c0eac8a5d..d9f1bb0b2 100644 --- a/common/elapi/elapi_test/Makefile.am +++ b/common/elapi/elapi_test/Makefile.am @@ -33,13 +33,17 @@ libelapi_test_la_SOURCES = \ ../elapi_resolve.c \ ../elapi_async.c \ ../elapi_subst.c \ + ../elapi_ioctl.c \ ../elapi_event.h \ ../elapi_priv.h \ ../elapi_sink.h \ ../elapi_log.h \ ../elapi_async.h \ + ../elapi_ioctl.h \ + ../elapi_net.h \ ../elapi_fd.h \ ../elapi_tm.h \ + ../elapi_defines.h \ ../elapi.h \ ../providers/file/file_provider.c \ ../providers/file/file_provider.h \ -- cgit