char * if_indextoname(unsigned int ifindex, char *ifname) { struct ifaddrs *ifaddrs, *ifa; int error = 0; if (getifaddrs(&ifaddrs) < 0) return(NULL); /* getifaddrs properly set errno */ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK && ifindex == LLINDEX((struct sockaddr_dl*)ifa->ifa_addr)) break; } if (ifa == NULL) { error = ENXIO; ifname = NULL; } else strncpy(ifname, ifa->ifa_name, IFNAMSIZ); freeifaddrs(ifaddrs); errno = error; return(ifname); }
/* * Internal: Map an IPv4 unicast address to an interface index. * This is quite inefficient so it is recommended applications use * the newer, more portable, protocol independent API. */ static uint32_t __inaddr_to_index(in_addr_t ifaddr) { struct ifaddrs *ifa; struct ifaddrs *ifaddrs; char *ifname; int ifindex; sockunion_t *psu; if (getifaddrs(&ifaddrs) < 0) return (0); ifindex = 0; ifname = NULL; /* * Pass #1: Find the ifaddr entry corresponding to the * supplied IPv4 address. We should really use the ifindex * consistently for matches, however it is not available to * us on this pass. */ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { psu = (sockunion_t *)ifa->ifa_addr; if (psu && psu->ss.ss_family == AF_INET && psu->sin.sin_addr.s_addr == ifaddr) { ifname = ifa->ifa_name; break; } } if (ifname == NULL) goto out; /* * Pass #2: Find the index of the interface matching the name * we obtained from looking up the IPv4 ifaddr in pass #1. * There must be a better way of doing this. */ for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { psu = (sockunion_t *)ifa->ifa_addr; if (psu && psu->ss.ss_family == AF_LINK && strcmp(ifa->ifa_name, ifname) == 0) { ifindex = LLINDEX(&psu->sdl); break; } } assert(ifindex != 0); out: freeifaddrs(ifaddrs); return (ifindex); }
qint64 QNativeSocketEnginePrivate::nativeReceiveDatagram(char *data, qint64 maxSize, QIpPacketHeader *header, QAbstractSocketEngine::PacketHeaderOptions options) { // we use quintptr to force the alignment quintptr cbuf[(CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)) #if !defined(IP_PKTINFO) && defined(IP_RECVIF) && defined(Q_OS_BSD4) + CMSG_SPACE(sizeof(sockaddr_dl)) #endif + sizeof(quintptr) - 1) / sizeof(quintptr)]; struct msghdr msg; struct iovec vec; qt_sockaddr aa; char c; memset(&msg, 0, sizeof(msg)); memset(&aa, 0, sizeof(aa)); // we need to receive at least one byte, even if our user isn't interested in it vec.iov_base = maxSize ? data : &c; vec.iov_len = maxSize ? maxSize : 1; msg.msg_iov = &vec; msg.msg_iovlen = 1; if (options & QAbstractSocketEngine::WantDatagramSender) { msg.msg_name = &aa; msg.msg_namelen = sizeof(aa); } if (options & (QAbstractSocketEngine::WantDatagramHopLimit | QAbstractSocketEngine::WantDatagramDestination)) { msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); } ssize_t recvResult = 0; do { recvResult = ::recvmsg(socketDescriptor, &msg, 0); } while (recvResult == -1 && errno == EINTR); if (recvResult == -1) { setError(QAbstractSocket::NetworkError, ReceiveDatagramErrorString); if (header) header->clear(); } else if (options != QAbstractSocketEngine::WantNone) { Q_ASSERT(header); qt_socket_getPortAndAddress(&aa, &header->senderPort, &header->senderAddress); header->destinationPort = localPort; // parse the ancillary data struct cmsghdr *cmsgptr; for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { if (cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_PKTINFO && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in6_pktinfo))) { in6_pktinfo *info = reinterpret_cast<in6_pktinfo *>(CMSG_DATA(cmsgptr)); header->destinationAddress.setAddress(reinterpret_cast<quint8 *>(&info->ipi6_addr)); header->ifindex = info->ipi6_ifindex; if (header->ifindex) header->destinationAddress.setScopeId(QString::number(info->ipi6_ifindex)); } #ifdef IP_PKTINFO if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_PKTINFO && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_pktinfo))) { in_pktinfo *info = reinterpret_cast<in_pktinfo *>(CMSG_DATA(cmsgptr)); header->destinationAddress.setAddress(ntohl(info->ipi_addr.s_addr)); header->ifindex = info->ipi_ifindex; } #else # ifdef IP_RECVDSTADDR if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVDSTADDR && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(in_addr))) { in_addr *addr = reinterpret_cast<in_addr *>(CMSG_DATA(cmsgptr)); header->destinationAddress.setAddress(ntohl(addr->s_addr)); } # endif # if defined(IP_RECVIF) && defined(Q_OS_BSD4) if (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_RECVIF && cmsgptr->cmsg_len >= CMSG_LEN(sizeof(sockaddr_dl))) { sockaddr_dl *sdl = reinterpret_cast<sockaddr_dl *>(CMSG_DATA(cmsgptr)); header->ifindex = LLINDEX(sdl); } # endif #endif if (cmsgptr->cmsg_len == CMSG_LEN(sizeof(int)) && ((cmsgptr->cmsg_level == IPPROTO_IPV6 && cmsgptr->cmsg_type == IPV6_HOPLIMIT) || (cmsgptr->cmsg_level == IPPROTO_IP && cmsgptr->cmsg_type == IP_TTL))) { header->hopLimit = *reinterpret_cast<int *>(CMSG_DATA(cmsgptr)); } } } #if defined (QNATIVESOCKETENGINE_DEBUG) qDebug("QNativeSocketEnginePrivate::nativeReceiveDatagram(%p \"%s\", %lli, %s, %i) == %lli", data, qt_prettyDebug(data, qMin(recvResult, ssize_t(16)), recvResult).data(), maxSize, (recvResult != -1 && options != QAbstractSocketEngine::WantNone) ? header->senderAddress.toString().toLatin1().constData() : "(unknown)", (recvResult != -1 && options != QAbstractSocketEngine::WantNone) ? header->senderPort : 0, (qint64) recvResult); #endif return qint64(maxSize ? recvResult : recvResult == -1 ? -1 : 0); }
struct if_nameindex * if_nameindex(void) { struct ifaddrs *ifaddrs, *ifa; unsigned int ni; int nbytes; struct if_nameindex *ifni, *ifni2; char *cp; if (getifaddrs(&ifaddrs) < 0) return(NULL); /* * First, find out how many interfaces there are, and how * much space we need for the string names. */ ni = 0; nbytes = 0; for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK) { nbytes += strlen(ifa->ifa_name) + 1; ni++; } } /* * Next, allocate a chunk of memory, use the first part * for the array of structures, and the last part for * the strings. */ cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes); ifni = (struct if_nameindex *)cp; if (ifni == NULL) goto out; cp += (ni + 1) * sizeof(struct if_nameindex); /* * Now just loop through the list of interfaces again, * filling in the if_nameindex array and making copies * of all the strings. */ ifni2 = ifni; for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) { if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK) { ifni2->if_index = LLINDEX((struct sockaddr_dl*)ifa->ifa_addr); ifni2->if_name = cp; strcpy(cp, ifa->ifa_name); ifni2++; cp += strlen(cp) + 1; } } /* * Finally, don't forget to terminate the array. */ ifni2->if_index = 0; ifni2->if_name = NULL; out: freeifaddrs(ifaddrs); return(ifni); }