dns-client: fix tcp connect timeout issue.

This commit is contained in:
Nick Peng
2023-02-21 22:38:55 +08:00
parent c21be04632
commit 995d5dce95
4 changed files with 191 additions and 39 deletions

View File

@@ -41,13 +41,14 @@
#include <netinet/ip_icmp.h>
#include <netinet/tcp.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -196,7 +197,6 @@ struct dns_client {
/* query list */
struct list_head dns_request_list;
pthread_cond_t run_cond;
atomic_t run_period;
atomic_t dns_server_num;
@@ -208,6 +208,8 @@ struct dns_client {
pthread_mutex_t domain_map_lock;
DECLARE_HASHTABLE(domain_map, 6);
DECLARE_HASHTABLE(group, 4);
int fd_wakeup;
};
/* dns replied server info */
@@ -264,6 +266,8 @@ static pthread_mutex_t pending_server_mutex = PTHREAD_MUTEX_INITIALIZER;
static int dns_client_has_bootstrap_dns = 0;
static int _dns_client_send_udp(struct dns_server_info *server_info, void *packet, int len);
static void _dns_client_clear_wakeup_event(void);
static void _dns_client_do_wakeup_event(void);
static ssize_t _ssl_read(struct dns_server_info *server, void *buff, int num)
{
@@ -1337,9 +1341,8 @@ static int _dns_client_server_pending(char *server_ip, int port, dns_server_type
atomic_set(&client.run_period, 1);
pthread_mutex_unlock(&pending_server_mutex);
pthread_mutex_lock(&client.domain_map_lock);
pthread_cond_signal(&client.run_cond);
pthread_mutex_unlock(&client.domain_map_lock);
_dns_client_do_wakeup_event();
return 0;
errout:
if (pending) {
@@ -1514,7 +1517,7 @@ static void _dns_client_check_tcp(void)
}
if (server_info->status == DNS_SERVER_STATUS_CONNECTING) {
if (server_info->last_send + DNS_TCP_CONNECT_TIMEOUT < now) {
if (server_info->last_recv + DNS_TCP_CONNECT_TIMEOUT < now) {
tlog(TLOG_DEBUG, "server %s connect timeout.", server_info->ip);
_dns_client_close_socket(server_info);
}
@@ -3569,7 +3572,7 @@ int dns_client_query(const char *domain, int qtype, dns_client_callback callback
pthread_mutex_lock(&client.domain_map_lock);
if (hash_hashed(&query->domain_node)) {
if (list_empty(&client.dns_request_list)) {
pthread_cond_signal(&client.run_cond);
_dns_client_do_wakeup_event();
}
list_add_tail(&query->dns_request_list, &client.dns_request_list);
@@ -3818,15 +3821,12 @@ static void _dns_client_period_run_second(void)
_dns_client_add_pending_servers();
}
static void _dns_client_period_run(void)
static void _dns_client_period_run(unsigned int msec)
{
struct dns_query_struct *query = NULL;
struct dns_query_struct *tmp = NULL;
static unsigned int msec = 0;
msec++;
LIST_HEAD(check_list);
unsigned long now = get_tick_count();
/* get query which timed out to check list */
@@ -3869,9 +3869,11 @@ static void *_dns_client_work(void *arg)
int i = 0;
unsigned long now = {0};
unsigned long last = {0};
unsigned int msec = 0;
unsigned int sleep = 100;
int sleep_time = 0;
unsigned long expect_time = 0;
int unused __attribute__((unused));
sleep_time = sleep;
now = get_tick_count() - sleep;
@@ -3884,11 +3886,17 @@ static void *_dns_client_work(void *arg)
if (sleep_time <= 0) {
sleep_time = 0;
}
int cnt = sleep_time / sleep;
msec -= cnt;
expect_time -= cnt * sleep;
sleep_time -= cnt * sleep;
}
if (now >= expect_time) {
msec++;
if (last != now) {
_dns_client_period_run();
_dns_client_period_run(msec);
}
sleep_time = sleep - (now - expect_time);
@@ -3896,19 +3904,21 @@ static void *_dns_client_work(void *arg)
sleep_time = 0;
expect_time = now;
}
/* When client is idle, the sleep time is 1000ms, to reduce CPU usage */
pthread_mutex_lock(&client.domain_map_lock);
if (list_empty(&client.dns_request_list)) {
int cnt = 10 - (msec % 10) - 1;
sleep_time += sleep * cnt;
msec += cnt;
/* sleep to next second */
expect_time += sleep * cnt;
}
pthread_mutex_unlock(&client.domain_map_lock);
expect_time += sleep;
}
last = now;
pthread_mutex_lock(&client.domain_map_lock);
if (list_empty(&client.dns_request_list) && atomic_read(&client.run_period) == 0) {
pthread_cond_wait(&client.run_cond, &client.domain_map_lock);
expect_time = get_tick_count();
pthread_mutex_unlock(&client.domain_map_lock);
continue;
}
pthread_mutex_unlock(&client.domain_map_lock);
num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
if (num < 0) {
usleep(100000);
@@ -3918,6 +3928,11 @@ static void *_dns_client_work(void *arg)
for (i = 0; i < num; i++) {
struct epoll_event *event = &events[i];
struct dns_server_info *server_info = (struct dns_server_info *)event->data.ptr;
if (event->data.fd == client.fd_wakeup) {
_dns_client_clear_wakeup_event();
continue;
}
if (server_info == NULL) {
tlog(TLOG_WARN, "server info is invalid.");
continue;
@@ -3971,10 +3986,71 @@ int dns_client_set_ecs(char *ip, int subnet)
return 0;
}
static int _dns_client_create_wakeup_event(void)
{
int fd_wakeup = -1;
fd_wakeup = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
if (fd_wakeup < 0) {
tlog(TLOG_ERROR, "create eventfd failed, %s\n", strerror(errno));
goto errout;
}
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.fd = fd_wakeup;
if (epoll_ctl(client.epoll_fd, EPOLL_CTL_ADD, fd_wakeup, &event) < 0) {
tlog(TLOG_ERROR, "add eventfd to epoll failed, %s\n", strerror(errno));
goto errout;
}
return fd_wakeup;
errout:
if (fd_wakeup > 0) {
close(fd_wakeup);
}
return -1;
}
static void _dns_client_close_wakeup_event(void)
{
if (client.fd_wakeup > 0) {
close(client.fd_wakeup);
client.fd_wakeup = -1;
}
}
static void _dns_client_clear_wakeup_event(void)
{
uint64_t val = 0;
int unused __attribute__((unused));
if (client.fd_wakeup <= 0) {
return;
}
unused = read(client.fd_wakeup, &val, sizeof(val));
}
static void _dns_client_do_wakeup_event(void)
{
uint64_t val = 1;
int unused __attribute__((unused));
if (client.fd_wakeup <= 0) {
return;
}
unused = write(client.fd_wakeup, &val, sizeof(val));
}
int dns_client_init(void)
{
pthread_attr_t attr;
int epollfd = -1;
int fd_wakeup = -1;
int ret = 0;
if (client.epoll_fd > 0) {
@@ -4002,8 +4078,6 @@ int dns_client_init(void)
hash_init(client.group);
INIT_LIST_HEAD(&client.dns_request_list);
pthread_cond_init(&client.run_cond, NULL);
if (dns_client_add_group(DNS_SERVER_GROUP_DEFAULT) != 0) {
tlog(TLOG_ERROR, "add default server group failed.");
goto errout;
@@ -4020,6 +4094,14 @@ int dns_client_init(void)
goto errout;
}
fd_wakeup = _dns_client_create_wakeup_event();
if (fd_wakeup < 0) {
tlog(TLOG_ERROR, "create wakeup event failed, %s\n", strerror(errno));
goto errout;
}
client.fd_wakeup = fd_wakeup;
return 0;
errout:
if (client.tid) {
@@ -4029,13 +4111,16 @@ errout:
client.tid = 0;
}
if (epollfd) {
if (epollfd > 0) {
close(epollfd);
}
if (fd_wakeup > 0) {
close(fd_wakeup);
}
pthread_mutex_destroy(&client.server_list_lock);
pthread_mutex_destroy(&client.domain_map_lock);
pthread_cond_destroy(&client.run_cond);
return -1;
}
@@ -4045,14 +4130,13 @@ void dns_client_exit(void)
if (client.tid) {
void *ret = NULL;
atomic_set(&client.run, 0);
pthread_mutex_lock(&client.domain_map_lock);
pthread_cond_signal(&client.run_cond);
pthread_mutex_unlock(&client.domain_map_lock);
_dns_client_do_wakeup_event();
pthread_join(client.tid, &ret);
client.tid = 0;
}
/* free all resources */
_dns_client_close_wakeup_event();
_dns_client_remove_all_pending_servers();
_dns_client_server_remove_all();
_dns_client_query_remove_all();
@@ -4060,7 +4144,6 @@ void dns_client_exit(void)
pthread_mutex_destroy(&client.server_list_lock);
pthread_mutex_destroy(&client.domain_map_lock);
pthread_cond_destroy(&client.run_cond);
if (client.ssl_ctx) {
SSL_CTX_free(client.ssl_ctx);
client.ssl_ctx = NULL;

View File

@@ -2948,6 +2948,12 @@ static int _dns_server_passthrough_rule_check(struct dns_request *request, const
dns_get_CNAME(rrs, name, DNS_MAX_CNAME_LEN, &ttl, cname, DNS_MAX_CNAME_LEN);
} break;
default:
if (ttl == 0) {
/* Get TTL */
char tmpname[DNS_MAX_CNAME_LEN];
char tmpbuf[DNS_MAX_CNAME_LEN];
dns_get_CNAME(rrs, tmpname, DNS_MAX_CNAME_LEN, &ttl, tmpbuf, DNS_MAX_CNAME_LEN);
}
break;
}
}

View File

@@ -110,6 +110,7 @@ struct tlog {
tlog_log_output_func output_func;
struct tlog_log *wait_on_log;
int is_wait;
char gzip_cmd[PATH_MAX];
};
struct tlog_segment_log_head {
@@ -520,7 +521,7 @@ static int _tlog_vprintf(struct tlog_log *log, vprint_callback print_callback, v
return -1;
}
if (unlikely(log->logcount <= 0 && log->logscreen == 0) ) {
if (unlikely(log->logcount <= 0 && log->logscreen == 0)) {
return 0;
}
@@ -1018,7 +1019,6 @@ errout:
static int _tlog_archive_log_compressed(struct tlog_log *log)
{
char gzip_file[TLOG_BUFF_LEN];
char gzip_cmd[PATH_MAX * 2];
char log_file[TLOG_BUFF_LEN];
char pending_file[TLOG_BUFF_LEN];
@@ -1046,12 +1046,11 @@ static int _tlog_archive_log_compressed(struct tlog_log *log)
}
/* start gzip process to compress log file */
snprintf(gzip_cmd, sizeof(gzip_cmd), "gzip -1 %s", pending_file);
if (log->zip_pid <= 0) {
int pid = vfork();
if (pid == 0) {
_tlog_close_all_fd();
execl("/bin/sh", "sh", "-c", gzip_cmd, NULL);
execl(tlog.gzip_cmd, "-1", pending_file, NULL);
_exit(1);
} else if (pid < 0) {
goto errout;
@@ -1363,12 +1362,26 @@ static struct tlog_log *_tlog_wait_log_locked(struct tlog_log *last_log)
int ret = 0;
struct timespec tm;
struct tlog_log *log = NULL;
struct tlog_log *next = NULL;
int need_wait_pid = 0;
for (next = tlog.log; next != NULL; next = next->next) {
if (next->zip_pid > 0) {
need_wait_pid = 1;
break;
}
}
clock_gettime(CLOCK_REALTIME, &tm);
tm.tv_sec += 2;
tlog.is_wait = 1;
tlog.wait_on_log = last_log;
ret = pthread_cond_timedwait(&tlog.cond, &tlog.lock, &tm);
if (need_wait_pid != 0) {
ret = pthread_cond_timedwait(&tlog.cond, &tlog.lock, &tm);
} else {
ret = pthread_cond_wait(&tlog.cond, &tlog.lock);
}
tlog.is_wait = 0;
tlog.wait_on_log = NULL;
errno = ret;
@@ -1676,6 +1689,15 @@ int tlog_setlevel(tlog_level level)
return 0;
}
int tlog_log_enabled(tlog_level level)
{
if (level >= TLOG_END) {
return 0;
}
return (tlog_set_level >= level) ? 1 : 0;
}
tlog_level tlog_getlevel(void)
{
return tlog_set_level;
@@ -1686,6 +1708,35 @@ void tlog_set_logfile(const char *logfile)
tlog_rename_logfile(tlog.root, logfile);
}
static void _tlog_get_gzip_cmd_path(void)
{
char *copy_path = NULL;
char gzip_cmd_path[PATH_MAX];
const char *env_path = getenv("PATH");
char *save_ptr = NULL;
if (env_path == NULL) {
env_path = "/bin:/usr/bin:/usr/local/bin";
}
copy_path = strdup(env_path);
if (copy_path == NULL) {
return;
}
for (char *tok = strtok_r(copy_path, ":", &save_ptr); tok; tok = strtok_r(NULL, ":", &save_ptr)) {
snprintf(gzip_cmd_path, sizeof(gzip_cmd_path), "%s/gzip", tok);
if (access(gzip_cmd_path, X_OK) != 0) {
continue;
}
snprintf(tlog.gzip_cmd, sizeof(tlog.gzip_cmd), "%s", gzip_cmd_path);
break;
}
free(copy_path);
}
tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int buffsize, unsigned int flag)
{
struct tlog_log *log = NULL;
@@ -1726,6 +1777,10 @@ tlog_log *tlog_open(const char *logfile, int maxlogsize, int maxlogcount, int bu
log->file_perm = S_IRUSR | S_IWUSR | S_IRGRP;
log->archive_perm = S_IRUSR | S_IRGRP;
if (log->nocompress == 0 && tlog.gzip_cmd[0] == '\0') {
log->nocompress = 1;
}
tlog_rename_logfile(log, logfile);
if (log->nocompress) {
strncpy(log->suffix, TLOG_SUFFIX_LOG, sizeof(log->suffix));
@@ -1859,6 +1914,7 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
memset(&tlog, 0, sizeof(tlog));
tlog.is_wait = 0;
_tlog_get_gzip_cmd_path();
pthread_attr_init(&attr);
pthread_cond_init(&tlog.cond, NULL);
pthread_mutex_init(&tlog.lock, NULL);
@@ -1871,6 +1927,10 @@ int tlog_init(const char *logfile, int maxlogsize, int maxlogcount, int buffsize
}
tlog_reg_output_func(log, _tlog_root_write_log);
if ((flag & TLOG_NOCOMPRESS) == 0 && tlog.gzip_cmd[0] == '\0') {
fprintf(stderr, "can not find gzip command, disable compress.\n");
}
tlog.root = log;
ret = pthread_create(&tlog.tid, &attr, _tlog_work, NULL);
if (ret != 0) {

View File

@@ -79,9 +79,9 @@ level: Current log Levels
format: Log formats
*/
#ifndef BASE_FILE_NAME
#define BASE_FILE_NAME \
(__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \
: __FILE__)
#define BASE_FILE_NAME \
(__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 \
: __FILE__)
#endif
#define tlog(level, format, ...) tlog_ext(level, BASE_FILE_NAME, __LINE__, __func__, NULL, format, ##__VA_ARGS__)
@@ -95,6 +95,9 @@ extern int tlog_write_log(char *buff, int bufflen);
/* set log level */
extern int tlog_setlevel(tlog_level level);
/* is log level enabled*/
extern int tlog_log_enabled(tlog_level level);
/* get log level */
extern tlog_level tlog_getlevel(void);
@@ -137,7 +140,7 @@ read _tlog_format for example.
typedef int (*tlog_format_func)(char *buff, int maxlen, struct tlog_loginfo *info, void *userptr, const char *format, va_list ap);
extern int tlog_reg_format_func(tlog_format_func func);
/* register log output callback
/* register log output callback
Note: info is invalid when flag TLOG_SEGMENT is not set.
*/
typedef int (*tlog_log_output_func)(struct tlog_loginfo *info, const char *buff, int bufflen, void *private_data);
@@ -213,7 +216,7 @@ file: log file permission, default is 640
archive: archive file permission, default is 440
*/
extern void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive);
extern void tlog_set_permission(struct tlog_log *log, mode_t file, mode_t archive);
#ifdef __cplusplus
class Tlog {