/*! * Copyright (c) 2009, Jay Loden, Dave Daeschler, Giampaolo Rodola. * Licensed under the BSD 3-Clause License. * See https://github.com/giampaolo/psutil/blob/master/LICENSE */ #if (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__)) #include #include #include #include #include #include #include #include #include #include "ifaddrs_patch.h" #define MAX(x, y) ((x) > (y)?(x):(y)) #define SIZE(p) MAX((p).ss_len, sizeof(p)) static struct sockaddr * sa_dup(struct sockaddr_storage *sa1) { struct sockaddr *sa2; size_t sz = sizeof(struct sockaddr_storage); sa2 = (struct sockaddr *) calloc(1, sz); memcpy(sa2, sa1, sz); return(sa2); } void freeifaddrs(struct ifaddrs *ifp) { if (NULL == ifp) return; free(ifp->ifa_name); free(ifp->ifa_addr); free(ifp->ifa_netmask); free(ifp->ifa_dstaddr); freeifaddrs(ifp->ifa_next); free(ifp); } int getifaddrs(struct ifaddrs **ifap) { int sd = -1; char *ccp, *ecp; struct lifconf ifc; struct lifreq *ifr; struct lifnum lifn; struct ifaddrs *cifa = NULL; /* current */ struct ifaddrs *pifa = NULL; /* previous */ const size_t IFREQSZ = sizeof(struct lifreq); sd = socket(AF_INET, SOCK_STREAM, 0); if (sd < 0) goto error; ifc.lifc_buf = NULL; *ifap = NULL; /* find how much memory to allocate for the SIOCGLIFCONF call */ lifn.lifn_family = AF_UNSPEC; lifn.lifn_flags = 0; if (ioctl(sd, SIOCGLIFNUM, &lifn) < 0) goto error; /* Sun and Apple code likes to pad the interface count here in case interfaces * are coming up between calls */ lifn.lifn_count += 4; ifc.lifc_family = AF_UNSPEC; ifc.lifc_len = lifn.lifn_count * sizeof(struct lifreq); ifc.lifc_buf = static_cast(calloc(1, ifc.lifc_len)); if (ioctl(sd, SIOCGLIFCONF, &ifc) < 0) goto error; ccp = reinterpret_cast(ifc.lifc_req); ecp = ccp + ifc.lifc_len; while (ccp < ecp) { ifr = (struct lifreq *) ccp; cifa = (struct ifaddrs *) calloc(1, sizeof(struct ifaddrs)); cifa->ifa_next = NULL; cifa->ifa_name = strdup(ifr->lifr_name); if (pifa == NULL) { *ifap = cifa; /* first one */ } else { pifa->ifa_next = cifa; } if (ioctl(sd, SIOCGLIFADDR, ifr, IFREQSZ) < 0) goto error; cifa->ifa_addr = sa_dup(&ifr->lifr_addr); if (ioctl(sd, SIOCGLIFNETMASK, ifr, IFREQSZ) < 0) goto error; cifa->ifa_netmask = sa_dup(&ifr->lifr_addr); cifa->ifa_flags = 0; cifa->ifa_dstaddr = NULL; if (0 == ioctl(sd, SIOCGLIFFLAGS, ifr)) /* optional */ cifa->ifa_flags = ifr->lifr_flags; if (ioctl(sd, SIOCGLIFDSTADDR, ifr, IFREQSZ) < 0) { if (0 == ioctl(sd, SIOCGLIFBRDADDR, ifr, IFREQSZ)) cifa->ifa_dstaddr = sa_dup(&ifr->lifr_addr); } else { cifa->ifa_dstaddr = sa_dup(&ifr->lifr_addr); } pifa = cifa; ccp += IFREQSZ; } free(ifc.lifc_buf); close(sd); return 0; error: if (ifc.lifc_buf != NULL) free(ifc.lifc_buf); if (sd != -1) close(sd); freeifaddrs(*ifap); return (-1); } #endif // (defined(sun) || defined(__sun)) && (defined(__SVR4) || defined(__svr4__))