acl/app/jaws/global/dns_cache.c

349 lines
8.2 KiB
C
Raw Blame History

#include "lib_acl.h"
#ifdef ACL_BCB_COMPILER
#pragma hdrstop
#endif
#include "dns.h"
static int __thread_safe;
typedef struct CACHE {
ACL_DNS_DB *dns_db;
char name[256];
time_t tm_timeout;
ACL_RING ring_entry;
} CACHE;
struct DNS_CACHE {
acl_pthread_mutex_t cache_mutex;
ACL_HTABLE *cache_table;
ACL_RING cache_ring;
};
static int __use_trylock = 0;
static int __cache_timeout = 300; /* 300 seconds */
static void cache_lock(DNS_CACHE *dns_cache)
{
const char *myname = "cache_lock";
char buf[256];
int status;
if (__thread_safe == 0)
return;
status = acl_pthread_mutex_lock(&dns_cache->cache_mutex);
if (status) {
acl_msg_fatal("%s: pthread_mutex_lock error(%s)",
myname, acl_last_strerror(buf, sizeof(buf)));
}
}
static int cache_trylock(DNS_CACHE *dns_cache)
{
int status;
if (__thread_safe == 0)
return (0);
status = acl_pthread_mutex_trylock(&dns_cache->cache_mutex);
if (status == 0)
return (0);
else {
return (-1);
}
}
static void cache_unlock(DNS_CACHE *dns_cache)
{
const char *myname = "cache_unlock";
char buf[256];
int status;
if (__thread_safe == 0)
return;
status = acl_pthread_mutex_unlock(&dns_cache->cache_mutex);
if (status) {
acl_msg_fatal("%s: pthread_mutex_lock error(%s)",
myname, acl_last_strerror(buf, sizeof(buf)));
}
}
static void free_cache_fn(DNS_CACHE *dns_cache, CACHE *cache)
{
if (cache->dns_db)
acl_netdb_free(cache->dns_db);
acl_ring_detach(&cache->ring_entry);
acl_htable_delete(dns_cache->cache_table, cache->name, NULL);
acl_myfree(cache);
}
static void cache_timer_fn(DNS_CACHE *dns_cache)
{
CACHE *cache, *tmp;
ACL_RING *iter;
time_t current;
current = time(NULL);
for (iter = acl_ring_succ(&dns_cache->cache_ring);
iter != &dns_cache->cache_ring;)
{
cache = acl_ring_to_appl(iter, CACHE, ring_entry);
if (current >= cache->tm_timeout) {
tmp = cache;
iter = acl_ring_succ(iter);
free_cache_fn(dns_cache, tmp);
} else
break;
}
}
void dns_cache_push_one(DNS_CACHE *dns_cache, const ACL_DNS_DB *dns_db, int timeout)
{
const char *myname = "dns_cache_push_one";
CACHE *cache;
if (dns_db == NULL || dns_db->h_db == NULL) {
acl_msg_error("%s(%d): input invalid", myname, __LINE__);
return;
}
if (dns_db->name[0] == 0) {
acl_msg_error("%s(%d): host name empty", myname, __LINE__);
return;
}
if (dns_db->size <= 0) {
acl_msg_error("%s(%d): size(%d) <= 0", myname, __LINE__, dns_db->size);
return;
}
if (dns_db->size != acl_array_size(dns_db->h_db)) {
acl_msg_fatal("%s(%d): size(%d) != array size(%d)",
myname, __LINE__, dns_db->size,
acl_array_size(dns_db->h_db));
}
if (__use_trylock) {
if (cache_trylock(dns_cache) < 0) {
return;
}
} else
cache_lock(dns_cache);
cache = (CACHE *) acl_htable_find(dns_cache->cache_table, dns_db->name);
if (cache == NULL) {
cache = (CACHE *) acl_mycalloc(1, sizeof(CACHE));
if (cache == NULL) {
cache_unlock(dns_cache);
acl_msg_error("%s(%d): calloc error(%s)",
myname, __LINE__, acl_last_serror());
return;
}
if (acl_htable_enter(dns_cache->cache_table,
dns_db->name, (char *) cache) == NULL)
{
cache_unlock(dns_cache);
acl_myfree(cache);
acl_msg_error("%s(%d): add to htable error(%s)",
myname, __LINE__, acl_last_serror());
return;
}
acl_ring_prepend(&dns_cache->cache_ring, &cache->ring_entry);
ACL_SAFE_STRNCPY(cache->name, dns_db->name, sizeof(cache->name));
} else {
/* override the old cache */
if (cache->dns_db != NULL)
acl_netdb_free(cache->dns_db);
cache->dns_db = NULL;
acl_ring_detach(&cache->ring_entry);
acl_ring_prepend(&dns_cache->cache_ring, &cache->ring_entry);
}
cache->tm_timeout = time(NULL) + timeout;
cache->dns_db = acl_netdb_clone(dns_db);
if (cache->dns_db == NULL) {
free_cache_fn(dns_cache, cache);
}
cache_unlock(dns_cache);
}
void dns_cache_push(DNS_CACHE *dns_cache, const ACL_DNS_DB *dns_db)
{
dns_cache_push_one(dns_cache, dns_db, __cache_timeout);
}
void dns_cache_push2(DNS_CACHE *dns_cache, const DNS_CTX *dns_ctx)
{
const char *myname = "dns_cache_push2";
ACL_DNS_DB *dns_db;
CACHE *cache;
int i;
if (dns_ctx == NULL) {
acl_msg_error("%s(%d): input invalid", myname, __LINE__);
return;
}
if (dns_ctx->domain_key[0] == 0) {
acl_msg_error("%s(%d): domain_key empty", myname, __LINE__);
return;
}
if (dns_ctx->ip_cnt <= 0) {
acl_msg_error("%s(%d): size(%d) <= 0",
myname, __LINE__, dns_ctx->ip_cnt);
return;
}
dns_db = acl_netdb_new(dns_ctx->domain_key);
for (i = 0; i < dns_ctx->ip_cnt; i++) {
acl_netdb_addip(dns_db, dns_ctx->ip[i]);
}
if (__use_trylock) {
if (cache_trylock(dns_cache) < 0) {
acl_netdb_free(dns_db);
return;
}
} else
cache_lock(dns_cache);
cache = (CACHE *) acl_htable_find(dns_cache->cache_table, dns_ctx->domain_key);
if (cache == NULL) {
cache = (CACHE *) acl_mycalloc(1, sizeof(CACHE));
if (cache == NULL) {
cache_unlock(dns_cache);
acl_netdb_free(dns_db);
acl_msg_error("%s(%d): calloc error(%s)",
myname, __LINE__, acl_last_serror());
return;
}
if (acl_htable_enter(dns_cache->cache_table,
dns_db->name, (char *) cache) == NULL)
{
cache_unlock(dns_cache);
acl_netdb_free(dns_db);
acl_msg_error("%s(%d): add to htable error(%s)",
myname, __LINE__, acl_last_serror());
return;
}
acl_ring_append(&dns_cache->cache_ring, &cache->ring_entry);
ACL_SAFE_STRNCPY(cache->name, dns_db->name, sizeof(cache->name));
} else {
/* override the old cache */
if (cache->dns_db != NULL)
acl_netdb_free(cache->dns_db);
cache->dns_db = NULL;
acl_ring_detach(&cache->ring_entry);
acl_ring_append(&dns_cache->cache_ring, &cache->ring_entry);
}
cache->tm_timeout = time(NULL) + __cache_timeout;
cache->dns_db = dns_db;
cache_unlock(dns_cache);
}
ACL_DNS_DB *dns_cache_lookup(DNS_CACHE *dns_cache, const char *name)
{
const char *myname = "dns_cache_lookup";
CACHE *cache;
char buf[256];
ACL_DNS_DB *dns_db;
if (__use_trylock) {
if (cache_trylock(dns_cache) < 0)
return (NULL);
} else
cache_lock(dns_cache);
cache_timer_fn(dns_cache); /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڵ<EFBFBD>DNS<4E><53><EFBFBD><EFBFBD>ȥ<EFBFBD><C8A5> */
ACL_SAFE_STRNCPY(buf, name, sizeof(buf));
acl_lowercase(buf);
cache = (CACHE *) acl_htable_find(dns_cache->cache_table, buf);
if (cache == NULL) {
cache_unlock(dns_cache);
return (NULL);
}
if (cache->dns_db == NULL) { /* XXX */
acl_msg_error("%s, %s(%d): dns_db null",
__FILE__, myname, __LINE__);
free_cache_fn(dns_cache, cache);
cache_unlock(dns_cache);
return (NULL);
}
/* if the dns cache has been timeout ? */
if (time(NULL) >= cache->tm_timeout) {
free_cache_fn(dns_cache, cache);
cache_unlock(dns_cache);
return (NULL);
}
/* clone the ACL_DNS_DB object */
dns_db = acl_netdb_clone(cache->dns_db);
if (dns_db == NULL) {
acl_msg_error("%s, %s(%d): calloc error(%s)",
__FILE__, myname, __LINE__, acl_last_serror());
cache_unlock(dns_cache);
return (NULL);
}
cache_unlock(dns_cache);
return (dns_db);
}
void dns_cache_del_host(DNS_CACHE *dns_cache, const char *name)
{
CACHE *cache;
cache_lock(dns_cache);
cache = (CACHE *) acl_htable_find(dns_cache->cache_table, name);
if (cache)
free_cache_fn(dns_cache, cache);
cache_unlock(dns_cache);
}
DNS_CACHE *dns_cache_create(int timeout, int thread_safe)
{
const char *myname = "dns_cache_create";
int status;
DNS_CACHE *dns_cache = (DNS_CACHE*) acl_mycalloc(1, sizeof(DNS_CACHE));
if (timeout > 0)
__cache_timeout = timeout;
if (thread_safe) {
status = acl_pthread_mutex_init(&dns_cache->cache_mutex, NULL);
if (status) {
acl_msg_fatal("%s: pthread_mutex_init error(%s)",
myname, acl_last_serror());
}
__use_trylock = 1;
__thread_safe = 1;
} else
__thread_safe = 0;
dns_cache->cache_table = acl_htable_create(256, 0);
if (dns_cache->cache_table == NULL)
acl_msg_fatal("%s: create htable error(%s)",
myname, acl_last_serror());
acl_ring_init(&dns_cache->cache_ring);
return (dns_cache);
}