dns_cache: Replace cache timeout mechanism with time wheel algorithm to reduce CPU usage
This commit is contained in:
@@ -15,8 +15,8 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
BIN=smartdns
|
BIN=smartdns
|
||||||
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o
|
OBJS_LIB=lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/timer_wheel.o
|
||||||
OBJS_MAIN=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o lib/conf.o lib/nftset.o
|
OBJS_MAIN=smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o timer.o lib/conf.o lib/nftset.o
|
||||||
OBJS=$(OBJS_MAIN) $(OBJS_LIB)
|
OBJS=$(OBJS_MAIN) $(OBJS_LIB)
|
||||||
|
|
||||||
# cflags
|
# cflags
|
||||||
|
|||||||
349
src/dns_cache.c
349
src/dns_cache.c
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "dns_cache.h"
|
#include "dns_cache.h"
|
||||||
#include "stringutil.h"
|
#include "stringutil.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "tlog.h"
|
#include "tlog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
@@ -27,31 +28,28 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define DNS_CACHE_MAX_HITNUM 5000
|
#define DNS_CACHE_MAX_HITNUM 6000
|
||||||
#define DNS_CACHE_HITNUM_STEP 2
|
#define DNS_CACHE_HITNUM_STEP 3
|
||||||
#define DNS_CACHE_HITNUM_STEP_MAX 6
|
#define DNS_CACHE_HITNUM_STEP_MAX 6
|
||||||
|
#define DNS_CACHE_READ_TIMEOUT 60
|
||||||
|
|
||||||
struct dns_cache_head {
|
struct dns_cache_head {
|
||||||
struct hash_table cache_hash;
|
struct hash_table cache_hash;
|
||||||
struct list_head cache_list;
|
struct list_head cache_list;
|
||||||
struct list_head inactive_list;
|
|
||||||
atomic_t num;
|
atomic_t num;
|
||||||
int size;
|
int size;
|
||||||
int enable_inactive;
|
|
||||||
int inactive_list_expired;
|
|
||||||
pthread_mutex_t lock;
|
pthread_mutex_t lock;
|
||||||
struct dns_cache *last_active_inserted;
|
dns_cache_callback timeout_callback;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int (*dns_cache_read_callback)(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data);
|
typedef int (*dns_cache_read_callback)(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data);
|
||||||
|
|
||||||
static struct dns_cache_head dns_cache_head;
|
static struct dns_cache_head dns_cache_head;
|
||||||
|
|
||||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired)
|
int dns_cache_init(int size, dns_cache_callback timeout_callback)
|
||||||
{
|
{
|
||||||
int bits = 0;
|
int bits = 0;
|
||||||
INIT_LIST_HEAD(&dns_cache_head.cache_list);
|
INIT_LIST_HEAD(&dns_cache_head.cache_list);
|
||||||
INIT_LIST_HEAD(&dns_cache_head.inactive_list);
|
|
||||||
|
|
||||||
bits = ilog2(size) - 1;
|
bits = ilog2(size) - 1;
|
||||||
if (bits >= 20) {
|
if (bits >= 20) {
|
||||||
@@ -63,35 +61,14 @@ int dns_cache_init(int size, int enable_inactive, int inactive_list_expired)
|
|||||||
hash_table_init(dns_cache_head.cache_hash, bits, malloc);
|
hash_table_init(dns_cache_head.cache_hash, bits, malloc);
|
||||||
atomic_set(&dns_cache_head.num, 0);
|
atomic_set(&dns_cache_head.num, 0);
|
||||||
dns_cache_head.size = size;
|
dns_cache_head.size = size;
|
||||||
dns_cache_head.enable_inactive = enable_inactive;
|
dns_cache_head.timeout_callback = timeout_callback;
|
||||||
dns_cache_head.inactive_list_expired = inactive_list_expired;
|
|
||||||
dns_cache_head.last_active_inserted = NULL;
|
|
||||||
pthread_mutex_init(&dns_cache_head.lock, NULL);
|
pthread_mutex_init(&dns_cache_head.lock, NULL);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static __attribute__((unused)) struct dns_cache *_dns_cache_last(void)
|
static struct dns_cache *_dns_cache_first(void)
|
||||||
{
|
{
|
||||||
struct dns_cache *dns_cache = NULL;
|
|
||||||
|
|
||||||
dns_cache = list_last_entry(&dns_cache_head.inactive_list, struct dns_cache, list);
|
|
||||||
if (dns_cache) {
|
|
||||||
return dns_cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list_last_entry(&dns_cache_head.cache_list, struct dns_cache, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct dns_cache *_dns_inactive_cache_first(void)
|
|
||||||
{
|
|
||||||
struct dns_cache *dns_cache = NULL;
|
|
||||||
|
|
||||||
dns_cache = list_first_entry_or_null(&dns_cache_head.inactive_list, struct dns_cache, list);
|
|
||||||
if (dns_cache) {
|
|
||||||
return dns_cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
return list_first_entry_or_null(&dns_cache_head.cache_list, struct dns_cache, list);
|
return list_first_entry_or_null(&dns_cache_head.cache_list, struct dns_cache, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +94,7 @@ void dns_cache_release(struct dns_cache *dns_cache)
|
|||||||
if (dns_cache == NULL) {
|
if (dns_cache == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!atomic_dec_and_test(&dns_cache->ref)) {
|
if (!atomic_dec_and_test(&dns_cache->ref)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -128,23 +106,8 @@ static void _dns_cache_remove(struct dns_cache *dns_cache)
|
|||||||
{
|
{
|
||||||
hash_del(&dns_cache->node);
|
hash_del(&dns_cache->node);
|
||||||
list_del_init(&dns_cache->list);
|
list_del_init(&dns_cache->list);
|
||||||
|
dns_timer_del(&dns_cache->timer);
|
||||||
dns_cache_release(dns_cache);
|
dns_cache_release(dns_cache);
|
||||||
|
|
||||||
if (dns_cache == dns_cache_head.last_active_inserted) {
|
|
||||||
dns_cache_release(dns_cache_head.last_active_inserted);
|
|
||||||
dns_cache_head.last_active_inserted = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void _dns_cache_move_inactive(struct dns_cache *dns_cache)
|
|
||||||
{
|
|
||||||
list_del(&dns_cache->list);
|
|
||||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
|
||||||
if (dns_cache == dns_cache_head.last_active_inserted) {
|
|
||||||
dns_cache_release(dns_cache_head.last_active_inserted);
|
|
||||||
dns_cache_head.last_active_inserted = NULL;
|
|
||||||
}
|
|
||||||
time(&dns_cache->info.replace_time);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
enum CACHE_TYPE dns_cache_data_type(struct dns_cache_data *cache_data)
|
||||||
@@ -271,41 +234,33 @@ struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len
|
|||||||
return (struct dns_cache_data *)cache_packet;
|
return (struct dns_cache_data *)cache_packet;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_cache_insert_sorted(struct dns_cache *dns_cache, struct list_head *head)
|
static void dns_cache_timer_relase(struct tw_timer_list *timer, void *data)
|
||||||
{
|
{
|
||||||
time_t ttl;
|
struct dns_cache *dns_cache = data;
|
||||||
struct dns_cache *tmp = NULL;
|
dns_cache_release(dns_cache);
|
||||||
struct list_head *insert_head = head;
|
|
||||||
|
|
||||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl;
|
|
||||||
if (dns_cache_head.last_active_inserted && dns_cache != dns_cache_head.last_active_inserted) {
|
|
||||||
time_t ttl_last =
|
|
||||||
dns_cache_head.last_active_inserted->info.insert_time + dns_cache_head.last_active_inserted->info.ttl;
|
|
||||||
if (ttl == ttl_last) {
|
|
||||||
insert_head = &(dns_cache_head.last_active_inserted->list);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ascending order */
|
|
||||||
list_for_each_entry_reverse(tmp, head, list)
|
|
||||||
{
|
|
||||||
if ((tmp->info.insert_time + tmp->info.ttl) <= ttl) {
|
|
||||||
insert_head = &tmp->list;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
if (dns_cache_head.last_active_inserted) {
|
|
||||||
dns_cache_release(dns_cache_head.last_active_inserted);
|
|
||||||
}
|
|
||||||
list_add(&dns_cache->list, insert_head);
|
|
||||||
dns_cache_head.last_active_inserted = dns_cache;
|
|
||||||
dns_cache_get(dns_cache);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive, int inactive,
|
static void dns_cache_expired(struct tw_timer_list *timer, void *data, unsigned long timestamp)
|
||||||
|
{
|
||||||
|
struct dns_cache *dns_cache = data;
|
||||||
|
|
||||||
|
if (dns_cache->del_pending == 1) {
|
||||||
|
dns_cache_release(dns_cache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dns_cache_head.timeout_callback) {
|
||||||
|
if (dns_cache_head.timeout_callback(dns_cache) != 0) {
|
||||||
|
dns_cache_release(dns_cache);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_cache->del_pending = 1;
|
||||||
|
dns_timer_mod(&dns_cache->timer, 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int timeout, int update_time,
|
||||||
struct dns_cache_data *cache_data)
|
struct dns_cache_data *cache_data)
|
||||||
{
|
{
|
||||||
struct dns_cache *dns_cache = NULL;
|
struct dns_cache *dns_cache = NULL;
|
||||||
@@ -318,7 +273,7 @@ static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int spee
|
|||||||
/* lookup existing cache */
|
/* lookup existing cache */
|
||||||
dns_cache = dns_cache_lookup(cache_key);
|
dns_cache = dns_cache_lookup(cache_key);
|
||||||
if (dns_cache == NULL) {
|
if (dns_cache == NULL) {
|
||||||
return dns_cache_insert(cache_key, ttl, speed, no_inactive, cache_data);
|
return dns_cache_insert(cache_key, ttl, speed, timeout, cache_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ttl < DNS_CACHE_TTL_MIN) {
|
if (ttl < DNS_CACHE_TTL_MIN) {
|
||||||
@@ -333,38 +288,35 @@ static int _dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int spee
|
|||||||
dns_cache->info.query_flag = cache_key->query_flag;
|
dns_cache->info.query_flag = cache_key->query_flag;
|
||||||
dns_cache->info.ttl = ttl;
|
dns_cache->info.ttl = ttl;
|
||||||
dns_cache->info.speed = speed;
|
dns_cache->info.speed = speed;
|
||||||
dns_cache->info.no_inactive = no_inactive;
|
dns_cache->info.timeout = timeout;
|
||||||
dns_cache->info.is_visited = 1;
|
dns_cache->info.is_visited = 1;
|
||||||
old_cache_data = dns_cache->cache_data;
|
if (cache_data) {
|
||||||
dns_cache->cache_data = cache_data;
|
old_cache_data = dns_cache->cache_data;
|
||||||
list_del(&dns_cache->list);
|
dns_cache->cache_data = cache_data;
|
||||||
|
if (old_cache_data == cache_data) {
|
||||||
if (inactive == 0) {
|
old_cache_data = NULL;
|
||||||
time(&dns_cache->info.insert_time);
|
}
|
||||||
time(&dns_cache->info.replace_time);
|
|
||||||
_dns_cache_insert_sorted(dns_cache, &dns_cache_head.cache_list);
|
|
||||||
} else {
|
|
||||||
time(&dns_cache->info.replace_time);
|
|
||||||
list_add_tail(&dns_cache->list, &dns_cache_head.inactive_list);
|
|
||||||
}
|
}
|
||||||
|
if (update_time) {
|
||||||
|
time(&dns_cache->info.insert_time);
|
||||||
|
}
|
||||||
|
time(&dns_cache->info.replace_time);
|
||||||
|
list_del(&dns_cache->list);
|
||||||
|
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||||
|
dns_timer_mod(&dns_cache->timer, timeout);
|
||||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||||
|
|
||||||
dns_cache_data_free(old_cache_data);
|
if (old_cache_data) {
|
||||||
|
dns_cache_data_free(old_cache_data);
|
||||||
|
}
|
||||||
dns_cache_release(dns_cache);
|
dns_cache_release(dns_cache);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive,
|
int dns_cache_replace(struct dns_cache_key *cache_key, int ttl, int speed, int timeout, int update_time,
|
||||||
struct dns_cache_data *cache_data)
|
struct dns_cache_data *cache_data)
|
||||||
{
|
{
|
||||||
return _dns_cache_replace(cache_key, ttl, speed, no_inactive, 0, cache_data);
|
return _dns_cache_replace(cache_key, ttl, speed, timeout, update_time, cache_data);
|
||||||
}
|
|
||||||
|
|
||||||
int dns_cache_replace_inactive(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive,
|
|
||||||
struct dns_cache_data *cache_data)
|
|
||||||
{
|
|
||||||
return _dns_cache_replace(cache_key, ttl, speed, no_inactive, 1, cache_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
static void _dns_cache_remove_by_domain(struct dns_cache_key *cache_key)
|
||||||
@@ -430,24 +382,26 @@ static int _dns_cache_insert(struct dns_cache_info *info, struct dns_cache_data
|
|||||||
memcpy(&dns_cache->info, info, sizeof(*info));
|
memcpy(&dns_cache->info, info, sizeof(*info));
|
||||||
dns_cache->del_pending = 0;
|
dns_cache->del_pending = 0;
|
||||||
dns_cache->cache_data = cache_data;
|
dns_cache->cache_data = cache_data;
|
||||||
|
dns_cache->timer.function = dns_cache_expired;
|
||||||
|
dns_cache->timer.del_function = dns_cache_timer_relase;
|
||||||
|
dns_cache->timer.expires = info->timeout;
|
||||||
|
dns_cache->timer.data = dns_cache;
|
||||||
pthread_mutex_lock(&dns_cache_head.lock);
|
pthread_mutex_lock(&dns_cache_head.lock);
|
||||||
hash_table_add(dns_cache_head.cache_hash, &dns_cache->node, key);
|
hash_table_add(dns_cache_head.cache_hash, &dns_cache->node, key);
|
||||||
if (head == &dns_cache_head.inactive_list) {
|
list_add_tail(&dns_cache->list, head);
|
||||||
list_add_tail(&dns_cache->list, head);
|
|
||||||
} else {
|
|
||||||
_dns_cache_insert_sorted(dns_cache, head);
|
|
||||||
}
|
|
||||||
INIT_LIST_HEAD(&dns_cache->check_list);
|
INIT_LIST_HEAD(&dns_cache->check_list);
|
||||||
|
|
||||||
/* Release extra cache, remove oldest cache record */
|
/* Release extra cache, remove oldest cache record */
|
||||||
if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
|
if (atomic_inc_return(&dns_cache_head.num) > dns_cache_head.size) {
|
||||||
struct dns_cache *del_cache = NULL;
|
struct dns_cache *del_cache = NULL;
|
||||||
del_cache = _dns_inactive_cache_first();
|
del_cache = _dns_cache_first();
|
||||||
if (del_cache) {
|
if (del_cache) {
|
||||||
_dns_cache_remove(del_cache);
|
_dns_cache_remove(del_cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||||
|
dns_cache_get(dns_cache);
|
||||||
|
dns_timer_add(&dns_cache->timer);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
errout:
|
errout:
|
||||||
@@ -458,7 +412,7 @@ errout:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int no_inactive,
|
int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int timeout,
|
||||||
struct dns_cache_data *cache_data)
|
struct dns_cache_data *cache_data)
|
||||||
{
|
{
|
||||||
struct dns_cache_info info;
|
struct dns_cache_info info;
|
||||||
@@ -485,7 +439,7 @@ int dns_cache_insert(struct dns_cache_key *cache_key, int ttl, int speed, int no
|
|||||||
info.ttl = ttl;
|
info.ttl = ttl;
|
||||||
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
info.hitnum_update_add = DNS_CACHE_HITNUM_STEP;
|
||||||
info.speed = speed;
|
info.speed = speed;
|
||||||
info.no_inactive = no_inactive;
|
info.timeout = timeout;
|
||||||
info.is_visited = 1;
|
info.is_visited = 1;
|
||||||
time(&info.insert_time);
|
time(&info.insert_time);
|
||||||
time(&info.replace_time);
|
time(&info.replace_time);
|
||||||
@@ -535,13 +489,7 @@ struct dns_cache *dns_cache_lookup(struct dns_cache_key *cache_key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dns_cache_ret) {
|
if (dns_cache_ret) {
|
||||||
/* Return NULL if the cache times out */
|
dns_cache_get(dns_cache_ret);
|
||||||
if (dns_cache_head.enable_inactive == 0 && (now - dns_cache_ret->info.insert_time > dns_cache_ret->info.ttl)) {
|
|
||||||
_dns_cache_remove(dns_cache_ret);
|
|
||||||
dns_cache_ret = NULL;
|
|
||||||
} else {
|
|
||||||
dns_cache_get(dns_cache_ret);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||||
@@ -638,6 +586,8 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
|||||||
{
|
{
|
||||||
pthread_mutex_lock(&dns_cache_head.lock);
|
pthread_mutex_lock(&dns_cache_head.lock);
|
||||||
if (!list_empty(&dns_cache->list)) {
|
if (!list_empty(&dns_cache->list)) {
|
||||||
|
list_del_init(&dns_cache->list);
|
||||||
|
list_add_tail(&dns_cache->list, &dns_cache_head.cache_list);
|
||||||
dns_cache->info.hitnum += dns_cache->info.hitnum_update_add;
|
dns_cache->info.hitnum += dns_cache->info.hitnum_update_add;
|
||||||
if (dns_cache->info.hitnum > DNS_CACHE_MAX_HITNUM) {
|
if (dns_cache->info.hitnum > DNS_CACHE_MAX_HITNUM) {
|
||||||
dns_cache->info.hitnum = DNS_CACHE_MAX_HITNUM;
|
dns_cache->info.hitnum = DNS_CACHE_MAX_HITNUM;
|
||||||
@@ -651,141 +601,20 @@ void dns_cache_update(struct dns_cache *dns_cache)
|
|||||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
pthread_mutex_unlock(&dns_cache_head.lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_cache_remove_expired_ttl(dns_cache_callback inactive_precallback, int ttl_inactive_pre,
|
|
||||||
unsigned int max_callback_num, const time_t *now)
|
|
||||||
{
|
|
||||||
struct dns_cache *dns_cache = NULL;
|
|
||||||
struct dns_cache *tmp = NULL;
|
|
||||||
unsigned int callback_num = 0;
|
|
||||||
int ttl = 0;
|
|
||||||
LIST_HEAD(checklist);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&dns_cache_head.lock);
|
|
||||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
|
||||||
{
|
|
||||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - *now;
|
|
||||||
if (ttl > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dns_cache_head.inactive_list_expired + ttl < 0) {
|
|
||||||
_dns_cache_remove(dns_cache);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (inactive_precallback == NULL) {
|
|
||||||
if (dns_cache_head.inactive_list_expired + ttl > 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ttl = *now - dns_cache->info.replace_time;
|
|
||||||
if (ttl < ttl_inactive_pre) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callback_num >= max_callback_num) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dns_cache->del_pending == 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
|
||||||
dns_cache_get(dns_cache);
|
|
||||||
list_add_tail(&dns_cache->check_list, &checklist);
|
|
||||||
dns_cache->del_pending = 1;
|
|
||||||
callback_num++;
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
|
||||||
{
|
|
||||||
/* run inactive_precallback */
|
|
||||||
if (inactive_precallback) {
|
|
||||||
inactive_precallback(dns_cache);
|
|
||||||
}
|
|
||||||
dns_cache_release(dns_cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, unsigned int max_callback_num,
|
|
||||||
dns_cache_callback inactive_precallback, int ttl_inactive_pre)
|
|
||||||
{
|
|
||||||
struct dns_cache *dns_cache = NULL;
|
|
||||||
struct dns_cache *tmp = NULL;
|
|
||||||
time_t now = 0;
|
|
||||||
int ttl = 0;
|
|
||||||
LIST_HEAD(checklist);
|
|
||||||
unsigned int callback_num = 0;
|
|
||||||
|
|
||||||
if (max_callback_num <= 0) {
|
|
||||||
max_callback_num = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dns_cache_head.size <= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
time(&now);
|
|
||||||
pthread_mutex_lock(&dns_cache_head.lock);
|
|
||||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
|
||||||
{
|
|
||||||
ttl = dns_cache->info.insert_time + dns_cache->info.ttl - now;
|
|
||||||
if (ttl > ttl_pre) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ttl > 0 && ttl < ttl_pre) {
|
|
||||||
/* If the TTL time is in the pre-timeout range, call callback function */
|
|
||||||
if (precallback && dns_cache->del_pending == 0 && callback_num < max_callback_num) {
|
|
||||||
list_add_tail(&dns_cache->check_list, &checklist);
|
|
||||||
dns_cache_get(dns_cache);
|
|
||||||
dns_cache->del_pending = 1;
|
|
||||||
callback_num++;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ttl <= 0) {
|
|
||||||
if (dns_cache_head.enable_inactive && dns_cache->info.no_inactive == 0) {
|
|
||||||
_dns_cache_move_inactive(dns_cache);
|
|
||||||
} else {
|
|
||||||
_dns_cache_remove(dns_cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pthread_mutex_unlock(&dns_cache_head.lock);
|
|
||||||
|
|
||||||
if (dns_cache_head.enable_inactive && dns_cache_head.inactive_list_expired != 0) {
|
|
||||||
_dns_cache_remove_expired_ttl(inactive_precallback, ttl_inactive_pre, max_callback_num, &now);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry_safe(dns_cache, tmp, &checklist, check_list)
|
|
||||||
{
|
|
||||||
/* run callback */
|
|
||||||
if (precallback) {
|
|
||||||
precallback(dns_cache);
|
|
||||||
}
|
|
||||||
list_del(&dns_cache->check_list);
|
|
||||||
dns_cache_release(dns_cache);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int _dns_cache_read_to_cache(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data)
|
static int _dns_cache_read_to_cache(struct dns_cache_record *cache_record, struct dns_cache_data *cache_data)
|
||||||
{
|
{
|
||||||
struct list_head *head = NULL;
|
struct list_head *head = NULL;
|
||||||
|
head = &dns_cache_head.cache_list;
|
||||||
|
struct dns_cache_info *info = &cache_record->info;
|
||||||
|
|
||||||
if (cache_record->type == CACHE_RECORD_TYPE_ACTIVE) {
|
time_t now = time(NULL);
|
||||||
head = &dns_cache_head.cache_list;
|
unsigned int seed_tmp = now;
|
||||||
} else if (cache_record->type == CACHE_RECORD_TYPE_INACTIVE) {
|
int passed_time = now - info->replace_time;
|
||||||
head = &dns_cache_head.inactive_list;
|
int timeout = info->timeout - passed_time;
|
||||||
} else {
|
if (timeout < DNS_CACHE_READ_TIMEOUT * 2) {
|
||||||
tlog(TLOG_ERROR, "read cache record type is invalid.");
|
timeout = DNS_CACHE_READ_TIMEOUT + (rand_r(&seed_tmp) % DNS_CACHE_READ_TIMEOUT);
|
||||||
goto errout;
|
|
||||||
}
|
}
|
||||||
|
info->timeout = timeout;
|
||||||
|
|
||||||
if (_dns_cache_insert(&cache_record->info, cache_data, head) != 0) {
|
if (_dns_cache_insert(&cache_record->info, cache_data, head) != 0) {
|
||||||
tlog(TLOG_ERROR, "insert cache data failed.");
|
tlog(TLOG_ERROR, "insert cache data failed.");
|
||||||
@@ -854,11 +683,6 @@ static int _dns_cache_read_record(int fd, uint32_t cache_number, dns_cache_read_
|
|||||||
cache_record.info.is_visited = 0;
|
cache_record.info.is_visited = 0;
|
||||||
cache_record.info.domain[DNS_MAX_CNAME_LEN - 1] = '\0';
|
cache_record.info.domain[DNS_MAX_CNAME_LEN - 1] = '\0';
|
||||||
cache_record.info.dns_group_name[DNS_GROUP_NAME_LEN - 1] = '\0';
|
cache_record.info.dns_group_name[DNS_GROUP_NAME_LEN - 1] = '\0';
|
||||||
if (cache_record.type >= CACHE_RECORD_TYPE_END) {
|
|
||||||
tlog(TLOG_ERROR, "read cache record type is invalid.");
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = callback(&cache_record, cache_data);
|
ret = callback(&cache_record, cache_data);
|
||||||
if (ret == -2) {
|
if (ret == -2) {
|
||||||
cache_data = NULL;
|
cache_data = NULL;
|
||||||
@@ -930,7 +754,7 @@ int dns_cache_load(const char *file)
|
|||||||
return _dns_cache_file_read(file, _dns_cache_read_to_cache);
|
return _dns_cache_file_read(file, _dns_cache_read_to_cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RECORD_TYPE type, struct list_head *head)
|
static int _dns_cache_write_record(int fd, uint32_t *cache_number, struct list_head *head)
|
||||||
{
|
{
|
||||||
struct dns_cache *dns_cache = NULL;
|
struct dns_cache *dns_cache = NULL;
|
||||||
struct dns_cache *tmp = NULL;
|
struct dns_cache *tmp = NULL;
|
||||||
@@ -940,7 +764,6 @@ static int _dns_cache_write_record(int fd, uint32_t *cache_number, enum CACHE_RE
|
|||||||
list_for_each_entry_safe(dns_cache, tmp, head, list)
|
list_for_each_entry_safe(dns_cache, tmp, head, list)
|
||||||
{
|
{
|
||||||
cache_record.magic = MAGIC_RECORD;
|
cache_record.magic = MAGIC_RECORD;
|
||||||
cache_record.type = type;
|
|
||||||
memcpy(&cache_record.info, &dns_cache->info, sizeof(struct dns_cache_info));
|
memcpy(&cache_record.info, &dns_cache->info, sizeof(struct dns_cache_info));
|
||||||
ssize_t ret = write(fd, &cache_record, sizeof(cache_record));
|
ssize_t ret = write(fd, &cache_record, sizeof(cache_record));
|
||||||
if (ret != sizeof(cache_record)) {
|
if (ret != sizeof(cache_record)) {
|
||||||
@@ -968,11 +791,7 @@ errout:
|
|||||||
|
|
||||||
static int _dns_cache_write_records(int fd, uint32_t *cache_number)
|
static int _dns_cache_write_records(int fd, uint32_t *cache_number)
|
||||||
{
|
{
|
||||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_ACTIVE, &dns_cache_head.cache_list) != 0) {
|
if (_dns_cache_write_record(fd, cache_number, &dns_cache_head.cache_list) != 0) {
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_dns_cache_write_record(fd, cache_number, CACHE_RECORD_TYPE_INACTIVE, &dns_cache_head.inactive_list) != 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1060,17 +879,7 @@ void dns_cache_destroy(void)
|
|||||||
struct dns_cache *dns_cache = NULL;
|
struct dns_cache *dns_cache = NULL;
|
||||||
struct dns_cache *tmp = NULL;
|
struct dns_cache *tmp = NULL;
|
||||||
|
|
||||||
if (dns_cache_head.last_active_inserted) {
|
|
||||||
dns_cache_release(dns_cache_head.last_active_inserted);
|
|
||||||
dns_cache_head.last_active_inserted = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
pthread_mutex_lock(&dns_cache_head.lock);
|
pthread_mutex_lock(&dns_cache_head.lock);
|
||||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.inactive_list, list)
|
|
||||||
{
|
|
||||||
_dns_cache_delete(dns_cache);
|
|
||||||
}
|
|
||||||
|
|
||||||
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
list_for_each_entry_safe(dns_cache, tmp, &dns_cache_head.cache_list, list)
|
||||||
{
|
{
|
||||||
_dns_cache_delete(dns_cache);
|
_dns_cache_delete(dns_cache);
|
||||||
@@ -1083,6 +892,6 @@ void dns_cache_destroy(void)
|
|||||||
|
|
||||||
const char *dns_cache_file_version(void)
|
const char *dns_cache_file_version(void)
|
||||||
{
|
{
|
||||||
const char *version = "cache ver 1.0";
|
const char *version = "cache ver 1.2";
|
||||||
return version;
|
return version;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
#include "hashtable.h"
|
#include "hashtable.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "timer.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
@@ -45,12 +46,6 @@ enum CACHE_TYPE {
|
|||||||
CACHE_TYPE_PACKET,
|
CACHE_TYPE_PACKET,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum CACHE_RECORD_TYPE {
|
|
||||||
CACHE_RECORD_TYPE_ACTIVE,
|
|
||||||
CACHE_RECORD_TYPE_INACTIVE,
|
|
||||||
CACHE_RECORD_TYPE_END,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct dns_cache_data_head {
|
struct dns_cache_data_head {
|
||||||
enum CACHE_TYPE cache_type;
|
enum CACHE_TYPE cache_type;
|
||||||
int is_soa;
|
int is_soa;
|
||||||
@@ -90,7 +85,7 @@ struct dns_cache_info {
|
|||||||
int ttl;
|
int ttl;
|
||||||
int hitnum;
|
int hitnum;
|
||||||
int speed;
|
int speed;
|
||||||
int no_inactive;
|
int timeout;
|
||||||
int hitnum_update_add;
|
int hitnum_update_add;
|
||||||
int is_visited;
|
int is_visited;
|
||||||
time_t insert_time;
|
time_t insert_time;
|
||||||
@@ -99,7 +94,6 @@ struct dns_cache_info {
|
|||||||
|
|
||||||
struct dns_cache_record {
|
struct dns_cache_record {
|
||||||
uint32_t magic;
|
uint32_t magic;
|
||||||
enum CACHE_RECORD_TYPE type;
|
|
||||||
struct dns_cache_info info;
|
struct dns_cache_info info;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -113,6 +107,8 @@ struct dns_cache {
|
|||||||
|
|
||||||
struct dns_cache_info info;
|
struct dns_cache_info info;
|
||||||
struct dns_cache_data *cache_data;
|
struct dns_cache_data *cache_data;
|
||||||
|
|
||||||
|
struct tw_timer_list timer;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct dns_cache_file {
|
struct dns_cache_file {
|
||||||
@@ -138,15 +134,14 @@ void dns_cache_data_free(struct dns_cache_data *data);
|
|||||||
|
|
||||||
struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len);
|
struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len);
|
||||||
|
|
||||||
int dns_cache_init(int size, int enable_inactive, int inactive_list_expired);
|
typedef int (*dns_cache_callback)(struct dns_cache *dns_cache);
|
||||||
|
|
||||||
int dns_cache_replace(struct dns_cache_key *key, int ttl, int speed, int no_inactive,
|
int dns_cache_init(int size, dns_cache_callback timeout_callback);
|
||||||
|
|
||||||
|
int dns_cache_replace(struct dns_cache_key *key, int ttl, int speed, int tiemout, int update_time,
|
||||||
struct dns_cache_data *cache_data);
|
struct dns_cache_data *cache_data);
|
||||||
|
|
||||||
int dns_cache_replace_inactive(struct dns_cache_key *key, int ttl, int speed, int no_inactive,
|
int dns_cache_insert(struct dns_cache_key *key, int ttl, int speed, int timeout, struct dns_cache_data *cache_data);
|
||||||
struct dns_cache_data *cache_data);
|
|
||||||
|
|
||||||
int dns_cache_insert(struct dns_cache_key *key, int ttl, int speed, int no_inactive, struct dns_cache_data *cache_data);
|
|
||||||
|
|
||||||
struct dns_cache *dns_cache_lookup(struct dns_cache_key *key);
|
struct dns_cache *dns_cache_lookup(struct dns_cache_key *key);
|
||||||
|
|
||||||
@@ -162,11 +157,6 @@ int dns_cache_is_visited(struct dns_cache *dns_cache);
|
|||||||
|
|
||||||
void dns_cache_update(struct dns_cache *dns_cache);
|
void dns_cache_update(struct dns_cache *dns_cache);
|
||||||
|
|
||||||
typedef void dns_cache_callback(struct dns_cache *dns_cache);
|
|
||||||
|
|
||||||
void dns_cache_invalidate(dns_cache_callback precallback, int ttl_pre, unsigned int max_callback_num,
|
|
||||||
dns_cache_callback inactive_precallback, int ttl_inactive_pre);
|
|
||||||
|
|
||||||
int dns_cache_get_ttl(struct dns_cache *dns_cache);
|
int dns_cache_get_ttl(struct dns_cache *dns_cache);
|
||||||
|
|
||||||
int dns_cache_get_cname_ttl(struct dns_cache *dns_cache);
|
int dns_cache_get_cname_ttl(struct dns_cache *dns_cache);
|
||||||
|
|||||||
144
src/dns_server.c
144
src/dns_server.c
@@ -1253,6 +1253,43 @@ static int _dns_reply_inpacket(struct dns_request *request, unsigned char *inpac
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _dns_server_get_cache_timeout(struct dns_request *request, int ttl)
|
||||||
|
{
|
||||||
|
int timeout = 0;
|
||||||
|
if (dns_conf_prefetch) {
|
||||||
|
if (dns_conf_serve_expired) {
|
||||||
|
timeout = dns_conf_serve_expired_prefetch_time;
|
||||||
|
if (timeout == 0) {
|
||||||
|
timeout = dns_conf_serve_expired_ttl / 2;
|
||||||
|
if (timeout == 0 || timeout > EXPIRED_DOMAIN_PREFETCH_TIME) {
|
||||||
|
timeout = EXPIRED_DOMAIN_PREFETCH_TIME;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->prefetch == 0) {
|
||||||
|
timeout += ttl;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeout = ttl - 3;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
timeout = ttl;
|
||||||
|
if (dns_conf_serve_expired) {
|
||||||
|
timeout += dns_conf_serve_expired_ttl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->prefetch) {
|
||||||
|
timeout -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (timeout <= 0) {
|
||||||
|
timeout = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
|
static int _dns_server_request_update_cache(struct dns_request *request, dns_type_t qtype,
|
||||||
struct dns_cache_data *cache_data, int has_soa, int cache_ttl)
|
struct dns_cache_data *cache_data, int has_soa, int cache_ttl)
|
||||||
{
|
{
|
||||||
@@ -1293,18 +1330,13 @@ static int _dns_server_request_update_cache(struct dns_request *request, dns_typ
|
|||||||
cache_key.query_flag = request->server_flags;
|
cache_key.query_flag = request->server_flags;
|
||||||
|
|
||||||
if (request->prefetch) {
|
if (request->prefetch) {
|
||||||
if (request->prefetch_expired_domain == 0) {
|
if (dns_cache_replace(&cache_key, ttl, speed, _dns_server_get_cache_timeout(request, ttl),
|
||||||
if (dns_cache_replace(&cache_key, ttl, speed, request->no_serve_expired, cache_data) != 0) {
|
!request->prefetch_expired_domain, cache_data) != 0) {
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dns_cache_replace_inactive(&cache_key, ttl, speed, request->no_serve_expired, cache_data) != 0) {
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* insert result to cache */
|
/* insert result to cache */
|
||||||
if (dns_cache_insert(&cache_key, ttl, speed, request->no_serve_expired, cache_data) != 0) {
|
if (dns_cache_insert(&cache_key, ttl, speed, _dns_server_get_cache_timeout(request, ttl), cache_data) != 0) {
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1441,18 +1473,13 @@ static int _dns_cache_cname_packet(struct dns_server_post_context *context)
|
|||||||
cache_key.query_flag = request->server_flags;
|
cache_key.query_flag = request->server_flags;
|
||||||
|
|
||||||
if (request->prefetch) {
|
if (request->prefetch) {
|
||||||
if (request->prefetch_expired_domain == 0) {
|
if (dns_cache_replace(&cache_key, ttl, speed, _dns_server_get_cache_timeout(request, ttl),
|
||||||
if (dns_cache_replace(&cache_key, ttl, speed, request->no_serve_expired, cache_packet) != 0) {
|
!request->prefetch_expired_domain, cache_packet) != 0) {
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (dns_cache_replace_inactive(&cache_key, ttl, speed, request->no_serve_expired, cache_packet) != 0) {
|
|
||||||
goto errout;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* insert result to cache */
|
/* insert result to cache */
|
||||||
if (dns_cache_insert(&cache_key, ttl, speed, request->no_serve_expired, cache_packet) != 0) {
|
if (dns_cache_insert(&cache_key, ttl, speed, _dns_server_get_cache_timeout(request, ttl), cache_packet) != 0) {
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1484,12 +1511,15 @@ static int _dns_cache_packet(struct dns_server_post_context *context)
|
|||||||
cache_key.query_flag = request->server_flags;
|
cache_key.query_flag = request->server_flags;
|
||||||
|
|
||||||
if (request->prefetch) {
|
if (request->prefetch) {
|
||||||
if (dns_cache_replace(&cache_key, context->reply_ttl, -1, request->no_serve_expired, cache_packet) != 0) {
|
if (dns_cache_replace(&cache_key, context->reply_ttl, -1,
|
||||||
|
_dns_server_get_cache_timeout(request, context->reply_ttl),
|
||||||
|
!request->prefetch_expired_domain, cache_packet) != 0) {
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* insert result to cache */
|
/* insert result to cache */
|
||||||
if (dns_cache_insert(&cache_key, context->reply_ttl, -1, request->no_serve_expired, cache_packet) != 0) {
|
if (dns_cache_insert(&cache_key, context->reply_ttl, -1,
|
||||||
|
_dns_server_get_cache_timeout(request, context->reply_ttl), cache_packet) != 0) {
|
||||||
goto errout;
|
goto errout;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3061,9 +3091,9 @@ static int _dns_server_process_answer_AAAA(struct dns_rrs *rrs, struct dns_reque
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(ip, sizeof(ip), "[%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x]", paddr[0], paddr[1],
|
snprintf(ip, sizeof(ip), "[%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x]", paddr[0],
|
||||||
paddr[2], paddr[3], paddr[4], paddr[5], paddr[6], paddr[7], paddr[8], paddr[9], paddr[10], paddr[11],
|
paddr[1], paddr[2], paddr[3], paddr[4], paddr[5], paddr[6], paddr[7], paddr[8], paddr[9], paddr[10],
|
||||||
paddr[12], paddr[13], paddr[14], paddr[15]);
|
paddr[11], paddr[12], paddr[13], paddr[14], paddr[15]);
|
||||||
|
|
||||||
/* start ping */
|
/* start ping */
|
||||||
_dns_server_request_get(request);
|
_dns_server_request_get(request);
|
||||||
@@ -6450,13 +6480,13 @@ static int _dns_server_second_ping_check(struct dns_request *request)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
static int _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
||||||
{
|
{
|
||||||
/* If there are still hits, continue pre-fetching */
|
/* If there are still hits, continue pre-fetching */
|
||||||
struct dns_server_query_option server_query_option;
|
struct dns_server_query_option server_query_option;
|
||||||
int hitnum = dns_cache_hitnum_dec_get(dns_cache);
|
int hitnum = dns_cache_hitnum_dec_get(dns_cache);
|
||||||
if (hitnum <= 0) {
|
if (hitnum <= 0) {
|
||||||
return;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* start prefetch domain */
|
/* start prefetch domain */
|
||||||
@@ -6467,11 +6497,19 @@ static void _dns_server_prefetch_domain(struct dns_cache *dns_cache)
|
|||||||
server_query_option.ecs_enable_flag = 0;
|
server_query_option.ecs_enable_flag = 0;
|
||||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0, &server_query_option) != 0) {
|
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 0, &server_query_option) != 0) {
|
||||||
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
|
static int _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
|
||||||
{
|
{
|
||||||
|
time_t ttl = dns_cache->info.insert_time + dns_cache->info.ttl + dns_conf_serve_expired_ttl - time(NULL);
|
||||||
|
if (ttl < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* start prefetch domain */
|
/* start prefetch domain */
|
||||||
tlog(TLOG_DEBUG, "expired domain, prefetch by cache %s, qtype %d, ttl %d", dns_cache->info.domain,
|
tlog(TLOG_DEBUG, "expired domain, prefetch by cache %s, qtype %d, ttl %d", dns_cache->info.domain,
|
||||||
dns_cache->info.qtype, dns_cache->info.ttl);
|
dns_cache->info.qtype, dns_cache->info.ttl);
|
||||||
@@ -6483,7 +6521,23 @@ static void _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
|
|||||||
|
|
||||||
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1, &server_query_option) != 0) {
|
if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, 1, &server_query_option) != 0) {
|
||||||
tlog(TLOG_DEBUG, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
tlog(TLOG_DEBUG, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _dns_server_cache_expired(struct dns_cache *dns_cache)
|
||||||
|
{
|
||||||
|
if (dns_conf_prefetch == 1) {
|
||||||
|
if (dns_conf_serve_expired == 1) {
|
||||||
|
return _dns_server_prefetch_expired_domain(dns_cache);
|
||||||
|
} else {
|
||||||
|
return _dns_server_prefetch_domain(dns_cache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _dns_server_tcp_idle_check(void)
|
static void _dns_server_tcp_idle_check(void)
|
||||||
@@ -6592,44 +6646,8 @@ static void _dns_server_save_cache_to_file(void)
|
|||||||
static void _dns_server_period_run_second(void)
|
static void _dns_server_period_run_second(void)
|
||||||
{
|
{
|
||||||
static unsigned int sec = 0;
|
static unsigned int sec = 0;
|
||||||
static time_t last = 0;
|
|
||||||
time_t now = 0;
|
|
||||||
sec++;
|
sec++;
|
||||||
|
|
||||||
time(&now);
|
|
||||||
if (last == 0) {
|
|
||||||
last = now;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (now - 180 > last) {
|
|
||||||
dns_cache_invalidate(NULL, 0, 0, NULL, 0);
|
|
||||||
tlog(TLOG_WARN, "Service paused for 180s, force invalidate cache.");
|
|
||||||
}
|
|
||||||
|
|
||||||
last = now;
|
|
||||||
|
|
||||||
if (sec % 2 == 0) {
|
|
||||||
if (dns_conf_prefetch) {
|
|
||||||
/* do pre-fetching */
|
|
||||||
if (dns_conf_serve_expired) {
|
|
||||||
int prefetch_time = dns_conf_serve_expired_prefetch_time;
|
|
||||||
|
|
||||||
if (prefetch_time == 0) {
|
|
||||||
prefetch_time = dns_conf_serve_expired_ttl / 2;
|
|
||||||
if (prefetch_time == 0 || prefetch_time > EXPIRED_DOMAIN_PREFETCH_TIME) {
|
|
||||||
prefetch_time = EXPIRED_DOMAIN_PREFETCH_TIME;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dns_cache_invalidate(NULL, 0, DNS_MAX_DOMAIN_REFETCH_NUM, _dns_server_prefetch_expired_domain,
|
|
||||||
prefetch_time);
|
|
||||||
} else {
|
|
||||||
dns_cache_invalidate(_dns_server_prefetch_domain, 3, DNS_MAX_DOMAIN_REFETCH_NUM, NULL, 0);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dns_cache_invalidate(NULL, 0, 0, NULL, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_dns_server_tcp_idle_check();
|
_dns_server_tcp_idle_check();
|
||||||
_dns_server_check_need_exit();
|
_dns_server_check_need_exit();
|
||||||
|
|
||||||
@@ -7212,7 +7230,7 @@ static int _dns_server_audit_init(void)
|
|||||||
|
|
||||||
static int _dns_server_cache_init(void)
|
static int _dns_server_cache_init(void)
|
||||||
{
|
{
|
||||||
if (dns_cache_init(dns_conf_cachesize, dns_conf_serve_expired, dns_conf_serve_expired_ttl) != 0) {
|
if (dns_cache_init(dns_conf_cachesize, _dns_server_cache_expired) != 0) {
|
||||||
tlog(TLOG_ERROR, "init cache failed.");
|
tlog(TLOG_ERROR, "init cache failed.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|||||||
50
src/include/timer_wheel.h
Normal file
50
src/include/timer_wheel.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||||
|
*
|
||||||
|
* smartdns is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* smartdns is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __TIMER_WHEEL_H
|
||||||
|
#define __TIMER_WHEEL_H
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
struct tw_base;
|
||||||
|
struct tw_timer_list;
|
||||||
|
|
||||||
|
typedef void (*tw_func)(struct tw_timer_list *, void *, unsigned long);
|
||||||
|
typedef void (*tw_del_func)(struct tw_timer_list *, void *);
|
||||||
|
|
||||||
|
struct tw_timer_list {
|
||||||
|
void *data;
|
||||||
|
unsigned long expires;
|
||||||
|
tw_func function;
|
||||||
|
tw_del_func del_function;
|
||||||
|
struct list_head entry;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tw_base *tw_init_timers(void);
|
||||||
|
|
||||||
|
int tw_cleanup_timers(struct tw_base *);
|
||||||
|
|
||||||
|
void tw_add_timer(struct tw_base *, struct tw_timer_list *);
|
||||||
|
|
||||||
|
int tw_del_timer(struct tw_base *, struct tw_timer_list *);
|
||||||
|
|
||||||
|
int tw_mod_timer_pending(struct tw_base *, struct tw_timer_list *, unsigned long);
|
||||||
|
|
||||||
|
int tw_mod_timer(struct tw_base *, struct tw_timer_list *, unsigned long);
|
||||||
|
|
||||||
|
#endif
|
||||||
419
src/lib/timer_wheel.c
Normal file
419
src/lib/timer_wheel.c
Normal file
@@ -0,0 +1,419 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||||
|
*
|
||||||
|
* smartdns is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* smartdns is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "bitops.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/select.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "timer_wheel.h"
|
||||||
|
|
||||||
|
#define TVR_BITS 8
|
||||||
|
#define TVN_BITS 6
|
||||||
|
#define TVR_SIZE (1 << TVR_BITS)
|
||||||
|
#define TVN_SIZE (1 << TVN_BITS)
|
||||||
|
#define TVR_MASK (TVR_SIZE - 1)
|
||||||
|
#define TVN_MASK (TVN_SIZE - 1)
|
||||||
|
#define INDEX(N) ((base->jiffies >> (TVR_BITS + N * TVN_BITS)) & TVN_MASK)
|
||||||
|
|
||||||
|
struct tvec {
|
||||||
|
struct list_head vec[TVN_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tvec_root {
|
||||||
|
struct list_head vec[TVR_SIZE];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tw_base {
|
||||||
|
pthread_spinlock_t lock;
|
||||||
|
|
||||||
|
pthread_t runner;
|
||||||
|
|
||||||
|
unsigned long jiffies;
|
||||||
|
|
||||||
|
struct tvec_root tv1;
|
||||||
|
struct tvec tv2;
|
||||||
|
struct tvec tv3;
|
||||||
|
struct tvec tv4;
|
||||||
|
struct tvec tv5;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void _tw_add_timer(struct tw_base *base, struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long idx;
|
||||||
|
unsigned long expires;
|
||||||
|
struct list_head *vec;
|
||||||
|
|
||||||
|
expires = timer->expires;
|
||||||
|
|
||||||
|
idx = expires - base->jiffies;
|
||||||
|
|
||||||
|
if (idx < TVR_SIZE) {
|
||||||
|
i = expires & TVR_MASK;
|
||||||
|
vec = base->tv1.vec + i;
|
||||||
|
} else if (idx < 1 << (TVR_BITS + TVN_BITS)) {
|
||||||
|
i = (expires >> TVR_BITS) & TVN_MASK;
|
||||||
|
vec = base->tv2.vec + i;
|
||||||
|
} else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS)) {
|
||||||
|
i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
|
||||||
|
vec = base->tv3.vec + i;
|
||||||
|
} else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS)) {
|
||||||
|
i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
|
||||||
|
vec = base->tv4.vec + i;
|
||||||
|
} else if ((long)idx < 0) {
|
||||||
|
vec = base->tv1.vec + (base->jiffies & TVR_MASK);
|
||||||
|
} else {
|
||||||
|
i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
|
||||||
|
vec = base->tv5.vec + i;
|
||||||
|
}
|
||||||
|
|
||||||
|
list_add_tail(&timer->entry, vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned long _apply_slack(struct tw_base *base, struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
long delta;
|
||||||
|
unsigned long mask, expires, expires_limit;
|
||||||
|
|
||||||
|
expires = timer->expires;
|
||||||
|
|
||||||
|
delta = expires - base->jiffies;
|
||||||
|
if (delta < 256) {
|
||||||
|
return expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
expires_limit = expires + delta / 256;
|
||||||
|
mask = expires ^ expires_limit;
|
||||||
|
if (mask == 0) {
|
||||||
|
return expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bit = fls_long(mask);
|
||||||
|
mask = (1UL << bit) - 1;
|
||||||
|
|
||||||
|
expires_limit = expires_limit & ~(mask);
|
||||||
|
return expires_limit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void _tw_detach_timer(struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
struct list_head *entry = &timer->entry;
|
||||||
|
|
||||||
|
list_del(entry);
|
||||||
|
entry->next = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int _tw_cascade(struct tw_base *base, struct tvec *tv, int index)
|
||||||
|
{
|
||||||
|
struct tw_timer_list *timer, *tmp;
|
||||||
|
struct list_head tv_list;
|
||||||
|
|
||||||
|
list_replace_init(tv->vec + index, &tv_list);
|
||||||
|
|
||||||
|
list_for_each_entry_safe(timer, tmp, &tv_list, entry)
|
||||||
|
{
|
||||||
|
_tw_add_timer(base, timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int timer_pending(struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
struct list_head *entry = &timer->entry;
|
||||||
|
|
||||||
|
return (entry->next != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __detach_if_pending(struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
if (!timer_pending(timer)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_tw_detach_timer(timer);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __mod_timer(struct tw_base *base, struct tw_timer_list *timer, int pending_only)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = __detach_if_pending(timer);
|
||||||
|
if (!ret && pending_only) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
_tw_add_timer(base, timer);
|
||||||
|
|
||||||
|
done:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tw_add_timer(struct tw_base *base, struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
if (timer->function == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
{
|
||||||
|
timer->expires += base->jiffies;
|
||||||
|
timer->expires = _apply_slack(base, timer);
|
||||||
|
_tw_add_timer(base, timer);
|
||||||
|
}
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
int tw_del_timer(struct tw_base *base, struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
{
|
||||||
|
if (timer_pending(timer)) {
|
||||||
|
ret = 1;
|
||||||
|
_tw_detach_timer(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
|
||||||
|
if (ret == 1 && timer->del_function) {
|
||||||
|
timer->del_function(timer, timer->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tw_mod_timer_pending(struct tw_base *base, struct tw_timer_list *timer, unsigned long expires)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
{
|
||||||
|
timer->expires = expires + base->jiffies;
|
||||||
|
timer->expires = _apply_slack(base, timer);
|
||||||
|
|
||||||
|
ret = __mod_timer(base, timer, 1);
|
||||||
|
}
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tw_mod_timer(struct tw_base *base, struct tw_timer_list *timer, unsigned long expires)
|
||||||
|
{
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
{
|
||||||
|
if (timer_pending(timer) && timer->expires == expires) {
|
||||||
|
goto unblock;
|
||||||
|
}
|
||||||
|
|
||||||
|
timer->expires = expires + base->jiffies;
|
||||||
|
timer->expires = _apply_slack(base, timer);
|
||||||
|
|
||||||
|
ret = __mod_timer(base, timer, 0);
|
||||||
|
}
|
||||||
|
unblock:
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tw_cleanup_timers(struct tw_base *base)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
void *res = NULL;
|
||||||
|
|
||||||
|
ret = pthread_cancel(base->runner);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
ret = pthread_join(base->runner, &res);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
if (res != PTHREAD_CANCELED) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pthread_spin_destroy(&base->lock);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(base);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
errout:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void run_timers(struct tw_base *base)
|
||||||
|
{
|
||||||
|
unsigned long index, call_time;
|
||||||
|
struct tw_timer_list *timer;
|
||||||
|
|
||||||
|
struct list_head work_list;
|
||||||
|
struct list_head *head = &work_list;
|
||||||
|
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
{
|
||||||
|
index = base->jiffies & TVR_MASK;
|
||||||
|
|
||||||
|
if (!index && (!_tw_cascade(base, &base->tv2, INDEX(0))) && (!_tw_cascade(base, &base->tv3, INDEX(1))) &&
|
||||||
|
(!_tw_cascade(base, &base->tv4, INDEX(2))))
|
||||||
|
_tw_cascade(base, &base->tv5, INDEX(3));
|
||||||
|
|
||||||
|
call_time = base->jiffies++;
|
||||||
|
list_replace_init(base->tv1.vec + index, head);
|
||||||
|
while (!list_empty(head)) {
|
||||||
|
tw_func fn;
|
||||||
|
void *data;
|
||||||
|
|
||||||
|
timer = list_first_entry(head, struct tw_timer_list, entry);
|
||||||
|
fn = timer->function;
|
||||||
|
data = timer->data;
|
||||||
|
|
||||||
|
_tw_detach_timer(timer);
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
{
|
||||||
|
fn(timer, data, call_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
if ( (timer_pending(timer) == 0 && timer->del_function) ) {
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
timer->del_function(timer, timer->data);
|
||||||
|
pthread_spin_lock(&base->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pthread_spin_unlock(&base->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned long _tw_tick_count(void)
|
||||||
|
{
|
||||||
|
struct timespec ts;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
|
|
||||||
|
return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *timer_work(void *arg)
|
||||||
|
{
|
||||||
|
struct tw_base *base = arg;
|
||||||
|
int sleep = 1000;
|
||||||
|
int sleep_time = 0;
|
||||||
|
unsigned long now = {0};
|
||||||
|
unsigned long last = {0};
|
||||||
|
unsigned long expect_time = 0;
|
||||||
|
|
||||||
|
sleep_time = sleep;
|
||||||
|
now = _tw_tick_count() - sleep;
|
||||||
|
last = now;
|
||||||
|
expect_time = now + sleep;
|
||||||
|
while (1) {
|
||||||
|
run_timers(base);
|
||||||
|
|
||||||
|
now = _tw_tick_count();
|
||||||
|
if (sleep_time > 0) {
|
||||||
|
sleep_time -= now - last;
|
||||||
|
if (sleep_time <= 0) {
|
||||||
|
sleep_time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cnt = sleep_time / sleep;
|
||||||
|
expect_time -= cnt * sleep;
|
||||||
|
sleep_time -= cnt * sleep;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (now >= expect_time) {
|
||||||
|
sleep_time = sleep - (now - expect_time);
|
||||||
|
if (sleep_time < 0) {
|
||||||
|
sleep_time = 0;
|
||||||
|
expect_time = now;
|
||||||
|
}
|
||||||
|
expect_time += sleep;
|
||||||
|
}
|
||||||
|
last = now;
|
||||||
|
|
||||||
|
usleep(sleep_time * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct tw_base *tw_init_timers(void)
|
||||||
|
{
|
||||||
|
int j = 0;
|
||||||
|
int ret = 0;
|
||||||
|
struct timeval tv = {
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
struct tw_base *base = NULL;
|
||||||
|
|
||||||
|
base = malloc(sizeof(*base));
|
||||||
|
if (!base) {
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pthread_spin_init(&base->lock, 0);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto errout2;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < TVN_SIZE; j++) {
|
||||||
|
INIT_LIST_HEAD(base->tv5.vec + j);
|
||||||
|
INIT_LIST_HEAD(base->tv4.vec + j);
|
||||||
|
INIT_LIST_HEAD(base->tv3.vec + j);
|
||||||
|
INIT_LIST_HEAD(base->tv2.vec + j);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (j = 0; j < TVR_SIZE; j++) {
|
||||||
|
INIT_LIST_HEAD(base->tv1.vec + j);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = gettimeofday(&tv, 0);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto errout1;
|
||||||
|
}
|
||||||
|
base->jiffies = tv.tv_sec;
|
||||||
|
|
||||||
|
ret = pthread_create(&base->runner, NULL, timer_work, base);
|
||||||
|
if (ret != 0) {
|
||||||
|
goto errout1;
|
||||||
|
}
|
||||||
|
return base;
|
||||||
|
|
||||||
|
errout1:
|
||||||
|
(void)pthread_spin_destroy(&base->lock);
|
||||||
|
errout2:
|
||||||
|
free(base);
|
||||||
|
errout:
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "rbtree.h"
|
#include "rbtree.h"
|
||||||
#include "tlog.h"
|
#include "tlog.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "timer.h"
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
@@ -486,6 +487,11 @@ static int _smartdns_init(void)
|
|||||||
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build: %s %s)", __DATE__,
|
tlog(TLOG_NOTICE, "smartdns starting...(Copyright (C) Nick Peng <pymumu@gmail.com>, build: %s %s)", __DATE__,
|
||||||
__TIME__);
|
__TIME__);
|
||||||
|
|
||||||
|
if (dns_timer_init() != 0) {
|
||||||
|
tlog(TLOG_ERROR, "init timer failed.");
|
||||||
|
goto errout;
|
||||||
|
}
|
||||||
|
|
||||||
if (_smartdns_init_ssl() != 0) {
|
if (_smartdns_init_ssl() != 0) {
|
||||||
tlog(TLOG_ERROR, "init ssl failed.");
|
tlog(TLOG_ERROR, "init ssl failed.");
|
||||||
goto errout;
|
goto errout;
|
||||||
@@ -573,6 +579,7 @@ static void _smartdns_exit(void)
|
|||||||
fast_ping_exit();
|
fast_ping_exit();
|
||||||
dns_server_exit();
|
dns_server_exit();
|
||||||
_smartdns_destroy_ssl();
|
_smartdns_destroy_ssl();
|
||||||
|
dns_timer_destroy();
|
||||||
tlog_exit();
|
tlog_exit();
|
||||||
dns_server_load_exit();
|
dns_server_load_exit();
|
||||||
}
|
}
|
||||||
|
|||||||
70
src/timer.c
Normal file
70
src/timer.c
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||||
|
*
|
||||||
|
* smartdns is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* smartdns is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "timer.h"
|
||||||
|
#include "timer_wheel.h"
|
||||||
|
|
||||||
|
static struct tw_base *dns_timer_base = NULL;
|
||||||
|
|
||||||
|
int dns_timer_init(void)
|
||||||
|
{
|
||||||
|
struct tw_base *tw = tw_init_timers();
|
||||||
|
if (tw == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dns_timer_base = tw;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_timer_destroy(void)
|
||||||
|
{
|
||||||
|
if (dns_timer_base != NULL) {
|
||||||
|
tw_cleanup_timers(dns_timer_base);
|
||||||
|
dns_timer_base = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void dns_timer_add(struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
if (dns_timer_base == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tw_add_timer(dns_timer_base, timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_timer_del(struct tw_timer_list *timer)
|
||||||
|
{
|
||||||
|
if (dns_timer_base == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tw_del_timer(dns_timer_base, timer);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dns_timer_mod(struct tw_timer_list *timer, unsigned long expires)
|
||||||
|
{
|
||||||
|
if (dns_timer_base == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tw_mod_timer(dns_timer_base, timer, expires);
|
||||||
|
}
|
||||||
|
|
||||||
41
src/timer.h
Normal file
41
src/timer.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*************************************************************************
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018-2023 Ruilin Peng (Nick) <pymumu@gmail.com>.
|
||||||
|
*
|
||||||
|
* smartdns is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* smartdns is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SMART_DNS_TIMER_H
|
||||||
|
#define SMART_DNS_TIMER_H
|
||||||
|
|
||||||
|
#include "timer_wheel.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif /*__cplusplus */
|
||||||
|
|
||||||
|
int dns_timer_init(void);
|
||||||
|
|
||||||
|
void dns_timer_add(struct tw_timer_list *timer);
|
||||||
|
|
||||||
|
int dns_timer_del(struct tw_timer_list *timer);
|
||||||
|
|
||||||
|
int dns_timer_mod(struct tw_timer_list *timer, unsigned long expires);
|
||||||
|
|
||||||
|
void dns_timer_destroy(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif /*__cplusplus */
|
||||||
|
#endif
|
||||||
@@ -23,8 +23,8 @@ CXXFLAGS += -g
|
|||||||
CXXFLAGS += -DTEST
|
CXXFLAGS += -DTEST
|
||||||
CXXFLAGS += -I./ -I../src -I../src/include
|
CXXFLAGS += -I./ -I../src -I../src/include
|
||||||
|
|
||||||
SMARTDNS_OBJS = lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o
|
SMARTDNS_OBJS = lib/rbtree.o lib/art.o lib/bitops.o lib/radix.o lib/conf.o lib/nftset.o lib/timer_wheel.o
|
||||||
SMARTDNS_OBJS += smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o
|
SMARTDNS_OBJS += smartdns.o fast_ping.o dns_client.o dns_server.o dns.o util.o tlog.o dns_conf.o dns_cache.o http_parse.o proxy.o timer.o
|
||||||
OBJS = $(addprefix ../src/, $(SMARTDNS_OBJS))
|
OBJS = $(addprefix ../src/, $(SMARTDNS_OBJS))
|
||||||
|
|
||||||
TEST_SOURCES := $(wildcard *.cc) $(wildcard */*.cc) $(wildcard */*/*.cc)
|
TEST_SOURCES := $(wildcard *.cc) $(wildcard */*.cc) $(wildcard */*/*.cc)
|
||||||
|
|||||||
Reference in New Issue
Block a user