From 63db66546cbd8369903f033bf0f58199d49353a4 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Fri, 15 Mar 2019 00:33:44 +0800 Subject: [PATCH] Fix cache leak issue --- src/dns_cache.c | 29 ++++++++++++++++------------- src/dns_cache.h | 2 +- src/dns_client.c | 2 +- src/dns_server.c | 20 +++++++++++++++----- 4 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/dns_cache.c b/src/dns_cache.c index 5031234..ecd04e9 100644 --- a/src/dns_cache.c +++ b/src/dns_cache.c @@ -5,7 +5,7 @@ struct dns_cache_head { DECLARE_HASHTABLE(cache_hash, 10); struct list_head cache_list; - int num; + atomic_t num; int size; pthread_mutex_t lock; }; @@ -16,7 +16,7 @@ int dns_cache_init(int size) { INIT_LIST_HEAD(&dns_cache_head.cache_list); hash_init(dns_cache_head.cache_hash); - dns_cache_head.num = 0; + atomic_set(&dns_cache_head.num, 0); dns_cache_head.size = size; pthread_mutex_init(&dns_cache_head.lock, NULL); @@ -38,7 +38,7 @@ static void _dns_cache_delete(struct dns_cache *dns_cache) { hash_del(&dns_cache->node); list_del_init(&dns_cache->list); - dns_cache_head.num--; + atomic_dec(&dns_cache_head.num); free(dns_cache); } @@ -52,6 +52,9 @@ void dns_cache_get(struct dns_cache *dns_cache) void dns_cache_release(struct dns_cache *dns_cache) { + if (dns_cache == NULL) { + return; + } if (!atomic_dec_and_test(&dns_cache->ref)) { return; } @@ -92,30 +95,31 @@ int dns_cache_replace(char *domain, char *cname, int cname_ttl, int ttl, dns_typ dns_cache->del_pending = 0; dns_cache->speed = speed; time(&dns_cache->insert_time); - pthread_mutex_unlock(&dns_cache_head.lock); if (qtype == DNS_T_A) { if (addr_len != DNS_RR_A_LEN) { - goto errout; + goto errout_unlock; } memcpy(dns_cache->addr, addr, DNS_RR_A_LEN); } else if (qtype == DNS_T_AAAA) { if (addr_len != DNS_RR_AAAA_LEN) { - goto errout; + goto errout_unlock; } memcpy(dns_cache->addr, addr, DNS_RR_AAAA_LEN); } else { - goto errout; + goto errout_unlock; } if (cname) { strncpy(dns_cache->cname, cname, DNS_MAX_CNAME_LEN); dns_cache->cname_ttl = cname_ttl; } + pthread_mutex_unlock(&dns_cache_head.lock); dns_cache_release(dns_cache); return 0; - -errout: +errout_unlock: + pthread_mutex_unlock(&dns_cache_head.lock); +//errout: if (dns_cache) { dns_cache_release(dns_cache); } @@ -154,7 +158,7 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type dns_cache->cname[0] = 0; dns_cache->qtype = qtype; dns_cache->ttl = ttl; - dns_cache->hitnum = 2; + atomic_set(&dns_cache->hitnum, 2); dns_cache->del_pending = 0; dns_cache->speed = speed; atomic_set(&dns_cache->ref, 1); @@ -183,9 +187,8 @@ int dns_cache_insert(char *domain, char *cname, int cname_ttl, int ttl, dns_type list_add_tail(&dns_cache->list, &dns_cache_head.cache_list); INIT_LIST_HEAD(&dns_cache->check_list); - dns_cache_head.num++; /* Release extra cache, remove oldest cache record */ - if (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; del_cache = _dns_cache_first(); if (del_cache) { @@ -276,7 +279,7 @@ void dns_cache_update(struct dns_cache *dns_cache) 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->hitnum++; + atomic_inc(&dns_cache->hitnum); } pthread_mutex_unlock(&dns_cache_head.lock); } diff --git a/src/dns_cache.h b/src/dns_cache.h index 8bf1bfd..cff4d11 100644 --- a/src/dns_cache.h +++ b/src/dns_cache.h @@ -21,7 +21,7 @@ struct dns_cache { unsigned int cname_ttl; unsigned int ttl;; int speed; - int hitnum; + atomic_t hitnum; int del_pending; time_t insert_time; dns_type_t qtype; diff --git a/src/dns_client.c b/src/dns_client.c index fdaaea9..5e49fa3 100644 --- a/src/dns_client.c +++ b/src/dns_client.c @@ -1270,7 +1270,7 @@ static int _DNS_client_create_socket_tls(struct dns_server_info *server_info) if (connect(fd, (struct sockaddr *)&server_info->addr, server_info->ai_addrlen) != 0) { if (errno != EINPROGRESS) { - tlog(TLOG_ERROR, "connect failed."); + tlog(TLOG_ERROR, "connect %s failed, %s", server_info->ip, strerror(errno)); goto errout; } } diff --git a/src/dns_server.c b/src/dns_server.c index 15d063a..50f5f61 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -1467,6 +1467,7 @@ errout: static int _dns_server_process_cache(struct dns_request *request, struct dns_packet *packet) { struct dns_cache *dns_cache = NULL; + struct dns_cache *dns_cache_A = NULL; dns_cache = dns_cache_lookup(request->domain, request->qtype); if (dns_cache == NULL) { @@ -1478,10 +1479,12 @@ static int _dns_server_process_cache(struct dns_request *request, struct dns_pac } if (dns_conf_dualstack_ip_selection && request->qtype == DNS_T_AAAA) { - struct dns_cache *dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A); + dns_cache_A = dns_cache_lookup(request->domain, DNS_T_A); if (dns_cache_A && (dns_cache_A->speed > 0)) { if ((dns_cache_A->speed + (dns_conf_dualstack_ip_selection_threshold * 10)) < dns_cache->speed || dns_cache->speed < 0) { tlog(TLOG_DEBUG, "Force IPV4 perfered."); + dns_cache_release(dns_cache_A); + dns_cache_release(dns_cache); return _dns_server_reply_SOA(DNS_RC_NOERROR, request, NULL); } } @@ -1515,11 +1518,20 @@ static int _dns_server_process_cache(struct dns_request *request, struct dns_pac dns_cache_update(dns_cache); dns_cache_release(dns_cache); + if (dns_cache_A) { + dns_cache_release(dns_cache_A); + dns_cache_A = NULL; + } + return 0; errout: if (dns_cache) { dns_cache_release(dns_cache); } + if (dns_cache_A) { + dns_cache_release(dns_cache_A); + dns_cache_A = NULL; + } return -1; } @@ -2064,14 +2076,12 @@ static void _dns_server_tcp_ping_check(struct dns_request *request) static void _dns_server_prefetch_domain(struct dns_cache *dns_cache) { /* If there are still hits, continue pre-fetching */ - if (dns_cache->hitnum <= 0) { + if (atomic_dec_return(&dns_cache->hitnum) <= 0) { return; } - dns_cache->hitnum--; - /* start prefetch domain */ - tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->domain, dns_cache->qtype, dns_cache->ttl, dns_cache->hitnum); + tlog(TLOG_DEBUG, "prefetch by cache %s, qtype %d, ttl %d, hitnum %d", dns_cache->domain, dns_cache->qtype, dns_cache->ttl, atomic_read(&dns_cache->hitnum)); if (_dns_server_prefetch_request(dns_cache->domain, dns_cache->qtype) != 0) { tlog(TLOG_ERROR, "prefetch domain %s, qtype %d, failed.", dns_cache->domain, dns_cache->qtype); }