wac_network_dns.cpp 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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 "wac_network_dns.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. wa::Components::WAC_Network_AsyncDNS::WAC_Network_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. if ( m_cache )
  37. memset( m_cache, 0, sizeof( cache_entry ) * m_cache_size );
  38. else
  39. m_cache_size = 0;
  40. }
  41. wa::Components::WAC_Network_AsyncDNS::~WAC_Network_AsyncDNS()
  42. {
  43. m_thread_kill = 1;
  44. #ifdef _WIN32
  45. if ( m_thread )
  46. {
  47. WaitForSingleObject( m_thread, INFINITE );
  48. CloseHandle( m_thread );
  49. }
  50. #else
  51. if ( m_thread )
  52. {
  53. void *p;
  54. pthread_join( m_thread, &p );
  55. }
  56. #endif//!_WIN32
  57. // free all the addrinfo stuff
  58. for ( int x = 0; x < m_cache_size; x++ )
  59. {
  60. if ( m_cache[ x ].addr )
  61. freeaddrinfo( m_cache[ x ].addr );
  62. }
  63. free( m_cache );
  64. }
  65. int wa::Components::WAC_Network_AsyncDNS::resolvenow( const char *hostname, unsigned short port, addrinfo **addr, int sockettype )
  66. {
  67. addrinfo hints;
  68. memset( &hints, 0, sizeof( hints ) );
  69. hints.ai_family = PF_UNSPEC;
  70. if ( hostname )
  71. hints.ai_flags = AI_NUMERICHOST;
  72. else
  73. hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
  74. hints.ai_socktype = sockettype;
  75. char portString[ 32 ] = { 0 };
  76. sprintf( portString, "%u", (unsigned int)port );
  77. if ( getaddrinfo( hostname, portString, &hints, addr ) == 0 )
  78. {
  79. return 0;
  80. }
  81. else
  82. {
  83. hints.ai_flags = 0;
  84. if ( getaddrinfo( hostname, portString, &hints, addr ) == 0 )
  85. return 0;
  86. else
  87. return -1;
  88. }
  89. }
  90. #ifdef _WIN32
  91. unsigned long WINAPI wa::Components::WAC_Network_AsyncDNS::_threadfunc( LPVOID _d )
  92. #else
  93. unsigned int WAC_Network_AsyncDNS::_threadfunc( void *_d )
  94. #endif
  95. {
  96. int nowinsock = JNL::open_socketlib();
  97. wa::Components::WAC_Network_AsyncDNS *_this = (WAC_Network_AsyncDNS *)_d;
  98. int x;
  99. for ( x = 0; x < _this->m_cache_size && !_this->m_thread_kill; x++ )
  100. {
  101. if ( _this->m_cache[ x ].last_used && !_this->m_cache[ x ].resolved )
  102. {
  103. if ( !nowinsock )
  104. {
  105. if ( _this->m_cache[ x ].mode == 0 )
  106. {
  107. addrinfo *res = 0;
  108. if ( resolvenow( _this->m_cache[ x ].hostname, _this->m_cache[ x ].port, &res, _this->m_cache[ x ].sockettype ) == 0 )
  109. {
  110. _this->m_cache[ x ].addr = res;
  111. }
  112. else
  113. {
  114. _this->m_cache[ x ].addr = 0; //INADDR_NONE;
  115. }
  116. }
  117. else if ( _this->m_cache[ x ].mode == 1 )
  118. {
  119. /*
  120. hostent *ent;
  121. // TODO: replace with getnameinfo for IPv6
  122. ent=gethostbyaddr((const char *)&_this->m_cache[x].addr,4,AF_INET);
  123. if (ent)
  124. lstrcpyn(_this->m_cache[x].hostname, ent->h_name, 256);
  125. else
  126. _this->m_cache[x].hostname[0]=0;
  127. */
  128. }
  129. _this->m_cache[ x ].resolved = true;
  130. }
  131. else
  132. {
  133. if ( _this->m_cache[ x ].mode == 0 )
  134. {
  135. _this->m_cache[ x ].addr = 0;//INADDR_NONE;
  136. _this->m_cache[ x ].resolved = true;
  137. }
  138. else if ( _this->m_cache[ x ].mode == 1 )
  139. {
  140. _this->m_cache[ x ].hostname[ 0 ] = 0;
  141. _this->m_cache[ x ].resolved = true;
  142. }
  143. }
  144. }
  145. }
  146. if ( !nowinsock )
  147. JNL::close_socketlib();
  148. _this->m_thread_kill = 1;
  149. return 0;
  150. }
  151. int wa::Components::WAC_Network_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. void wa::Components::WAC_Network_AsyncDNS::makesurethreadisrunning( void )
  209. {
  210. if ( m_thread_kill )
  211. {
  212. #ifdef _WIN32
  213. if ( m_thread )
  214. {
  215. WaitForSingleObject( m_thread, INFINITE );
  216. CloseHandle( m_thread );
  217. }
  218. DWORD id;
  219. m_thread_kill = 0;
  220. m_thread = CreateThread( NULL, 0, _threadfunc, (LPVOID)this, 0, &id );
  221. if ( !m_thread )
  222. {
  223. #else
  224. if ( m_thread )
  225. {
  226. void *p;
  227. pthread_join( m_thread, &p );
  228. }
  229. m_thread_kill = 0;
  230. if ( pthread_create( &m_thread, NULL, ( void *( * ) ( void * ) )_threadfunc, (void *)this ) != 0 )
  231. {
  232. #endif
  233. m_thread_kill = 1;
  234. }
  235. }
  236. }
  237. #define CBCLASS wa::Components::WAC_Network_AsyncDNS
  238. START_DISPATCH;
  239. CB( API_DNS_RESOLVE, resolve );
  240. END_DISPATCH;
  241. #undef CBCLASS