dns_cache.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include "dns_cache.h"
  2. #include "tlog.h"
  3. #include "stringutil.h"
  4. #include <pthread.h>
  5. struct dns_cache_head {
  6. DECLARE_HASHTABLE(cache_hash, 10);
  7. struct list_head cache_list;
  8. atomic_t num;
  9. int size;
  10. pthread_mutex_t lock;
  11. };
  12. static struct dns_cache_head dns_cache_head;
  13. int dns_cache_init(int size)
  14. {
  15. INIT_LIST_HEAD(&dns_cache_head.cache_list);
  16. hash_init(dns_cache_head.cache_hash);
  17. atomic_set(&dns_cache_head.num, 0);
  18. dns_cache_head.size = size;
  19. pthread_mutex_init(&dns_cache_head.lock, NULL);
  20. return 0;
  21. }
  22. static __attribute__((unused)) struct dns_cache *_dns_cache_last(void)
  23. {
  24. return list_last_entry(&dns_cache_head.cache_list, struct dns_cache, list);
  25. }
  26. static struct dns_cache *_dns_cache_first(void)
  27. {
  28. return list_first_entry_or_null(&dns_cache_head.cache_list, struct dns_cache, list);
  29. }
  30. static void _dns_cache_delete(struct dns_cache *dns_cache)
  31. {
  32. hash_del(&dns_cache->node);
  33. list_del_init(&dns_cache->list);
  34. atomic_dec(&dns_cache_head.num);
  35. free(dns_cache);
  36. }
  37. void dns_cache_get(struct dns_cache *dns_cache)
  38. {
  39. if (atomic_inc_return(&dns_cache->ref) == 1) {
  40. tlog(TLOG_ERROR, "BUG: dns_cache is invalid.");
  41. return;
  42. }
  43. }
  44. void dns_cache_release(struct dns_cache *dns_cache)
  45. {
  46. if (dns_cache == NULL) {
  47. return;
  48. }
  49. if (!atomic_dec_and_test(&dns_cache->ref)) {
  50. return;
  51. }
  52. _dns_cache_delete(dns_cache);
  53. }
  54. static void _dns_cache_remove(struct dns_cache *dns_cache)
  55. {
  56. hash_del(&dns_cache->node);
  57. list_del_init(&dns_cache->list);
  58. dns_cache_release(dns_cache);
  59. }
  60. int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len, int speed)
  61. {
  62. struct dns_cache *dns_cache = NULL;
  63. if (dns_cache_head.size <= 0) {
  64. return 0;
  65. }
  66. /* lookup existing cache */
  67. dns_cache = dns_cache_lookup(domain, qtype);
  68. if (dns_cache == NULL) {
  69. return 0;
  70. }
  71. if (ttl < DNS_CACHE_TTL_MIN) {
  72. ttl = DNS_CACHE_TTL_MIN;
  73. }
  74. /* update cache data */
  75. pthread_mutex_lock(&dns_cache_head.lock);
  76. dns_cache->ttl = ttl;
  77. dns_cache->qtype = qtype;
  78. dns_cache->ttl = ttl;
  79. dns_cache->del_pending = 0;
  80. dns_cache->speed = speed;
  81. time(&dns_cache->insert_time);
  82. if (qtype == DNS_T_A) {
  83. if (addr_len != DNS_RR_A_LEN) {
  84. goto errout_unlock;
  85. }
  86. memcpy(dns_cache->addr, addr, DNS_RR_A_LEN);
  87. } else if (qtype == DNS_T_AAAA) {
  88. if (addr_len != DNS_RR_AAAA_LEN) {
  89. goto errout_unlock;
  90. }
  91. memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN);
  92. } else {
  93. goto errout_unlock;
  94. }
  95. if (cname) {
  96. safe_strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN);
  97. dns_cache->cname_ttl = cname_ttl;
  98. }
  99. pthread_mutex_unlock(&dns_cache_head.lock);
  100. dns_cache_release(dns_cache);
  101. return 0;
  102. errout_unlock:
  103. pthread_mutex_unlock(&dns_cache_head.lock);
  104. //errout:
  105. if (dns_cache) {
  106. dns_cache_release(dns_cache);
  107. }
  108. return -1;
  109. }
  110. int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type_t qtype, unsigned char *addr, int addr_len, int speed)
  111. {
  112. uint32_t key = 0;
  113. struct dns_cache *dns_cache = NULL;
  114. if (dns_cache_head.size <= 0) {
  115. return 0;
  116. }
  117. /* if cache already exists, free */
  118. dns_cache = dns_cache_lookup(domain, qtype);
  119. if (dns_cache) {
  120. dns_cache_delete(dns_cache);
  121. dns_cache_release(dns_cache);
  122. dns_cache = NULL;
  123. }
  124. dns_cache = malloc(sizeof(*dns_cache));
  125. if (dns_cache == NULL) {
  126. goto errout;
  127. }
  128. if (ttl < DNS_CACHE_TTL_MIN) {
  129. ttl = DNS_CACHE_TTL_MIN;
  130. }
  131. key = hash_string(domain);
  132. key = jhash(&qtype, sizeof(qtype), key);
  133. safe_strncpy(dns_cache->domain, domain, DNS_MAX_CNAME_LEN);
  134. dns_cache->cname[0] = 0;
  135. dns_cache->qtype = qtype;
  136. dns_cache->ttl = ttl;
  137. atomic_set(&dns_cache->hitnum, 2);
  138. dns_cache->del_pending = 0;
  139. dns_cache->speed = speed;
  140. atomic_set(&dns_cache->ref, 1);
  141. time(&dns_cache->insert_time);
  142. if (qtype == DNS_T_A) {
  143. if (addr_len != DNS_RR_A_LEN) {
  144. goto errout;
  145. }
  146. memcpy(dns_cache->addr, addr, DNS_RR_A_LEN);
  147. } else if (qtype == DNS_T_AAAA) {
  148. if (addr_len != DNS_RR_AAAA_LEN) {
  149. goto errout;
  150. }
  151. memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN);
  152. } else {
  153. goto errout;
  154. }
  155. if (cname) {
  156. safe_strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN);
  157. dns_cache->cname_ttl = cname_ttl;
  158. }
  159. pthread_mutex_lock(&dns_cache_head.lock);
  160. hash_add(dns_cache_head.cache_hash, &dns_cache->node, key);
  161. list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
  162. INIT_LIST_HEAD(&dns_cache->check_list);
  163. /* Release extra cache, remove oldest cache record */
  164. if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
  165. struct dns_cache *del_cache;
  166. del_cache = _dns_cache_first();
  167. if (del_cache) {
  168. _dns_cache_remove(del_cache);
  169. }
  170. }
  171. pthread_mutex_unlock(&dns_cache_head.lock);
  172. return 0;
  173. errout:
  174. if (dns_cache) {
  175. free(dns_cache);
  176. }
  177. return -1;
  178. }
  179. struct dns_cache *dns_cache_lookup(char *domain, dns_type_t qtype)
  180. {
  181. uint32_t key = 0;
  182. struct dns_cache *dns_cache = NULL;
  183. struct dns_cache *dns_cache_ret = NULL;
  184. time_t now;
  185. if (dns_cache_head.size <= 0) {
  186. return NULL;
  187. }
  188. key = hash_string(domain);
  189. key = jhash(&qtype, sizeof(qtype), key);
  190. time(&now);
  191. /* find cache */
  192. pthread_mutex_lock(&dns_cache_head.lock);
  193. hash_for_each_possible(dns_cache_head.cache_hash, dns_cache, node, key)
  194. {
  195. if (dns_cache->qtype != qtype) {
  196. continue;
  197. }
  198. if (strncmp(domain, dns_cache->domain, DNS_MAX_CNAME_LEN) != 0) {
  199. continue;
  200. }
  201. dns_cache_ret = dns_cache;
  202. break;
  203. }
  204. if (dns_cache_ret) {
  205. /* Return NULL if the cache times out */
  206. if (now - dns_cache_ret->insert_time > dns_cache_ret->ttl) {
  207. _dns_cache_remove(dns_cache_ret);
  208. dns_cache_ret = NULL;
  209. } else {
  210. dns_cache_get(dns_cache_ret);
  211. }
  212. }
  213. pthread_mutex_unlock(&dns_cache_head.lock);
  214. return dns_cache_ret;
  215. }
  216. int dns_cache_get_ttl(struct dns_cache *dns_cache)
  217. {
  218. time_t now;
  219. int ttl = 0;
  220. time(&now);
  221. ttl = dns_cache->insert_time + dns_cache->ttl - now;
  222. if (ttl < 0) {
  223. return 0;
  224. }
  225. return ttl;
  226. }
  227. void dns_cache_delete(struct dns_cache *dns_cache)
  228. {
  229. pthread_mutex_lock(&dns_cache_head.lock);
  230. _dns_cache_remove(dns_cache);
  231. pthread_mutex_unlock(&dns_cache_head.lock);
  232. }
  233. void dns_cache_update(struct dns_cache *dns_cache)
  234. {
  235. pthread_mutex_lock(&dns_cache_head.lock);
  236. if (!list_empty(&dns_cache->list)) {
  237. list_del_init(&dns_cache->list);
  238. list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
  239. atomic_inc(&dns_cache->hitnum);
  240. }
  241. pthread_mutex_unlock(&dns_cache_head.lock);
  242. }
  243. void dns_cache_invalidate(dns_cache_preinvalid_callback callback, int ttl_pre)
  244. {
  245. struct dns_cache *dns_cache = NULL;
  246. struct dns_cache *tmp;
  247. time_t now;
  248. int ttl = 0;
  249. LIST_HEAD(checklist);
  250. if (dns_cache_head.size <= 0) {
  251. return;
  252. }
  253. time(&now);
  254. pthread_mutex_lock(&dns_cache_head.lock);
  255. list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
  256. {
  257. ttl = dns_cache->insert_time + dns_cache->ttl - now;
  258. if (ttl > 0 && ttl < ttl_pre) {
  259. /* If the TTL time is in the pre-timeout range, call callback function */
  260. if (callback && dns_cache->del_pending == 0) {
  261. list_add_tail(&dns_cache->check_list, &checklist);
  262. dns_cache_get(dns_cache);
  263. dns_cache->del_pending = 1;
  264. continue;
  265. }
  266. }
  267. if (ttl < 0) {
  268. _dns_cache_remove(dns_cache);
  269. }
  270. }
  271. pthread_mutex_unlock(&dns_cache_head.lock);
  272. list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
  273. {
  274. /* run callback */
  275. if (callback) {
  276. callback(dns_cache);
  277. }
  278. dns_cache_release(dns_cache);
  279. }
  280. }
  281. void dns_cache_destroy(void)
  282. {
  283. struct dns_cache *dns_cache = NULL;
  284. struct dns_cache *tmp;
  285. pthread_mutex_lock(&dns_cache_head.lock);
  286. list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
  287. {
  288. _dns_cache_delete(dns_cache);
  289. }
  290. pthread_mutex_unlock(&dns_cache_head.lock);
  291. pthread_mutex_destroy(&dns_cache_head.lock);
  292. }