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
}