asyncdns.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. /*
  2. ** JNetLib
  3. ** Copyright (C) 2000-2007 Nullsoft, Inc.
  4. ** Author: Justin Frankel
  5. ** File: asyncdns.cpp - JNL portable asynchronous DNS implementation
  6. ** License: see jnetlib.h
  7. */
  8. #include "netinc.h"
  9. #include "util.h"
  10. #include "asyncdns.h"
  11. #include <time.h>
  12. #ifdef _WIN32
  13. #include <strsafe.h>
  14. #endif
  15. enum
  16. {
  17. MODE_RESOLVE=0,
  18. MODE_REVERSE=1,
  19. };
  20. struct cache_entry
  21. {
  22. time_t last_used; // timestamp.
  23. bool resolved;
  24. int mode; // 1=reverse
  25. unsigned short port;
  26. char hostname[256];
  27. addrinfo *addr;
  28. int sockettype;
  29. };
  30. JNL_AsyncDNS::JNL_AsyncDNS(int max_cache_entries)
  31. {
  32. m_thread_kill=1;
  33. m_thread=0;
  34. m_cache_size=max_cache_entries;
  35. m_cache=(cache_entry *)malloc(sizeof(cache_entry)*m_cache_size);
  36. memset(m_cache, 0, sizeof(cache_entry)*m_cache_size);
  37. }
  38. JNL_AsyncDNS::~JNL_AsyncDNS()
  39. {
  40. m_thread_kill=1;
  41. #ifdef _WIN32
  42. if (m_thread)
  43. {
  44. WaitForSingleObject(m_thread,INFINITE);
  45. CloseHandle(m_thread);
  46. }
  47. #else
  48. if (m_thread)
  49. {
  50. void *p;
  51. pthread_join(m_thread,&p);
  52. }
  53. #endif//!_WIN32
  54. // free all the addrinfo stuff
  55. for (int x = 0; x < m_cache_size; x ++)
  56. {
  57. if (m_cache[x].addr)
  58. freeaddrinfo(m_cache[x].addr);
  59. }
  60. free(m_cache);
  61. }
  62. int JNL_AsyncDNS::resolvenow(const char *hostname, unsigned short port, addrinfo **addr, int sockettype)
  63. {
  64. addrinfo hints;
  65. memset(&hints,0,sizeof(hints));
  66. hints.ai_family = PF_UNSPEC;
  67. if (hostname)
  68. hints.ai_flags = AI_NUMERICHOST;
  69. else
  70. hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
  71. hints.ai_socktype = sockettype;
  72. char portString[32] = {0};
  73. sprintf(portString, "%u", (unsigned int)port);
  74. if (getaddrinfo(hostname, portString, &hints, addr) == 0)
  75. {
  76. return 0;
  77. }
  78. else
  79. {
  80. hints.ai_flags = 0;
  81. if (getaddrinfo(hostname, portString, &hints, addr) == 0)
  82. {
  83. return 0;
  84. }
  85. else
  86. {
  87. return -1;
  88. }
  89. }
  90. }
  91. #ifdef _WIN32
  92. unsigned long WINAPI JNL_AsyncDNS::_threadfunc(LPVOID _d)
  93. #else
  94. unsigned int JNL_AsyncDNS::_threadfunc(void *_d)
  95. #endif
  96. {
  97. int nowinsock=JNL::open_socketlib();
  98. JNL_AsyncDNS *_this=(JNL_AsyncDNS*)_d;
  99. int x;
  100. for (x = 0; x < _this->m_cache_size && !_this->m_thread_kill; x ++)
  101. {
  102. if (_this->m_cache[x].last_used && !_this->m_cache[x].resolved)
  103. {
  104. if (!nowinsock)
  105. {
  106. if (_this->m_cache[x].mode==0)
  107. {
  108. addrinfo *res=0;
  109. if (resolvenow(_this->m_cache[x].hostname, _this->m_cache[x].port, &res, _this->m_cache[x].sockettype) == 0)
  110. {
  111. _this->m_cache[x].addr=res;
  112. }
  113. else
  114. {
  115. _this->m_cache[x].addr=0;//INADDR_NONE;
  116. }
  117. }
  118. else if (_this->m_cache[x].mode==1)
  119. {
  120. /*
  121. hostent *ent;
  122. // TODO: replace with getnameinfo for IPv6
  123. ent=gethostbyaddr((const char *)&_this->m_cache[x].addr,4,AF_INET);
  124. if (ent)
  125. lstrcpyn(_this->m_cache[x].hostname, ent->h_name, 256);
  126. else
  127. _this->m_cache[x].hostname[0]=0;
  128. */
  129. }
  130. _this->m_cache[x].resolved=true;
  131. }
  132. else
  133. {
  134. if (_this->m_cache[x].mode==0)
  135. {
  136. _this->m_cache[x].addr=0;//INADDR_NONE;
  137. _this->m_cache[x].resolved=true;
  138. }
  139. else if (_this->m_cache[x].mode==1)
  140. {
  141. _this->m_cache[x].hostname[0]=0;
  142. _this->m_cache[x].resolved=true;
  143. }
  144. }
  145. }
  146. }
  147. if (!nowinsock) JNL::close_socketlib();
  148. _this->m_thread_kill=1;
  149. return 0;
  150. }
  151. int JNL_AsyncDNS::resolve(const char *hostname, unsigned short port, addrinfo **addr, int sockettype)
  152. {
  153. // return 0 on success, 1 on wait, -1 on unresolvable
  154. int x;
  155. for (x = 0; x < m_cache_size; x ++)
  156. {
  157. if (!strcasecmp(m_cache[x].hostname,hostname) && port == m_cache[x].port && m_cache[x].mode==0 && m_cache[x].sockettype==sockettype)
  158. {
  159. m_cache[x].last_used=time(0);
  160. if (m_cache[x].resolved)
  161. {
  162. if (m_cache[x].addr == 0)//INADDR_NONE)
  163. {
  164. return DNS_RESOLVE_UNRESOLVABLE;
  165. }
  166. *addr =m_cache[x].addr;
  167. return DNS_RESOLVE_SUCCESS;
  168. }
  169. makesurethreadisrunning();
  170. return DNS_RESOLVE_WAIT;
  171. }
  172. }
  173. // add to resolve list
  174. int oi=-1;
  175. for (x = 0; x < m_cache_size; x ++)
  176. {
  177. if (!m_cache[x].last_used)
  178. {
  179. oi=x;
  180. break;
  181. }
  182. if ((oi==-1 || m_cache[x].last_used < m_cache[oi].last_used) && m_cache[x].resolved)
  183. {
  184. oi=x;
  185. }
  186. }
  187. if (oi == -1)
  188. {
  189. return DNS_RESOLVE_UNRESOLVABLE;
  190. }
  191. #ifdef _WIN32
  192. StringCchCopyA(m_cache[oi].hostname, 256, hostname);
  193. #elif defined(__APPLE__)
  194. strlcpy(m_cache[oi].hostname, hostname, 255);
  195. #else
  196. strncpy(m_cache[oi].hostname, hostname, 255);
  197. m_cache[oi].hostname[255]=0;
  198. #endif
  199. m_cache[oi].port=port;
  200. m_cache[oi].mode=0;
  201. m_cache[oi].addr=0;//INADDR_NONE;
  202. m_cache[oi].resolved=false;
  203. m_cache[oi].last_used=time(0);
  204. m_cache[oi].sockettype=sockettype;
  205. makesurethreadisrunning();
  206. return DNS_RESOLVE_WAIT;
  207. }
  208. /*
  209. int JNL_AsyncDNS::reverse(unsigned long addr, char *hostname, size_t hostnameSize)
  210. {
  211. // return 0 on success, 1 on wait, -1 on unresolvable
  212. int x;
  213. if (addr == INADDR_NONE)
  214. {
  215. return DNS_REVERSE_UNRESOLVABLE;
  216. }
  217. #ifndef NO_DNS_SUPPORT
  218. for (x = 0; x < m_cache_size; x ++)
  219. {
  220. if (m_cache[x].addr==addr && m_cache[x].mode==1)
  221. {
  222. m_cache[x].last_used=time(0);
  223. if (m_cache[x].resolved)
  224. {
  225. if (!m_cache[x].hostname[0])
  226. {
  227. return DNS_REVERSE_UNRESOLVABLE;
  228. }
  229. lstrcpyn(hostname,m_cache[x].hostname, hostnameSize);
  230. return DNS_REVERSE_SUCCESS;
  231. }
  232. makesurethreadisrunning();
  233. return DNS_REVERSE_WAIT;
  234. }
  235. }
  236. // add to resolve list
  237. int oi=-1;
  238. for (x = 0; x < m_cache_size; x ++)
  239. {
  240. if (!m_cache[x].last_used)
  241. {
  242. oi=x;
  243. break;
  244. }
  245. if ((oi==-1 || m_cache[x].last_used < m_cache[oi].last_used) && m_cache[x].resolved)
  246. {
  247. oi=x;
  248. }
  249. }
  250. if (oi == -1)
  251. {
  252. return DNS_REVERSE_UNRESOLVABLE;
  253. }
  254. m_cache[oi].addr=addr;
  255. m_cache[oi].hostname[0]=0;
  256. m_cache[oi].resolved=false;
  257. m_cache[oi].mode=1;
  258. m_cache[oi].last_used=time(0);
  259. makesurethreadisrunning();
  260. return DNS_REVERSE_WAIT;
  261. #else
  262. return DNS_REVERSE_UNRESOLVABLE;
  263. #endif
  264. }
  265. */
  266. void JNL_AsyncDNS::makesurethreadisrunning(void)
  267. {
  268. if (m_thread_kill)
  269. {
  270. #ifdef _WIN32
  271. if (m_thread)
  272. {
  273. WaitForSingleObject(m_thread,INFINITE);
  274. CloseHandle(m_thread);
  275. }
  276. DWORD id;
  277. m_thread_kill=0;
  278. m_thread=CreateThread(NULL,0,_threadfunc,(LPVOID)this,0,&id);
  279. if (!m_thread)
  280. {
  281. #else
  282. if (m_thread)
  283. {
  284. void *p;
  285. pthread_join(m_thread,&p);
  286. }
  287. m_thread_kill=0;
  288. if (pthread_create(&m_thread,NULL,(void *(*) (void *))_threadfunc,(void*)this) != 0)
  289. {
  290. #endif
  291. m_thread_kill=1;
  292. }
  293. }
  294. }