tb_bool_t tb_ifaddrs_ipaddr(tb_ifaddrs_ref_t ifaddrs, tb_char_t const* name, tb_bool_t reload, tb_size_t family, tb_ipaddr_ref_t ipaddr) { // check tb_assert_and_check_return_val(ifaddrs && ipaddr, tb_false); // clear it first tb_ipaddr_clear(ipaddr); // the iterator tb_iterator_ref_t iterator = tb_ifaddrs_itor(ifaddrs, reload); tb_assert_and_check_return_val(iterator, tb_false); // reload it if the cached interfaces is empty if (!reload && !tb_iterator_size(iterator)) iterator = tb_ifaddrs_itor(ifaddrs, tb_true); // the ipaddr flags tb_uint32_t ipflags = 0; if (family == TB_IPADDR_FAMILY_IPV4) ipflags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4; else if (family == TB_IPADDR_FAMILY_IPV6) ipflags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6; // done tb_bool_t ok = tb_false; tb_for_all_if (tb_ifaddrs_interface_ref_t, interface, iterator, interface) { // is this? if ( (name || !(interface->flags & TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK)) && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) && (!name || (interface->name && !tb_strcmp(interface->name, name)))) { // ipv4? if ( interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4 && (!family || family == TB_IPADDR_FAMILY_IPV4)) { // save ipaddr4 tb_ipaddr_ipv4_set(ipaddr, &interface->ipaddr4); // ok ok = tb_true; break; } // ipv6? else if ( interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6 && (!family || family == TB_IPADDR_FAMILY_IPV6)) { // save ipaddr6 tb_ipaddr_ipv6_set(ipaddr, &interface->ipaddr6); // ok ok = tb_true; break; } } } // ok? return ok; }
static tb_size_t tb_ifaddrs_netlink_ipaddr_save(tb_ipaddr_ref_t ipaddr, tb_size_t family, tb_size_t scope_id, tb_cpointer_t saddr) { // check tb_assert_and_check_return_val(ipaddr && saddr, 0); // clear address tb_ipaddr_clear(ipaddr); // done tb_size_t size = 0; switch (family) { case AF_INET: { // the ipv4 ipaddr struct in_addr* addr4 = (struct in_addr*)saddr; // save family tb_ipaddr_family_set(ipaddr, TB_IPADDR_FAMILY_IPV4); // make ipv4 tb_ipv4_t ipv4; ipv4.u32 = (tb_uint32_t)addr4->s_addr; // save ipv4 tb_ipaddr_ipv4_set(ipaddr, &ipv4); // save size size = sizeof(struct in_addr); } break; case AF_INET6: { // the ipv6 ipaddr struct in6_addr* addr6 = (struct in6_addr*)saddr; // check tb_assert_static(sizeof(ipaddr->u.ipv6.addr.u8) == sizeof(addr6->s6_addr)); tb_assert_static(tb_arrayn(ipaddr->u.ipv6.addr.u8) == tb_arrayn(addr6->s6_addr)); // save family tb_ipaddr_family_set(ipaddr, TB_IPADDR_FAMILY_IPV6); // make ipv6 tb_ipv6_t ipv6; tb_memcpy(ipv6.addr.u8, addr6->s6_addr, sizeof(ipv6.addr.u8)); // save scope id ipv6.scope_id = 0; if (IN6_IS_ADDR_LINKLOCAL(addr6) || IN6_IS_ADDR_MC_LINKLOCAL(addr6)) ipv6.scope_id = (tb_uint32_t)scope_id; // save ipv6 tb_ipaddr_ipv6_set(ipaddr, &ipv6); // save size size = sizeof(struct in6_addr); } break; default: tb_assert(0); break; } // ok? return size; }