예제 #1
0
bool KviDnsResolver::event(QEvent *e)
{
	if(e->type() == QEvent::User)
	{
		KviDnsResolverThreadEvent * pEvent = dynamic_cast<KviDnsResolverThreadEvent *>(e);
		if(pEvent)
		{
			if(m_pDnsResult)delete m_pDnsResult;
			m_pDnsResult = pEvent->releaseResult();
			m_state = (m_pDnsResult->error() == KviError::Success) ? Success : Failure;
			emit lookupDone(this);
			return true;
		} // else ops... unknown thread event ?
	}
	return QObject::event(e);
}
예제 #2
0
void KviDnsResolverThread::run()
{
    KviDnsResolverResult * dns = new KviDnsResolverResult();

    dns->setQuery(m_szQuery);

    if(m_szQuery.isEmpty())
    {
        postDnsError(dns, KviError::NoHostToResolve);
        return;
    }

#ifndef COMPILE_IPV6_SUPPORT
    if(m_queryType != KviDnsResolver::IPv4)
    {
        if(m_queryType == KviDnsResolver::IPv6)
        {
            postDnsError(dns, KviError::NoIPv6Support);
            return;
        }
        m_queryType = KviDnsResolver::IPv4;
    }
#endif

#if(defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)) && !defined(COMPILE_IPV6_SUPPORT)

    if(m_queryType == KviDnsResolver::IPv6)
    {
        postDnsError(dns, KviError::NoIPv6Support);
        return;
    }

    // gethostbyaddr and gethostbyname are thread-safe on Windoze
    struct in_addr inAddr;
    struct hostent * pHostEntry = 0;

    // DIE DIE!....I hope that this stuff will disappear sooner or later :)

    if(KviNetUtils::stringIpToBinaryIp(m_szQuery, &inAddr))
    {
        pHostEntry = gethostbyaddr((const char *)&inAddr, sizeof(inAddr), AF_INET);
    }
    else
    {
        pHostEntry = gethostbyname(m_szQuery.toUtf8().data());
    }

    if(!pHostEntry)
    {
        switch(h_errno)
        {
        case HOST_NOT_FOUND:
            dns->setError(KviError::HostNotFound);
            break;
        case NO_ADDRESS:
            dns->setError(KviError::ValidNameButNoIpAddress);
            break;
        case NO_RECOVERY:
            dns->setError(KviError::UnrecoverableNameserverError);
            break;
        case TRY_AGAIN:
            dns->setError(KviError::DNSTemporaneousFault);
            break;
        default:
            dns->setError(KviError::DNSQueryFailed);
            break;
        }
    }
    else
    {
        dns->appendHostname(pHostEntry->h_name);
        QString szIp;
        KviNetUtils::binaryIpToStringIp(*((struct in_addr *)(pHostEntry->h_addr)), szIp);
        dns->appendAddress(szIp);

        int idx = 1;
        while(pHostEntry->h_addr_list[idx])
        {
            QString tmp;
            KviNetUtils::binaryIpToStringIp(*((struct in_addr *)(pHostEntry->h_addr_list[idx])), tmp);
            if(!tmp.isEmpty())
                dns->appendAddress(tmp);
            ++idx;
        }
        if(pHostEntry->h_aliases[0])
        {
            dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[0]));
            if(pHostEntry->h_aliases[1])
                dns->appendHostname(QString::fromUtf8(pHostEntry->h_aliases[1]));
        }
    }

#else

    int retVal;

    struct sockaddr_in ipv4Addr;

#ifdef COMPILE_IPV6_SUPPORT
    struct sockaddr_in6 ipv6Addr;
    bool bIsIPv6Ip = false;
#endif

    bool bIsIPv4Ip = KviNetUtils::stringIpToBinaryIp(m_szQuery, (struct in_addr *)&(ipv4Addr.sin_addr));

#ifdef COMPILE_IPV6_SUPPORT
    if(!bIsIPv4Ip)
        bIsIPv6Ip = KviNetUtils::stringIpToBinaryIp_V6(m_szQuery, (struct in6_addr *)&(ipv6Addr.sin6_addr));
#endif


