#include "pmix_config.h"
#include "pmix_common.h"
#include <string.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
#endif
#ifdef HAVE_SYS_SOCKIO_H
# include <sys/sockio.h>
#endif
#ifdef HAVE_SYS_IOCTL_H
# include <sys/ioctl.h>
#endif
#ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
#endif
#ifdef HAVE_NET_IF_H
# include <net/if.h>
#endif
#ifdef HAVE_NETDB_H
# include <netdb.h>
#endif
#ifdef HAVE_IFADDRS_H
# include <ifaddrs.h>
#endif
#include "src/mca/pif/base/base.h"
#include "src/mca/pif/pif.h"
#include "src/util/pmix_output.h"
#include "src/util/pmix_if.h"
static int if_posix_open(void);
pmix_pif_base_component_t pmix_mca_pif_posix_ipv4_component = {
PMIX_PIF_BASE_VERSION_2_0_0,
.pmix_mca_component_name = "posix_ipv4",
PMIX_MCA_BASE_MAKE_VERSION(component,
PMIX_MAJOR_VERSION,
PMIX_MINOR_VERSION,
PMIX_RELEASE_VERSION),
.pmix_mca_open_component = if_posix_open
};
static int prefix(uint32_t netmask)
{
uint32_t mask = ntohl(netmask);
int plen = 0;
if (0 == mask) {
plen = 32;
} else {
while ((mask % 2) == 0) {
plen += 1;
mask /= 2;
}
}
return (32 - plen);
}
static int if_posix_open(void)
{
int sd;
int lastlen, rem;
char *ptr;
struct ifconf ifconf;
int ifc_len;
bool successful_locate = false;
struct ifreq *ifr;
pmix_pif_t *intf;
int length;
if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
pmix_output(0, "pmix_ifinit: socket() failed with errno=%d\n", errno);
return PMIX_ERROR;
}
lastlen = 0;
ifc_len = sizeof(struct ifreq) * DEFAULT_NUMBER_INTERFACES;
do {
ifconf.ifc_len = ifc_len;
ifconf.ifc_req = (struct ifreq *) malloc(ifc_len);
if (NULL == ifconf.ifc_req) {
close(sd);
return PMIX_ERROR;
}
memset(ifconf.ifc_req, 0, ifconf.ifc_len);
if (ioctl(sd, SIOCGIFCONF, &ifconf) < 0) {
if (errno != EINVAL && lastlen != 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFCONF) \
failed with errno=%d",
errno);
free(ifconf.ifc_req);
close(sd);
return PMIX_ERROR;
}
} else {
if (ifconf.ifc_len == lastlen && ifconf.ifc_len > 0) {
successful_locate = true;
break;
}
lastlen = ifconf.ifc_len;
}
free(ifconf.ifc_req);
ifc_len = (ifc_len == 0) ? 1 : ifc_len * 2;
} while (ifc_len < MAX_PIFCONF_SIZE);
if (!successful_locate) {
pmix_output(0, "pmix_ifinit: unable to find network interfaces.");
close(sd);
return PMIX_ERROR;
}
ifr = (struct ifreq *) malloc(ifc_len);
ptr = (char *) ifconf.ifc_req;
rem = ifconf.ifc_len;
while (rem > 0) {
memset(ifr, 0, ifc_len);
memcpy(ifr, ptr, rem);
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
length = sizeof(struct sockaddr);
if (ifr->ifr_addr.sa_len > length) {
length = ifr->ifr_addr.sa_len;
}
length += sizeof(ifr->ifr_name);
#else
length = sizeof(struct ifreq);
#endif
rem -= length;
ptr += length;
if (AF_INET != ifr->ifr_addr.sa_family) {
continue;
}
if (ioctl(sd, SIOCGIFFLAGS, ifr) < 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFFLAGS) failed with errno=%d", errno);
continue;
}
if ((ifr->ifr_flags & IFF_UP) == 0) {
continue;
}
#ifdef IFF_SLAVE
if ((ifr->ifr_flags & IFF_SLAVE) != 0) {
continue;
}
#endif
#if 0#endif
intf = PMIX_NEW(pmix_pif_t);
if (NULL == intf) {
pmix_output(0, "pmix_ifinit: unable to allocated %lu bytes\n",
(unsigned long) sizeof(pmix_pif_t));
free(ifconf.ifc_req);
close(sd);
free(ifr);
return PMIX_ERR_OUT_OF_RESOURCE;
}
intf->af_family = AF_INET;
memset(intf->if_name, 0, sizeof(intf->if_name));
pmix_strncpy(intf->if_name, ifr->ifr_name, sizeof(intf->if_name) - 1);
intf->if_flags = ifr->ifr_flags;
intf->if_index = pmix_list_get_size(&pmix_if_list) + 1;
pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "found interface %s",
intf->if_name);
#ifndef SIOCGIFINDEX
intf->if_kernel_index = intf->if_index;
#else
if (ioctl(sd, SIOCGIFINDEX, ifr) < 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFINDEX) failed with errno=%d", errno);
PMIX_RELEASE(intf);
continue;
}
# if defined(ifr_ifindex)
intf->if_kernel_index = ifr->ifr_ifindex;
# elif defined(ifr_index)
intf->if_kernel_index = ifr->ifr_index;
# else
intf->if_kernel_index = -1;
# endif
#endif
if (ioctl(sd, SIOCGIFADDR, ifr) < 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFADDR) failed with errno=%d", errno);
PMIX_RELEASE(intf);
break;
}
if (AF_INET != ifr->ifr_addr.sa_family) {
PMIX_RELEASE(intf);
continue;
}
memcpy(&intf->if_addr, &ifr->ifr_addr, sizeof(struct sockaddr_in));
if (ioctl(sd, SIOCGIFNETMASK, ifr) < 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFNETMASK) failed with errno=%d", errno);
PMIX_RELEASE(intf);
continue;
}
intf->if_mask = prefix(((struct sockaddr_in *) &ifr->ifr_addr)->sin_addr.s_addr);
#if defined(SIOCGIFHWADDR) && defined(HAVE_STRUCT_IFREQ_IFR_HWADDR)
if (ioctl(sd, SIOCGIFHWADDR, ifr) < 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFHWADDR) failed with errno=%d", errno);
break;
}
memcpy(intf->if_mac, ifr->ifr_hwaddr.sa_data, 6);
#endif
#if defined(SIOCGIFMTU) && defined(HAVE_STRUCT_IFREQ_IFR_MTU)
if (ioctl(sd, SIOCGIFMTU, ifr) < 0) {
pmix_output(0, "pmix_ifinit: ioctl(SIOCGIFMTU) failed with errno=%d", errno);
break;
}
intf->ifmtu = ifr->ifr_mtu;
#endif
pmix_output_verbose(1, pmix_pif_base_framework.framework_output, "adding interface %s",
intf->if_name);
pmix_list_append(&pmix_if_list, &(intf->super));
}
free(ifconf.ifc_req);
close(sd);
free(ifr);
return PMIX_SUCCESS;
}