/* ** JNetLib ** 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" 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); memset(m_cache,0,sizeof(cache_entry)*m_cache_size); } 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 long WINAPI JNL_AsyncDNS::_threadfunc(LPVOID _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) { _this->m_cache[x].addr=*((int*)hostentry->h_addr); } 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); if (ent) { strncpy(_this->m_cache[x].hostname,ent->h_name,255); _this->m_cache[x].hostname[255]=0; } else { _this->m_cache[x].hostname[0]=0; } } _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(char *hostname, unsigned long *addr) { // return 0 on success, 1 on wait, -1 on unresolvable int x; unsigned long 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 (!strcasecmp(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; } struct in_addr in; in.s_addr=m_cache[x].addr; *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 long 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; } strncpy(hostname,m_cache[x].hostname,255); hostname[255]=0; 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); } DWORD id; m_thread_kill=0; m_thread=CreateThread(NULL,0,_threadfunc,(LPVOID)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 }