#ifdef COMPILE_IPV6_SUPPORT
    if(bIsIPv4Ip || bIsIPv6Ip)
    {
#else
    if(bIsIPv4Ip)
    {
#endif
        // use getnameinfo...
        char retname[1025]; // should be enough....

#ifdef COMPILE_IPV6_SUPPORT
        if(bIsIPv4Ip)
        {
#endif
            ipv4Addr.sin_family = AF_INET;
            ipv4Addr.sin_port = 0;
            // NI_NAMEREQD as last param ?
            retVal = getnameinfo((struct sockaddr *)&ipv4Addr, sizeof(ipv4Addr), retname, 1025, nullptr, 0, NI_NAMEREQD);
#ifdef COMPILE_IPV6_SUPPORT
        }
        else
        {
            ipv6Addr.sin6_family = AF_INET6;
            ipv6Addr.sin6_port = 0;
            retVal = getnameinfo((struct sockaddr *)&ipv6Addr, sizeof(ipv6Addr), retname, 1025, nullptr, 0, NI_NAMEREQD);
        }
#endif

        if(retVal != 0)
            dns->setError(translateDnsError(retVal));
        else
        {
            dns->appendHostname(retname);
            dns->appendAddress(m_szQuery);
        }
    }
    else
    {
        struct addrinfo * pRet = nullptr;
        struct addrinfo * pNext;
        struct addrinfo hints;
        hints.ai_flags = 0; //AI_CANONNAME; <-- for IPV6 it makes cannoname to point to the IP address!
#ifdef COMPILE_IPV6_SUPPORT
        hints.ai_family = (m_queryType == KviDnsResolver::IPv6) ? PF_INET6 : ((m_queryType == KviDnsResolver::IPv4) ? PF_INET : PF_UNSPEC);
#else
        hints.ai_family = PF_INET;
#endif
        hints.ai_socktype = SOCK_STREAM;
        hints.ai_protocol = 0;
        hints.ai_addrlen = 0;
        hints.ai_canonname = nullptr;
        hints.ai_addr = nullptr;
        hints.ai_next = nullptr;

        retVal = getaddrinfo(m_szQuery.toUtf8().data(), nullptr, &hints, &pRet);

        if(retVal != 0)
        {
            dns->setError(translateDnsError(retVal));
        }
        else if(!pRet)
        {
            dns->setError(KviError::DNSQueryFailed);
        }
        else
        {
            dns->appendHostname(pRet->ai_canonname ? QString::fromUtf8(pRet->ai_canonname) : m_szQuery);
            QString szIp;
#ifdef COMPILE_IPV6_SUPPORT
            if(pRet->ai_family == PF_INET6)
                KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pRet->ai_addr))->sin6_addr, szIp);
            else
            {
#endif
                KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pRet->ai_addr))->sin_addr, szIp);
#ifdef COMPILE_IPV6_SUPPORT
            }
#endif
            dns->appendAddress(szIp);

            pNext = pRet->ai_next;
            while(pNext)
            {
                QString tmp;
#ifdef COMPILE_IPV6_SUPPORT
                if(pNext->ai_family == PF_INET6)
                    KviNetUtils::binaryIpToStringIp_V6(((sockaddr_in6 *)(pNext->ai_addr))->sin6_addr, tmp);
                else
                {
#endif
                    KviNetUtils::binaryIpToStringIp(((sockaddr_in *)(pNext->ai_addr))->sin_addr, tmp);
#ifdef COMPILE_IPV6_SUPPORT
                }
#endif
                if(!tmp.isEmpty())
                    dns->appendAddress(tmp);

                if(pNext->ai_canonname)
                {
                    // FIXME: only of not equal to other names ?
                    dns->appendHostname(QString::fromUtf8(pNext->ai_canonname));
                }

                pNext = pNext->ai_next;
            }
        }
        if(pRet)
            freeaddrinfo(pRet);
    }

#endif // !COMPILE_ON_WINDOWS

    KviDnsResolverThreadEvent * pEvent = new KviDnsResolverThreadEvent(dns);
    QApplication::postEvent(m_pParentDns, pEvent);
}

KviDnsResolver::KviDnsResolver()
    : QObject()
{
    m_pSlaveThread = new KviDnsResolverThread(this);
    m_pDnsResult = new KviDnsResolverResult();
    m_state = Idle;
}

KviDnsResolver::~KviDnsResolver()
{
    if(m_pSlaveThread)
    {
        if(!m_pSlaveThread->wait(30000))
            qDebug("Failed to wait for the slave DNS thread: we're probably going to crash!");
        delete m_pSlaveThread; // will eventually terminate it (but it will also block us!!!)
    }

    delete m_pDnsResult;
}

bool KviDnsResolver::isRunning() const
{
    return (m_state == Busy);
}

bool KviDnsResolver::lookup(const QString & szQuery, QueryType type)
{
    if(m_state == Busy)
        return false;
    m_pSlaveThread->setQuery(szQuery.trimmed(), type);
    m_pSlaveThread->start();
    m_state = Busy;
    return true;
}

KviError::Code KviDnsResolver::error()
{
    if(!m_pDnsResult)
        return KviError::DNSQueryFailed;
    return m_pDnsResult->error();
}

QString KviDnsResolver::errorString()
{
    return KviError::getDescription(error());
}

KviDnsResolverResult * KviDnsResolver::result()
{
    if(!m_pDnsResult)
        m_pDnsResult = new KviDnsResolverResult();
    return m_pDnsResult;
}

const std::vector<QString> & KviDnsResolver::hostnameList()
{
    return result()->hostnameList();
}

const std::vector<QString> & KviDnsResolver::ipAddressList()
{
    return result()->ipAddressList();
}

std::size_t KviDnsResolver::hostnameCount()
{
    return result()->hostnameList().size();
}

std::size_t KviDnsResolver::ipAddressCount()
{
    return result()->ipAddressList().size();
}

const QString & KviDnsResolver::hostName()
{
    const auto & list = result()->hostnameList();
    return list.empty() ? KviQString::Empty : list.front();
}

const QString & KviDnsResolver::firstIpAddress()
{
    const auto & list = result()->ipAddressList();
    return list.empty() ? KviQString::Empty : list.front();
}

const QString & KviDnsResolver::query()
{
    return result()->query();
}

bool KviDnsResolver::event(QEvent * e)
{
    if(e->type() == QEvent::User)
    {
        KviDnsResolverThreadEvent * pEvent = dynamic_cast<KviDnsResolverThreadEvent *>(e);
        if(pEvent)
        {
            delete m_pDnsResult;
            m_pDnsResult = pEvent->releaseResult();
            m_state = (m_pDnsResult->error() == KviError::Success) ? Success : Failure;
            emit lookupDone(this);
            return true;
        } // else oops... unknown thread event ?
    }
    return QObject::event(e);
}