Selaa lähdekoodia

dns_cache: Fix several issues related to cache memory.

Nick Peng 1 vuosi sitten
vanhempi
sitoutus
7997300781

+ 2 - 2
package/luci-compat/files/luci/model/cbi/smartdns/smartdns.lua

@@ -135,7 +135,7 @@ o = s:taboption("advanced", Flag, "tls_server", translate("DOT Server"), transla
 o.rmempty = false
 o.default = o.disabled
 o.cfgvalue    = function(...)
-    return Flag.cfgvalue(...) or "1"
+    return Flag.cfgvalue(...) or "0"
 end
 
 o = s:taboption("advanced", Value, "tls_server_port", translate("DOT Server Port"), translate("Smartdns DOT server port."))
@@ -150,7 +150,7 @@ o = s:taboption("advanced", Flag, "doh_server", translate("DOH Server"), transla
 o.rmempty = false
 o.default = o.disabled
 o.cfgvalue    = function(...)
-    return Flag.cfgvalue(...) or "1"
+    return Flag.cfgvalue(...) or "0"
 end
 
 o = s:taboption("advanced", Value, "doh_server_port", translate("DOH Server Port"), translate("Smartdns DOH server port."))

+ 34 - 1
src/dns_cache.c

@@ -32,6 +32,7 @@
 #define DNS_CACHE_HITNUM_STEP 3
 #define DNS_CACHE_HITNUM_STEP_MAX 6
 #define DNS_CACHE_READ_TIMEOUT 60
+#define DNS_CACHE_FAIL_TIMEOUT (60 * 5)
 #define EXPIRED_DOMAIN_PREFETCH_TIME (3600 * 8)
 
 struct dns_cache_head {
@@ -168,9 +169,18 @@ static void dns_cache_expired(struct tw_base *base, struct tw_timer_list *timer,
 	}
 
 	if (dns_cache_head.timeout_callback) {
-		if (dns_cache_head.timeout_callback(dns_cache) != 0) {
+		dns_cache_tmout_action_t tmout_act = dns_cache_head.timeout_callback(dns_cache);
+		switch (tmout_act) {
+		case DNS_CACHE_TMOUT_ACTION_OK:
+			break;
+		case DNS_CACHE_TMOUT_ACTION_DEL:
 			dns_cache_release(dns_cache);
 			return;
+		case DNS_CACHE_TMOUT_ACTION_RETRY:
+			dns_timer_mod(&dns_cache->timer, DNS_CACHE_FAIL_TIMEOUT);
+			return;
+		default:
+			break;
 		}
 	}
 
@@ -201,6 +211,7 @@ static int _dns_cache_replace(struct dns_cache_key *cache_key, int rcode, int tt
 	/* update cache data */
 	pthread_mutex_lock(&dns_cache_head.lock);
 	dns_cache->del_pending = 0;
+	dns_cache->info.rcode = rcode;
 	dns_cache->info.qtype = cache_key->qtype;
 	dns_cache->info.query_flag = cache_key->query_flag;
 	dns_cache->info.ttl = ttl;
@@ -364,6 +375,23 @@ int dns_cache_insert(struct dns_cache_key *cache_key, int rcode, int ttl, int sp
 	return _dns_cache_insert(&info, cache_data, &dns_cache_head.cache_list, timeout);
 }
 
+int dns_cache_update_timer(struct dns_cache_key *key, int timeout)
+{
+	struct dns_cache *dns_cache = dns_cache_lookup(key);
+	if (dns_cache == NULL) {
+		return -1;
+	}
+
+	pthread_mutex_lock(&dns_cache_head.lock);
+	dns_timer_mod(&dns_cache->timer, timeout);
+	dns_cache->del_pending = 0;
+	pthread_mutex_unlock(&dns_cache_head.lock);
+
+	dns_cache_release(dns_cache);
+
+	return 0;
+}
+
 struct dns_cache *dns_cache_lookup(struct dns_cache_key *cache_key)
 {
 	uint32_t key = 0;
@@ -466,6 +494,11 @@ int dns_cache_is_visited(struct dns_cache *dns_cache)
 	return dns_cache->info.is_visited;
 }
 
+int dns_cache_total_num(void)
+{
+	return atomic_read(&dns_cache_head.num);
+}
+
 void dns_cache_delete(struct dns_cache *dns_cache)
 {
 	pthread_mutex_lock(&dns_cache_head.lock);

+ 11 - 1
src/dns_cache.h

@@ -124,7 +124,13 @@ const char *dns_cache_get_dns_group_name(struct dns_cache *dns_cache);
 
 struct dns_cache_data *dns_cache_new_data_packet(void *packet, size_t packet_len);
 
-typedef int (*dns_cache_callback)(struct dns_cache *dns_cache);
+typedef enum DNS_CACHE_TMOUT_ACTION {
+	DNS_CACHE_TMOUT_ACTION_OK = 0,
+	DNS_CACHE_TMOUT_ACTION_DEL = 1,
+	DNS_CACHE_TMOUT_ACTION_RETRY = 2,
+} dns_cache_tmout_action_t;
+
+typedef dns_cache_tmout_action_t (*dns_cache_callback)(struct dns_cache *dns_cache);
 
 int dns_cache_init(int size, dns_cache_callback timeout_callback);
 
@@ -136,6 +142,10 @@ int dns_cache_insert(struct dns_cache_key *key, int rcode, int ttl, int speed, i
 
 struct dns_cache *dns_cache_lookup(struct dns_cache_key *key);
 
+int dns_cache_total_num(void);
+
+int dns_cache_update_timer(struct dns_cache_key *key, int timeout);
+
 void dns_cache_delete(struct dns_cache *dns_cache);
 
 void dns_cache_get(struct dns_cache *dns_cache);

+ 34 - 17
src/dns_server.c

@@ -1012,7 +1012,8 @@ static int _dns_add_rrs(struct dns_server_post_context *context)
 	}
 
 	if (request->rcode != DNS_RC_NOERROR) {
-		tlog(TLOG_INFO, "result: %s, qtype: %d, rtcode: %d", domain, context->qtype, request->rcode);
+		tlog(TLOG_INFO, "result: %s, qtype: %d, rtcode: %d, id: %d", domain, context->qtype, request->rcode,
+			 request->id);
 	}
 
 	return ret;
@@ -1694,6 +1695,16 @@ static int _dns_cache_specify_packet(struct dns_server_post_context *context)
 	return _dns_cache_packet(context);
 }
 
+static int _dns_cache_try_keep_old_cache(struct dns_request *request)
+{
+	struct dns_cache_key cache_key;
+	cache_key.dns_group_name = request->dns_group_name;
+	cache_key.domain = request->domain;
+	cache_key.qtype = request->qtype;
+	cache_key.query_flag = request->server_flags;
+	return dns_cache_update_timer(&cache_key, DNS_SERVER_TMOUT_TTL);
+}
+
 static int _dns_cache_reply_packet(struct dns_server_post_context *context)
 {
 	struct dns_request *request = context->request;
@@ -1707,6 +1718,8 @@ static int _dns_cache_reply_packet(struct dns_server_post_context *context)
 		context->reply_ttl = DNS_SERVER_FAIL_TTL;
 		/* Do not cache record if cannot connect to remote */
 		if (request->remote_server_fail == 0 && context->packet->head.rcode == DNS_RC_SERVFAIL) {
+			/* Try keep old cache if server fail */
+			_dns_cache_try_keep_old_cache(request);
 			return 0;
 		}
 
@@ -3712,8 +3725,9 @@ static int dns_server_resolve_callback(const char *domain, dns_result_type rtype
 	}
 
 	if (rtype == DNS_QUERY_RESULT) {
-		tlog(TLOG_DEBUG, "query result from server %s:%d, type: %d", dns_client_get_server_ip(server_info),
-			 dns_client_get_server_port(server_info), dns_client_get_server_type(server_info));
+		tlog(TLOG_DEBUG, "query result from server %s:%d, type: %d, rcode: %d, id: %d",
+			 dns_client_get_server_ip(server_info), dns_client_get_server_port(server_info),
+			 dns_client_get_server_type(server_info), packet->head.rcode, request->id);
 
 		if (request->passthrough == 1 && atomic_read(&request->notified) == 0) {
 			struct dns_server_post_context context;
@@ -6663,13 +6677,13 @@ static int _dns_server_second_ping_check(struct dns_request *request)
 	return ret;
 }
 
-static int _dns_server_prefetch_domain(struct dns_cache *dns_cache)
+static dns_cache_tmout_action_t _dns_server_prefetch_domain(struct dns_cache *dns_cache)
 {
 	/* If there are still hits, continue pre-fetching */
 	struct dns_server_query_option server_query_option;
 	int hitnum = dns_cache_hitnum_dec_get(dns_cache);
 	if (hitnum <= 0) {
-		return -1;
+		return DNS_CACHE_TMOUT_ACTION_DEL;
 	}
 
 	/* start prefetch domain */
@@ -6681,23 +6695,26 @@ static int _dns_server_prefetch_domain(struct dns_cache *dns_cache)
 	if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, &server_query_option,
 									 PREFETCH_FLAGS_NO_DUALSTACK) != 0) {
 		tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
-		return -1;
+		return DNS_CACHE_TMOUT_ACTION_RETRY;
 	}
 
-	return 0;
+	return DNS_CACHE_TMOUT_ACTION_OK;
 }
 
-static int _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
+static dns_cache_tmout_action_t _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
 {
 	time_t ttl = _dns_server_expired_cache_ttl(dns_cache);
 	if (ttl <= 1) {
-		return -1;
+		return DNS_CACHE_TMOUT_ACTION_DEL;
 	}
 
 	/* start prefetch domain */
-	tlog(TLOG_DEBUG, "expired domain, prefetch by cache %s, qtype %d, ttl %llu, insert time %llu replace time %llu",
-		 dns_cache->info.domain, dns_cache->info.qtype, (unsigned long long)ttl,
-		 (unsigned long long)dns_cache->info.insert_time, (unsigned long long)dns_cache->info.replace_time);
+	tlog(TLOG_DEBUG,
+		 "expired domain, total %d, prefetch by cache %s, qtype %d, ttl %llu, rcode %d, insert time %llu replace time "
+		 "%llu",
+		 dns_cache_total_num(), dns_cache->info.domain, dns_cache->info.qtype, (unsigned long long)ttl,
+		 dns_cache->info.rcode, (unsigned long long)dns_cache->info.insert_time,
+		 (unsigned long long)dns_cache->info.replace_time);
 
 	struct dns_server_query_option server_query_option;
 	server_query_option.dns_group_name = dns_cache_get_dns_group_name(dns_cache);
@@ -6707,16 +6724,16 @@ static int _dns_server_prefetch_expired_domain(struct dns_cache *dns_cache)
 	if (_dns_server_prefetch_request(dns_cache->info.domain, dns_cache->info.qtype, &server_query_option,
 									 PREFETCH_FLAGS_EXPIRED) != 0) {
 		tlog(TLOG_DEBUG, "prefetch domain %s, qtype %d, failed.", dns_cache->info.domain, dns_cache->info.qtype);
-		return -1;
+		return DNS_CACHE_TMOUT_ACTION_RETRY;
 	}
 
-	return 0;
+	return DNS_CACHE_TMOUT_ACTION_OK;
 }
 
-static int _dns_server_cache_expired(struct dns_cache *dns_cache)
+static dns_cache_tmout_action_t _dns_server_cache_expired(struct dns_cache *dns_cache)
 {
 	if (dns_cache->info.rcode != DNS_RC_NOERROR) {
-		return -1;
+		return DNS_CACHE_TMOUT_ACTION_DEL;
 	}
 
 	if (dns_conf_prefetch == 1 && _dns_cache_is_specify_packet(dns_cache->info.qtype) != 0) {
@@ -6727,7 +6744,7 @@ static int _dns_server_cache_expired(struct dns_cache *dns_cache)
 		}
 	}
 
-	return -1;
+	return DNS_CACHE_TMOUT_ACTION_DEL;
 }
 
 static void _dns_server_tcp_idle_check(void)

+ 3 - 3
src/lib/timer_wheel.c

@@ -158,7 +158,7 @@ void tw_add_timer(struct tw_base *base, struct tw_timer_list *timer)
 
 	pthread_spin_lock(&base->lock);
 	{
-		timer->expires += base->jiffies;
+		timer->expires += base->jiffies - 1;
 		_tw_add_timer(base, timer);
 	}
 	pthread_spin_unlock(&base->lock);
@@ -190,7 +190,7 @@ int tw_mod_timer_pending(struct tw_base *base, struct tw_timer_list *timer, unsi
 
 	pthread_spin_lock(&base->lock);
 	{
-		timer->expires = expires + base->jiffies;
+		timer->expires = expires + base->jiffies - 1;
 		ret = __mod_timer(base, timer, 1);
 	}
 	pthread_spin_unlock(&base->lock);
@@ -208,7 +208,7 @@ int tw_mod_timer(struct tw_base *base, struct tw_timer_list *timer, unsigned lon
 			goto unblock;
 		}
 
-		timer->expires = expires + base->jiffies;
+		timer->expires = expires + base->jiffies - 1;
 
 		ret = __mod_timer(base, timer, 0);
 	}