engine/dlib/src/dlib/dns.cpp
// Note: This function should ultimately replace the dmSocket::GetHostByName, but there's a few places
//       left in the engine where the old version is still used. This is because we need to pass along a
//       dns channel to this function, which needs to be stored somewhere that's easily reachable by
//       the calling functions on the main thread. We could do something like a global channel that lives
//       in this module that can be accessed everywhere, but we need to make sure this solution works first.
This function should ultimately replace the dmSocket::GetHostByName, but there's a few places
left in the engine where the old version is still used. This is because we need to pass along a
dns channel to this function, which needs to be stored somewhere that's easily reachable by
the calling functions on the main thread. We could do something like a global channel that lives
in this module that can be accessed everywhere, but we need to make sure this solution works first.
This function should ultimately replace the dmSocket :: GetHostByName but there ' s a few places left in the engine where the old version is still used . This is because we need to pass along a dns channel to this function which needs to be stored somewhere that ' s easily reachable by the calling functions on the main thread . We could do something like a global channel that lives in this module that can be accessed everywhere but we need to make sure this solution works first .
Result GetHostByName(const char* name, dmSocket::Address* address, HChannel channel, int timeout, bool ipv4, bool ipv6)
    {
        assert(channel);
        assert(address);
        static const uint64_t request_timeout = (timeout > 0) ? timeout : 30 * 1000000;
        uint64_t              request_started = dmTime::GetTime();
        Channel* dns_channel = (Channel*) channel;
        RequestInfo req;
        req.m_Status  = ARES_ECANCELLED;
        req.m_Ipv4    = ipv4;
        req.m_Ipv6    = ipv6;
        struct in_addr       addr4;
        struct ares_in6_addr addr6;
        if (ares_inet_pton(AF_INET, name, &addr4) == 1)
        {
            req.m_Address.m_family     = dmSocket::DOMAIN_IPV4;
            req.m_Address.m_address[3] = addr4.s_addr;
            ares_gethostbyaddr(dns_channel->m_Handle, &addr4, sizeof(addr4), AF_INET, ares_gethost_callback, (void*)&req);
        }
        else if (ares_inet_pton(AF_INET6, name, &addr6) == 1)
        {
            req.m_Address.m_family     = dmSocket::DOMAIN_IPV6;
            memcpy(&req.m_Address.m_address[0], &addr6, sizeof(struct in6_addr));
            ares_gethostbyaddr(dns_channel->m_Handle, &addr6, sizeof(addr6), AF_INET6, ares_gethost_callback, (void*)&req);
        }
        else
        {
            int32_t want_family = 0;
            if (ipv4 == ipv6)
                want_family = AF_UNSPEC;
            else if (ipv4)
                want_family = AF_INET;
            else if (ipv6)
                want_family = AF_INET6;
            ares_addrinfo_hints hints;
            memset(&hints, 0x0, sizeof(hints));
            hints.ai_family   = want_family;
            hints.ai_socktype = SOCK_STREAM;
            ares_getaddrinfo(dns_channel->m_Handle, name, NULL, &hints, ares_addrinfo_callback, (void*)&req);
        }
        while(1)
        {
            if (dns_channel->m_Running == 0)
            {
                ares_cancel(dns_channel->m_Handle);
                req.m_Status = ARES_ECANCELLED;
                break;
            }
            dmSocket::Selector selector;
            selector.m_Nfds = ares_fds(dns_channel->m_Handle,
                &selector.m_FdSets[dmSocket::SELECTOR_KIND_READ],
                &selector.m_FdSets[dmSocket::SELECTOR_KIND_WRITE]);
            if (selector.m_Nfds == 0)
            {
                ares_cancel(dns_channel->m_Handle);
                break;
            }
            else
            {
                selector.m_Nfds -= 1;
            }
            if ((dmTime::GetTime() - request_started) > request_timeout)
            {
                req.m_Status = ARES_ETIMEOUT;
                break;
            }
            dmSocket::Select(&selector, 50000);
            ares_process(dns_channel->m_Handle,
                &selector.m_FdSets[dmSocket::SELECTOR_KIND_READ],
                &selector.m_FdSets[dmSocket::SELECTOR_KIND_WRITE]);
        }
        if (req.m_Status == ARES_SUCCESS)
        {
            memcpy(address, &req.m_Address, sizeof(req.m_Address));
        }
        return AresStatusToDNSResult(req.m_Status);
    }
