Jelajahi Sumber

dns-client: fix tcp connect timeout issue.

Nick Peng 2 tahun lalu
induk
melakukan
995d5dce95
4 mengubah file dengan 191 tambahan dan 39 penghapusan
  1. 112 29
      src/dns_client.c
  2. 6 0
      src/dns_server.c
  3. 65 5
      src/tlog.c
  4. 8 5
      src/tlog.h

+ 112 - 29
src/dns_client.c

@@ -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,18 +3904,20 @@ static void *_dns_client_work(void *arg)
 				sleep_time = 0;
 				expect_time = now;
 			}
-			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();
+			/* 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);
-			continue;
+			expect_time += sleep;
 		}
-		pthread_mutex_unlock(&client.domain_map_lock);
+		last = now;
 
 		num = epoll_wait(client.epoll_fd, events, DNS_MAX_EVENTS, sleep_time);
 		if (num < 0) {
@@ -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;

+ 6 - 0
src/dns_server.c

@@ -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;
 			}
 		}

+ 65 - 5
src/tlog.c

@@ -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) {

+ 8 - 5
src/tlog.h

@@ -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 {