0

I am facing race conditions when using c-ares to perform reverse DNS lookups in multiple threads. Code can be found below.

static void callback(void * arg, int status, int, struct hostent * host)
{
    auto * ptr_records = static_cast<std::unordered_set<std::string>*>(arg);
    if (ptr_records && status == ARES_SUCCESS)
    {
        /*
         * In some cases (e.g /etc/hosts), hostent::h_name is filled and hostent::h_aliases is empty.
         * Thus, we can't rely solely on hostent::h_aliases. More info on:
         * https://github.com/ClickHouse/ClickHouse/issues/40595#issuecomment-1230526931
         * */
        if (auto * ptr_record = host->h_name)
        {
            ptr_records->insert(ptr_record);
        }

        if (host->h_aliases)
        {
            int i = 0;
            while (auto * ptr_record = host->h_aliases[i])
            {
                ptr_records->insert(ptr_record);
                i++;
            }
        }
    }
}

std::unordered_set<std::string> CaresPTRResolver::resolve(const std::string & ip)
{
    std::unordered_set<std::string> ptr_records;

    in_addr addr;

    inet_pton(AF_INET, ip.c_str(), &addr);

    ares_gethostbyaddr(channel, reinterpret_cast<const void*>(&addr), sizeof(addr), AF_INET, callback, &ptr_records);

    timeval * tvp, tv;
    fd_set read_fds;
    fd_set write_fds;
    int nfds;

    for (;;)
    {
        FD_ZERO(&read_fds);
        FD_ZERO(&write_fds);
        nfds = ares_fds(channel, &read_fds,&write_fds);
        if (nfds == 0)
        {
            break;
        }
        tvp = ares_timeout(channel, nullptr, &tv);
        select(nfds, &read_fds, &write_fds, nullptr, tvp);
        ares_process(channel, &read_fds, &write_fds);
    }

    return ptr_records;
}

The CaresPTRResolver::resolve method is called from multiple threads. Each thread has a different instance of CaresPTRResolver, which means no data sharing on application side, not even the ares_channel. If I add a mutex around ares_fds call, the application doesn't crash anymore. This code was derived from a few examples I saw on the web, I found the docs to be very incomprehensive and lacking real examples.

The main question is: what's the proper way to use c-ares library in a multithread environment?

0 Answers0