Result GetHostByName ( const char * name , dmSocket :: Address * address , HChannel channel , int timeout , bool ipv4 , bool ipv6 ) { assert ( channel ) ; assert ( address ) ; static const uint64_t request_timeout = ( timeout > 0 ) ? timeout : 30 * 1000000 ; uint64_t request_started = dmTime :: GetTime ( ) ; Channel * dns_channel = ( Channel * ) channel ; RequestInfo req ; req . m_Status = ARES_ECANCELLED ; req . m_Ipv4 = ipv4 ; req . m_Ipv6 = ipv6 ; struct in_addr addr4 ; struct ares_in6_addr addr6 ; if ( ares_inet_pton ( AF_INET , name , & addr4 ) == 1 ) { req . m_Address . m_family = dmSocket :: DOMAIN_IPV4 ; req . m_Address . m_address [ 3 ] = addr4 . s_addr ; ares_gethostbyaddr ( dns_channel -> m_Handle , & addr4 , sizeof ( addr4 ) , AF_INET , ares_gethost_callback , ( void * ) & req ) ; } else if ( ares_inet_pton ( AF_INET6 , name , & addr6 ) == 1 ) { req . m_Address . m_family = dmSocket :: DOMAIN_IPV6 ; memcpy ( & req . m_Address . m_address [ 0 ] , & addr6 , sizeof ( struct in6_addr ) ) ; ares_gethostbyaddr ( dns_channel -> m_Handle , & addr6 , sizeof ( addr6 ) , AF_INET6 , ares_gethost_callback , ( void * ) & req ) ; } else { int32_t want_family = 0 ; if ( ipv4 == ipv6 ) want_family = AF_UNSPEC ; else if ( ipv4 ) want_family = AF_INET ; else if ( ipv6 ) want_family = AF_INET6 ; ares_addrinfo_hints hints ; memset ( & hints , 0x0 , sizeof ( hints ) ) ; hints . ai_family = want_family ; hints . ai_socktype = SOCK_STREAM ; ares_getaddrinfo ( dns_channel -> m_Handle , name , NULL , & hints , ares_addrinfo_callback , ( void * ) & req ) ; } while ( 1 ) { if ( dns_channel -> m_Running == 0 ) { ares_cancel ( dns_channel -> m_Handle ) ; req . m_Status = ARES_ECANCELLED ; break ; } dmSocket :: Selector selector ; selector . m_Nfds = ares_fds ( dns_channel -> m_Handle , & selector . m_FdSets [ dmSocket :: SELECTOR_KIND_READ ] , & selector . m_FdSets [ dmSocket :: SELECTOR_KIND_WRITE ] ) ; if ( selector . m_Nfds == 0 ) { ares_cancel ( dns_channel -> m_Handle ) ; break ; } else { selector . m_Nfds -= 1 ; } if ( ( dmTime :: GetTime ( ) - request_started ) > request_timeout ) { req . m_Status = ARES_ETIMEOUT ; break ; } dmSocket :: Select ( & selector , 50000 ) ; ares_process ( dns_channel -> m_Handle , & selector . m_FdSets [ dmSocket :: SELECTOR_KIND_READ ] , & selector . m_FdSets [ dmSocket :: SELECTOR_KIND_WRITE ] ) ; } if ( req . m_Status == ARES_SUCCESS ) { memcpy ( address , & req . m_Address , sizeof ( req . m_Address ) ) ; } return AresStatusToDNSResult ( req . m_Status ) ; }
Note: This function should ultimately replace the dmSocket::GetHostByName, but there's a few places
left in the engine where the old version is still used.
Note : This function should ultimately replace the dmSocket :: GetHostByName but there ' s a few places left in the engine where the old version is still used .
// We need to check the address if it's an actual IP address or not. // The regular getaddrinfo returns an address in that case, so we need to // mimick that behaviour here aswell. // Note: SOCK_STREAM TCP hint doesn't do anything. To force TCP transport, set the ARES_FLAG_USEVC //       in the flags for ares when initializing the channel. // Here, we block until the request is handled. The engine is built to wait for the result from each // of these requests, so we need to accept that for now. This can easily be translated into a threaded // queue, but is put on hold until we know this solution actually solves the ANR issue. // Early-out if a different thread has decided to stop the channel. // This might happen when the engine is shutting down, and // we have lost or no connection and don't want to wait for // the full timeout.. // Ares adds a + 1 to the socket, as does our own dmSocket::Select impl, // so we just need to compensate for this. // This is a manual timeout. C-ares is supposed to handle this, but it doesn't work. // Select on this socket for a little bit (50ms)