/* ** JNetLib ** Copyright (C) 2008 Cockos Inc ** Copyright (C) 2000-2001 Nullsoft, Inc. ** Author: Justin Frankel ** File: asyncdns.cpp - JNL portable asynchronous DNS implementation ** License: see jnetlib.h */ #include "netinc.h" #include "util.h" #include "asyncdns.h" #ifdef _WIN32 #include #endif #include "../wdlcstring.h" JNL_AsyncDNS::JNL_AsyncDNS(int max_cache_entries) { m_thread_kill=1; m_thread=0; m_cache_size=max_cache_entries; m_cache=(cache_entry *)::malloc(sizeof(cache_entry)*m_cache_size); if (m_cache) memset(m_cache,0,sizeof(cache_entry)*m_cache_size); else m_cache_size = 0; } JNL_AsyncDNS::~JNL_AsyncDNS() { #ifndef NO_DNS_SUPPORT m_thread_kill=1; #ifdef _WIN32 if (m_thread) { WaitForSingleObject(m_thread,INFINITE); CloseHandle(m_thread); } #else if (m_thread) { void *p; pthread_join(m_thread,&p); } #endif//!_WIN32 #endif//NO_DNS_SUPPORT free(m_cache); } #ifdef _WIN32 unsigned WINAPI JNL_AsyncDNS::_threadfunc(void *_d) #else unsigned int JNL_AsyncDNS::_threadfunc(void *_d) #endif { #ifndef NO_DNS_SUPPORT int nowinsock=JNL::open_socketlib(); JNL_AsyncDNS *_this=(JNL_AsyncDNS*)_d; int x; for (x = 0; x < _this->m_cache_size && !_this->m_thread_kill; x ++) { if (_this->m_cache[x].last_used && !_this->m_cache[x].resolved) { if (!nowinsock) { if (_this->m_cache[x].mode==0) { struct hostent *hostentry; hostentry=::gethostbyname(_this->m_cache[x].hostname); if (hostentry) { memcpy(&_this->m_cache[x].addr,hostentry->h_addr,sizeof(int)); } else _this->m_cache[x].addr=INADDR_NONE; } else if (_this->m_cache[x].mode==1) { struct hostent *ent; ent=::gethostbyaddr((const char *)&_this->m_cache[x].addr,4,AF_INET); lstrcpyn_safe(_this->m_cache[x].hostname,ent ? ent->h_name : "",sizeof(_this->m_cache[x].hostname)); } _this->m_cache[x].resolved=1; } else { if (_this->m_cache[x].mode==0) { _this->m_cache[x].addr=INADDR_NONE; _this->m_cache[x].resolved=1; } else if (_this->m_cache[x].mode==1) { _this->m_cache[x].hostname[0]=0; _this->m_cache[x].resolved=1; } } } } if (!nowinsock) JNL::close_socketlib(); _this->m_thread_kill=1; #endif // NO_DNS_SUPPORT return 0; } int JNL_AsyncDNS::resolve(const char *hostname, unsigned int *addr) { // return 0 on success, 1 on wait, -1 on unresolvable int x; unsigned int ip=inet_addr(hostname); if (ip != INADDR_NONE) { *addr=ip; return 0; } #ifndef NO_DNS_SUPPORT for (x = 0; x < m_cache_size; x ++) { if (!stricmp(m_cache[x].hostname,hostname) && m_cache[x].mode==0) { m_cache[x].last_used=time(NULL); if (m_cache[x].resolved) { if (m_cache[x].addr == INADDR_NONE) { return -1; } *addr=m_cache[x].addr; return 0; } makesurethreadisrunning(); return 1; } } // add to resolve list int oi=-1; for (x = 0; x < m_cache_size; x ++) { if (!m_cache[x].last_used) { oi=x; break; } if ((oi==-1 || m_cache[x].last_used < m_cache[oi].last_used) && m_cache[x].resolved) { oi=x; } } if (oi == -1) { return -1; } strcpy(m_cache[oi].hostname,hostname); m_cache[oi].mode=0; m_cache[oi].addr=INADDR_NONE; m_cache[oi].resolved=0; m_cache[oi].last_used=time(NULL); makesurethreadisrunning(); return 1; #else return -1; #endif } int JNL_AsyncDNS::reverse(unsigned int addr, char *hostname) { // return 0 on success, 1 on wait, -1 on unresolvable int x; if (addr == INADDR_NONE) { return -1; } #ifndef NO_DNS_SUPPORT for (x = 0; x < m_cache_size; x ++) { if (m_cache[x].addr==addr && m_cache[x].mode==1) { m_cache[x].last_used=time(NULL); if (m_cache[x].resolved) { if (!m_cache[x].hostname[0]) { return -1; } lstrcpyn_safe(hostname,m_cache[x].hostname,256); return 0; } makesurethreadisrunning(); return 1; } } // add to resolve list int oi=-1; for (x = 0; x < m_cache_size; x ++) { if (!m_cache[x].last_used) { oi=x; break; } if ((oi==-1 || m_cache[x].last_used < m_cache[oi].last_used) && m_cache[x].resolved) { oi=x; } } if (oi == -1) { return -1; } m_cache[oi].addr=addr; m_cache[oi].hostname[0]=0; m_cache[oi].resolved=0; m_cache[oi].mode=1; m_cache[oi].last_used=time(NULL); makesurethreadisrunning(); return 1; #else return -1; #endif } void JNL_AsyncDNS::makesurethreadisrunning(void) { #ifndef NO_DNS_SUPPORT if (m_thread_kill) { #ifdef _WIN32 if (m_thread) { WaitForSingleObject(m_thread,INFINITE); CloseHandle(m_thread); } unsigned id; m_thread_kill=0; m_thread=(HANDLE)_beginthreadex(NULL,0,_threadfunc,(void *)this,0,&id); if (!m_thread) { #else if (m_thread) { void *p; pthread_join(m_thread,&p); } m_thread_kill=0; if (pthread_create(&m_thread,NULL,(void *(*) (void *))_threadfunc,(void*)this) != 0) { #endif m_thread_kill=1; } } #endif//NO_DNS_SUPPORT }