Exemple #1
0
static tb_void_t tb_element_str_dupl(tb_element_ref_t element, tb_pointer_t buff, tb_cpointer_t data)
{
    // check
    tb_assert_and_check_return(element && buff);

    // duplicate it
    if (data) *((tb_char_t const**)buff) = tb_strdup((tb_char_t const*)data);
    // clear it
    else *((tb_char_t const**)buff) = tb_null;
}
Exemple #2
0
static tb_void_t tb_find_str_test()
{
    __tb_volatile__ tb_size_t i = 0;
    __tb_volatile__ tb_size_t n = 1000;

    // init data
    tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*));
    tb_assert_and_check_return(data);

    // init iterator
    tb_array_iterator_t array_iterator;
    tb_iterator_ref_t   iterator = tb_array_iterator_init_str(&array_iterator, data, n);

    // make
    tb_char_t s[256] = {0};
    for (i = 0; i < n; i++) 
    {
        tb_long_t r = tb_snprintf(s, 256, "%04lu", i); 
        s[r] = '\0'; 
        data[i] = tb_strdup(s);
    }

    // find
    tb_size_t itor = tb_iterator_tail(iterator);
    tb_hong_t time = tb_mclock();
    for (i = 0; i < n; i++) itor = tb_find_all(iterator, (tb_pointer_t)data[800]);
    time = tb_mclock() - time;

    // item
    tb_char_t* item = itor != tb_iterator_tail(iterator)? (tb_char_t*)tb_iterator_item(iterator, itor) : 0;

    // time
    tb_trace_i("tb_find_str_all[%s ?= %s]: %lld ms", item, data[800], time);

    // free data
    for (i = 0; i < n; i++) tb_free(data[i]);
    tb_free(data);
}
Exemple #3
0
static tb_void_t tb_sort_str_test_perf_heap(tb_size_t n)
{
    __tb_volatile__ tb_size_t i = 0;

    // init data
    tb_char_t** data = (tb_char_t**)tb_nalloc0(n, sizeof(tb_char_t*));
    tb_assert_and_check_return(data);

    // init iterator
    tb_array_iterator_t array_iterator;
    tb_iterator_ref_t   iterator = tb_iterator_make_for_str(&array_iterator, data, n);

    // make
    tb_random_clear(tb_null);
    tb_char_t s[256] = {0};
    for (i = 0; i < n; i++)
    {
        tb_long_t r = tb_snprintf(s, 256, "%x", tb_random_range(tb_null, 0, TB_MAXU32));
        s[r] = '\0';
        data[i] = tb_strdup(s);
    }

    // sort
    tb_hong_t time = tb_mclock();
    tb_heap_sort_all(iterator, tb_null);
    time = tb_mclock() - time;

    // time
    tb_trace_i("tb_heap_sort_str_all: %lld ms", time);

    // check
    for (i = 1; i < n; i++) tb_assert_and_check_break(tb_strcmp(data[i - 1], data[i]) <= 0);

    // free data
    for (i = 0; i < n; i++) tb_free(data[i]);
    tb_free(data);
}
Exemple #4
0
static tb_void_t tb_ifaddrs_interface_load4(tb_list_ref_t interfaces)
{
    // check
    tb_assert_and_check_return(interfaces);

    // done
    PIP_ADAPTER_INFO adapter_info = tb_null;
    do
    {
        // make the adapter info 
        adapter_info = tb_malloc0_type(IP_ADAPTER_INFO);
        tb_assert_and_check_break(adapter_info);

        // get the real adapter info size
        ULONG size = sizeof(IP_ADAPTER_INFO);
        if (tb_iphlpapi()->GetAdaptersInfo(adapter_info, &size) == ERROR_BUFFER_OVERFLOW)
        {
            // grow the adapter info buffer
            adapter_info = (PIP_ADAPTER_INFO)tb_ralloc(adapter_info, size);
            tb_assert_and_check_break(adapter_info);

            // reclear it
            tb_memset(adapter_info, 0, size);
        }
    
        // get the adapter info 
        if (tb_iphlpapi()->GetAdaptersInfo(adapter_info, &size) != NO_ERROR) break;

        // done
        PIP_ADAPTER_INFO adapter = adapter_info;
        while (adapter)
        {
            // check
            tb_assert(adapter->AdapterName);

            /* 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, adapter->AdapterName);
            if (!interface) interface = &interface_new;

            // check
            tb_assert(interface == &interface_new || interface->name);

            // save flags
            if (adapter->Type == MIB_IF_TYPE_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK;

            // save hwaddr
            if (adapter->AddressLength == sizeof(interface->hwaddr.u8))
            {
                interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR;
                tb_memcpy(interface->hwaddr.u8, adapter->Address, sizeof(interface->hwaddr.u8));
            }

            // save ipaddrs
            PIP_ADDR_STRING ipAddress = &adapter->IpAddressList;
            while (ipAddress && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) != TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR)
            {
                // done
                tb_ipaddr_t ipaddr;
                if (    ipAddress->IpAddress.String
                    &&  tb_ipaddr_ip_cstr_set(&ipaddr, ipAddress->IpAddress.String, TB_IPADDR_FAMILY_NONE))
                {
                    if (ipaddr.family == TB_IPADDR_FAMILY_IPV4)
                    {
                        interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4;
                        interface->ipaddr4 = ipaddr.u.ipv4;
                    }
                    else if (ipaddr.family == TB_IPADDR_FAMILY_IPV6)
                    {
                        interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6;
                        interface->ipaddr6 = ipaddr.u.ipv6;
                    }
                }

                // the next
                ipAddress = ipAddress->Next;
            }

            // new interface? save it
            if (    interface == &interface_new
                &&  interface->flags)
            {
                // save interface name
                interface->name = tb_strdup(adapter->AdapterName);
                tb_assert(interface->name);

                // save interface
                tb_list_insert_tail(interfaces, interface);
            }

            // the next adapter
            adapter = adapter->Next;
        }

    } while (0);

    // exit the adapter info
    if (adapter_info) tb_free(adapter_info);
    adapter_info = tb_null;
}
Exemple #5
0
static tb_void_t tb_ifaddrs_interface_load6(tb_list_ref_t interfaces)
{
    // check
    tb_assert_and_check_return(interfaces);

    // done
    PIP_ADAPTER_ADDRESSES addresses = tb_null;
    do
    {
        // make the addresses
        addresses = (PIP_ADAPTER_ADDRESSES)tb_malloc0_type(IP_ADAPTER_ADDRESSES);
        tb_assert_and_check_break(addresses);

        // get the real adapter info size
        ULONG size = sizeof(IP_ADAPTER_ADDRESSES);
        if (tb_iphlpapi()->GetAdaptersAddresses(AF_INET6, GAA_FLAG_SKIP_DNS_SERVER, tb_null, addresses, &size) == ERROR_BUFFER_OVERFLOW)
        {
            // grow the adapter info buffer
            addresses = (PIP_ADAPTER_ADDRESSES)tb_ralloc(addresses, size);
            tb_assert_and_check_break(addresses);

            // reclear it
            tb_memset(addresses, 0, size);
        }
     
        // get the addresses
        if (tb_iphlpapi()->GetAdaptersAddresses(AF_INET6, GAA_FLAG_SKIP_DNS_SERVER, tb_null, addresses, &size) != NO_ERROR) break;

        // done
        PIP_ADAPTER_ADDRESSES address = addresses;
        while (address)
        {
            // check
            tb_assert(address->AdapterName);

            /* 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, address->AdapterName);
            if (!interface) interface = &interface_new;

            // check
            tb_assert(interface == &interface_new || interface->name);

            // save flags
            if (address->IfType == IF_TYPE_SOFTWARE_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK;

            // save hwaddr
            if (address->PhysicalAddressLength == sizeof(interface->hwaddr.u8))
            {
                interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR;
                tb_memcpy(interface->hwaddr.u8, address->PhysicalAddress, sizeof(interface->hwaddr.u8));
            }

            // save ipaddrs
            PIP_ADAPTER_UNICAST_ADDRESS ipAddress = address->FirstUnicastAddress;
            while (ipAddress && (interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR) != TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR)
            {
                // done
                tb_ipaddr_t ipaddr;
                struct sockaddr_storage* saddr = (struct sockaddr_storage*)ipAddress->Address.lpSockaddr;
                if (saddr && tb_sockaddr_save(&ipaddr, saddr))
                {
                    if (ipaddr.family == TB_IPADDR_FAMILY_IPV4)
                    {
                        interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR4;
                        interface->ipaddr4 = ipaddr.u.ipv4;
                    }
                    else if (ipaddr.family == TB_IPADDR_FAMILY_IPV6)
                    {
                        interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_IPADDR6;
                        interface->ipaddr6 = ipaddr.u.ipv6;
                    }
                }

                // the next
                ipAddress = ipAddress->Next;
            }

            // new interface? save it
            if (    interface == &interface_new
                &&  interface->flags)
            {
                // save interface name
                interface->name = tb_strdup(address->AdapterName);
                tb_assert(interface->name);

                // save interface
                tb_list_insert_tail(interfaces, interface);
            }

            // the next address
            address = address->Next;
        }

    } while (0);

    // exit the addresses
    if (addresses) tb_free(addresses);
    addresses = tb_null;
}
Exemple #6
0
static tb_object_ref_t tb_object_xplist_reader_func_data(tb_object_xplist_reader_t* reader, tb_size_t event)
{
    // check
    tb_assert_and_check_return_val(reader && reader->reader && event, tb_null);

    // empty?
    if (event == TB_XML_READER_EVENT_ELEMENT_EMPTY) 
        return tb_object_data_init_from_data(tb_null, 0);

    // done
    tb_bool_t           leave = tb_false;
    tb_char_t*          base64 = tb_null;
    tb_object_ref_t     data = tb_null;
    while (!leave && (event = tb_xml_reader_next(reader->reader)))
    {
        switch (event)
        {
        case TB_XML_READER_EVENT_ELEMENT_END: 
            {
                // name
                tb_char_t const* name = tb_xml_reader_element(reader->reader);
                tb_assert_and_check_break_state(name, leave, tb_true);
                
                // is end?
                if (!tb_stricmp(name, "data"))
                {
                    // empty?
                    if (!data) data = tb_object_data_init_from_data(tb_null, 0);
                    
                    // leave it
                    leave = tb_true;
                }
            }
            break;
        case TB_XML_READER_EVENT_TEXT: 
            {
                // text
                tb_char_t const* text = tb_xml_reader_text(reader->reader);
                tb_assert_and_check_break_state(text, leave, tb_true);
                tb_trace_d("data: %s", text);

                // base64
                base64 = tb_strdup(text);
                tb_char_t* p = base64;
                tb_char_t* q = p;
                for (; *p; p++) if (!tb_isspace(*p)) *q++ = *p;
                *q = '\0';

                // decode base64 data
                tb_char_t const*    ib = base64;
                tb_size_t           in = tb_strlen(base64); 
                if (in)
                {
                    tb_size_t           on = in;
                    tb_byte_t*          ob = tb_malloc0_bytes(on);
                    tb_assert_and_check_break_state(ob && on, leave, tb_true);
                    on = tb_base64_decode(ib, in, ob, on);
                    tb_trace_d("base64: %u => %u", in, on);

                    // init data
                    data = tb_object_data_init_from_data(ob, on); tb_free(ob);
                }
                else data = tb_object_data_init_from_data(tb_null, 0);
                tb_assert_and_check_break_state(data, leave, tb_true);
            }
            break;
        default:
            break;
        }
    }

    // free
    if (base64) tb_free(base64);

    // ok?
    return data;
}
Exemple #7
0
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;
}
Exemple #8
0
static tb_void_t tb_ifaddrs_interface_done_hwaddr(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);

    // 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 = IFLA_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 IFLA_IFNAME:
                    {
                        // 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 = IFLA_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);
        tb_size_t       rta_data_size = RTA_PAYLOAD(rta);
        switch(rta->rta_type)
        {
            case IFLA_ADDRESS:
                {
                    // no hwaddr?
                    if (!(interface->flags & TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR))
                    {
                        // check
                        tb_check_break(rta_data_size == sizeof(interface->hwaddr.u8));

                        // save flags
                        interface->flags |= TB_IFADDRS_INTERFACE_FLAG_HAVE_HWADDR;
                        if (info->ifa_flags & IFF_LOOPBACK) interface->flags |= TB_IFADDRS_INTERFACE_FLAG_IS_LOOPBACK;

                        // save hwaddr
                        tb_memcpy(interface->hwaddr.u8, rta_data, sizeof(interface->hwaddr.u8));

                        // trace
                        tb_trace_d("name: %s, hwaddr: %{hwaddr}", name, &interface->hwaddr);

                        // new interface? save it
                        if (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 IFLA_IFNAME:
            case IFLA_BROADCAST:
            case IFLA_STATS:
                break;
            default:
                break;
        }
    }

    // exit name
    if (name && owner) tb_free(name);
    name = tb_null;
}
Exemple #9
0
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;
}