tb_iterator_ref_t tb_ifaddrs_itor(tb_ifaddrs_ref_t ifaddrs, tb_bool_t reload) { // check tb_list_ref_t interfaces = (tb_list_ref_t)ifaddrs; tb_assert_and_check_return_val(interfaces, tb_null); // uses the cached interfaces? tb_check_return_val(reload, (tb_iterator_ref_t)interfaces); // clear interfaces first tb_list_clear(interfaces); // query the list of interfaces. struct ifaddrs* list = tb_null; if (!getifaddrs(&list) && list) { #if 0 // init sock tb_long_t sock = socket(AF_INET, SOCK_DGRAM, 0); #endif // done struct ifaddrs* item = tb_null; for (item = list; item; item = item->ifa_next) { // check tb_check_continue(item->ifa_addr && item->ifa_name); /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, item->ifa_name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done switch (item->ifa_addr->sa_family) { case AF_INET: { // the address struct sockaddr_storage const* addr = (struct sockaddr_storage const*)item->ifa_addr; // save ipaddr4 tb_ipaddr_t ipaddr4; if (!tb_sockaddr_save(&ipaddr4, addr)) break; interface->ipaddr4 = ipaddr4.u.ipv4; // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; if ((item->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr4)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; #if 0 // no hwaddr? get it if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // attempt get the hwaddr struct ifreq ifr; tb_memset(&ifr, 0, sizeof(ifr)); tb_strcpy(ifr.ifr_name, item->ifa_name); if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { // have hwaddr interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; // save hwaddr tb_memcpy(interface->hwaddr.u8, ifr.ifr_hwaddr.sa_data, sizeof(interface->hwaddr.u8)); } } #endif // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(item->ifa_name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case AF_INET6: { // the address struct sockaddr_storage const* addr = (struct sockaddr_storage const*)item->ifa_addr; // save ipaddr6 tb_ipaddr_t ipaddr6; if (!tb_sockaddr_save(&ipaddr6, addr)) break; interface->ipaddr6 = ipaddr6.u.ipv6; // save flags interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; if ((item->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr6)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; #if 0 // no hwaddr? get it if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // attempt get the hwaddr struct ifreq ifr; tb_memset(&ifr, 0, sizeof(ifr)); tb_strcpy(ifr.ifr_name, item->ifa_name); if (!ioctl(sock, SIOCGIFHWADDR, &ifr)) { // have hwaddr interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; // save hwaddr tb_memcpy(interface->hwaddr.u8, ifr.ifr_hwaddr.sa_data, sizeof(interface->hwaddr.u8)); } } #endif // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(item->ifa_name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case AF_PACKET: { // the address struct sockaddr_ll const* addr = (struct sockaddr_ll const*)item->ifa_addr; // check tb_check_break(addr->sll_halen == sizeof(interface->hwaddr.u8)); // no hwaddr? get it if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR)) { // have hwaddr interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR; // save hwaddr tb_memcpy(interface->hwaddr.u8, addr->sll_addr, sizeof(interface->hwaddr.u8)); // new interface? save it if (interface == &interface_new) { // save interface name interface->name = tb_strdup(item->ifa_name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } } break; default: { // trace tb_trace_d("unknown family: %d", item->ifa_addr->sa_family); } break; } } #if 0 // exit socket if (sock) close(sock); sock = 0; #endif // exit the interface list freeifaddrs(list); } // ok? return (tb_iterator_ref_t)interfaces; }
static tb_void_t tb_ifaddrs_interface_done_ipaddr(tb_list_ref_t interfaces, tb_hash_map_ref_t names, struct nlmsghdr* response) { // check tb_assert_and_check_return(interfaces && names && response); // the info struct ifaddrmsg* info = (struct ifaddrmsg *)NLMSG_DATA(response); // must be not link tb_assert_and_check_return(info->ifa_family != AF_PACKET); // attempt to find the interface name tb_bool_t owner = tb_false; tb_char_t* name = (tb_char_t*)tb_hash_map_get(names, tb_u2p(info->ifa_index)); if (!name) { // get the interface name struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { // done tb_pointer_t rta_data = RTA_DATA(rta); tb_size_t rta_data_size = RTA_PAYLOAD(rta); switch(rta->rta_type) { case IFA_LABEL: { // make name name = (tb_char_t*)tb_ralloc(name, rta_data_size + 1); tb_assert_and_check_break(name); // copy name tb_strlcpy(name, rta_data, rta_data_size + 1); // save name tb_hash_map_insert(names, tb_u2p(info->ifa_index), name); owner = tb_true; } break; default: break; } } } // check tb_check_return(name); // done struct rtattr* rta = tb_null; tb_size_t rta_size = NLMSG_PAYLOAD(response, sizeof(struct ifaddrmsg)); for(rta = IFA_RTA(info); RTA_OK(rta, rta_size); rta = RTA_NEXT(rta, rta_size)) { /* attempt to get the interface from the cached interfaces * and make a new interface if no the cached interface */ tb_ifaddrs_interface_t interface_new = {0}; tb_ifaddrs_interface_ref_t interface = tb_ifaddrs_interface_find((tb_iterator_ref_t)interfaces, name); if (!interface) interface = &interface_new; // check tb_assert(interface == &interface_new || interface->name); // done tb_pointer_t rta_data = RTA_DATA(rta); switch(rta->rta_type) { case IFA_LOCAL: case IFA_ADDRESS: { // make ipaddr tb_ipaddr_t ipaddr; if (!tb_ifaddrs_netlink_ipaddr_save(&ipaddr, info->ifa_family, info->ifa_index, rta_data)) break; // save flags if ((info->ifa_flags & IFF_LOOPBACK) || tb_ipaddr_ip_is_loopback(&ipaddr)) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK; // save ipaddr switch (tb_ipaddr_family(&ipaddr)) { case TB_IPADDR_FAMILY_IPV4: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; interface->ipaddr4 = ipaddr.u.ipv4; } break; case TB_IPADDR_FAMILY_IPV6: { interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; interface->ipaddr6 = ipaddr.u.ipv6; } break; default: break; } // trace tb_trace_d("name: %s, ipaddr: %{ipaddr}", name, &ipaddr); // new interface? save it if (tb_ipaddr_family(&ipaddr) && interface == &interface_new) { // save interface name interface->name = tb_strdup(name); tb_assert(interface->name); // save interface tb_list_insert_tail(interfaces, interface); } } break; case IFA_LABEL: case IFA_BROADCAST: break; default: break; } } // exit name if (name && owner) tb_free(name); name = tb_null; }