gethostbyname or getaddrinfo that doesn’t block

gethostbyname and getaddrinfo block.  There is no way to stop them once they’ve started.  (BTW, getaddrinfo is recommended over gethostbyname as it’s IPv6 compatible.)  This little class will provide a neat way to get the info without blocking.  Classes extra::Thread and extra::auto_HANDLE are thread and and auto handle closing classes respectivly (is that english?).  When the user requires to cancel the request or connect, call m_hostNameGetter.Abort() from within MySocketClass.

The Class:

class CGetAddrInfoThread : private extra::Thread
{
public:
    CGetAddrInfoThread();
    void Abort();
    struct addrinfo *GetAddrInfo(const extra::tstring &host, ULONG nPort);
private:
    extra::auto_HANDLE m_abort;
    extra::tstring m_host;
    ULONG m_port;
    struct addrinfo *m_ret;
    virtual DWORD ThreadProc();
};

The Implementation

CGetAddrInfoThread::CGetAddrInfoThread() :
        m_port(0), m_ret(0), m_abort(0,0,CloseHandle)
{
}
void CGetAddrInfoThread::Abort()
{
    SetEvent(m_abort);
}
struct addrinfo *CGetAddrInfoThread::GetAddrInfo(const extra::tstring &host, ULONG nPort)
{
    if(!m_abort.Valid())
        m_abort = CreateEvent(0,TRUE,FALSE,0);
    m_host = host;
    m_port = nPort;
    m_ret = 0;
    ResetEvent(m_abort
    if(!Create().Valid())
        return 0
    HANDLE handles[] = {ThreadHandle(),m_abort};
    return ((WaitForMultipleObjects(sizeof(handles)/sizeof(handles[0]),
                handles,FALSE,INFINITE)==WAIT_OBJECT_0) ? m_ret : 0);
}
DWORD CGetAddrInfoThread::ThreadProc()
{
    char port[16];
    if(_ultoa_s(m_port,port,10))
        return 0;
    struct addrinfo aiHints;
    memset(&aiHints, 0, sizeof(aiHints));
    aiHints.ai_family = AF_INET;
    aiHints.ai_socktype = SOCK_STREAM;
    aiHints.ai_protocol = IPPROTO_TCP;
    if (::getaddrinfo(CT2CA(m_host.c_str()), port, &aiHints, &m_ret))
        m_ret = 0;
    return 0;
}

Using the class:

void MySocketClass::MyConnectingMethod()
{
    // do stuff
    struct addrinfo *aiList = m_hostNameGetter.GetAddrInfo(host,nPort);
    if(!aiList)
        return 0;
    // do stuff
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s