dnscache.c 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #include "stx.h"
  2. #include "common.h"
  3. /*****************************************
  4. * Basic types definitions
  5. */
  6. typedef struct _stx_dns_data {
  7. struct in_addr *addrs;
  8. int num_addrs;
  9. int cur;
  10. time_t expires;
  11. } stx_dns_data_t;
  12. #define MAX_HOST_ADDRS 1024
  13. static struct in_addr addr_list[MAX_HOST_ADDRS];
  14. stx_cache_t *_stx_dns_cache = NULL;
  15. extern int _stx_dns_ttl;
  16. extern int _stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
  17. int *num_addrs, st_utime_t timeout);
  18. static unsigned long hash_hostname(const void *key)
  19. {
  20. const char *name = (const char *)key;
  21. unsigned long hash = 0;
  22. while (*name)
  23. hash = (hash << 4) - hash + *name++; /* hash = hash * 15 + *name++ */
  24. return hash;
  25. }
  26. static void cleanup_entry(void *key, void *data)
  27. {
  28. if (key)
  29. free(key);
  30. if (data) {
  31. if (((stx_dns_data_t *)data)->addrs)
  32. free(((stx_dns_data_t *)data)->addrs);
  33. free(data);
  34. }
  35. }
  36. static int lookup_entry(const char *host, struct in_addr *addrs,
  37. int *num_addrs, int rotate)
  38. {
  39. stx_cache_entry_t *entry;
  40. stx_dns_data_t *data;
  41. int n;
  42. entry = stx_cache_entry_lookup(_stx_dns_cache, host);
  43. if (entry) {
  44. data = (stx_dns_data_t *)stx_cache_entry_getdata(entry);
  45. if (st_time() <= data->expires) {
  46. if (*num_addrs == 1) {
  47. if (rotate) {
  48. *addrs = data->addrs[data->cur++];
  49. if (data->cur >= data->num_addrs)
  50. data->cur = 0;
  51. } else {
  52. *addrs = data->addrs[0];
  53. }
  54. } else {
  55. n = STX_MIN(*num_addrs, data->num_addrs);
  56. memcpy(addrs, data->addrs, n * sizeof(*addrs));
  57. *num_addrs = n;
  58. }
  59. stx_cache_entry_release(_stx_dns_cache, entry);
  60. return 1;
  61. }
  62. /*
  63. * Cache entry expired: decrement its refcount and purge it from cache.
  64. */
  65. stx_cache_entry_release(_stx_dns_cache, entry);
  66. stx_cache_entry_delete(_stx_dns_cache, entry);
  67. }
  68. return 0;
  69. }
  70. static void insert_entry(const char *host, struct in_addr *addrs, int count)
  71. {
  72. stx_cache_entry_t *entry;
  73. stx_dns_data_t *data;
  74. char *key;
  75. size_t n;
  76. if (_stx_dns_ttl > 0) {
  77. key = strdup(host);
  78. data = (stx_dns_data_t *)malloc(sizeof(stx_dns_data_t));
  79. n = count * sizeof(*addrs);
  80. if (data) {
  81. data->addrs = (struct in_addr *)malloc(n);
  82. if (data->addrs)
  83. memcpy(data->addrs, addrs, n);
  84. data->num_addrs = count;
  85. data->cur = 0;
  86. data->expires = st_time() + _stx_dns_ttl;
  87. }
  88. entry = stx_cache_entry_create(key, data, strlen(host) + 1 +
  89. sizeof(stx_dns_data_t) + n +
  90. stx_cache_entry_sizeof());
  91. if (key && data && data->addrs && entry &&
  92. stx_cache_entry_insert(_stx_dns_cache, entry) == 0) {
  93. stx_cache_entry_release(_stx_dns_cache, entry);
  94. return;
  95. }
  96. if (entry)
  97. stx_cache_entry_delete(_stx_dns_cache, entry);
  98. else
  99. cleanup_entry(key, data);
  100. }
  101. }
  102. int _stx_dns_cache_getaddrlist(const char *hostname, struct in_addr *addrs,
  103. int *num_addrs, st_utime_t timeout,
  104. int rotate)
  105. {
  106. char host[128];
  107. int n, count;
  108. if (!_stx_dns_cache)
  109. return _stx_dns_getaddrlist(hostname, addrs, num_addrs, timeout);
  110. for (n = 0; n < sizeof(host) - 1 && hostname[n]; n++) {
  111. host[n] = tolower(hostname[n]);
  112. }
  113. host[n] = '\0';
  114. if (lookup_entry(host, addrs, num_addrs, rotate))
  115. return 0;
  116. count = MAX_HOST_ADDRS;
  117. if (_stx_dns_getaddrlist(host, addr_list, &count, timeout) < 0)
  118. return -1;
  119. n = STX_MIN(*num_addrs, count);
  120. memcpy(addrs, addr_list, n * sizeof(*addrs));
  121. *num_addrs = n;
  122. insert_entry(host, addr_list, count);
  123. return 0;
  124. }
  125. int stx_dns_cache_init(size_t max_size, size_t max_bytes, size_t hash_size)
  126. {
  127. _stx_dns_cache = stx_cache_create(max_size, max_bytes, hash_size,
  128. hash_hostname,
  129. (long (*)(const void *, const void *))strcmp,
  130. cleanup_entry);
  131. if (!_stx_dns_cache)
  132. return -1;
  133. return 0;
  134. }
  135. void stx_dns_cache_getinfo(stx_cache_info_t *info)
  136. {
  137. if (_stx_dns_cache)
  138. stx_cache_getinfo(_stx_dns_cache, info);
  139. else
  140. memset(info, 0, sizeof(stx_cache_info_t));
  141. }
  142. int stx_dns_getaddrlist(const char *hostname, struct in_addr *addrs,
  143. int *num_addrs, st_utime_t timeout)
  144. {
  145. return _stx_dns_cache_getaddrlist(hostname, addrs, num_addrs, timeout, 0);
  146. }
  147. int stx_dns_getaddr(const char *hostname, struct in_addr *addr,
  148. st_utime_t timeout)
  149. {
  150. int n = 1;
  151. return _stx_dns_cache_getaddrlist(hostname, addr, &n, timeout, 1);
  152. }